Compare commits

..
96 Commits
Author SHA1 Message Date
Riyyi cc33b5d481 Render+Asset: Fix derived Renderer2D, fix Skybox uniform 2024-08-31 19:54:23 +02:00
Riyyi 67bb6a5671 Render: Fix release build via out-of-line destructors 2024-08-31 00:29:03 +02:00
Riyyi 3ff8838e01 Render: Fix memory leak, use after free :^) 2024-08-30 23:02:28 +02:00
Riyyi 3ae6ecae8a Meta: Enable ASan and UBSan, disable warnings in vendor directory
(address sanitizer, undefined behavior sanitizer)
2024-08-29 22:15:13 +02:00
Riyyi 6b6c588378 Component: Put JSON serialization functions in a separate file 2024-08-25 21:10:03 +02:00
Riyyi 9145f90c1d Meta: Update ruc library 2024-08-25 13:26:04 +02:00
Riyyi b9043dbb4b Render: Add and implement shader storage buffer (SSBO) 2024-08-24 20:14:06 +02:00
Riyyi b6e68eccec Doc: Add GLSL std430 memory layout documentation 2024-08-20 21:31:01 +02:00
Riyyi d16fade497 Everywhere: Work towards lighting support 2024-08-19 17:56:57 +02:00
Riyyi b8e4d9ef3f Render: Allow arbitrary data in uniformbuffer objects 2024-08-19 17:41:31 +02:00
Riyyi 03e8210165 Event+Asset+Keycodes: Add keybind for taking screenshots 2024-08-17 21:05:43 +02:00
Riyyi dcf2a85208 Asset+Component+Render: Render quads in the world as 3D objects 2024-08-11 22:06:55 +02:00
Riyyi b2ed951b1e Render: Add more value setter types for uniformbuffer objects 2024-08-11 22:06:55 +02:00
Riyyi d63dfe2f9f Render: Update getter to match naming convention 2024-08-10 22:05:21 +02:00
Riyyi faacdca424 App: Print average frame-time on exit 2024-08-10 21:58:50 +02:00
Riyyi b5f3cae5ba Render+Scene: Implement uniformbuffer objects 2024-08-10 21:58:50 +02:00
Riyyi 1d5f5a1ad8 Shader: Cache uniform location lookup 2024-08-09 23:10:39 +02:00
Riyyi 3cd2fab637 Render: Add support for int/double shader attributes 2024-08-07 21:52:13 +02:00
Riyyi c5ed219ad2 Render: Dont create double framebuffers 2024-08-05 19:26:38 +02:00
Riyyi 4dbac7ee38 Render: Make Framebuffer class more flexible 2024-08-05 19:24:38 +02:00
Riyyi a5b7a49447 Render: Make Framebuffer class more flexible 2024-08-05 19:12:39 +02:00
Riyyi fd72f6610e Render: Change RenderCommand::clearBit function 2024-08-05 15:19:16 +02:00
Riyyi 21319b93ad Render: Cleanup buffer 2024-08-05 11:24:52 +02:00
Riyyi cd36841039 Asset+Render+App: Implement render to framebuffer 2024-08-04 20:54:57 +02:00
Riyyi 538d0b5ce7 Asset+Render: Add Framebuffers 2024-08-03 22:41:23 +02:00
Riyyi 5f6a5f48dd Asset+Component+Render: Fix assimp modeling loading + batching 2024-08-02 02:08:12 +02:00
Riyyi c06b06ed62 Scene+System: Enable model loading 2024-05-13 14:20:42 +02:00
Riyyi 5721b4249c Asset: Add 3D shader 2024-05-13 14:15:37 +02:00
Riyyi 95a64be4cd Renderer: Implement 3D 2024-05-13 14:14:36 +02:00
Riyyi 79b4f1c3d1 Asset: Implement assimp texture loading 2024-05-13 14:05:21 +02:00
Riyyi a266a27f88 Asset+Component: Add model component and asset 2024-05-13 14:05:05 +02:00
Riyyi 08969e32d1 Meta: Add assimp dependency 2024-05-13 13:56:48 +02:00
Riyyi 2793956be4 Render+Asset: De-duplicate different manager classes into one for assets 2024-04-29 13:36:49 +02:00
Riyyi 51c5874318 Add license file for glad 2024-04-20 16:51:32 +02:00
Riyyi d01a4429ca Renderer: Rename Character -> Font/Symbol 2024-01-20 00:17:15 +01:00
Riyyi d22effdfa3 Renderer: De-duplicate code between renderer types 2024-01-20 00:15:24 +01:00
Riyyi 52611beeab Renderer: Move RenderCommand to separate file 2024-01-14 20:24:17 +01:00
Riyyi fd8973d10d Engine: Implement skybox 2024-01-07 16:37:42 +01:00
Riyyi bc3f2c9db5 Component+Scene+System: Implement parent-child transform components 2024-01-05 20:50:49 +01:00
Riyyi 0dd7a05d46 Component+Scene: Restructure scene .json to allow multiple components 2024-01-01 13:10:20 +01:00
Riyyi c607ebcc72 Engine: Do not use offset for character advance 2023-12-29 22:53:29 +01:00
Riyyi 15b71f8387 Engine: Allow configuration of font size and line spacing 2023-12-29 22:12:13 +01:00
Riyyi 6e5f82913e Script: Add missing macro CONCAT 2023-12-26 22:06:02 +01:00
Riyyi d02d5a528b Assets: Add text entity to example scene1.json 2023-12-26 13:07:56 +01:00
Riyyi 574f2a8b5a Engine: Fix font spacing in TextAreaComponent 2023-12-26 01:31:12 +01:00
Riyyi 2b0635ed69 Meta: Assets in separate CMakeLists.txt 2023-12-18 21:50:10 +01:00
Riyyi 649d196577 Script+System: Allow native scripts from projects, decoupled from engine 2023-12-03 20:05:21 +01:00
Riyyi f47babe5cf Engine: Add ability to set camera zoom-level via scene JSON 2022-10-16 12:44:35 +02:00
Riyyi efae5b9adb Engine: Add Scene::findEntity() function 2022-10-16 11:39:19 +02:00
Riyyi a1b02c2e3a Meta: Update ruc library 2022-10-15 11:33:19 +02:00
Riyyi e926d3ce4a CMake: Link against ruc-test library 2022-09-28 14:36:44 +02:00
Riyyi 4c479cfb64 Meta: Update ruc library 2022-09-28 14:34:17 +02:00
Riyyi cf0a20e208 Engine: Add scene getter 2022-09-28 14:20:28 +02:00
Riyyi 55af11d831 Engine: Add constructor for raw data texture 2022-09-28 14:15:52 +02:00
Riyyi 26cd35d679 CMake: Populate list of required include directories for library targets
PUBLIC items will populate the INTERFACE_INCLUDE_DIRECTORIES property of
<target>. This property is a list of public include directories
requirements for a library.

Targets may populate this property to publish the include directories
required to compile against the headers for the target.
2022-09-28 14:05:02 +02:00
Riyyi 6972128ad2 Assets: Remove font from test scene, as font assets aren't added yet 2022-09-27 13:12:13 +02:00
Riyyi c858ef3b1d CMake: Always copy assets to build directory, fixes example: $ make run 2022-09-27 13:10:33 +02:00
Riyyi 3d22334be9 Meta: Update debugging path to example executable 2022-09-27 12:32:02 +02:00
Riyyi 9d26f20bde Script: Prefer using script files from the ruc library 2022-09-27 12:28:57 +02:00
Riyyi 0305b2c464 Doc: Update git submodule instructions in readme 2022-09-27 12:23:31 +02:00
Riyyi 17e3a8a5eb CMake: Copy assets to the build directory automatically 2022-09-27 12:12:03 +02:00
Riyyi 85b222984d Meta: Remove nlohmann/json dependency 2022-09-26 22:37:25 +02:00
Riyyi 124479876b Engine: Make event handle functions virtual 2022-09-26 14:19:49 +02:00
Riyyi aec1a80623 Engine: Rename getWindow() => window() 2022-09-26 14:18:34 +02:00
Riyyi ae8bb46a7d Engine+Example: Improve entrypoint via manual singleton 2022-09-26 13:07:05 +02:00
Riyyi 1dcb25ea5e CMake: Change include directories to use relative path 2022-09-26 13:00:00 +02:00
Riyyi 10a5b70520 Engine: Comment out text-area test code 2022-09-26 13:00:00 +02:00
Riyyi 67b4eb0cc0 Scene: Load text-areas from JSON 2022-09-26 13:00:00 +02:00
Riyyi e1d88a1872 Component: Add ability to load TextAreaComponent from JSON 2022-09-26 13:00:00 +02:00
Riyyi 3db5845bb4 Scene: Load quads from JSON 2022-09-26 13:00:00 +02:00
Riyyi c7a8f92970 Component: Add ability to read SpriteComponent from JSON 2022-09-26 13:00:00 +02:00
Riyyi 892be89728 Scene: Load camera from JSON 2022-09-26 13:00:00 +02:00
Riyyi c2c5777566 Component: Add ability to read TransformComponent from JSON 2022-09-26 13:00:00 +02:00
Riyyi aedb1a5fc9 Everywhere: Add copyright headers 2022-09-26 13:00:00 +02:00
Riyyi 2ab555af5e Engine: Remove unused utility classes 2022-09-26 13:00:00 +02:00
Riyyi 01e5179ec7 Engine: Update std::stou, remove need for intToHex() 2022-09-26 13:00:00 +02:00
Riyyi 324da69bb2 Engine: Remove unnecessary unused warning suppressions 2022-09-26 13:00:00 +02:00
Riyyi f44c82d06e Engine: Add function for finding key names 2022-09-26 13:00:00 +02:00
Riyyi 8a03d84580 Engine: Switch inferno/io/log.h => ruc/format/log.h 2022-09-26 13:00:00 +02:00
Riyyi f61f402116 Engine: Switch to ruc::File 2022-09-26 13:00:00 +02:00
Riyyi 470f90fbdd Engine: Switch inferno core.h => ruc core.h 2022-09-26 13:00:00 +02:00
Riyyi 6302bb4ae1 Engine: Make sure glad gets included before GLFW in context 2022-09-26 13:00:00 +02:00
Riyyi b72da1278d Engine: Run clang-format 2022-09-26 13:00:00 +02:00
Riyyi 3da83e9cea Meta: Bump C++ version to 20 in .clang-format 2022-09-26 13:00:00 +02:00
Riyyi 766f24d6b9 Engine: Switch to ASSERT macro to ruc's VERIFY 2022-09-26 13:00:00 +02:00
Riyyi 722bdd82b1 Engine: Change include guards to #pragma once 2022-09-26 13:00:00 +02:00
Riyyi 4af037a7fb Engine: Switch to ruc's singleton 2022-09-26 13:00:00 +02:00
Riyyi 2f1c6b5e75 Engine: Make it compile again 2022-09-26 13:00:00 +02:00
Riyyi 478dccd3df Meta+CMake: Add ruc library 2022-09-26 13:00:00 +02:00
Riyyi edc0ef7203 Everywhere: Update work in progress 2022-09-16 20:22:08 +02:00
Riyyi 6b0095dadf CMake: Move source directory to project root 2022-09-16 20:15:49 +02:00
Riyyi 4468b1ffb9 CMake: Move vendor directory to the project root 2022-09-16 19:16:53 +02:00
Riyyi 90bfd30f7f CMake: Move engine source compilation to separate file 2022-09-16 17:12:57 +02:00
Riyyi ed935e50cd CMake: Automatically build examples during standalone compilation 2022-09-16 12:46:44 +02:00
Riyyi 8b11e51109 CMake: Restructure main file, move example to its own directory 2022-09-16 12:41:08 +02:00
Riyyi da757365d0 CMake: Exclude unnecessary lua files from compilation 2022-09-16 11:14:09 +02:00
222 changed files with 10256 additions and 6573 deletions
+5 -1
View File
@@ -14,14 +14,17 @@ AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortLambdasOnASingleLine: All
AlwaysBreakTemplateDeclarations: Yes
IndentPPDirectives: BeforeHash
BraceWrapping:
AfterEnum: false
AfterFunction: true
BeforeCatch: true
BeforeElse: true
BeforeLambdaBody: false
SplitEmptyRecord: false
BreakBeforeBraces: Custom
BreakInheritanceList: BeforeComma
@@ -29,7 +32,8 @@ BreakInheritanceList: BeforeComma
SpaceAfterTemplateKeyword: false
SpaceInEmptyBlock: false
NamespaceIndentation: None
Standard: c++11
FixNamespaceComments: true
Standard: c++20
TabWidth: 4
UseTab: AlignWithSpaces
...
+12 -9
View File
@@ -1,21 +1,24 @@
[submodule "inferno/vendor/glfw"]
path = inferno/vendor/glfw
path = vendor/glfw
url = https://github.com/glfw/glfw
[submodule "inferno/vendor/glm"]
path = inferno/vendor/glm
path = vendor/glm
url = https://github.com/g-truc/glm
[submodule "inferno/vendor/json"]
path = inferno/vendor/json
url = https://github.com/nlohmann/json
[submodule "inferno/vendor/entt"]
path = inferno/vendor/entt
path = vendor/entt
url = https://github.com/skypjack/entt
[submodule "inferno/vendor/lua/lua"]
path = inferno/vendor/lua/lua
path = vendor/lua/lua
url = https://github.com/lua/lua
[submodule "inferno/vendor/sol2"]
path = inferno/vendor/sol2
path = vendor/sol2
url = https://github.com/ThePhD/sol2
[submodule "inferno/vendor/stb/stb"]
path = inferno/vendor/stb/stb
path = vendor/stb/stb
url = https://github.com/nothings/stb
[submodule "inferno/vendor/ruc"]
path = vendor/ruc
url = https://github.com/Riyyi/ruc
[submodule "inferno/vendor/assimp"]
path = vendor/assimp
url = https://github.com/assimp/assimp
+76 -99
View File
@@ -1,115 +1,92 @@
# User config between these lines
# ------------------------------------------
# User config between these lines
# Set engine name
set(ENGINE "inferno")
# Set project name
set(GAME "game")
# Set debugging, ON/OFF
set(DEBUG "ON")
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(INFERNO_STANDALONE TRUE)
endif()
# Options
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
option(INFERNO_BUILD_EXAMPLES "Build the Inferno example programs" ${INFERNO_STANDALONE})
option(INFERNO_BUILD_WARNINGS "Build with warnings enabled" ${INFERNO_STANDALONE})
# ------------------------------------------
# Add 'make run' target
add_custom_target(run
COMMAND ${GAME}
)
cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
project(${ENGINE} CXX C)
# ------------------------------------------
# Setup C++ compiler
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Compiler flags used for all build types
set(COMPILE_FLAGS_DEPS -w)
if(INFERNO_BUILD_WARNINGS)
set(COMPILE_FLAGS_PROJECT -Wall -Wextra -Wpedantic)
# -Wall = All warnings about contructions that are easily avoidable
# -Wextra = Extra warning flags not covered by -Wall
# -Wpedantic = Warnings for compiler extensions not part of the standard
else()
set(COMPILE_FLAGS_PROJECT ${COMPILE_FLAGS_DEPS})
endif()
# Set default build type if not specified
set(DEFAULT_BUILD_TYPE Release)
if(EXISTS ${CMAKE_SOURCE_DIR}/.git)
set(DEFAULT_BUILD_TYPE Debug)
endif()
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE ${DEFAULT_BUILD_TYPE})
endif()
# Set build type specific compiler flags
message("--- ${CMAKE_BUILD_TYPE} ---")
if(${CMAKE_BUILD_TYPE} STREQUAL Debug)
# Optimizations that do not interfere with debugging
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -Og")
# Produce debugging information in OS's native format
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -g")
# Generate profile information for analysis with gprof
# $ gprof <PROJECT> gmon.out > profile-data.txt
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -pg")
# Enable ASan (Address Sanitizer) and UBSan (Undefined Behavior Sanitizer)
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fsanitize=address,undefined")
# Do not omit frame pointer, which helps with debugging.
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fno-omit-frame-pointer")
elseif(${CMAKE_BUILD_TYPE} STREQUAL Release)
# Optimizations that increase compilation time and performance
string(APPEND CMAKE_CXX_FLAGS_RELEASE " -O3")
endif()
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Check if the build should include debugging symbols
option(DEBUG "" ${DEBUG})
if(DEBUG)
# cmake -DDEBUG=on .. && make
message("--- Debug ---")
set(CMAKE_BUILD_TYPE "Debug")
# ------------------------------------------
# Engine dependencies target
# -Og = Optimizations that do not interfere with debugging
# -Wall = All warnings about contructions that are easily avoidable
# -Wextra = Extra warning flags not covered by -Wall
# -g = Produce debugging information in OS's native format
# -pg = Generate profile information for analysis with gprof
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og -Wall -Wextra -g -pg")
# gprof <GAME> gmon.out > profile-data.txt
else()
# cmake -DDEBUG=off .. && make
message("--- Release ---")
set(CMAKE_BUILD_TYPE "Release")
# Add engine target to project
add_subdirectory("vendor")
# -O3 = Optimizations that increases compilation time and performance
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
# ------------------------------------------
# Engine target
# Add engine target to project
add_subdirectory("src")
# ------------------------------------------
# Assets target
add_subdirectory("assets")
# ------------------------------------------
# Examples target
if (INFERNO_BUILD_EXAMPLES)
# Add examples target to project
add_subdirectory("example")
endif()
# Include all headers
include_directories(
"${ENGINE}/src"
"${ENGINE}/vendor/entt/src"
"${ENGINE}/vendor/glad/include"
"${ENGINE}/vendor/glfw/include"
"${ENGINE}/vendor/glm"
"${ENGINE}/vendor/json/include"
"${ENGINE}/vendor/lua"
"${ENGINE}/vendor/sol2/include"
"${ENGINE}/vendor/stb"
)
# Define engine source files
file(GLOB_RECURSE GLAD "${ENGINE}/vendor/glad/*.c")
file(GLOB LUA "${ENGINE}/vendor/lua/lua/*.c")
list(REMOVE_ITEM LUA "${CMAKE_SOURCE_DIR}/${ENGINE}/vendor/lua/lua/lua.c") # Do not compile stand-alone main()
file(GLOB_RECURSE ENGINE_SOURCES "${ENGINE}/src/${ENGINE}/*.cpp")
set(ENGINE_SOURCES ${GLAD} ${LUA} ${ENGINE_SOURCES})
# Define game source files
file(GLOB_RECURSE GAME_SOURCES "${GAME}/src/*.cpp")
set(GAME_SOURCES ${GAME_SOURCES})
# ------------------------------------------
project(${ENGINE})
set(CMAKE_CXX_STANDARD 17)
# GLFW options
set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
# Add GLFW target to project
add_subdirectory(${ENGINE}/vendor/glfw)
add_library(${ENGINE} STATIC ${ENGINE_SOURCES})
target_link_libraries(${ENGINE} glfw)
# ------------------------------------------
project(${GAME})
set(CMAKE_CXX_STANDARD 17)
add_executable(${GAME} ${GAME_SOURCES})
target_link_libraries(${GAME} ${ENGINE})
# ------------------------------------------
target_precompile_headers(${ENGINE} PRIVATE
"$<$<COMPILE_LANGUAGE:CXX>:<algorithm$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<array$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<csignal$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<cstddef$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<cstdint$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<functional$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<iostream$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<memory$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<ostream$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<sstream$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<string$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<string_view$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<unordered_map$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<utility$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<vector$<ANGLE-R>>"
)
target_precompile_headers(${GAME} REUSE_FROM ${ENGINE})
+7 -5
View File
@@ -7,14 +7,13 @@ Inferno game engine project.
** Clone
#+BEGIN_SRC sh
$ git clone https://gitlab.com/riyyi/inferno
$ git clone https://github.com/riyyi/inferno
$ cd inferno
$ git submodule init
$ git submodule update
$ git submodule update --init --recursive
#+END_SRC
Or
#+BEGIN_SRC sh
$ git clone --recursive https://gitlab.com/riyyi/inferno
$ git clone --recursive https://github.com/riyyi/inferno
#+END_SRC
** Update
@@ -34,13 +33,14 @@ Or
* Libraries
- [[https://github.com/assimp/assimp][assimp]]
# - [[https://github.com/bulletphysics/bullet3][Bullet]]
- [[https://github.com/skypjack/entt][EnTT]]
- [[https://github.com/Dav1dde/glad][glad]]
- [[https://github.com/glfw/glfw][GLFW]]
- [[https://github.com/g-truc/glm][GLM]]
- [[https://github.com/nlohmann/json][JSON]]
- [[https://github.com/lua/lua][Lua]]
- [[https://github.com/riyyi/ruc][ruc]]
- [[https://github.com/ThePhD/sol2][sol3]]
- [[https://github.com/nothings/stb][stb]]
@@ -49,3 +49,5 @@ Or
- [[https://www.glfw.org/docs/latest/build_guide.html#build_link_cmake_source][Build GLFW using CMake]]
- [[https://learnopengl.com][Learn OpenGL]]
- [[https://www.youtube.com/playlist?list=PLlrATfBNZ98dC-V-N3m0Go4deliWHPFwT][Game Engine]] by The Cherno
- [[https://www.youtube.com/watch?v=mnIQEQoHHCU][OpenGL 3D Game Tutorial 32: Font Rendering]]
- [[https://youtu.be/d8cfgcJR9Tk][OpenGL 3D Game Tutorial 33: Distance Field Text Rendering]]
+4
View File
@@ -0,0 +1,4 @@
add_custom_target(${ENGINE}-assets
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/copy-assets.cmake
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
add_dependencies(${ENGINE} ${ENGINE}-assets)
+87
View File
@@ -0,0 +1,87 @@
SIL OPEN FONT LICENSE
Version 1.1, 26 February 2007
Copyright (C) 2010-2023 Steve Matteson
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide development
of collaborative font projects, to support the font creation efforts of academic
and linguistic communities, and to provide a free and open framework in which
fonts may be shared and improved in partnership with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The fonts,
including any derivative works, can be bundled, embedded, redistributed and/or
sold with any software provided that any reserved names are not used by
derivative works. The fonts and derivatives, however, cannot be released under
any other type of license. The requirement for fonts to remain under this
license does not apply to any document created using the fonts or their
derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright Holder(s)
under this license and clearly marked as such. This may include source files,
build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the copyright
statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting, or
substituting in part or in whole any of the components of the Original
Version, by changing formats or by porting the Font Software to a new
environment.
"Author" refers to any designer, engineer, programmer, technical writer or other
person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining a copy of
the Font Software, to use, study, copy, merge, embed, modify, redistribute, and
sell modified and unmodified copies of the Font Software, subject to the
following conditions:
Neither the Font Software nor any of its individual components, in Original
or Modified Versions, may be sold by itself.
Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be included
either as stand-alone text files, human-readable headers or in the
appropriate machine-readable metadata fields within text or binary files as
long as those fields can be easily viewed by the user.
No Modified Version of the Font Software may use the Reserved Font Name(s)
unless explicit written permission is granted by the corresponding Copyright
Holder. This restriction only applies to the primary font name as presented
to the users.
The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software
shall not be used to promote, endorse or advertise any Modified Version,
except to acknowledge the contribution(s) of the Copyright Holder(s) and the
Author(s) or with their explicit written permission.
The Font Software, modified or unmodified, in part or in whole, must be
distributed entirely under this license, and must not be distributed under
any other license. The requirement for fonts to remain under this license
does not apply to any document created using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR
OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT,
INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR
FROM OTHER DEALINGS IN THE FONT SOFTWARE.
+415
View File
@@ -0,0 +1,415 @@
info face="Open Sans Regular" size=62 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=8,8,8,8 spacing=-2,-20
common lineHeight=82 base=67 scaleW=512 scaleH=512 pages=1 packed=0
page id=0 file="open-sans.png"
chars count=97
char id=0 x=377 y=326 width=41 height=60 xoffset=-2 yoffset=15 xadvance=51 page=0 chnl=0
char id=10 x=0 y=0 width=0 height=0 xoffset=-8 yoffset=0 xadvance=14 page=0 chnl=0
char id=32 x=0 y=0 width=0 height=0 xoffset=-8 yoffset=0 xadvance=30 page=0 chnl=0
char id=33 x=142 y=205 width=24 height=61 xoffset=-4 yoffset=15 xadvance=31 page=0 chnl=0
char id=34 x=319 y=437 width=33 height=32 xoffset=-4 yoffset=15 xadvance=39 page=0 chnl=0
char id=35 x=323 y=326 width=54 height=60 xoffset=-7 yoffset=15 xadvance=54 page=0 chnl=0
char id=36 x=349 y=0 width=44 height=67 xoffset=-5 yoffset=12 xadvance=49 page=0 chnl=0
char id=37 x=372 y=143 width=61 height=62 xoffset=-5 yoffset=14 xadvance=65 page=0 chnl=0
char id=38 x=433 y=143 width=58 height=62 xoffset=-5 yoffset=14 xadvance=59 page=0 chnl=0
char id=39 x=352 y=437 width=22 height=32 xoffset=-4 yoffset=15 xadvance=28 page=0 chnl=0
char id=40 x=151 y=0 width=31 height=70 xoffset=-6 yoffset=15 xadvance=32 page=0 chnl=0
char id=41 x=182 y=0 width=31 height=70 xoffset=-7 yoffset=15 xadvance=32 page=0 chnl=0
char id=42 x=273 y=437 width=46 height=44 xoffset=-6 yoffset=12 xadvance=48 page=0 chnl=0
char id=43 x=178 y=437 width=47 height=47 xoffset=-6 yoffset=22 xadvance=49 page=0 chnl=0
char id=44 x=419 y=437 width=26 height=31 xoffset=-7 yoffset=52 xadvance=29 page=0 chnl=0
char id=45 x=45 y=486 width=32 height=21 xoffset=-6 yoffset=40 xadvance=34 page=0 chnl=0
char id=46 x=474 y=437 width=25 height=25 xoffset=-4 yoffset=51 xadvance=31 page=0 chnl=0
char id=47 x=245 y=326 width=39 height=60 xoffset=-8 yoffset=15 xadvance=37 page=0 chnl=0
char id=48 x=285 y=143 width=45 height=62 xoffset=-5 yoffset=14 xadvance=49 page=0 chnl=0
char id=49 x=467 y=266 width=33 height=60 xoffset=-3 yoffset=15 xadvance=49 page=0 chnl=0
char id=50 x=51 y=205 width=46 height=61 xoffset=-6 yoffset=14 xadvance=49 page=0 chnl=0
char id=51 x=103 y=143 width=46 height=62 xoffset=-6 yoffset=14 xadvance=49 page=0 chnl=0
char id=52 x=150 y=326 width=49 height=60 xoffset=-7 yoffset=15 xadvance=49 page=0 chnl=0
char id=53 x=97 y=205 width=45 height=61 xoffset=-5 yoffset=15 xadvance=49 page=0 chnl=0
char id=54 x=149 y=143 width=46 height=62 xoffset=-5 yoffset=14 xadvance=49 page=0 chnl=0
char id=55 x=199 y=326 width=46 height=60 xoffset=-6 yoffset=15 xadvance=49 page=0 chnl=0
char id=56 x=195 y=143 width=45 height=62 xoffset=-5 yoffset=14 xadvance=49 page=0 chnl=0
char id=57 x=240 y=143 width=45 height=62 xoffset=-5 yoffset=14 xadvance=49 page=0 chnl=0
char id=58 x=174 y=386 width=25 height=51 xoffset=-4 yoffset=25 xadvance=31 page=0 chnl=0
char id=59 x=475 y=205 width=26 height=58 xoffset=-6 yoffset=25 xadvance=31 page=0 chnl=0
char id=60 x=88 y=437 width=45 height=47 xoffset=-5 yoffset=21 xadvance=49 page=0 chnl=0
char id=61 x=374 y=437 width=45 height=32 xoffset=-5 yoffset=29 xadvance=49 page=0 chnl=0
char id=62 x=133 y=437 width=45 height=47 xoffset=-5 yoffset=21 xadvance=49 page=0 chnl=0
char id=63 x=330 y=143 width=42 height=62 xoffset=-8 yoffset=14 xadvance=41 page=0 chnl=0
char id=64 x=393 y=0 width=66 height=66 xoffset=-5 yoffset=15 xadvance=70 page=0 chnl=0
char id=65 x=166 y=205 width=55 height=60 xoffset=-8 yoffset=15 xadvance=53 page=0 chnl=0
char id=66 x=221 y=205 width=47 height=60 xoffset=-2 yoffset=15 xadvance=54 page=0 chnl=0
char id=67 x=384 y=78 width=51 height=62 xoffset=-5 yoffset=14 xadvance=53 page=0 chnl=0
char id=68 x=268 y=205 width=52 height=60 xoffset=-2 yoffset=15 xadvance=59 page=0 chnl=0
char id=69 x=320 y=205 width=41 height=60 xoffset=-2 yoffset=15 xadvance=48 page=0 chnl=0
char id=70 x=361 y=205 width=41 height=60 xoffset=-2 yoffset=15 xadvance=46 page=0 chnl=0
char id=71 x=435 y=78 width=54 height=62 xoffset=-5 yoffset=14 xadvance=59 page=0 chnl=0
char id=72 x=402 y=205 width=50 height=60 xoffset=-2 yoffset=15 xadvance=60 page=0 chnl=0
char id=73 x=452 y=205 width=23 height=60 xoffset=-3 yoffset=15 xadvance=31 page=0 chnl=0
char id=74 x=114 y=0 width=37 height=71 xoffset=-13 yoffset=15 xadvance=31 page=0 chnl=0
char id=75 x=0 y=266 width=48 height=60 xoffset=-2 yoffset=15 xadvance=52 page=0 chnl=0
char id=76 x=48 y=266 width=41 height=60 xoffset=-2 yoffset=15 xadvance=46 page=0 chnl=0
char id=77 x=89 y=266 width=60 height=60 xoffset=-2 yoffset=15 xadvance=70 page=0 chnl=0
char id=78 x=149 y=266 width=51 height=60 xoffset=-2 yoffset=15 xadvance=61 page=0 chnl=0
char id=79 x=0 y=143 width=58 height=62 xoffset=-5 yoffset=14 xadvance=62 page=0 chnl=0
char id=80 x=200 y=266 width=44 height=60 xoffset=-2 yoffset=15 xadvance=51 page=0 chnl=0
char id=81 x=56 y=0 width=58 height=72 xoffset=-5 yoffset=14 xadvance=62 page=0 chnl=0
char id=82 x=244 y=266 width=47 height=60 xoffset=-2 yoffset=15 xadvance=52 page=0 chnl=0
char id=83 x=58 y=143 width=45 height=62 xoffset=-5 yoffset=14 xadvance=48 page=0 chnl=0
char id=84 x=291 y=266 width=50 height=60 xoffset=-8 yoffset=15 xadvance=48 page=0 chnl=0
char id=85 x=0 y=205 width=51 height=61 xoffset=-3 yoffset=15 xadvance=59 page=0 chnl=0
char id=86 x=341 y=266 width=53 height=60 xoffset=-8 yoffset=15 xadvance=51 page=0 chnl=0
char id=87 x=394 y=266 width=73 height=60 xoffset=-8 yoffset=15 xadvance=71 page=0 chnl=0
char id=88 x=0 y=326 width=52 height=60 xoffset=-8 yoffset=15 xadvance=50 page=0 chnl=0
char id=89 x=52 y=326 width=51 height=60 xoffset=-8 yoffset=15 xadvance=49 page=0 chnl=0
char id=90 x=103 y=326 width=47 height=60 xoffset=-6 yoffset=15 xadvance=49 page=0 chnl=0
char id=91 x=213 y=0 width=31 height=70 xoffset=-4 yoffset=15 xadvance=34 page=0 chnl=0
char id=92 x=284 y=326 width=39 height=60 xoffset=-8 yoffset=15 xadvance=37 page=0 chnl=0
char id=93 x=244 y=0 width=31 height=70 xoffset=-7 yoffset=15 xadvance=34 page=0 chnl=0
char id=94 x=225 y=437 width=48 height=44 xoffset=-7 yoffset=14 xadvance=48 page=0 chnl=0
char id=95 x=77 y=486 width=46 height=20 xoffset=-9 yoffset=65 xadvance=42 page=0 chnl=0
char id=96 x=445 y=437 width=29 height=26 xoffset=3 yoffset=11 xadvance=50 page=0 chnl=0
char id=97 x=455 y=326 width=44 height=51 xoffset=-6 yoffset=25 xadvance=48 page=0 chnl=0
char id=98 x=92 y=78 width=46 height=64 xoffset=-3 yoffset=12 xadvance=52 page=0 chnl=0
char id=99 x=0 y=386 width=41 height=51 xoffset=-5 yoffset=25 xadvance=44 page=0 chnl=0
char id=100 x=138 y=78 width=46 height=64 xoffset=-5 yoffset=12 xadvance=52 page=0 chnl=0
char id=101 x=41 y=386 width=45 height=51 xoffset=-5 yoffset=25 xadvance=49 page=0 chnl=0
char id=102 x=231 y=78 width=42 height=63 xoffset=-8 yoffset=12 xadvance=35 page=0 chnl=0
char id=103 x=459 y=0 width=48 height=65 xoffset=-7 yoffset=25 xadvance=48 page=0 chnl=0
char id=104 x=273 y=78 width=45 height=63 xoffset=-3 yoffset=12 xadvance=52 page=0 chnl=0
char id=105 x=489 y=78 width=22 height=62 xoffset=-3 yoffset=13 xadvance=30 page=0 chnl=0
char id=106 x=22 y=0 width=34 height=77 xoffset=-12 yoffset=13 xadvance=30 page=0 chnl=0
char id=107 x=318 y=78 width=44 height=63 xoffset=-3 yoffset=12 xadvance=47 page=0 chnl=0
char id=108 x=362 y=78 width=22 height=63 xoffset=-3 yoffset=12 xadvance=30 page=0 chnl=0
char id=109 x=199 y=386 width=64 height=50 xoffset=-3 yoffset=25 xadvance=72 page=0 chnl=0
char id=110 x=263 y=386 width=45 height=50 xoffset=-3 yoffset=25 xadvance=52 page=0 chnl=0
char id=111 x=86 y=386 width=47 height=51 xoffset=-5 yoffset=25 xadvance=51 page=0 chnl=0
char id=112 x=0 y=78 width=46 height=65 xoffset=-3 yoffset=25 xadvance=52 page=0 chnl=0
char id=113 x=46 y=78 width=46 height=65 xoffset=-5 yoffset=25 xadvance=52 page=0 chnl=0
char id=114 x=308 y=386 width=36 height=50 xoffset=-3 yoffset=25 xadvance=39 page=0 chnl=0
char id=115 x=133 y=386 width=41 height=51 xoffset=-5 yoffset=25 xadvance=44 page=0 chnl=0
char id=116 x=418 y=326 width=37 height=58 xoffset=-8 yoffset=18 xadvance=36 page=0 chnl=0
char id=117 x=344 y=386 width=45 height=50 xoffset=-4 yoffset=26 xadvance=52 page=0 chnl=0
char id=118 x=389 y=386 width=47 height=49 xoffset=-8 yoffset=26 xadvance=45 page=0 chnl=0
char id=119 x=436 y=386 width=64 height=49 xoffset=-8 yoffset=26 xadvance=62 page=0 chnl=0
char id=120 x=0 y=437 width=47 height=49 xoffset=-8 yoffset=26 xadvance=46 page=0 chnl=0
char id=121 x=184 y=78 width=47 height=64 xoffset=-8 yoffset=26 xadvance=45 page=0 chnl=0
char id=122 x=47 y=437 width=41 height=49 xoffset=-6 yoffset=26 xadvance=43 page=0 chnl=0
char id=123 x=275 y=0 width=37 height=70 xoffset=-7 yoffset=15 xadvance=38 page=0 chnl=0
char id=124 x=0 y=0 width=22 height=78 xoffset=6 yoffset=12 xadvance=48 page=0 chnl=0
char id=125 x=312 y=0 width=37 height=70 xoffset=-6 yoffset=15 xadvance=38 page=0 chnl=0
char id=126 x=0 y=486 width=45 height=24 xoffset=-5 yoffset=33 xadvance=49 page=0 chnl=0
kernings count=313
kerning first=70 second=46 amount=-4
kerning first=79 second=86 amount=-1
kerning first=107 second=113 amount=-1
kerning first=39 second=65 amount=-4
kerning first=86 second=79 amount=-1
kerning first=89 second=122 amount=-1
kerning first=68 second=88 amount=-1
kerning first=75 second=81 amount=-1
kerning first=84 second=121 amount=-1
kerning first=88 second=71 amount=-1
kerning first=89 second=67 amount=-1
kerning first=121 second=44 amount=-2
kerning first=39 second=99 amount=-4
kerning first=86 second=113 amount=-1
kerning first=65 second=79 amount=-1
kerning first=87 second=109 amount=-1
kerning first=79 second=65 amount=-1
kerning first=67 second=71 amount=-1
kerning first=89 second=101 amount=-3
kerning first=84 second=100 amount=-4
kerning first=44 second=79 amount=-3
kerning first=89 second=46 amount=-4
kerning first=84 second=45 amount=-2
kerning first=46 second=71 amount=-3
kerning first=40 second=74 amount=6
kerning first=79 second=44 amount=-2
kerning first=98 second=120 amount=-1
kerning first=68 second=46 amount=-2
kerning first=39 second=112 amount=-2
kerning first=84 second=79 amount=-1
kerning first=34 second=111 amount=-4
kerning first=66 second=88 amount=-1
kerning first=86 second=71 amount=-1
kerning first=89 second=114 amount=-2
kerning first=87 second=67 amount=-1
kerning first=119 second=44 amount=-2
kerning first=84 second=113 amount=-4
kerning first=65 second=71 amount=-1
kerning first=46 second=84 amount=-4
kerning first=87 second=101 amount=-1
kerning first=111 second=34 amount=-1
kerning first=87 second=46 amount=-3
kerning first=112 second=119 amount=-1
kerning first=44 second=71 amount=-3
kerning first=101 second=121 amount=-1
kerning first=114 second=111 amount=-1
kerning first=66 second=46 amount=-2
kerning first=84 second=71 amount=-1
kerning first=65 second=84 amount=-4
kerning first=87 second=114 amount=-1
kerning first=34 second=103 amount=-2
kerning first=86 second=63 amount=1
kerning first=44 second=84 amount=-4
kerning first=86 second=97 amount=-1
kerning first=109 second=34 amount=-1
kerning first=85 second=46 amount=-1
kerning first=39 second=117 amount=-2
kerning first=90 second=81 amount=-1
kerning first=84 second=84 amount=1
kerning first=120 second=100 amount=-1
kerning first=114 second=103 amount=-1
kerning first=84 second=118 amount=-1
kerning first=86 second=110 amount=-1
kerning first=84 second=63 amount=1
kerning first=46 second=89 amount=-4
kerning first=111 second=39 amount=-1
kerning first=84 second=97 amount=-5
kerning first=120 second=113 amount=-1
kerning first=81 second=88 amount=-1
kerning first=88 second=81 amount=-1
kerning first=76 second=87 amount=-1
kerning first=39 second=109 amount=-2
kerning first=65 second=89 amount=-4
kerning first=67 second=81 amount=-1
kerning first=65 second=34 amount=-4
kerning first=89 second=111 amount=-3
kerning first=84 second=110 amount=-3
kerning first=44 second=89 amount=-4
kerning first=109 second=39 amount=-1
kerning first=46 second=81 amount=-3
kerning first=34 second=87 amount=1
kerning first=111 second=120 amount=-1
kerning first=81 second=46 amount=-2
kerning first=79 second=88 amount=-1
kerning first=101 second=118 amount=-1
kerning first=86 second=81 amount=-1
kerning first=68 second=90 amount=-1
kerning first=76 second=79 amount=-1
kerning first=121 second=46 amount=-2
kerning first=39 second=101 amount=-4
kerning first=86 second=115 amount=-1
kerning first=65 second=81 amount=-1
kerning first=87 second=111 amount=-1
kerning first=34 second=100 amount=-4
kerning first=89 second=103 amount=-1
kerning first=44 second=81 amount=-3
kerning first=79 second=46 amount=-2
kerning first=98 second=122 amount=-1
kerning first=39 second=114 amount=-2
kerning first=84 second=81 amount=-1
kerning first=91 second=74 amount=6
kerning first=34 second=113 amount=-4
kerning first=66 second=90 amount=-1
kerning first=114 second=100 amount=-1
kerning first=65 second=39 amount=-4
kerning first=119 second=46 amount=-2
kerning first=84 second=115 amount=-4
kerning first=76 second=71 amount=-1
kerning first=46 second=86 amount=-4
kerning first=87 second=103 amount=-1
kerning first=112 second=121 amount=-1
kerning first=101 second=34 amount=-1
kerning first=114 second=113 amount=-1
kerning first=118 second=63 amount=1
kerning first=76 second=84 amount=-1
kerning first=65 second=86 amount=-2
kerning first=107 second=99 amount=-1
kerning first=86 second=65 amount=-2
kerning first=75 second=67 amount=-1
kerning first=44 second=86 amount=-4
kerning first=86 second=99 amount=-1
kerning first=34 second=84 amount=1
kerning first=86 second=44 amount=-3
kerning first=99 second=34 amount=1
kerning first=68 second=87 amount=-1
kerning first=84 second=120 amount=-1
kerning first=86 second=112 amount=-1
kerning first=84 second=65 amount=-4
kerning first=34 second=97 amount=-2
kerning first=118 second=34 amount=2
kerning first=89 second=100 amount=-3
kerning first=84 second=99 amount=-4
kerning first=101 second=39 amount=-1
kerning first=84 second=44 amount=-4
kerning first=97 second=34 amount=-1
kerning first=81 second=90 amount=-1
kerning first=76 second=89 amount=-2
kerning first=89 second=79 amount=-1
kerning first=98 second=119 amount=-1
kerning first=39 second=111 amount=-4
kerning first=76 second=34 amount=-5
kerning first=34 second=110 amount=-2
kerning first=66 second=87 amount=-1
kerning first=114 second=97 amount=-1
kerning first=89 second=113 amount=-3
kerning first=84 second=112 amount=-3
kerning first=116 second=34 amount=1
kerning first=87 second=100 amount=-1
kerning first=34 second=89 amount=1
kerning first=99 second=39 amount=1
kerning first=111 second=122 amount=-1
kerning first=112 second=118 amount=-1
kerning first=79 second=90 amount=-1
kerning first=101 second=120 amount=-1
kerning first=87 second=79 amount=-1
kerning first=76 second=81 amount=-1
kerning first=89 second=71 amount=-1
kerning first=39 second=103 amount=-2
kerning first=86 second=117 amount=-1
kerning first=90 second=67 amount=-1
kerning first=87 second=113 amount=-1
kerning first=118 second=39 amount=2
kerning first=80 second=65 amount=-3
kerning first=114 second=34 amount=2
kerning first=123 second=74 amount=6
kerning first=70 second=63 amount=1
kerning first=97 second=39 amount=-1
kerning first=80 second=44 amount=-8
kerning first=76 second=39 amount=-5
kerning first=34 second=115 amount=-2
kerning first=120 second=99 amount=-1
kerning first=87 second=71 amount=-1
kerning first=68 second=84 amount=-2
kerning first=84 second=117 amount=-3
kerning first=88 second=67 amount=-1
kerning first=89 second=63 amount=1
kerning first=86 second=109 amount=-1
kerning first=116 second=39 amount=1
kerning first=67 second=67 amount=-1
kerning first=89 second=97 amount=-3
kerning first=112 second=34 amount=-1
kerning first=46 second=67 amount=-3
kerning first=81 second=87 amount=-1
kerning first=76 second=86 amount=-1
kerning first=66 second=84 amount=-2
kerning first=107 second=101 amount=-1
kerning first=86 second=67 amount=-1
kerning first=118 second=44 amount=-2
kerning first=89 second=110 amount=-2
kerning first=87 second=63 amount=1
kerning first=84 second=109 amount=-3
kerning first=114 second=39 amount=2
kerning first=45 second=84 amount=-2
kerning first=39 second=87 amount=1
kerning first=86 second=101 amount=-1
kerning first=65 second=67 amount=-1
kerning first=87 second=97 amount=-1
kerning first=110 second=34 amount=-1
kerning first=34 second=86 amount=1
kerning first=86 second=46 amount=-3
kerning first=111 second=119 amount=-1
kerning first=44 second=67 amount=-3
kerning first=79 second=87 amount=-1
kerning first=68 second=89 amount=-1
kerning first=34 second=65 amount=-4
kerning first=84 second=122 amount=-2
kerning first=39 second=100 amount=-4
kerning first=86 second=114 amount=-1
kerning first=84 second=67 amount=-1
kerning first=87 second=110 amount=-1
kerning first=34 second=99 amount=-4
kerning first=112 second=39 amount=-1
kerning first=84 second=101 amount=-4
kerning first=84 second=46 amount=-4
kerning first=89 second=81 amount=-1
kerning first=98 second=121 amount=-1
kerning first=39 second=113 amount=-4
kerning first=34 second=112 amount=-2
kerning first=66 second=89 amount=-1
kerning first=114 second=99 amount=-1
kerning first=89 second=115 amount=-2
kerning first=84 second=114 amount=-3
kerning first=46 second=85 amount=-1
kerning first=110 second=39 amount=-1
kerning first=112 second=120 amount=-1
kerning first=101 second=122 amount=-1
kerning first=80 second=88 amount=-1
kerning first=87 second=81 amount=-1
kerning first=81 second=84 amount=-2
kerning first=87 second=115 amount=-1
kerning first=44 second=85 amount=-1
kerning first=70 second=65 amount=-1
kerning first=39 second=84 amount=1
kerning first=104 second=34 amount=-1
kerning first=80 second=46 amount=-8
kerning first=121 second=63 amount=1
kerning first=34 second=117 amount=-2
kerning first=70 second=44 amount=-4
kerning first=79 second=84 amount=-2
kerning first=107 second=111 amount=-1
kerning first=120 second=101 amount=-1
kerning first=68 second=86 amount=-1
kerning first=75 second=79 amount=-1
kerning first=84 second=119 amount=-1
kerning first=89 second=65 amount=-4
kerning first=39 second=97 amount=-2
kerning first=86 second=111 amount=-1
kerning first=89 second=99 amount=-3
kerning first=68 second=65 amount=-1
kerning first=89 second=44 amount=-4
kerning first=102 second=34 amount=4
kerning first=119 second=63 amount=1
kerning first=81 second=89 amount=-1
kerning first=98 second=118 amount=-1
kerning first=68 second=44 amount=-2
kerning first=39 second=110 amount=-2
kerning first=34 second=109 amount=-2
kerning first=66 second=86 amount=-1
kerning first=118 second=46 amount=-2
kerning first=89 second=112 amount=-2
kerning first=87 second=65 amount=-2
kerning first=75 second=71 amount=-1
kerning first=84 second=111 amount=-4
kerning first=69 second=74 amount=4
kerning first=76 second=67 amount=-1
kerning first=121 second=34 amount=2
kerning first=39 second=89 amount=1
kerning first=86 second=103 amount=-1
kerning first=87 second=99 amount=-1
kerning first=104 second=39 amount=-1
kerning first=66 second=65 amount=-1
kerning first=87 second=44 amount=-3
kerning first=111 second=121 amount=-1
kerning first=79 second=89 amount=-1
kerning first=101 second=119 amount=-1
kerning first=66 second=44 amount=-2
kerning first=87 second=112 amount=-1
kerning first=34 second=101 amount=-4
kerning first=85 second=65 amount=-1
kerning first=119 second=34 amount=2
kerning first=84 second=103 amount=-4
kerning first=102 second=39 amount=4
kerning first=85 second=44 amount=-1
kerning first=98 second=34 amount=-1
kerning first=39 second=115 amount=-2
kerning first=90 second=79 amount=-1
kerning first=34 second=114 amount=-2
kerning first=114 second=101 amount=-1
kerning first=89 second=117 amount=-2
kerning first=121 second=39 amount=2
kerning first=65 second=74 amount=8
kerning first=46 second=87 amount=-4
kerning first=112 second=122 amount=-1
kerning first=120 second=111 amount=-1
kerning first=80 second=90 amount=-1
kerning first=81 second=86 amount=-1
kerning first=88 second=79 amount=-1
kerning first=76 second=85 amount=-1
kerning first=90 second=71 amount=-1
kerning first=65 second=87 amount=-2
kerning first=87 second=117 amount=-1
kerning first=107 second=100 amount=-1
kerning first=67 second=79 amount=-1
kerning first=89 second=109 amount=-2
kerning first=119 second=39 amount=2
kerning first=81 second=65 amount=-1
kerning first=44 second=87 amount=-4
kerning first=39 second=86 amount=1
kerning first=86 second=100 amount=-1
kerning first=46 second=79 amount=-3
kerning first=98 second=39 amount=-1
kerning first=111 second=118 amount=-1
kerning first=81 second=44 amount=-2
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

@@ -4,14 +4,14 @@ layout(location = 0) out vec4 color;
in vec4 v_color;
in vec2 v_textureCoordinates;
in flat float v_textureIndex;
in flat uint v_textureIndex;
uniform sampler2D u_textures[32];
void main()
{
vec4 textureColor = v_color;
switch(int(v_textureIndex)) {
switch(v_textureIndex) {
case 0: break; // Texture unit 0 is reserved for no texture
case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break;
case 2: textureColor *= texture(u_textures[2], v_textureCoordinates); break;
+19
View File
@@ -0,0 +1,19 @@
#version 450 core
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec4 a_color;
layout(location = 2) in vec2 a_textureCoordinates;
layout(location = 3) in uint a_textureIndex;
out vec4 v_color;
out vec2 v_textureCoordinates;
out flat uint v_textureIndex;
void main()
{
v_color = a_color;
v_textureCoordinates = a_textureCoordinates;
v_textureIndex = a_textureIndex;
// Vclip = Model transform * Vlocal
gl_Position = vec4(a_position, 1.0f);
}
+57
View File
@@ -0,0 +1,57 @@
#version 450 core
layout(location = 0) out vec4 albedoSpec; // RGB diffuse color
layout(location = 1) out vec4 position;
layout(location = 2) out vec4 normal;
in vec3 v_position;
in vec3 v_normal;
in vec4 v_color;
in vec2 v_textureCoordinates;
in flat uint v_textureIndex;
uniform sampler2D u_textures[32];
void main()
{
vec4 textureColor = v_color;
switch(v_textureIndex) {
case 0: break; // Texture unit 0 is reserved for no texture
case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break;
case 2: textureColor *= texture(u_textures[2], v_textureCoordinates); break;
case 3: textureColor *= texture(u_textures[3], v_textureCoordinates); break;
case 4: textureColor *= texture(u_textures[4], v_textureCoordinates); break;
case 5: textureColor *= texture(u_textures[5], v_textureCoordinates); break;
case 6: textureColor *= texture(u_textures[6], v_textureCoordinates); break;
case 7: textureColor *= texture(u_textures[7], v_textureCoordinates); break;
case 8: textureColor *= texture(u_textures[8], v_textureCoordinates); break;
case 9: textureColor *= texture(u_textures[9], v_textureCoordinates); break;
case 10: textureColor *= texture(u_textures[10], v_textureCoordinates); break;
case 11: textureColor *= texture(u_textures[11], v_textureCoordinates); break;
case 12: textureColor *= texture(u_textures[12], v_textureCoordinates); break;
case 13: textureColor *= texture(u_textures[13], v_textureCoordinates); break;
case 14: textureColor *= texture(u_textures[14], v_textureCoordinates); break;
case 15: textureColor *= texture(u_textures[15], v_textureCoordinates); break;
case 16: textureColor *= texture(u_textures[16], v_textureCoordinates); break;
case 17: textureColor *= texture(u_textures[17], v_textureCoordinates); break;
case 18: textureColor *= texture(u_textures[18], v_textureCoordinates); break;
case 19: textureColor *= texture(u_textures[19], v_textureCoordinates); break;
case 20: textureColor *= texture(u_textures[20], v_textureCoordinates); break;
case 21: textureColor *= texture(u_textures[21], v_textureCoordinates); break;
case 22: textureColor *= texture(u_textures[22], v_textureCoordinates); break;
case 23: textureColor *= texture(u_textures[23], v_textureCoordinates); break;
case 24: textureColor *= texture(u_textures[24], v_textureCoordinates); break;
case 25: textureColor *= texture(u_textures[25], v_textureCoordinates); break;
case 26: textureColor *= texture(u_textures[26], v_textureCoordinates); break;
case 27: textureColor *= texture(u_textures[27], v_textureCoordinates); break;
case 28: textureColor *= texture(u_textures[28], v_textureCoordinates); break;
case 29: textureColor *= texture(u_textures[29], v_textureCoordinates); break;
case 30: textureColor *= texture(u_textures[30], v_textureCoordinates); break;
case 31: textureColor *= texture(u_textures[31], v_textureCoordinates); break;
}
albedoSpec.rgb = textureColor.rgb;
albedoSpec.a = 1.0; // TODO: read specular from model material
position = vec4(v_position, 1.0f);
normal = vec4(normalize(v_normal), 1.0f);
}
+30
View File
@@ -0,0 +1,30 @@
#version 450 core
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec3 a_normal;
layout(location = 2) in vec4 a_color;
layout(location = 3) in vec2 a_textureCoordinates;
layout(location = 4) in uint a_textureIndex;
out vec3 v_position;
out vec3 v_normal;
out vec4 v_color;
out vec2 v_textureCoordinates;
out flat uint v_textureIndex;
layout(std140, binding = 0) uniform Camera
{
mat4 u_projectionView;
vec3 u_position;
};
void main()
{
v_position = a_position;
v_normal = a_normal;
v_color = a_color;
v_textureCoordinates = a_textureCoordinates;
v_textureIndex = a_textureIndex;
// Vclip = Camera projection * Camera view * Model transform * Vlocal
gl_Position = u_projectionView * vec4(a_position, 1.0f);
}
+49
View File
@@ -0,0 +1,49 @@
#version 450 core
layout(location = 0) out vec4 color;
in vec4 v_color;
in vec3 v_textureCoordinates;
in flat uint v_textureIndex;
uniform samplerCube u_textures[32];
void main()
{
vec4 textureColor = v_color;
switch(v_textureIndex) {
case 0: break; // Texture unit 0 is reserved for no texture
case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break;
case 2: textureColor *= texture(u_textures[2], v_textureCoordinates); break;
case 3: textureColor *= texture(u_textures[3], v_textureCoordinates); break;
case 4: textureColor *= texture(u_textures[4], v_textureCoordinates); break;
case 5: textureColor *= texture(u_textures[5], v_textureCoordinates); break;
case 6: textureColor *= texture(u_textures[6], v_textureCoordinates); break;
case 7: textureColor *= texture(u_textures[7], v_textureCoordinates); break;
case 8: textureColor *= texture(u_textures[8], v_textureCoordinates); break;
case 9: textureColor *= texture(u_textures[9], v_textureCoordinates); break;
case 10: textureColor *= texture(u_textures[10], v_textureCoordinates); break;
case 11: textureColor *= texture(u_textures[11], v_textureCoordinates); break;
case 12: textureColor *= texture(u_textures[12], v_textureCoordinates); break;
case 13: textureColor *= texture(u_textures[13], v_textureCoordinates); break;
case 14: textureColor *= texture(u_textures[14], v_textureCoordinates); break;
case 15: textureColor *= texture(u_textures[15], v_textureCoordinates); break;
case 16: textureColor *= texture(u_textures[16], v_textureCoordinates); break;
case 17: textureColor *= texture(u_textures[17], v_textureCoordinates); break;
case 18: textureColor *= texture(u_textures[18], v_textureCoordinates); break;
case 19: textureColor *= texture(u_textures[19], v_textureCoordinates); break;
case 20: textureColor *= texture(u_textures[20], v_textureCoordinates); break;
case 21: textureColor *= texture(u_textures[21], v_textureCoordinates); break;
case 22: textureColor *= texture(u_textures[22], v_textureCoordinates); break;
case 23: textureColor *= texture(u_textures[23], v_textureCoordinates); break;
case 24: textureColor *= texture(u_textures[24], v_textureCoordinates); break;
case 25: textureColor *= texture(u_textures[25], v_textureCoordinates); break;
case 26: textureColor *= texture(u_textures[26], v_textureCoordinates); break;
case 27: textureColor *= texture(u_textures[27], v_textureCoordinates); break;
case 28: textureColor *= texture(u_textures[28], v_textureCoordinates); break;
case 29: textureColor *= texture(u_textures[29], v_textureCoordinates); break;
case 30: textureColor *= texture(u_textures[30], v_textureCoordinates); break;
case 31: textureColor *= texture(u_textures[31], v_textureCoordinates); break;
}
color = textureColor;
}
@@ -2,19 +2,18 @@
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec4 a_color;
layout(location = 2) in vec2 a_textureCoordinates;
layout(location = 3) in float a_textureIndex;
layout(location = 2) in uint a_textureIndex;
out vec4 v_color;
out vec2 v_textureCoordinates;
out flat float v_textureIndex;
out vec3 v_textureCoordinates;
out flat uint v_textureIndex;
uniform mat4 u_projectionView;
void main()
{
v_color = a_color;
v_textureCoordinates = a_textureCoordinates;
v_textureCoordinates = a_position;
v_textureIndex = a_textureIndex;
// Vclip = Camera projection * Camera view * Model transform * Vlocal
gl_Position = u_projectionView * vec4(a_position, 1.0f);
+3 -2
View File
@@ -4,7 +4,7 @@ layout(location = 0) out vec4 color;
in vec4 v_color;
in vec2 v_textureCoordinates;
in flat float v_textureIndex;
in flat uint v_textureIndex;
in float v_width;
in float v_edge;
in float v_borderWidth;
@@ -25,8 +25,9 @@ float alpha(float textureAlpha)
void main()
{
vec4 textureColor = v_color;
switch(int(v_textureIndex)) {
switch(v_textureIndex) {
case 0: break; // Texture unit 0 is reserved for no texture
// case 1: textureColor.a = 1; break;
case 1: textureColor.a = alpha(texture(u_textures[1], v_textureCoordinates).a); break;
// case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break;
case 2: textureColor.a = alpha(texture(u_textures[2], v_textureCoordinates).a); break;
+2 -2
View File
@@ -3,7 +3,7 @@
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec4 a_color;
layout(location = 2) in vec2 a_textureCoordinates;
layout(location = 3) in float a_textureIndex;
layout(location = 3) in uint a_textureIndex;
layout(location = 4) in float a_width;
layout(location = 5) in float a_edge;
layout(location = 6) in float a_borderWidth;
@@ -13,7 +13,7 @@ layout(location = 9) in float a_offset;
out vec4 v_color;
out vec2 v_textureCoordinates;
out flat float v_textureIndex;
out flat uint v_textureIndex;
out float v_width;
out float v_edge;
out float v_borderWidth;
+17
View File
@@ -0,0 +1,17 @@
#version 450 core
layout(location = 0) out vec4 color;
in vec4 v_color;
in vec3 v_textureCoordinates;
in flat uint v_textureIndex;
uniform samplerCube u_textures[32];
void main()
{
// Prevent u_textures variable from getting optimized away
if (texture(u_textures[0], vec3(0.0f)).x > 99999.0f) { discard; }
color = v_color;
}
+24
View File
@@ -0,0 +1,24 @@
#version 450 core
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec4 a_color;
layout(location = 2) in uint a_textureIndex;
out vec4 v_color;
out vec3 v_textureCoordinates;
out flat uint v_textureIndex;
layout(std140, binding = 0) uniform Camera
{
mat4 u_projectionView;
vec3 u_position;
};
void main()
{
v_color = a_color;
v_textureCoordinates = a_position;
v_textureIndex = a_textureIndex;
// Vclip = Camera projection * Camera view * Model transform * Vlocal
gl_Position = u_projectionView * vec4(a_position, 1.0f);
}
+78
View File
@@ -0,0 +1,78 @@
#version 450 core
layout(location = 0) out vec4 color;
in vec4 v_color;
in vec2 v_textureCoordinates;
in flat uint v_textureIndex;
uniform sampler2D u_textures[32];
// -----------------------------------------
layout(std140, binding = 0) uniform Camera {
mat4 u_projectionView;
vec3 u_position;
};
// -----------------------------------------
struct DirectionalLight {
vec3 direction;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
const int MAX_DIRECTIONAL_LIGHTS = 4;
layout(std430, binding = 0) buffer DirectionalLights {
DirectionalLight u_directionalLight[MAX_DIRECTIONAL_LIGHTS];
};
// -----------------------------------------
void main()
{
float isObject = texture(u_textures[v_textureIndex + 1], v_textureCoordinates).a;
if (isObject == 0.0f) {
color = vec4(0,0,0,0);
return;
}
vec3 albedo = texture(u_textures[v_textureIndex + 0], v_textureCoordinates).rgb;
float specular = texture(u_textures[v_textureIndex + 0], v_textureCoordinates).a;
vec3 position = texture(u_textures[v_textureIndex + 1], v_textureCoordinates).rgb;
vec3 normal = texture(u_textures[v_textureIndex + 2], v_textureCoordinates).rgb;
vec3 lighting = vec3(0.0f, 0.0f, 0.0f);//albedo * v_color.xyz;
vec3 viewDirection = normalize(u_position - position);
// Loop through all directional lights
for (int i = 0; i < MAX_DIRECTIONAL_LIGHTS; ++i) {
// Diffuse
vec3 lightDirection = normalize(-u_directionalLight[i].direction);
float diffuse = max(dot(normal, lightDirection), 0.0f);
// Specular
vec3 reflectionDirection = reflect(-lightDirection, normal);
float specular = pow(max(dot(viewDirection, reflectionDirection), 0.0f), 32);
lighting +=
(albedo * u_directionalLight[i].ambient) +
(albedo * diffuse * u_directionalLight[i].diffuse) +
(specular * u_directionalLight[i].specular);
}
// Loop through all point lights
// TODO
// vec3 lightDirection = normalize(lightPosition - position);
// float diffuse = max(dot(normal, lightDirection), 0.0f);
// lighting += diffuse * albedo * u_lightColor;
// Loop through all spot lights
// TODO
color = vec4(lighting, 1.0f);
}
+25
View File
@@ -0,0 +1,25 @@
#version 450 core
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec4 a_color;
layout(location = 2) in vec2 a_textureCoordinates;
layout(location = 3) in uint a_textureIndex;
out vec4 v_color;
out vec2 v_textureCoordinates;
out flat uint v_textureIndex;
layout(std140, binding = 0) uniform Camera
{
mat4 u_projectionView;
vec3 u_position;
};
void main()
{
v_color = a_color;
v_textureCoordinates = a_textureCoordinates;
v_textureIndex = a_textureIndex;
// Vclip = Model transform * Vlocal
gl_Position = vec4(a_position, 1.0f);
}
Binary file not shown.
+15
View File
@@ -0,0 +1,15 @@
# Blender 4.2.0
# www.blender.org
usemtl (null)
o Plane
v -1.000000 -1.000000 -0.000000
v 1.000000 -1.000000 -0.000000
v -1.000000 1.000000 0.000000
v 1.000000 1.000000 0.000000
vn -0.0000 -0.0000 1.0000
vt 0.000000 0.000000
vt 1.000000 0.000000
vt 1.000000 1.000000
vt 0.000000 1.000000
s 0
f 1/1/1 2/2/1 4/3/1 3/4/1
+116
View File
@@ -0,0 +1,116 @@
{
"init": "assets/lua/scene1-init.lua",
"entities": [
{
"id": { "id": 12312312 },
"tag": { "tag": "Camera" },
"transform" : {
"translate": [0.0, 0.0, 1.0],
"rotate": [0.0, 0.0, -1.0],
"scale": [1.0, 1.0, 1.0]
},
"camera": { "type": "perspective" },
"lua-scripts": [
{ "path": "assets/lua/cameracontroller.lua" }
]
},
{
"id": { "id": 212563732 },
"tag": { "tag": "Skybox" },
"transform" : {
"translate": [0.0, 0.0, 0.0],
"rotate": [0.0, 0.0, 0.0],
"scale": [100.0, 100.0, 100.0]
},
"cubemap": {
"color": [ 1.0, 1.0, 1.0, 1.0 ],
"texture": "assets/gfx/skybox.jpg"
}
},
{
"id": { "id": 564564564 },
"tag": { "tag": "Quad" },
"transform" : {
"translate": [ 0.0, 0.0, 0.0 ],
"rotate": [ 0.0, 0.0, 0.0 ],
"scale": [ 1.0, 1.0, 1.0 ]
},
"model": {
"color": [ 1.0, 1.0, 1.0, 1.0 ],
"model": "assets/model/quad.obj",
"texture": "assets/gfx/test.png"
}
},
{
"id": { "id": 97897897 },
"tag": { "tag": "Quad 2" },
"transform" : {
"translate": [ 2.5, 0.0, 0.0 ],
"rotate": [ 0.0, 0.0, 0.0 ],
"scale": [ 1.0, 1.0, 1.0 ]
},
"model": {
"color": [ 0.5, 0.6, 0.8, 1.0 ],
"model": "assets/model/quad.obj",
"texture": "assets/gfx/test.png"
}
},
{
"id": { "id": 3424242 },
"tag": { "tag": "Quad 3" },
"transform" : {
"translate": [ 5.0, 1.0, 0.0 ],
"rotate": [ 0.0, 0.0, -20.0 ],
"scale": [ 1.0, 1.0, 1.0 ]
},
"model": {
"color": [ 1.0, 1.0, 1.0, 1.0 ],
"model": "assets/model/quad.obj",
"texture": "assets/gfx/test-inverted.png"
},
"children": [
{
"id": { "id": 4345472 },
"tag": { "tag": "Quad 4" },
"transform" : {
"translate": [ 1.7, 0.0, 0.0 ],
"rotate": [ 0.0, 0.0, 0.0 ],
"scale": [ 0.5, 0.5, 1.0 ]
},
"model": {
"color": [ 1.0, 1.0, 1.0, 1.0 ],
"model": "assets/model/quad.obj",
"texture": "assets/gfx/test-inverted.png"
},
"children": [
{
"id": { "id": 5234723 },
"tag": { "tag": "Quad 5" },
"transform" : {
"translate": [ 2.0, 0.0, 0.0 ],
"rotate": [ 0.0, 0.0, -20.0 ],
"scale": [ 0.5, 0.5, 1.0 ]
},
"model": {
"color": [ 1.0, 1.0, 1.0, 1.0 ],
"model": "assets/model/quad.obj",
"texture": "assets/gfx/test-inverted.png"
}
}
]
}
]
},
{
"id": { "id": 675754 },
"tag": { "tag": "Text" },
"text": {
"content": "Hello World!",
"font": "assets/fnt/open-sans",
"font-size": 24,
"line-spacing": 1.0,
"width": 150
}
}
]
}
+1 -1
View File
@@ -3,7 +3,7 @@
"fullscreen": "windowed",
"height": 720,
"title": "Inferno",
"vsync": true,
"vsync": false,
"width": 1280
}
}
+1
View File
@@ -0,0 +1 @@
file(COPY ${CMAKE_CURRENT_LIST_DIR}/../assets DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+9
View File
@@ -0,0 +1,9 @@
#+TITLE: Documentation
#+AUTHOR: Riyyi
#+LANGUAGE: en
#+OPTIONS: toc:nil
Topics:
- [[./shaders.org][Shaders]]
- [[./references.org][References]]
+326
View File
@@ -0,0 +1,326 @@
#+TITLE: Memory Layout
#+AUTHOR: Riyyi
#+LANGUAGE: en
#+OPTIONS: toc:nil
This chapter is about the memory layout of interface blocks in GLSL.
An interface block is a group of variables, a struct if you will.
There are 4 types of memory layouts that can be used, where the first two aren't
widely used as those are implementation dependent and require querying the
OpenGL API for memory offsets.
- packed
- shared
- std140
- std430
** std140
This type is usable in Uniform Buffer Objects (=UBO=) and Shader Storage Buffer
Objects (=SSBO=).
** std430
This type is only usable in Shader Storage Buffer Objects (=SSBO=).
Main points:
- Memory is organized into chunks.
- One chunk has 4 slots, 4 bytes per slot.
- Can't fit? Move to next chunk.
- An interface block is at least the size of 1 chunk.
The rules:
- Scalar =bool=, =int=, =uint=, =float=, and =double=
#+BEGIN_SRC
Both the size and alignment are the size of the scalar in basic machine types
(e.g., sizeof(GLfloat))
#+END_SRC
- Two-componment Vectors (e.g., =ivec2=)
#+BEGIN_SRC
Both the size and alignment are twice the size of the underlying scalar type.
#+END_SRC
- Three-component Vectors (e.g., =vec3=) and Four-component Vectors (e.g., =vec4=)
#+BEGIN_SRC
Both the size and alignment are four times the size of the scalar type. However,
this is only true when the member is part of an array or nested structure
#+END_SRC
- Array of Scalars and Vectors
#+BEGIN_SRC
The size of each element in the array will be the same size of the element type,
where three-component vectors are rounded up to the size four-component
vectors. This is also the array's alignment. The array's size will be the
element size times the number of elements.
#+END_SRC
- Column-major matrix or an array of column-major matrices of size C columns and R rows
#+BEGIN_SRC
Same layout as an array of N vectors each with R components, where N is the
total number of columns present.
#+END_SRC
- Row-major matrix or an array of row-major matrices of size R rows and C columns
#+BEGIN_SRC
Same layout as an array of N vectors each with C components, where N is the
total number of rows present.
#+END_SRC
Both =GLSL= and the =GLM= math library we're using have column-major matrices!
- Single-structure definition or an array of structures
#+BEGIN_SRC
Structure alignment is the same as the alignment of the biggest structure
member, where three-component vectors are rounded up to the size of
four-component vectors. Each structure will start on this alignment, and its
size will be the space neeeded by its members, according to the previous rules,
rounded up to a multiple of the structure alignment.
#+END_SRC
All of the examples described in the following segments are verified by querying
the OpenGL API.
*** Scalars
These types take up 1 (or 2 with =double=) slot and can appear after anything.
In the example below you can see that due to the larger alignment, the ~double~
is forced to the next chunk.
#+BEGIN_SRC glsl
// Var Size Alignment Offset
bool a; // 4 4 0
int b; // 4 4 4
uint c; // 4 4 8
double d; // 8 8 16
float e; // 4 4 24
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][b][c][ ] #1
[d][d][e][ ] #2
#+END_SRC
*** Two-component Vectors
**** Float
A Vec2 takes up 2 slots, so will be in the first or last half of a chunk.
#+BEGIN_SRC glsl
// Var Size Alignment Offset
vec2 a; // 8 8 0
float b; // 4 4 8
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][a][b][ ] #1
#+END_SRC
#+BEGIN_SRC glsl
// Var Size Alignment Offset
float a; // 4 4 0
vec2 b; // 8 8 8
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][ ][b][b] #1
#+END_SRC
**** Double
#+BEGIN_SRC glsl
// Var Size Alignment Offset
float a; // 4 4 0
dvec2 b; // 16 16 16
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][ ][ ][ ] #1
[b][b][b][b] #2
#+END_SRC
*** Three-component and Four-component Vectors
A Vec3 takes up 3 slots, the alignment is 4 slots so only fits at the start of a
chunk.
#+BEGIN_SRC glsl
// Var Size Alignment Offset
vec3 a; // 12 16 0
float b; // 4 4 12
vec4 c; // 16 16 16
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][a][a][b] #1
[c][c][c][c] #2
#+END_SRC
#+BEGIN_SRC glsl
// Var Size Alignment Offset
float a; // 4 4 0
vec3 b; // 12 16 16
vec4 c; // 16 16 32
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][ ][ ][ ] #1
[b][b][b][ ] #2
[c][c][c][c] #3
#+END_SRC
*** Array of Scalars and Vectors
#+BEGIN_SRC glsl
// Var Size Alignment Offset
float[3] a; // 12 4 0
float b; // 4 4 12
float c; // 4 4 16
float[3] d; // 12 4 20
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][a][a][b] #1
[c][d][d][d] #1
#+END_SRC
*Note* the optimizations in the alignment and strides are not applicable to
~vec3~ elements, these remain unchanged from =std140=.
#+BEGIN_SRC glsl
// Var Size Alignment Offset
float a; // 4 4 0
vec3[3] b; // 48 16 16
float c; // 4 4 64
float d; // 4 4 68
vec2[2] e; // 16 8 72
float f; // 4 4 88
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][ ][ ][ ] #1, offset: 0
[b][b][b][ ] #2, offset: 16
[b][b][b][ ] #3, offset: 32
[b][b][b][ ] #4, offset: 48
[c][d][e][e] #5, offset: 64
[e][e][f][ ] #6, offset: 80
#+END_SRC
*Note* the offset needs to be a multiple of the alignment, forcing an entire
empty chunk in the example below.
#+BEGIN_SRC glsl
// Var Size Alignment Offset
float a; // 4 4 0
dvec2[2] b; // 32 16 16
dvec3[2] c; // 64 32 64
float d; // 4 4 128
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][ ][ ][ ] #1, offset: 0
[d][d][d][d] #2, offset: 16
[d][d][d][d] #3, offset: 32
[ ][ ][ ][ ] #4, offset: 48
[c][c][c][c] #5, offset: 64
[c][c][ ][ ] #6, offset: 80
[c][c][c][c] #7, offset: 96
[c][c][ ][ ] #8, offset: 112
[d][ ][ ][ ] #9, offset: 128
#+END_SRC
*** Matrices
Alignment is the same as an array of 1 “row” of the matrix.
No padding between the “rows” of a matrix, but will pad at the end.
#+BEGIN_SRC glsl
// Var Size Alignment Offset
float a; // 4 4 0
mat2 b; // 16 8 8
vec2 c; // 4 4 24
float d; // 4 4 32
mat2[2] e; // 32 8 40
float f; // 4 4 72
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][ ][b][b] #1, offset: 0
[b][b][c][c] #2, offset: 16
[d][ ][e][e] #3, offset: 32
[e][e][e][e] #4, offset: 48
[e][e][f][ ] #5, offset: 64
#+END_SRC
TODO: Add more examples
*** Structs
Alignment same as biggest struct member. Size is the size of all members,
rounded up to a multiple of the alignment.
In the example below you can see that the ~Stuff~ struct, including padding
between members, is 20 bytes in size. To make that a multiple of the alignment
additional padding needs to be put at the end, to make the total size 24 bytes.
Each element in the array of structs will apply the alignment again, as seen
with ~Stuff[1].a~.
#+BEGIN_SRC glsl
struct Stuff {
float a;
vec2 b;
float c;
};
// Var Size Alignment Offset
Stuff a; // 20 8
a.a; // 4 4 0
a.b; // 8 8 8
a.c; // 4 4 16
float b; // 4 4 24
Stuff[2] c; // 44 8
c.a; // 4 4 32
c.b; // 8 8 40
c.c; // 4 4 48
float d; // 4 4 80
#+END_SRC
#+BEGIN_SRC
Chunks:
[a][ ][a][a] #1, offset: 0
[a][ ][b][ ] #2, offset: 16
[c][ ][c][c] #3, offset: 32
[c][ ][c][ ] #4, offset: 48
[c][c][c][ ] #5, offset: 64
[d][ ][ ][ ] #6, offset: 80
#+END_SRC
TODO: Add more examples
* References
- https://learnopengl.com/Advanced-OpenGL/Advanced-GLSL
- https://www.khronos.org/opengl/wiki/Interface_Block_(GLSL)#Memory_layout
- [[https://www.oreilly.com/library/view/opengl-programming-guide/9780132748445/app09lev1sec2.html][The std140 Layout Rules]]
- [[https://www.youtube.com/watch?v=JPvbRko9lBg][(YouTube) WebGL 2: Uniform Buffer Objects]]
+1
View File
@@ -0,0 +1 @@
+8
View File
@@ -0,0 +1,8 @@
#+TITLE: Shaders
#+AUTHOR: Riyyi
#+LANGUAGE: en
#+OPTIONS: toc:nil
Topics:
- [[./memory-layout.org][Memory Layout]]
+28
View File
@@ -0,0 +1,28 @@
# ------------------------------------------
# User config between these lines
# Set project name
set(GAME "game")
# ------------------------------------------
project(${GAME} CXX)
# Define game source files
file(GLOB_RECURSE GAME_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_executable(${GAME} ${GAME_SOURCES})
target_include_directories(${GAME} PRIVATE
"src")
target_link_libraries(${GAME} ${ENGINE})
target_compile_options(${GAME} PRIVATE ${COMPILE_FLAGS_PROJECT})
target_precompile_headers(${GAME} REUSE_FROM ${ENGINE})
# ------------------------------------------
# Add 'make run' target
add_custom_target(run
COMMAND ${GAME}
WORKING_DIRECTORY "..")
add_dependencies(run ${ENGINE})
+132
View File
@@ -0,0 +1,132 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include "glm/ext/matrix_transform.hpp" // glm::radians
#include "inferno/component/cameracomponent.h"
#include "inferno/component/transformcomponent.h"
#include "inferno/io/input.h"
#include "inferno/keycodes.h"
#include "cameracontroller.h"
namespace example {
void CameraController::updateOrthographic(float deltaTime)
{
// Update camera rotation
float cameraRotateSpeed = ROTATE_SPEED * deltaTime;
if (Inferno::Input::isKeyPressed(Inferno::keyCode("GLFW_KEY_Q"))) {
transform->rotate.z -= cameraRotateSpeed;
}
if (Inferno::Input::isKeyPressed(Inferno::keyCode("GLFW_KEY_E"))) {
transform->rotate.z += cameraRotateSpeed;
}
if (transform->rotate.z > 180.0f) {
transform->rotate.z -= 360.0f;
}
else if (transform->rotate.z <= -180.0f) {
transform->rotate.z += 360.0f;
}
// Update camera translation
float cameraTranslateSpeed = TRANSLATE_SPEED * deltaTime;
// WASD movement
if (Inferno::Input::isKeyPressed(Inferno::keyCode("GLFW_KEY_W"))) {
transform->translate.x += -sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
transform->translate.y += cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
}
if (Inferno::Input::isKeyPressed(Inferno::keyCode("GLFW_KEY_S"))) {
transform->translate.x -= -sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
transform->translate.y -= cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
}
if (Inferno::Input::isKeyPressed(Inferno::keyCode("GLFW_KEY_A"))) {
transform->translate.x -= cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
transform->translate.y -= sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
}
if (Inferno::Input::isKeyPressed(Inferno::keyCode("GLFW_KEY_D"))) {
transform->translate.x += cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
transform->translate.y += sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
}
// Update camera zoom
float zoomSpeed = ZOOM_SENSITIVITY * deltaTime;
if (Inferno::Input::isKeyPressed(Inferno::keyCode("GLFW_KEY_EQUAL"))) {
m_camera->zoomLevel -= zoomSpeed;
}
if (Inferno::Input::isKeyPressed(Inferno::keyCode("GLFW_KEY_MINUS"))) {
m_camera->zoomLevel += zoomSpeed;
}
m_camera->zoomLevel = std::max(m_camera->zoomLevel, 0.25f);
m_camera->zoomLevel = std::min(m_camera->zoomLevel, 10.0f);
}
void CameraController::updatePerspective(float deltaTime)
{
// Get mouse movement offset compared to last frame
float xOffset = Inferno::Input::getXOffset() * MOUSE_SENSITIVITY;
float yOffset = Inferno::Input::getYOffset() * MOUSE_SENSITIVITY;
m_camera->yaw += xOffset;
m_camera->pitch += yOffset;
// Prevent gimbal lock
if (m_camera->pitch > 89.0f)
m_camera->pitch = 89.0f;
if (m_camera->pitch < -89.0f)
m_camera->pitch = -89.0f;
// Update camera rotation, by calculating direction vector via yaw and pitch
transform->rotate = {
cos(glm::radians(m_camera->pitch)) * cos(glm::radians(m_camera->yaw)),
sin(glm::radians(m_camera->pitch)),
cos(glm::radians(m_camera->pitch)) * sin(glm::radians(m_camera->yaw))
};
transform->rotate = glm::normalize(transform->rotate);
// The direction vector is based on
// Camera direction (z): normalize(position - target)
// Right axis (x): normalize(cross(up, direction))
// Up axis (y): cross(direction, right)
// Source: https://learnopengl.com/img/getting-started/camera_axes.png
// Cross = combination of two vectors in 3D space,
// where result is always perpendicular to both of the vectors
// Update camera translation
float cameraSpeed = TRANSLATE_SPEED * deltaTime;
// WASD movement
if (Inferno::Input::isKeyPressed(Inferno::keyCode("GLFW_KEY_W"))) {
transform->translate += transform->rotate * cameraSpeed;
}
if (Inferno::Input::isKeyPressed(Inferno::keyCode("GLFW_KEY_S"))) {
transform->translate -= transform->rotate * cameraSpeed;
}
if (Inferno::Input::isKeyPressed(Inferno::keyCode("GLFW_KEY_A"))) {
transform->translate -= glm::normalize(glm::cross(transform->rotate, m_camera->up)) * cameraSpeed;
}
if (Inferno::Input::isKeyPressed(Inferno::keyCode("GLFW_KEY_D"))) {
transform->translate += glm::normalize(glm::cross(transform->rotate, m_camera->up)) * cameraSpeed;
}
// Up / down movement
if (Inferno::Input::isKeyPressed(Inferno::keyCode("GLFW_KEY_SPACE"))) {
transform->translate.y += cameraSpeed;
}
if (Inferno::Input::isKeyPressed(Inferno::keyCode("GLFW_KEY_LEFT_SHIFT"))) {
transform->translate.y -= cameraSpeed;
}
}
} // namespace example
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "inferno/component/cameracomponent.h"
#include "inferno/script/nativescript.h"
#define TRANSLATE_SPEED 2.5f
#define ROTATE_SPEED 90.0f
#define ZOOM_SENSITIVITY 2.5f
#define MOUSE_SENSITIVITY 0.25f
namespace example {
class CameraController final : public Inferno::NativeScript {
public:
virtual void update(float deltaTime) override
{
m_camera = &getComponent<Inferno::CameraComponent>();
if (m_camera->type == Inferno::CameraType::Orthographic) {
updateOrthographic(deltaTime);
}
else if (m_camera->type == Inferno::CameraType::Perspective) {
updatePerspective(deltaTime);
}
}
void updateOrthographic(float deltaTime);
void updatePerspective(float deltaTime);
private:
Inferno::CameraComponent* m_camera { nullptr };
};
BIND_NATIVE(CameraController);
} // namespace example
+29
View File
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include "game.h"
Game::Game()
: Application()
{
}
Game::~Game()
{
}
void Game::update()
{
}
void Game::render()
{
}
Inferno::Application* Inferno::createApplication(int argc, char* argv[])
{
return new Game;
}
+19
View File
@@ -0,0 +1,19 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include "inferno.h"
#include "inferno/entrypoint.h"
class Game final : public Inferno::Application {
public:
Game();
~Game();
void update() override;
void render() override;
};
Inferno::Application* Inferno::createApplication(int argc, char* argv[]);
-15
View File
@@ -1,15 +0,0 @@
#include "inferno.h"
#include "inferno/entrypoint.h"
class Game : public Inferno::Application
{
public:
Game() : Application({}) {}
~Game() {}
};
Inferno::Application& Inferno::createApplication()
{
Game::initialize();
return Game::the();
}
-210
View File
@@ -1,210 +0,0 @@
#include "inferno/application.h"
#include "inferno/assert.h"
#include "inferno/core.h"
#include "inferno/event/applicationevent.h"
#include "inferno/event/event.h"
#include "inferno/event/keyevent.h"
#include "inferno/event/mouseevent.h"
#include "inferno/keycodes.h"
#include "inferno/io/input.h"
#include "inferno/io/log.h"
#include "inferno/render/buffer.h"
#include "inferno/render/context.h"
#include "inferno/render/font.h"
#include "inferno/render/renderer.h"
#include "inferno/render/shader.h"
#include "inferno/render/texture.h"
#include "inferno/scene/scene.h"
#include "inferno/settings.h"
#include "inferno/time.h"
#include "inferno/window.h"
namespace Inferno {
Application::Application(s)
{
// Set singleton instance early
s_instance = this;
// Initialize
Settings::initialize();
m_window = std::make_unique<Window>();
m_window->setEventCallback(NF_BIND_EVENT(Application::onEvent));
Input::initialize();
ShaderManager::initialize();
TextureManager::initialize();
RenderCommand::initialize();
Renderer2D::initialize();
RendererCharacter::initialize();
FontManager::initialize();
m_scene = std::make_shared<Scene>();
m_scene->initialize();
// Load assets
m_font = FontManager::the().load("assets/fnt/dejavu-sans");
}
Application::~Application()
{
m_scene->destroy();
FontManager::destroy();
RendererCharacter::destroy();
Renderer2D::destroy();
RenderCommand::destroy();
TextureManager::destroy();
ShaderManager::destroy();
// Input::destroy();
Settings::destroy();
}
int Application::run()
{
dbg() << "Application startup";
std::array<CharacterVertex, Renderer::vertexPerQuad> character;
// character.at(0).quad.textureCoordinates = { 0.0f, 0.0f }; // bottom left
// character.at(1).quad.textureCoordinates = { 1.0f, 0.0f };
// character.at(2).quad.textureCoordinates = { 1.0f, 1.0f }; // top right
// character.at(3).quad.textureCoordinates = { 0.0f, 1.0f };
auto f = FontManager::the().get("assets/fnt/dejavu-sans");
auto c = f->get('5');
// dbg() << c->position << " " << c->size;
uint32_t textureWidth = f->texture()->width();
uint32_t textureHeight = f->texture()->height();
ASSERT(textureWidth == textureHeight, "Invalid font texture!");
float quadWidth = (c->size.x / (float)textureWidth) - 0.04; // @Todo something wrong with the width
float quadHeight = c->size.y / (float)textureHeight;
character.at(0).quad.position = { -quadWidth, -quadHeight, 0.0f }; // bottom left
character.at(1).quad.position = { quadWidth, -quadHeight, 0.0f }; // bottom right
character.at(2).quad.position = { quadWidth, quadHeight, 0.0f }; // top right
character.at(3).quad.position = { -quadWidth, quadHeight, 0.0f }; // top left
glm::vec2 x {
1 - (textureWidth - c->position.x) / (float)textureWidth,
1 - (textureWidth - c->position.x - c->size.x) / (float)textureWidth
};
glm::vec2 y {
(textureHeight - c->position.y - c->size.y) / (float)textureHeight,
(textureHeight - c->position.y) / (float)textureHeight
};
// dbg() < y;
character.at(0).quad.textureCoordinates = { x.x, y.x };
character.at(1).quad.textureCoordinates = { x.y, y.x };
character.at(2).quad.textureCoordinates = { x.y, y.y };
character.at(3).quad.textureCoordinates = { x.x, y.y };
// pos
// texcoords
//
// width
// edge
// borderwidth
// borderedge
// bordercolor
// offset
while (!m_window->shouldClose()) {
float time = Time::time();
float deltaTime = time - m_lastFrameTime;
m_lastFrameTime = time;
// dbg() << "Frametime " << deltaTime * 1000 << "ms";
// Update
Input::update();
m_window->update();
m_scene->update(deltaTime);
// Render
RenderCommand::clearColor({ 0.2f, 0.3f, 0.3f, 1.0f });
RenderCommand::clear();
Renderer2D::the().beginScene(m_scene->cameraProjectionView()); // camera, lights, environment
RendererCharacter::the().beginScene();
m_scene->render();
RendererCharacter::the().drawCharacter(character, f->texture());
Renderer2D::the().endScene();
RendererCharacter::the().endScene();
m_window->render();
}
dbg() << "Application shutdown";
return m_status;
}
void Application::onEvent(Event& e)
{
EventDispatcher dispatcher(e);
dispatcher.dispatch<WindowCloseEvent>(NF_BIND_EVENT(Application::onWindowClose));
dispatcher.dispatch<WindowResizeEvent>(NF_BIND_EVENT(Application::onWindowResize));
dispatcher.dispatch<KeyPressEvent>(NF_BIND_EVENT(Application::onKeyPress));
dispatcher.dispatch<MousePositionEvent>(NF_BIND_EVENT(Application::onMousePosition));
}
bool Application::onWindowClose(WindowCloseEvent& e)
{
// Suppress unused warning
(void)e;
info() << "WindowCloseEvent triggered";
m_window->setShouldClose(true);
return true;
}
bool Application::onWindowResize(WindowResizeEvent& e)
{
// Suppress unused warning
(void)e;
infoln("WindowResizeEvent {}x{} triggered", e.getWidth(), e.getHeight());
RenderCommand::setViewport(0, 0, e.getWidth(), e.getHeight());
return true;
}
bool Application::onKeyPress(KeyPressEvent& e)
{
// Suppress unused warning
(void)e;
infoln("KeyPressEvent {} ({}) triggered",
Input::getKeyName(e.getKey()),
e.getKey());
// Stop the main loop on 'Escape' keypress
if (e.getKey() == keyCode("GLFW_KEY_ESCAPE")) {
m_window->setShouldClose(true);
}
return true;
}
bool Application::onMousePosition(MousePositionEvent& e)
{
return Input::onMousePosition(e);
}
}
-89
View File
@@ -1,89 +0,0 @@
#ifndef APPLICATION_H
#define APPLICATION_H
#include <memory> // std::unique_ptr, std::shared_ptr
#include "inferno/singleton.h"
namespace Inferno {
class Event;
class Font;
class KeyPressEvent;
class MousePositionEvent;
class Scene;
class Window;
class WindowCloseEvent;
class WindowResizeEvent;
class Application : public Singleton<Application> {
public:
Application(s);
virtual ~Application();
int run();
void onEvent(Event& e);
bool onWindowClose(WindowCloseEvent& e);
bool onWindowResize(WindowResizeEvent& e);
bool onKeyPress(KeyPressEvent& e);
bool onMousePosition(MousePositionEvent& e);
inline void setStatus(int status) { m_status = status; }
inline Window& getWindow() const { return *m_window; }
private:
int m_status { 0 };
float m_lastFrameTime { 0.0f };
std::unique_ptr<Window> m_window;
std::shared_ptr<Scene> m_scene;
//
std::shared_ptr<Font> m_font;
//
};
// To be defined in the game
extern Application& createApplication();
}
#endif // APPLICATION_H
// C++17 features used:
// - std::string:view, log.h
// - std::shared_ptr array management, renderer.h
// OpenGL 4.5 features used:
// -
// Gameplan
// v Entrypoint
// v Logging
// v Events
// v Window
// v Settings loader (json)
// v Input polling
// v OpenGL context
// - GPUDriver (?)
// v Renderer
// v Buffers
// ~ Shader
// - Schene (camera, lights, environment)
// - Texture loading
// - Model loading
// - Entity Component System
// - Serialization
// - Level format
// - Tools (Tiled?)
// - Scripting (Lua)
// - Global object access can be done in 3 ways:
// - Singleton, static, extern
// @Todo
// - Settings should contain all file paths (ex: shaders)
// - RefPtr<>
// - Rename Application::get() to Application::the() for singleton
-64
View File
@@ -1,64 +0,0 @@
#ifndef ASSERT_H
#define ASSERT_H
#include <csignal> // raise
#include <cstdint> // uint32_t
#include "inferno/core.h"
#include "inferno/io/log.h"
#ifndef NDEBUG
#define NF_ENABLE_ASSERTS
#endif
// Asserts
#ifdef NF_ENABLE_ASSERTS
// Check if SIGTRAP is available
#ifdef SIGTRAP
#define ABORT_SIGNAL SIGTRAP
#else
#define ABORT_SIGNAL SIGABRT
#endif
// Non-standard function macro
#ifdef GCC
#define FUNCTION_MACRO __PRETTY_FUNCTION__
#elif MSVC
#define FUNCTION_MACRO __FUNCSIG__
#else
#define FUNCTION_MACRO __func__
#endif
// ##__VA_ARGS__ is a non-standard GCC extension, C++20 introduces __VA_OPT__
// https://stackoverflow.com/questions/52891546/what-does-va-args-mean
#define ASSERT(expr, ...) static_cast<bool>(expr) ? (void)0 : Inferno::__assert_fail(#expr, __FILE__, __LINE__, FUNCTION_MACRO, ##__VA_ARGS__)
#define ASSERT_NOT_REACHED() ASSERT(false)
#else
#define ASSERT(expr, ...)
#define ASSERT_NOT_REACHED() CRASH()
#endif
#define CRASH() raise(SIGABRT)
namespace Inferno {
#ifdef NF_ENABLE_ASSERTS
template<typename... P>
inline void __assert_fail(const char* assertion, const char* file, uint32_t line, const char* function, P&&... parameters)
{
dangerln(false, "ASSERTION `{}' FAILED.", assertion);
if (sizeof...(P) > 0) {
dbg(false) << " ";
dbgln(Log::Danger, false, std::forward<P>(parameters)...);
}
danger() << "\n " << file << ":" << line << " in " << function;
raise(ABORT_SIGNAL);
}
#endif
}
#endif // ASSERT_H
@@ -1,32 +0,0 @@
#ifndef CAMERA_COMPONENT_H
#define CAMERA_COMPONENT_H
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
#include "glm/ext/vector_float3.hpp" // glm::vec3
namespace Inferno {
enum CameraType {
Orthographic,
Perspective,
};
struct CameraComponent {
CameraType type = CameraType::Perspective;
// Orthographic
float zoomLevel = 1.0f;
glm::vec3 rotateAxis { 0.0f, 0.0f, 1.0f };
// Perspective
float fov = 90.0f;
float pitch = 0.0f;
float yaw = -90.0f;
glm::vec3 up { 0.0f, 1.0f, 0.0f };
glm::mat4 projection { 1.0f }; // Identity matrix
};
}
#endif // CAMERA_COMPONENT_H
@@ -1,22 +0,0 @@
#ifndef LUA_SCRIPT_COMPONENT_H
#define LUA_SCRIPT_COMPONENT_H
#include <string> // std::string
#include <utility> // std::move
namespace Inferno {
class LuaScript;
struct LuaScriptComponent {
LuaScript* instance { nullptr };
std::string path;
// Dont allow manually setting instance during construction
LuaScriptComponent() {}
LuaScriptComponent(const std::string& path)
: path(std::move(path)) {}
};
}
#endif // LUA_SCRIPT_COMPONENT_H
@@ -1,33 +0,0 @@
#ifndef NATIVE_SCRIPT_COMPONENT_H
#define NATIVE_SCRIPT_COMPONENT_H
#include "inferno/assert.h"
#include "inferno/script/nativescript.h"
namespace Inferno {
struct NativeScriptComponent {
NativeScript* instance { nullptr };
NativeScript* (*initialize)();
// Dont allow manually setting instance during construction
NativeScriptComponent() {}
template<typename T>
void bind()
{
ASSERT(instance == nullptr, "NativeScript already bound");
initialize = []() { return static_cast<NativeScript*>(new T()); };
}
void destroy() {
ASSERT(instance, "Attempting to destroy an uninitialized NativeScript");
delete instance;
instance = nullptr;
}
};
}
#endif // NATIVE_SCRIPT_COMPONENT_H
@@ -1,19 +0,0 @@
#ifndef SPRITE_COMPONENT_H
#define SPRITE_COMPONENT_H
#include <memory> // std::shared_ptr
#include "glm/ext/vector_float4.hpp" // glm::vec4
#include "inferno/render/texture.h"
namespace Inferno {
struct SpriteComponent {
glm::vec4 color { 1.0f };
std::shared_ptr<Texture> texture;
};
}
#endif // SPRITE_COMPONENT_H
@@ -1,21 +0,0 @@
#ifndef TAG_COMPONENT_H
#define TAG_COMPONENT_H
#include <string> // std::string
#include <utility> // std::move
namespace Inferno {
struct TagComponent {
std::string tag;
TagComponent() = default;
TagComponent(const std::string& tag)
: tag(std::move(tag)) {}
operator const std::string&() const { return tag; }
};
}
#endif // TAG_COMPONENT_H
@@ -1,47 +0,0 @@
#include "inferno/component/transformcomponent.h"
namespace Inferno {
const LogStream& operator<<(const LogStream& stream, const glm::vec2& value)
{
return stream << "{ "
<< (value.x >= 0.0f ? " " : "") << value.x << ", "
<< (value.y >= 0.0f ? " " : "") << value.y
<< " }";
}
const LogStream& operator<<(const LogStream& stream, const glm::vec3& value)
{
return stream << "{ "
<< (value.x >= 0.0f ? " " : "") << value.x << ", "
<< (value.y >= 0.0f ? " " : "") << value.y << ", "
<< (value.z >= 0.0f ? " " : "") << value.z
<< " }";
}
const LogStream& operator<<(const LogStream& stream, const glm::vec4& value)
{
return stream << "{ "
<< (value.x >= 0.0f ? " " : "") << value.x << ", "
<< (value.y >= 0.0f ? " " : "") << value.y << ", "
<< (value.z >= 0.0f ? " " : "") << value.z << ", "
<< (value.w >= 0.0f ? " " : "") << value.w
<< " }";
}
const LogStream& operator<<(const LogStream& stream, const glm::mat4& value)
{
return stream << "mat4 "
<< value[0] << "\n " << value[1] << "\n "
<< value[2] << "\n " << value[3];
}
const LogStream& operator<<(const LogStream& stream, const TransformComponent& value)
{
return stream << "transform "
<< value.translate << " t\n "
<< value.rotate << " r\n "
<< value.scale << " s";
}
}
@@ -1,27 +0,0 @@
#ifndef TRANSFORM_COMPONENT_H
#define TRANSFORM_COMPONENT_H
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
#include "glm/ext/vector_float3.hpp" // glm::vec3
#include "inferno/io/log.h"
namespace Inferno {
struct TransformComponent {
glm::vec3 translate { 0.0f, 0.0f, 0.0f };
glm::vec3 rotate { 0.0f, 0.0f, 0.0f } ;
glm::vec3 scale { 1.0f, 1.0f, 1.0f };
glm::mat4 transform { 1.0f }; // Identity matrix
};
// -----------------------------------------
const LogStream& operator<<(const LogStream& stream, const glm::vec2& value);
const LogStream& operator<<(const LogStream& stream, const glm::vec3& value);
const LogStream& operator<<(const LogStream& stream, const glm::vec4& value);
const LogStream& operator<<(const LogStream& stream, const glm::mat4& value);
const LogStream& operator<<(const LogStream& stream, const TransformComponent& value);
}
#endif // TRANSFORM_COMPONENT_H
-21
View File
@@ -1,21 +0,0 @@
#ifndef CORE_H
#define CORE_H
#include <functional> // std::bind
#define BIT(x) (1 << x)
#define NF_BIND_EVENT(f) std::bind(&f, this, std::placeholders::_1)
// Compiler
#if defined(__clang__)
#define GCC
#elif defined(__INTEL_COMPILER) // Supports some GCC extensions
#define GCC
#elif defined(__GNUG__) || (defined(__GNUC__) && defined(__cplusplus))
#define GCC
#elif defined(_MSC_VER)
#define MSVC
#endif
#endif // CORE_H
-27
View File
@@ -1,27 +0,0 @@
/*
* `m_` for member variables,
* `s_` for static variables,
* `g_` for global variables.
*/
#ifndef ENTRYPOINT_H
#define ENTRYPOINT_H
#include "inferno/application.h"
int main(int argc, char* argv[])
{
// Suppress unused warning
(void)argc;
(void)argv;
auto& app = Inferno::createApplication();
int status = app.run();
app.destroy();
return status;
}
#endif // ENTRYPOINT_H
@@ -1,42 +0,0 @@
#ifndef APPLICATIONEVENT_H
#define APPLICATIONEVENT_H
#include <sstream> // std::stringstream
#include "inferno/event/event.h"
namespace Inferno {
class WindowCloseEvent : public Event {
public:
EVENT_CLASS_TYPE(WindowClose)
EVENT_CLASS_CATEGORY(ApplicationEventCategory)
};
class WindowResizeEvent : public Event {
public:
WindowResizeEvent(int width, int height) :
m_width(width), m_height(height) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "WindowResize: " << m_width << "x" << m_height;
return ss.str();
}
// -----------------------------------------
inline int getWidth() const { return m_width; }
inline int getHeight() const { return m_height; }
EVENT_CLASS_TYPE(WindowResize)
EVENT_CLASS_CATEGORY(ApplicationEventCategory)
private:
int m_width;
int m_height;
};
}
#endif // APPLICATIONEVENT_H
-111
View File
@@ -1,111 +0,0 @@
#ifndef EVENT_H
#define EVENT_H
#include <ostream> // std::ostream
#include "inferno/core.h"
namespace Inferno {
enum class EventType {
None = 0,
WindowClose,
WindowResize,
KeyPress,
KeyRelease,
KeyRepeat,
MouseButtonPress,
MouseButtonRelease,
MousePosition,
MouseScroll,
JoystickConnected,
JoystickDisconnected,
};
enum EventCategory {
None = 0,
ApplicationEventCategory = BIT(0),
InputEventCategory = BIT(1),
KeyEventCategory = BIT(2),
MouseEventCategory = BIT(3),
MouseButtonEventCategory = BIT(4),
JoystickEventCatergory = BIT(5),
};
class Event {
// EventDispatcher is allowed to access Event private/protected members
friend class EventDispatcher;
public:
virtual ~Event() {}
virtual std::string toString() const { return getName(); }
inline bool inCategory(EventCategory category)
{
return getCategoryFlags() & category;
}
// -----------------------------------------
// Getter function templates
virtual char getCategoryFlags() const = 0;
virtual const char* getName() const = 0;
virtual EventType getType() const = 0;
private:
bool handled = false;
};
class EventDispatcher {
public:
EventDispatcher(Event& e) : m_event(e) {}
// Easily dispatch all type of Events, call with:
// dispatch<T>(std::bind(&F, this, std::placeholders::_1));
// T is the type of Event
// F is the function to call, signature: bool name(T& e);
template<typename T, typename F>
bool dispatch(const F& function)
{
// If <constructed> type is same as member variable type
if (T::getTypeStatic() == m_event.getType()) {
// Call the function
m_event.handled = function(static_cast<T& >(m_event));
return true;
}
return false;
}
private:
Event& m_event;
};
// Add class type functions macro
#define EVENT_CLASS_TYPE(type) \
virtual const char* getName() const override { return #type; } \
virtual EventType getType() const override { return getTypeStatic(); } \
static inline EventType getTypeStatic() { return EventType::type; }
// Add class catergory function macro
#define EVENT_CLASS_CATEGORY(category) \
virtual char getCategoryFlags() const override { return category; }
// Make Events easily printable
inline std::ostream& operator<<(std::ostream& os, const Event& e)
{
return os << e.toString();
}
}
#endif // EVENT_H
-56
View File
@@ -1,56 +0,0 @@
#ifndef JOYSTICKEVENT_H
#define JOYSTICKEVENT_H
#include <sstream> // std::stringstream
#include "inferno/event/event.h"
namespace Inferno {
class JoystickEvent : public Event {
public:
inline int getID() const { return m_id; }
EVENT_CLASS_CATEGORY(InputEventCategory | JoystickEventCatergory)
protected:
JoystickEvent(int id) :
m_id(id) {}
private:
int m_id;
};
class JoystickConnectedEvent : public JoystickEvent {
public:
JoystickConnectedEvent(int id) :
JoystickEvent(id) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "JoystickConnected: " << getID();
return ss.str();
}
EVENT_CLASS_TYPE(JoystickConnected)
};
class JoystickDisconnectedEvent : public JoystickEvent {
public:
JoystickDisconnectedEvent(int id) :
JoystickEvent(id) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "JoystickDisconnected: " << getID();
return ss.str();
}
EVENT_CLASS_TYPE(JoystickDisconnected)
};
}
#endif // JOYSTICKEVENT_H
-71
View File
@@ -1,71 +0,0 @@
#ifndef KEYEVENT_H
#define KEYEVENT_H
#include <sstream> // std::stringstream
#include "inferno/event/event.h"
namespace Inferno {
class KeyEvent : public Event {
public:
inline int getKey() const { return m_key; }
EVENT_CLASS_CATEGORY(InputEventCategory | KeyEventCategory)
protected:
KeyEvent(int key) :
m_key(key) {}
private:
int m_key;
};
class KeyPressEvent : public KeyEvent {
public:
KeyPressEvent(int key) :
KeyEvent(key) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "KeyPress: " << getKey();
return ss.str();
}
EVENT_CLASS_TYPE(KeyPress)
};
class KeyReleaseEvent : public KeyEvent {
public:
KeyReleaseEvent(int key) :
KeyEvent(key) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "KeyRelease: " << getKey();
return ss.str();
}
EVENT_CLASS_TYPE(KeyPress)
};
class KeyRepeatEvent : public KeyEvent {
public:
KeyRepeatEvent(int key) :
KeyEvent(key) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "KeyRepeat: " << getKey();
return ss.str();
}
EVENT_CLASS_TYPE(KeyPress)
};
}
#endif // KEYEVENT_H
-106
View File
@@ -1,106 +0,0 @@
#ifndef MOUSEEVENT_H
#define MOUSEEVENT_H
#include <sstream> // std::stringstream
#include "inferno/event/event.h"
namespace Inferno {
class MouseButtonEvent : public Event {
public:
inline int getButton() const { return m_button; }
EVENT_CLASS_CATEGORY(InputEventCategory | MouseEventCategory | MouseButtonEventCategory)
protected:
MouseButtonEvent(int button) :
m_button(button) {}
private:
int m_button;
};
class MouseButtonPressEvent : public MouseButtonEvent {
public:
MouseButtonPressEvent(int button) :
MouseButtonEvent(button) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "MouseButtonPressed: " << getButton();
return ss.str();
}
EVENT_CLASS_TYPE(MouseButtonPress)
};
class MouseButtonReleaseEvent : public MouseButtonEvent {
public:
MouseButtonReleaseEvent(int button) :
MouseButtonEvent(button) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "MouseButtonReleased: " << getButton();
return ss.str();
}
EVENT_CLASS_TYPE(MouseButtonRelease)
};
class MousePositionEvent : public Event {
public:
MousePositionEvent(float xPos, float yPos) :
m_xPos(xPos), m_yPos(yPos) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "MousePosition: " << m_xPos << "x" << m_yPos;
return ss.str();
}
// -----------------------------------------
inline float getXPos() const { return m_xPos; }
inline float getYPos() const { return m_yPos; }
EVENT_CLASS_TYPE(MousePosition)
EVENT_CLASS_CATEGORY(InputEventCategory | MouseEventCategory)
private:
float m_xPos;
float m_yPos;
};
class MouseScrollEvent : public Event {
public:
MouseScrollEvent(float xOffset, float yOffset) :
m_xOffset(xOffset), m_yOffset(yOffset) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "MouseScroll: " << m_xOffset << ":" << m_yOffset;
return ss.str();
}
// -----------------------------------------
inline float getXOffset() const { return m_xOffset; }
inline float getYOffset() const { return m_yOffset; }
EVENT_CLASS_TYPE(MouseScroll)
EVENT_CLASS_CATEGORY(InputEventCategory | MouseEventCategory)
private:
float m_xOffset;
float m_yOffset;
};
}
#endif // MOUSEEVENT_H
-47
View File
@@ -1,47 +0,0 @@
#include <ios> // std::ios
#include <memory> // std::make_unique
#include "inferno/assert.h"
#include "inferno/io/file.h"
namespace Inferno {
std::shared_ptr<char[]> File::raw(const std::string& path)
{
// Create input stream object and open file
std::ifstream file(path);
ASSERT(file.is_open(), "File could not open '{}'", path);
// Get length of the file
int32_t length = File::length(path, file);
// Allocate memory filled with zeros
auto buffer = std::shared_ptr<char[]>(new char[length + 1]);
// Fill buffer with file contents
file.read(buffer.get(), length);
file.close();
// Null termination
buffer[length] = '\0';
return buffer;
}
std::string File::read(const std::string &path)
{
// Create string from the buffer and return
return std::string(raw(path).get());
}
int32_t File::length(const std::string& path, std::ifstream& file)
{
file.seekg(0, std::ios::end);
int32_t length = file.tellg();
file.seekg(0, std::ios::beg);
ASSERT(length != -1, "File could not determine length '{}'", path);
return length;
}
}
-65
View File
@@ -1,65 +0,0 @@
#ifndef FILE_H
#define FILE_H
#include <fstream> // std::ifstream, std::ofstream
#include <iomanip> // std::setfill, std::setw
#include <memory> // std::shared_ptr
#include <string> // std::string
#include "inferno/assert.h"
#include "inferno/core.h"
#include "inferno/io/log.h"
namespace Inferno {
class File {
public:
static std::shared_ptr<char[]> raw(const std::string& path);
static std::string read(const std::string& path);
static int32_t length(const std::string& path, std::ifstream& file);
template<typename T>
static bool ioRead(T* t, const std::string& path)
{
std::ifstream file(path);
ASSERT(file.is_open(), "File could not open '{}'", path);
if (!file.is_open()) {
return false;
}
try {
file >> *t;
}
catch (...) {
return false;
}
return true;
}
template<typename T>
static bool ioWrite(T* t, const std::string& path)
{
std::ofstream file (path);
ASSERT(file.is_open(), "File could not open! {}", path);
if (!file.is_open()) {
return false;
}
try {
// Write file with single tabs, nicely formatted
file << std::setfill ('\t') << std::setw(1) << *t << std::endl;
}
catch (...) {
return false;
}
return true;
}
};
}
#endif // FILE_H
-103
View File
@@ -1,103 +0,0 @@
#include <cstring> // strcmp ??
#include <fstream> // std::ifstream
#include <ios> // std::ios
#include "inferno/assert.h"
#include "inferno/io/file.h"
#include "inferno/io/gltffile.h"
#include "inferno/io/log.h"
#include "inferno/util/string.h"
#include "inferno/util/json.h"
namespace Inferno {
std::pair<std::shared_ptr<char[]>, std::shared_ptr<char[]>> GltfFile::read(const std::string& path)
{
std::string extension = path.substr(path.find_first_of("."));
if (extension.compare(".glb") == 0) {
return glb(path);
}
else if (extension.compare(".gltf") == 0) {
return { File::raw(path), nullptr };
}
ASSERT(false, "GltfFile unknown file extension!");
return {};
}
std::pair<std::shared_ptr<char[]>, std::shared_ptr<char[]>> GltfFile::glb(const std::string& path)
{
// Create input stream object and open file
std::ifstream glb(path, std::ios::in | std::ios::binary);
ASSERT(glb.is_open(), "GltfFile could not open '{}'", path);
constexpr uint32_t size = 4;
constexpr uint32_t header = 12;
constexpr uint32_t json = 27; // Minimum valid glTF has an asset property with version specifier
// Get the actual length of the file
uint32_t length = static_cast<uint32_t>(File::length(path, glb));
ASSERT(length > header + json, "GltfFile too small to be valid '{}'", path);
// Read header
char magic[size];
char version[size];
char fileLength[size];
glb.read(magic, size);
glb.seekg(size * 1);
glb.read(version, size);
glb.seekg(size * 2);
glb.read(fileLength, size);
// Validate header
uint32_t magicInt = *reinterpret_cast<uint32_t*>(magic);
ASSERT(magicInt == 0x46546c67, "Gltf invalid header magic '{}'", magic);
uint32_t versionInt = *reinterpret_cast<uint32_t*>(version);
ASSERT(versionInt == 2, "Gltf unsupported version '{}'", versionInt);
uint32_t fileLengthInt = *reinterpret_cast<uint32_t*>(fileLength);
ASSERT(fileLengthInt == length, "Gltf file and reported byte size mismatch '{}' '{}'", length, fileLengthInt);
// Read JSON data
auto jsonChunk = readChunk(glb, header, 0x4e4f534a);
ASSERT(jsonChunk.second >= json, "Gltf file invalid JSON content length '{}'", jsonChunk.second);
// Read binary data
auto binaryChunk = readChunk(glb, header + size * 2 + jsonChunk.second, 0x004e4942);
glb.close();
return { jsonChunk.first, binaryChunk.first };
}
std::pair<std::shared_ptr<char[]>, uint32_t> GltfFile::readChunk(std::ifstream& ifstream, uint32_t offset, uint32_t type)
{
constexpr uint32_t size = 4;
char chunkLength[size];
char chunkType[size];
ifstream.seekg(offset);
ifstream.read(chunkLength, size);
ifstream.seekg(offset + size * 1);
ifstream.read(chunkType, size);
uint32_t chunkTypeInt = *reinterpret_cast<uint32_t*>(chunkType);
ASSERT(chunkTypeInt == type, "Gltf invalid chunk type '{}' != '{}'", chunkType, intToHex(type));
uint32_t chunkLengthInt = *reinterpret_cast<uint32_t*>(chunkLength);
// Allocate memory filled with zeros
std::shared_ptr<char[]> chunkData(new char[chunkLengthInt + 1]);
ifstream.seekg(offset + size * 2);
ifstream.read(chunkData.get(), chunkLengthInt);
chunkData.get()[chunkLengthInt] = '\0';
return { chunkData, chunkLengthInt };
}
} // namespace Inferno
-22
View File
@@ -1,22 +0,0 @@
#ifndef GLTF_FILE_H
#define GLTF_FILE_H
#include <cstdint> // uint32_t
#include <memory> // std::shared_ptr
#include <string> // std::string
#include <utility> // std::pair
namespace Inferno {
class GltfFile {
public:
static std::pair<std::shared_ptr<char[]>, std::shared_ptr<char[]>> read(const std::string& path);
private:
static std::pair<std::shared_ptr<char[]>, std::shared_ptr<char[]>> glb(const std::string& path);
static std::pair<std::shared_ptr<char[]>, uint32_t> readChunk(std::ifstream& ifstream, uint32_t offset, uint32_t type);
};
} // namespace Inferno
#endif // GLTF_FILE_H
-92
View File
@@ -1,92 +0,0 @@
#include "GLFW/glfw3.h"
#include "inferno/application.h"
#include "inferno/event/mouseevent.h"
#include "inferno/io/input.h"
#include "inferno/io/log.h"
#include "inferno/window.h"
namespace Inferno {
bool Input::m_firstMousePos = true;
float Input::m_xPosLast = 0.0f;
float Input::m_yPosLast = 0.0f;
float Input::m_xOffset = 0.0f;
float Input::m_yOffset = 0.0f;
void Input::initialize()
{
// Set cursor in the middle of the screen
m_xPosLast = Application::the().getWindow().getWidth() / 2.0f;
m_yPosLast = Application::the().getWindow().getHeight() / 2.0f;
info() << "Input initialized";
}
void Input::update()
{
// Stop infinite mouse movement
m_xOffset = 0.0f;
m_yOffset = 0.0f;
}
bool Input::onMousePosition(MousePositionEvent& e)
{
// Prevent weird jump on first cursor window enter
if(m_firstMousePos) {
m_firstMousePos = false;
m_xPosLast = e.getXPos();
m_yPosLast = e.getYPos();
}
m_xOffset = e.getXPos() - m_xPosLast;
// Reversed since y-coordinates range from bottom to top
m_yOffset = m_yPosLast - e.getYPos();
m_xPosLast = e.getXPos();
m_yPosLast = e.getYPos();
return true;
}
bool Input::isKeyPressed(int key)
{
GLFWwindow* w = Application::the().getWindow().getWindow();
return glfwGetKey(w, key) == GLFW_PRESS;
}
bool Input::isMouseButtonPressed(int button)
{
GLFWwindow* w = Application::the().getWindow().getWindow();
return glfwGetMouseButton(w, button) == GLFW_PRESS;
}
std::pair<float, float> Input::getMousePosition()
{
GLFWwindow* w = Application::the().getWindow().getWindow();
double xPos;
double yPos;
glfwGetCursorPos(w, &xPos, &yPos);
return { (float)xPos, (float)yPos };
}
float Input::getMouseX()
{
return getMousePosition().first;
}
float Input::getMouseY()
{
return getMousePosition().second;
}
const char* Input::getKeyName(int key)
{
return glfwGetKeyName(key, getKeyScancode(key));
}
int Input::getKeyScancode(int key)
{
return glfwGetKeyScancode(key);
}
}
-39
View File
@@ -1,39 +0,0 @@
#ifndef INPUT_H
#define INPUT_H
#include <utility> // std::pair
namespace Inferno {
class MousePositionEvent;
class Input {
public:
static void initialize();
static void update();
static bool onMousePosition(MousePositionEvent& e);
static bool isKeyPressed(int key);
static bool isMouseButtonPressed(int button);
static std::pair<float, float> getMousePosition();
static float getMouseX();
static float getMouseY();
static const char* getKeyName(int key);
static int getKeyScancode(int key);
static inline float getXOffset() { return m_xOffset; }
static inline float getYOffset() { return m_yOffset; }
private:
static bool m_firstMousePos;
static float m_xPosLast;
static float m_yPosLast;
static float m_xOffset;
static float m_yOffset;
};
}
#endif // INPUT_H
-320
View File
@@ -1,320 +0,0 @@
#include "inferno/assert.h"
#include "inferno/io/log.h"
#include <cstddef> // size_t
#include <cstdio> // fwrite, snprintf
#include <cstdlib> // malloc, free
#include <cstring> // memcpy, strlen
#include <string> // std::string
#include <string_view> // std::string_view
namespace Inferno {
BufferedLogStream::~BufferedLogStream()
{
// Free buffer memory
if (m_capacity > sizeof(m_buffer.stack)) {
free(m_buffer.heap);
}
}
void BufferedLogStream::grow(size_t bytes) const
{
// Bitwise & ~ example, we use 127 as binary starts at 0
// 0b001111111 127 ~
// 0b100000100 260 &
// -----------
// 0b110000000 384
// 0b100000100 260 &
// -----------
// 0b100000000 256
// Buffer is increased in chunks of 128 bytes
size_t newCapacity = (m_count + bytes + BUFFER_SIZE - 1) & ~(BUFFER_SIZE - 1);
unsigned char* newBuffer = static_cast<unsigned char*>(malloc(newCapacity));
// Copy the non-heap data into the new buffer
if (m_capacity <= sizeof(m_buffer.stack)) {
memcpy(newBuffer, m_buffer.stack, m_count);
}
// Copy old heap-buffer data into the new buffer, free old heap-buffer
else if (m_buffer.heap) {
memcpy(newBuffer, m_buffer.heap, m_count);
free(m_buffer.heap);
}
m_buffer.heap = newBuffer;
m_capacity = newCapacity;
}
// -----------------------------------------
DebugLogStream::~DebugLogStream()
{
if (m_type != Log::None) {
const char* clear = "\033[0m";
write(clear, strlen(clear));
}
if (m_newline) {
char newline = '\n';
write(&newline, 1);
}
fwrite(buffer(), 1, count(), stdout);
}
void DebugLogStream::color() const
{
const char* color = "";
if (m_type == Log::Info) {
color = "\x1B[34m";
}
else if (m_type == Log::Warn) {
color = "\x1B[33m";
}
else if (m_type == Log::Danger) {
color = "\x1B[31m";
}
else if (m_type == Log::Success) {
color = "\x1B[32m";
}
else if (m_type == Log::Comment) {
color = "\x1B[37m";
}
write(color, strlen(color));
}
// -----------------------------------------
StringLogStream::~StringLogStream()
{
char terminator = '\0';
write(&terminator, 1);
*m_fill = std::string(reinterpret_cast<char*>(buffer()));
}
// -----------------------------------------
const LogStream& operator<<(const LogStream& stream, const char* value)
{
if (value == nullptr) {
stream.write("(null)", 6);
return stream;
}
stream.write(value, strlen(value));
return stream;
}
const LogStream& operator<<(const LogStream& stream, const unsigned char* value)
{
if (value == nullptr) {
stream.write("(null)", 6);
return stream;
}
stream.write(value, strlen((const char*)value));
return stream;
}
const LogStream& operator<<(const LogStream& stream, const std::string& value)
{
stream.write(value.c_str(), value.length());
return stream;
}
const LogStream& operator<<(const LogStream& stream, const std::string_view& value)
{
stream.write(value.data(), value.length());
return stream;
}
const LogStream& operator<<(const LogStream& stream, char value)
{
stream.write(&value, 1);
return stream;
}
const LogStream& operator<<(const LogStream& stream, unsigned char value)
{
stream.write(&value, 1);
return stream;
}
const LogStream& operator<<(const LogStream& stream, int value)
{
// return stream << std::to_string(value);
char buffer[32];
snprintf(buffer, sizeof(buffer), "%d", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, long int value)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%ld", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, long long int value)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%lld", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, unsigned int value)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%u", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, long unsigned int value)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%lu", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, long long unsigned int value)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%llu", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, double value)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%.4f", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, float value)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%.4f", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, const void* value)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%p", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, bool value)
{
return stream << (value ? "true": "false");
}
const LogStream& operator<<(const LogStream& stream, Log value)
{
switch (value) {
case Log::None:
return stream << "Log";
case Log::Info:
return stream << "Info";
case Log::Warn:
return stream << "Warn";
case Log::Danger:
return stream << "Danger";
case Log::Success:
return stream << "Success";
case Log::Comment:
return stream << "Comment";
default:
ASSERT_NOT_REACHED();
return stream;
}
}
// -----------------------------------------
DebugLogStream dbg()
{
return {};
}
DebugLogStream dbg(bool newline)
{
return DebugLogStream(newline);
}
DebugLogStream info()
{
return DebugLogStream(Log::Info);
}
DebugLogStream warn()
{
return DebugLogStream(Log::Warn);
}
DebugLogStream danger()
{
return DebugLogStream(Log::Danger);
}
DebugLogStream success()
{
return DebugLogStream(Log::Success);
}
DebugLogStream comment()
{
return DebugLogStream(Log::Comment);
}
DebugLogStream info(bool newline)
{
return DebugLogStream(Log::Info, newline);
}
DebugLogStream warn(bool newline)
{
return DebugLogStream(Log::Warn, newline);
}
DebugLogStream danger(bool newline)
{
return DebugLogStream(Log::Danger, newline);
}
DebugLogStream success(bool newline)
{
return DebugLogStream(Log::Success, newline);
}
DebugLogStream comment(bool newline)
{
return DebugLogStream(Log::Comment, newline);
}
// -----------------------------------------
void dbgln(Log type, bool newline)
{
(void)type, DebugLogStream(newline);
}
void dbgln(Log type, bool newline, const char* format)
{
DebugLogStream(type, newline) << format;
}
// -----------------------------------------
StringLogStream str(std::string* fill)
{
return StringLogStream(fill);
}
}
-224
View File
@@ -1,224 +0,0 @@
#ifndef LOG_H
#define LOG_H
#include <cstddef> // size_t
#include <cstring> // memcpy
#include <string> // std::string
#include <string_view> // std::string_view
#include <utility> // std::forward
#define BUFFER_SIZE 128
namespace Inferno {
enum class Log {
None,
Info,
Warn,
Danger,
Success,
Comment,
};
// -----------------------------------------
class LogStream {
public:
LogStream() {}
virtual ~LogStream() {}
virtual void write(const char* characters, int length) const = 0;
virtual void write(const unsigned char* characters, int length) const = 0;
};
// -----------------------------------------
class BufferedLogStream : public LogStream {
public:
BufferedLogStream() {}
virtual ~BufferedLogStream();
inline virtual void write(const char* characters, int length) const override
{
write(reinterpret_cast<const unsigned char*>(characters), length);
}
inline virtual void write(const unsigned char* characters, int length) const override
{
size_t newSize = m_count + length;
if (newSize > m_capacity) {
grow(length);
}
// Append to buffer
memcpy(buffer() + m_count, characters, length);
m_count = newSize;
}
protected:
inline unsigned char* buffer() const
{
if (m_capacity <= sizeof(m_buffer.stack)) {
return m_buffer.stack;
}
return m_buffer.heap;
}
inline bool empty() const { return m_count == 0; }
inline size_t count() const { return m_count; }
private:
void grow(size_t bytes) const;
mutable size_t m_count { 0 };
mutable size_t m_capacity { BUFFER_SIZE };
union {
mutable unsigned char* heap { nullptr };
mutable unsigned char stack[BUFFER_SIZE];
} m_buffer;
};
// -----------------------------------------
class DebugLogStream final : public BufferedLogStream {
public:
DebugLogStream()
: m_newline(true), m_type(Log::None) {}
DebugLogStream(bool newline)
: m_newline(newline), m_type(Log::None) {}
DebugLogStream(Log type)
: m_newline(true), m_type(type) { color(); }
DebugLogStream(Log type, bool newline)
: m_newline(newline), m_type(type) { color(); }
virtual ~DebugLogStream() override;
void color() const;
private:
bool m_newline;
Log m_type;
};
// -----------------------------------------
class StringLogStream final : public BufferedLogStream {
public:
StringLogStream(std::string* fill)
: m_fill(fill) {}
virtual ~StringLogStream() override;
private:
std::string* m_fill { nullptr };
};
// -----------------------------------------
const LogStream& operator<<(const LogStream& stream, const char* value);
const LogStream& operator<<(const LogStream& stream, const unsigned char* value);
const LogStream& operator<<(const LogStream& stream, const std::string& value);
const LogStream& operator<<(const LogStream& stream, const std::string_view& value);
const LogStream& operator<<(const LogStream& stream, char value);
const LogStream& operator<<(const LogStream& stream, unsigned char value);
const LogStream& operator<<(const LogStream& stream, int value);
const LogStream& operator<<(const LogStream& stream, long int value);
const LogStream& operator<<(const LogStream& stream, long long int value);
const LogStream& operator<<(const LogStream& stream, unsigned int value);
const LogStream& operator<<(const LogStream& stream, long unsigned int value);
const LogStream& operator<<(const LogStream& stream, long long unsigned int value);
const LogStream& operator<<(const LogStream& stream, double value);
const LogStream& operator<<(const LogStream& stream, float value);
const LogStream& operator<<(const LogStream& stream, const void* value);
const LogStream& operator<<(const LogStream& stream, bool value);
const LogStream& operator<<(const LogStream& stream, Log value);
// -----------------------------------------
DebugLogStream dbg();
DebugLogStream info();
DebugLogStream warn();
DebugLogStream danger();
DebugLogStream success();
DebugLogStream comment();
DebugLogStream dbg(bool newline);
DebugLogStream info(bool newline);
DebugLogStream warn(bool newline);
DebugLogStream danger(bool newline);
DebugLogStream success(bool newline);
DebugLogStream comment(bool newline);
// -----------------------------------------
template<typename... P> void dbgln(const char* format, P&&... parameters) { dbgln(Log::None, true, format, std::forward<P>(parameters)...); }
template<typename... P> void infoln(const char* format, P&&... parameters) { dbgln(Log::Info, true, format, std::forward<P>(parameters)...); }
template<typename... P> void warnln(const char* format, P&&... parameters) { dbgln(Log::Warn, true, format, std::forward<P>(parameters)...); }
template<typename... P> void dangerln(const char* format, P&&... parameters) { dbgln(Log::Danger, true, format, std::forward<P>(parameters)...); }
template<typename... P> void successln(const char* format, P&&... parameters) { dbgln(Log::Success, true, format, std::forward<P>(parameters)...); }
template<typename... P> void commentln(const char* format, P&&... parameters) { dbgln(Log::Comment, true, format, std::forward<P>(parameters)...); }
template<typename... P> void dbgln(const std::string& format, P&&... parameters) { dbgln(Log::None, true, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void infoln(const std::string& format, P&&... parameters) { dbgln(Log::Info, true, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void warnln(const std::string& format, P&&... parameters) { dbgln(Log::Warn, true, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void dangerln(const std::string& format, P&&... parameters) { dbgln(Log::Danger, true, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void successln(const std::string& format, P&&... parameters) { dbgln(Log::Success, true, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void commentln(const std::string& format, P&&... parameters) { dbgln(Log::Comment, true, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void dbgln(const std::string_view& format, P&&... parameters) { dbgln(Log::None, true, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void infoln(const std::string_view& format, P&&... parameters) { dbgln(Log::Info, true, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void warnln(const std::string_view& format, P&&... parameters) { dbgln(Log::Warn, true, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void dangerln(const std::string_view& format, P&&... parameters) { dbgln(Log::Danger, true, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void successln(const std::string_view& format, P&&... parameters) { dbgln(Log::Success, true, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void commentln(const std::string_view& format, P&&... parameters) { dbgln(Log::Comment, true, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void dbgln(bool newline, const char* format, P&&... parameters) { dbgln(Log::None, newline, format, std::forward<P>(parameters)...); }
template<typename... P> void infoln(bool newline, const char* format, P&&... parameters) { dbgln(Log::Info, newline, format, std::forward<P>(parameters)...); }
template<typename... P> void warnln(bool newline, const char* format, P&&... parameters) { dbgln(Log::Warn, newline, format, std::forward<P>(parameters)...); }
template<typename... P> void dangerln(bool newline, const char* format, P&&... parameters) { dbgln(Log::Danger, newline, format, std::forward<P>(parameters)...); }
template<typename... P> void successln(bool newline, const char* format, P&&... parameters) { dbgln(Log::Success, newline, format, std::forward<P>(parameters)...); }
template<typename... P> void commentln(bool newline, const char* format, P&&... parameters) { dbgln(Log::Comment, newline, format, std::forward<P>(parameters)...); }
template<typename... P> void dbgln(bool newline, const std::string& format, P&&... parameters) { dbgln(Log::None, newline, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void infoln(bool newline, const std::string& format, P&&... parameters) { dbgln(Log::Info, newline, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void warnln(bool newline, const std::string& format, P&&... parameters) { dbgln(Log::Warn, newline, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void dangerln(bool newline, const std::string& format, P&&... parameters) { dbgln(Log::Danger, newline, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void successln(bool newline, const std::string& format, P&&... parameters) { dbgln(Log::Success, newline, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void commentln(bool newline, const std::string& format, P&&... parameters) { dbgln(Log::Comment, newline, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void dbgln(bool newline, const std::string_view& format, P&&... parameters) { dbgln(Log::None, newline, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void infoln(bool newline, const std::string_view& format, P&&... parameters) { dbgln(Log::Info, newline, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void warnln(bool newline, const std::string_view& format, P&&... parameters) { dbgln(Log::Warn, newline, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void dangerln(bool newline, const std::string_view& format, P&&... parameters) { dbgln(Log::Danger, newline, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void successln(bool newline, const std::string_view& format, P&&... parameters) { dbgln(Log::Success, newline, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void commentln(bool newline, const std::string_view& format, P&&... parameters) { dbgln(Log::Comment, newline, format.data(), std::forward<P>(parameters)...); }
// -----------------------------------------
void dbgln(Log type, bool newline);
void dbgln(Log type, bool newline, const char* format);
// https://en.cppreference.com/w/cpp/language/parameter_pack#Example
template<typename T, typename... P>
void dbgln(Log type, bool newline, const char* format, T value, P&&... parameters)
{
std::string_view view { format };
for(uint32_t i = 0; format[i] != '\0'; i++) {
if (format[i] == '{' && format[i + 1] == '}') {
DebugLogStream(type, false) << view.substr(0, i) << value;
dbgln(type, newline, format + i + 2, parameters...);
return;
}
}
}
// -----------------------------------------
StringLogStream str(std::string* fill);
}
#endif // LOG_H
-143
View File
@@ -1,143 +0,0 @@
#include <string> // std::string
#include <unordered_map> // std::unordered_map
#include "GLFW/glfw3.h"
#include "inferno/assert.h"
#include "inferno/keycodes.h"
namespace Inferno {
static std::unordered_map<std::string, int> keys ({
{ MAP_KEY(GLFW_KEY_UNKNOWN) },
{ MAP_KEY(GLFW_KEY_SPACE) },
{ MAP_KEY(GLFW_KEY_APOSTROPHE) },
{ MAP_KEY(GLFW_KEY_COMMA) },
{ MAP_KEY(GLFW_KEY_MINUS) },
{ MAP_KEY(GLFW_KEY_PERIOD) },
{ MAP_KEY(GLFW_KEY_SLASH) },
{ MAP_KEY(GLFW_KEY_0) },
{ MAP_KEY(GLFW_KEY_1) },
{ MAP_KEY(GLFW_KEY_2) },
{ MAP_KEY(GLFW_KEY_3) },
{ MAP_KEY(GLFW_KEY_4) },
{ MAP_KEY(GLFW_KEY_5) },
{ MAP_KEY(GLFW_KEY_6) },
{ MAP_KEY(GLFW_KEY_7) },
{ MAP_KEY(GLFW_KEY_8) },
{ MAP_KEY(GLFW_KEY_9) },
{ MAP_KEY(GLFW_KEY_SEMICOLON) },
{ MAP_KEY(GLFW_KEY_EQUAL) },
{ MAP_KEY(GLFW_KEY_A) },
{ MAP_KEY(GLFW_KEY_B) },
{ MAP_KEY(GLFW_KEY_C) },
{ MAP_KEY(GLFW_KEY_D) },
{ MAP_KEY(GLFW_KEY_E) },
{ MAP_KEY(GLFW_KEY_F) },
{ MAP_KEY(GLFW_KEY_G) },
{ MAP_KEY(GLFW_KEY_H) },
{ MAP_KEY(GLFW_KEY_I) },
{ MAP_KEY(GLFW_KEY_J) },
{ MAP_KEY(GLFW_KEY_K) },
{ MAP_KEY(GLFW_KEY_L) },
{ MAP_KEY(GLFW_KEY_M) },
{ MAP_KEY(GLFW_KEY_N) },
{ MAP_KEY(GLFW_KEY_O) },
{ MAP_KEY(GLFW_KEY_P) },
{ MAP_KEY(GLFW_KEY_Q) },
{ MAP_KEY(GLFW_KEY_R) },
{ MAP_KEY(GLFW_KEY_S) },
{ MAP_KEY(GLFW_KEY_T) },
{ MAP_KEY(GLFW_KEY_U) },
{ MAP_KEY(GLFW_KEY_V) },
{ MAP_KEY(GLFW_KEY_W) },
{ MAP_KEY(GLFW_KEY_X) },
{ MAP_KEY(GLFW_KEY_Y) },
{ MAP_KEY(GLFW_KEY_Z) },
{ MAP_KEY(GLFW_KEY_LEFT_BRACKET) },
{ MAP_KEY(GLFW_KEY_BACKSLASH) },
{ MAP_KEY(GLFW_KEY_RIGHT_BRACKET) },
{ MAP_KEY(GLFW_KEY_GRAVE_ACCENT) },
{ MAP_KEY(GLFW_KEY_WORLD_1) },
{ MAP_KEY(GLFW_KEY_WORLD_2) },
{ MAP_KEY(GLFW_KEY_ESCAPE) },
{ MAP_KEY(GLFW_KEY_ENTER) },
{ MAP_KEY(GLFW_KEY_TAB) },
{ MAP_KEY(GLFW_KEY_BACKSPACE) },
{ MAP_KEY(GLFW_KEY_INSERT) },
{ MAP_KEY(GLFW_KEY_DELETE) },
{ MAP_KEY(GLFW_KEY_RIGHT) },
{ MAP_KEY(GLFW_KEY_LEFT) },
{ MAP_KEY(GLFW_KEY_DOWN) },
{ MAP_KEY(GLFW_KEY_UP) },
{ MAP_KEY(GLFW_KEY_PAGE_UP) },
{ MAP_KEY(GLFW_KEY_PAGE_DOWN) },
{ MAP_KEY(GLFW_KEY_HOME) },
{ MAP_KEY(GLFW_KEY_END) },
{ MAP_KEY(GLFW_KEY_CAPS_LOCK) },
{ MAP_KEY(GLFW_KEY_SCROLL_LOCK) },
{ MAP_KEY(GLFW_KEY_NUM_LOCK) },
{ MAP_KEY(GLFW_KEY_PRINT_SCREEN) },
{ MAP_KEY(GLFW_KEY_PAUSE) },
{ MAP_KEY(GLFW_KEY_F1) },
{ MAP_KEY(GLFW_KEY_F2) },
{ MAP_KEY(GLFW_KEY_F3) },
{ MAP_KEY(GLFW_KEY_F4) },
{ MAP_KEY(GLFW_KEY_F5) },
{ MAP_KEY(GLFW_KEY_F6) },
{ MAP_KEY(GLFW_KEY_F7) },
{ MAP_KEY(GLFW_KEY_F8) },
{ MAP_KEY(GLFW_KEY_F9) },
{ MAP_KEY(GLFW_KEY_F10) },
{ MAP_KEY(GLFW_KEY_F11) },
{ MAP_KEY(GLFW_KEY_F12) },
{ MAP_KEY(GLFW_KEY_F13) },
{ MAP_KEY(GLFW_KEY_F14) },
{ MAP_KEY(GLFW_KEY_F15) },
{ MAP_KEY(GLFW_KEY_F16) },
{ MAP_KEY(GLFW_KEY_F17) },
{ MAP_KEY(GLFW_KEY_F18) },
{ MAP_KEY(GLFW_KEY_F19) },
{ MAP_KEY(GLFW_KEY_F20) },
{ MAP_KEY(GLFW_KEY_F21) },
{ MAP_KEY(GLFW_KEY_F22) },
{ MAP_KEY(GLFW_KEY_F23) },
{ MAP_KEY(GLFW_KEY_F24) },
{ MAP_KEY(GLFW_KEY_F25) },
{ MAP_KEY(GLFW_KEY_KP_0) },
{ MAP_KEY(GLFW_KEY_KP_1) },
{ MAP_KEY(GLFW_KEY_KP_2) },
{ MAP_KEY(GLFW_KEY_KP_3) },
{ MAP_KEY(GLFW_KEY_KP_4) },
{ MAP_KEY(GLFW_KEY_KP_5) },
{ MAP_KEY(GLFW_KEY_KP_6) },
{ MAP_KEY(GLFW_KEY_KP_7) },
{ MAP_KEY(GLFW_KEY_KP_8) },
{ MAP_KEY(GLFW_KEY_KP_9) },
{ MAP_KEY(GLFW_KEY_KP_DECIMAL) },
{ MAP_KEY(GLFW_KEY_KP_DIVIDE) },
{ MAP_KEY(GLFW_KEY_KP_MULTIPLY) },
{ MAP_KEY(GLFW_KEY_KP_SUBTRACT) },
{ MAP_KEY(GLFW_KEY_KP_ADD) },
{ MAP_KEY(GLFW_KEY_KP_ENTER) },
{ MAP_KEY(GLFW_KEY_KP_EQUAL) },
{ MAP_KEY(GLFW_KEY_LEFT_SHIFT) },
{ MAP_KEY(GLFW_KEY_LEFT_CONTROL) },
{ MAP_KEY(GLFW_KEY_LEFT_ALT) },
{ MAP_KEY(GLFW_KEY_LEFT_SUPER) },
{ MAP_KEY(GLFW_KEY_RIGHT_SHIFT) },
{ MAP_KEY(GLFW_KEY_RIGHT_CONTROL) },
{ MAP_KEY(GLFW_KEY_RIGHT_ALT) },
{ MAP_KEY(GLFW_KEY_RIGHT_SUPER) },
{ MAP_KEY(GLFW_KEY_MENU) },
});
// -----------------------------------------
int keyCode(const char* name)
{
ASSERT(keys.find(name) != keys.end(), "keyCode could not find '{}'", name);
return keys.at(name);
}
}
-12
View File
@@ -1,12 +0,0 @@
#ifndef INPUTCODES_H
#define INPUTCODES_H
#define MAP_KEY(key) #key, key
namespace Inferno {
int keyCode(const char* name);
}
#endif // INPUTCODES_H
-298
View File
@@ -1,298 +0,0 @@
#include "glad/glad.h"
#include "inferno/assert.h"
#include "inferno/core.h"
#include "inferno/io/log.h"
#include "inferno/render/buffer.h"
namespace Inferno {
// -----------------------------------------
BufferElement::BufferElement(BufferElementType type, std::string name, bool normalized) :
m_type(type),
m_name(name),
m_size(BufferElement::getTypeSize(type)),
m_normalized(normalized)
{
}
uint32_t BufferElement::getTypeSize() const
{
return BufferElement::getTypeSize(m_type);
}
uint32_t BufferElement::getTypeCount() const
{
return BufferElement::getTypeCount(m_type);
}
uint32_t BufferElement::getTypeGL() const
{
return BufferElement::getTypeGL(m_type);
}
uint32_t BufferElement::getTypeSize(const BufferElementType type)
{
switch (type) {
case BufferElementType::None: return 0;
case BufferElementType::Bool: return sizeof(bool);
case BufferElementType::Bool2: return sizeof(bool) * 2;
case BufferElementType::Bool3: return sizeof(bool) * 3;
case BufferElementType::Bool4: return sizeof(bool) * 4;
case BufferElementType::Int: return sizeof(int32_t);
case BufferElementType::Int2: return sizeof(int32_t) * 2;
case BufferElementType::Int3: return sizeof(int32_t) * 3;
case BufferElementType::Int4: return sizeof(int32_t) * 4;
case BufferElementType::Uint: return sizeof(uint32_t);
case BufferElementType::Uint2: return sizeof(uint32_t) * 2;
case BufferElementType::Uint3: return sizeof(uint32_t) * 3;
case BufferElementType::Uint4: return sizeof(uint32_t) * 4;
case BufferElementType::Float: return sizeof(float);
case BufferElementType::Vec2: return sizeof(float) * 2;
case BufferElementType::Vec3: return sizeof(float) * 3;
case BufferElementType::Vec4: return sizeof(float) * 4;
case BufferElementType::Double: return sizeof(double);
case BufferElementType::Double2: return sizeof(double);
case BufferElementType::Double3: return sizeof(double);
case BufferElementType::Double4: return sizeof(double);
case BufferElementType::Mat2: return sizeof(float) * 2 * 2;
case BufferElementType::Mat3: return sizeof(float) * 3 * 3;
case BufferElementType::Mat4: return sizeof(float) * 4 * 4;
case BufferElementType::DoubleMat2: return sizeof(double) * 2 * 2;
case BufferElementType::DoubleMat3: return sizeof(double) * 3 * 3;
case BufferElementType::DoubleMat4: return sizeof(double) * 4 * 4;
};
ASSERT(false, "BufferElement unknown BufferElementType size!");
return 0;
}
uint32_t BufferElement::getTypeCount(const BufferElementType type)
{
switch (type) {
case BufferElementType::None: return 0;
case BufferElementType::Bool: return 1;
case BufferElementType::Bool2: return 2;
case BufferElementType::Bool3: return 3;
case BufferElementType::Bool4: return 4;
case BufferElementType::Int: return 1;
case BufferElementType::Int2: return 2;
case BufferElementType::Int3: return 3;
case BufferElementType::Int4: return 4;
case BufferElementType::Uint: return 1;
case BufferElementType::Uint2: return 2;
case BufferElementType::Uint3: return 3;
case BufferElementType::Uint4: return 4;
case BufferElementType::Float: return 1;
case BufferElementType::Vec2: return 2;
case BufferElementType::Vec3: return 3;
case BufferElementType::Vec4: return 4;
case BufferElementType::Double: return 1;
case BufferElementType::Double2: return 2;
case BufferElementType::Double3: return 3;
case BufferElementType::Double4: return 4;
case BufferElementType::Mat2: return 2 * 2;
case BufferElementType::Mat3: return 3 * 3;
case BufferElementType::Mat4: return 4 * 4;
case BufferElementType::DoubleMat2: return 2 * 2;
case BufferElementType::DoubleMat3: return 3 * 3;
case BufferElementType::DoubleMat4: return 4 * 4;
};
ASSERT(false, "BufferElement unknown BufferElementType count!");
return 0;
}
uint32_t BufferElement::getTypeGL(const BufferElementType type)
{
switch (type) {
case BufferElementType::None: return GL_NONE;
case BufferElementType::Bool: return GL_BOOL;
case BufferElementType::Bool2: return GL_BOOL;
case BufferElementType::Bool3: return GL_BOOL;
case BufferElementType::Bool4: return GL_BOOL;
case BufferElementType::Int: return GL_INT;
case BufferElementType::Int2: return GL_INT;
case BufferElementType::Int3: return GL_INT;
case BufferElementType::Int4: return GL_INT;
case BufferElementType::Uint: return GL_UNSIGNED_INT;
case BufferElementType::Uint2: return GL_UNSIGNED_INT;
case BufferElementType::Uint3: return GL_UNSIGNED_INT;
case BufferElementType::Uint4: return GL_UNSIGNED_INT;
case BufferElementType::Float: return GL_FLOAT;
case BufferElementType::Vec2: return GL_FLOAT;
case BufferElementType::Vec3: return GL_FLOAT;
case BufferElementType::Vec4: return GL_FLOAT;
case BufferElementType::Double: return GL_DOUBLE;
case BufferElementType::Double2: return GL_DOUBLE;
case BufferElementType::Double3: return GL_DOUBLE;
case BufferElementType::Double4: return GL_DOUBLE;
case BufferElementType::Mat2: return GL_FLOAT;
case BufferElementType::Mat3: return GL_FLOAT;
case BufferElementType::Mat4: return GL_FLOAT;
case BufferElementType::DoubleMat2: return GL_DOUBLE;
case BufferElementType::DoubleMat3: return GL_DOUBLE;
case BufferElementType::DoubleMat4: return GL_DOUBLE;
};
ASSERT(false, "BufferElement unknown BufferElementType GL!");
return 0;
}
// -----------------------------------------
BufferLayout::BufferLayout(const std::initializer_list<BufferElement>& elements)
: m_elements(elements)
{
calculateOffsetsAndStride();
}
void BufferLayout::calculateOffsetsAndStride()
{
m_stride = 0;
for (auto& element : m_elements) {
element.setOffset(m_stride);
m_stride += element.getSize();
}
}
// -----------------------------------------
VertexBuffer::VertexBuffer(size_t size)
{
glGenBuffers(1, &m_id);
bind();
// Reserve data on the GPU
glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_DYNAMIC_DRAW);
unbind();
}
VertexBuffer::VertexBuffer(float* vertices, size_t size)
{
glGenBuffers(1, &m_id);
bind();
// Upload data to the GPU
glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);
unbind();
}
VertexBuffer::~VertexBuffer()
{
glDeleteBuffers(1, &m_id);
}
void VertexBuffer::bind() const
{
glBindBuffer(GL_ARRAY_BUFFER, m_id);
}
void VertexBuffer::unbind() const
{
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void VertexBuffer::uploadData(const void* data, uint32_t size)
{
bind();
// Upload data to the GPU
glBufferSubData(GL_ARRAY_BUFFER, 0, size, data);
unbind();
}
// -----------------------------------------
IndexBuffer::IndexBuffer(uint32_t* indices, size_t size) :
m_count(size / sizeof(uint32_t))
{
glCreateBuffers(1, &m_id);
bind();
// Upload data to the GPU
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, indices, GL_STATIC_DRAW);
unbind();
}
IndexBuffer::~IndexBuffer()
{
glDeleteBuffers(1, &m_id);
}
void IndexBuffer::bind() const
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_id);
}
void IndexBuffer::unbind() const
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
// -----------------------------------------
VertexArray::VertexArray()
{
glCreateVertexArrays(1, &m_id);
}
VertexArray::~VertexArray()
{
glDeleteVertexArrays(1, &m_id);
}
void VertexArray::bind() const
{
glBindVertexArray(m_id);
}
void VertexArray::unbind() const
{
glBindVertexArray(0);
}
void VertexArray::addVertexBuffer(std::shared_ptr<VertexBuffer> vertexBuffer)
{
const auto& layout = vertexBuffer->getLayout();
ASSERT(layout.getElements().size(), "VertexBuffer has no layout");
bind();
vertexBuffer->bind();
uint32_t index = 0;
for (const auto& element : layout) {
glEnableVertexAttribArray(index);
glVertexAttribPointer(
index,
element.getTypeCount(),
element.getTypeGL(),
element.getNormalized() ? GL_TRUE : GL_FALSE,
layout.getStride(),
reinterpret_cast<const void*>(element.getOffset()));
index++;
}
m_vertexBuffers.push_back(std::move(vertexBuffer));
unbind();
vertexBuffer->unbind();
}
void VertexArray::setIndexBuffer(std::shared_ptr<IndexBuffer> indexBuffer)
{
bind();
indexBuffer->bind();
m_indexBuffer = std::move(indexBuffer);
unbind();
indexBuffer->unbind();
}
}
-148
View File
@@ -1,148 +0,0 @@
#ifndef BUFFER_H
#define BUFFER_H
#include <cstddef> // size_t
#include <cstdint> // int32_t, uint32_t
#include <memory> // std::shared_ptr
#include <string> // std::string
#include <vector> // std::vector
namespace Inferno {
// https://www.khronos.org/opengl/wiki/Data_Type_(GLSL)
enum class BufferElementType {
None = 0,
Bool, Bool2, Bool3, Bool4, // bvec
Int, Int2, Int3, Int4, // ivec
Uint, Uint2, Uint3, Uint4, // uvec
Float, Vec2, Vec3, Vec4, // vec
Double, Double2, Double3, Double4, // dvec
Mat2, Mat3, Mat4, // mat
DoubleMat2, DoubleMat3, DoubleMat4, // dmat
};
// -----------------------------------------
// Describes one element of the BufferLayout
class BufferElement {
public:
BufferElement(BufferElementType type, std::string name, bool normalized = false);
uint32_t getTypeSize() const;
uint32_t getTypeCount() const;
uint32_t getTypeGL() const;
static uint32_t getTypeSize(const BufferElementType type);
static uint32_t getTypeCount(const BufferElementType type);
static uint32_t getTypeGL(const BufferElementType type);
inline BufferElementType getType() const{ return m_type; }
inline std::string getName() const { return m_name; }
inline uint32_t getSize() const { return m_size; }
inline uint32_t getOffset() const { return m_offset; }
inline bool getNormalized() const { return m_normalized; }
inline void setType(const BufferElementType& type) { m_type = type; }
inline void setName(const std::string& name) { m_name = name; }
inline void setSize(const uint32_t& size) { m_size = size; }
inline void setOffset(const uint32_t& offset) { m_offset = offset; }
inline void setNormalized(const bool& normalized) { m_normalized = normalized; }
private:
BufferElementType m_type;
std::string m_name;
uint32_t m_size { 0 };
uint32_t m_offset { 0 };
bool m_normalized { false };
};
// -----------------------------------------
// Layout that describes raw vertex data
class BufferLayout {
public:
BufferLayout() {}
BufferLayout(const std::initializer_list<BufferElement>& elements);
inline const std::vector<BufferElement>& getElements() const { return m_elements; }
inline uint32_t getStride() const { return m_stride; }
// Iterators
inline std::vector<BufferElement>::iterator begin() { return m_elements.begin(); }
inline std::vector<BufferElement>::iterator end() { return m_elements.end(); }
inline std::vector<BufferElement>::const_iterator begin() const { return m_elements.begin(); }
inline std::vector<BufferElement>::const_iterator end() const { return m_elements.end(); }
protected:
void calculateOffsetsAndStride();
private:
std::vector<BufferElement> m_elements;
uint32_t m_stride { 0 };
};
// -----------------------------------------
// GPU memory which holds raw vertex data
class VertexBuffer {
public:
VertexBuffer(size_t size);
VertexBuffer(float* vertices, size_t size);
~VertexBuffer();
void bind() const;
void unbind() const;
void uploadData(const void* data, uint32_t size);
inline const BufferLayout& getLayout() const { return m_layout; }
inline void setLayout(const BufferLayout& layout) { m_layout = layout; }
private:
uint32_t m_id { 0 };
BufferLayout m_layout;
};
// -----------------------------------------
// Vertices order of rendering
class IndexBuffer {
public:
IndexBuffer(uint32_t* indices, size_t size);
~IndexBuffer();
void bind() const;
void unbind() const;
inline uint32_t getCount() const { return m_count; }
private:
uint32_t m_id { 0 };
uint32_t m_count { 0 };
};
// -----------------------------------------
// Array that holds the vertex attributes configuration
class VertexArray {
public:
VertexArray();
~VertexArray();
void bind() const;
void unbind() const;
void addVertexBuffer(std::shared_ptr<VertexBuffer> vertexBuffer);
void setIndexBuffer(std::shared_ptr<IndexBuffer> indexBuffer);
inline const std::vector<std::shared_ptr<VertexBuffer>>& getVertexBuffers() const { return m_vertexBuffers; }
inline std::shared_ptr<IndexBuffer> getIndexBuffer() const { return m_indexBuffer; }
private:
uint32_t m_id { 0 };
std::vector<std::shared_ptr<VertexBuffer>> m_vertexBuffers;
std::shared_ptr<IndexBuffer> m_indexBuffer;
};
}
#endif // BUFFER_H
-52
View File
@@ -1,52 +0,0 @@
#include "glad/glad.h"
#include "GLFW/glfw3.h"
#include "inferno/assert.h"
#include "inferno/core.h"
#include "inferno/io/log.h"
#include "inferno/render/context.h"
#include "inferno/window.h"
namespace Inferno {
Context::Context(GLFWwindow* window) :
m_window(window)
{
ASSERT(window, "Context window is nullptr!");
}
void Context::initialize()
{
Context::setCurrent();
// Initialize glad
int glad = gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
ASSERT(glad, "Failed to initialize glad!");
// Log OpenGL properties
comment() << "OpenGL Info:";
comment() << " Vendor: " << glGetString(GL_VENDOR);
comment() << " Renderer: " << glGetString(GL_RENDERER);
comment() << " Version: " << glGetString(GL_VERSION);
// Check OpenGL version
ASSERT(GLVersion.major > 4 || (GLVersion.major == 4 && GLVersion.minor >= 5),
"Inferno requires at least OpenGL version 4.5!");
}
void Context::destroy()
{
}
void Context::render()
{
glfwSwapBuffers(m_window);
}
void Context::setCurrent()
{
// Set current OpenGL context to this window
glfwMakeContextCurrent(m_window);
}
}
-25
View File
@@ -1,25 +0,0 @@
#ifndef CONTEXT_H
#define CONTEXT_H
struct GLFWwindow;
namespace Inferno {
class Context {
public:
Context(GLFWwindow* window);
void initialize();
void destroy();
void render();
void setCurrent();
private:
GLFWwindow* m_window { nullptr };
};
}
#endif // CONTEXT_H
-163
View File
@@ -1,163 +0,0 @@
#include <limits> // std::numeric_limits
#include <string> // std::getline, std::stoi
#include <utility> // std::move
#include "inferno/assert.h"
#include "inferno/io/file.h"
#include "inferno/render/font.h"
#include "inferno/render/texture.h"
#include "inferno/util/integer.h"
namespace Inferno {
Font::Font(const std::string& name)
: m_name(std::move(name))
{
std::string path = name + ".fnt";
std::string image = name + ".png";
std::string font = File::read(path);
parseFont(font);
m_texture = std::make_shared<Texture>(image);
}
void Font::parseFont(const std::string& font)
{
std::istringstream iss(font);
for (std::string line; std::getline(iss, line);) {
if (findAction(line).compare("info") != 0 &&
findAction(line).compare("char") != 0) {
continue;
}
const std::vector<std::string> columns = findColumns(line);
// Info
if (findAction(line).compare("info") == 0) {
m_size = std::stou(findValue("size", columns));
continue;
}
// Character
unsigned char id = std::stoi(findValue("id", columns));
Character character = {
{ std::stou(findValue("x", columns)), std::stou(findValue("y", columns)) },
{ std::stou(findValue("width", columns)), std::stou(findValue("height", columns)) },
{ std::stoi(findValue("xoffset", columns)), std::stoi(findValue("yoffset", columns)) },
std::stou(findValue("xadvance", columns))
};
m_characterList.emplace(id, std::make_shared<Character>(character));
}
}
const std::string Font::findAction(const std::string& line)
{
return line.substr(0, line.find(" "));
}
const std::vector<std::string> Font::findColumns(const std::string& line)
{
std::vector<std::string> elements;
size_t index = 0;
size_t find = 0;
size_t findFirstNotOf = 0;
// Loop over line characters
while (find != std::string::npos) {
find = line.find(" ", index);
findFirstNotOf = line.find_first_not_of(" ", index);
// Add element
if (find > findFirstNotOf) {
elements.push_back(line.substr(index, find - findFirstNotOf));
index += 1 + find - findFirstNotOf;
}
// Skip double spaces
else {
index = findFirstNotOf;
}
}
ASSERT(!elements.empty(), "Font file did not find any columns");
return elements;
}
const std::string Font::findValue(const std::string& key, const std::vector<std::string>& columns)
{
size_t find = 0;
// Loop over columns
for (auto& column : columns) {
find = column.find(key + "=");
if (find != std::string::npos) {
return column.substr(key.length() + 1);
}
}
ASSERT(false, "Font file did not contain key '{}'", key);
return "";
}
// -----------------------------------------
FontManager::FontManager(s)
{
info() << "FontManager initialized";
}
FontManager::~FontManager()
{
}
void FontManager::add(const std::string& name, std::shared_ptr<Font> font)
{
// Construct (key, value) pair and insert it into the unordered_map
m_fontList.emplace(std::move(name), std::move(font));
}
std::shared_ptr<Font> FontManager::load(const std::string& name)
{
if (exists(name)) {
return get(name);
}
std::shared_ptr<Font> font = std::make_shared<Font>(name);
add(name, font);
return get(name);
}
std::shared_ptr<Font> FontManager::get(const std::string& name)
{
return exists(name) ? m_fontList.at(name) : nullptr;
}
bool FontManager::exists(const std::string& name)
{
return m_fontList.find(name) != m_fontList.end();
}
void FontManager::remove(const std::string& name)
{
if (exists(name)) {
m_fontList.erase(name);
}
}
void FontManager::remove(std::shared_ptr<Font> font)
{
if (exists(font->name())) {
m_fontList.erase(font->name());
}
}
// -----------------------------------------
const LogStream& operator<<(const LogStream& stream, const glm::ivec2& value)
{
return stream << "{ " << value.x << ", " << value.y << " }";
}
}
-87
View File
@@ -1,87 +0,0 @@
#ifndef FONT_H
#define FONT_H
#include <cstdint> // uint32_t
#include <memory> // std::shared_ptr
#include <string> // std::string
#include <unordered_map> // std::unordered_map
#include <vector> // std::vector
#include "glm/ext/vector_uint2.hpp" // glm::uvec2
#include "glm/ext/vector_int2.hpp" // glm::ivec2
#include "inferno/io/log.h"
#include "inferno/singleton.h"
namespace Inferno {
class Texture;
struct Character {
glm::uvec2 position; // Position
glm::uvec2 size; // Width/height
glm::ivec2 offset; // Offset from baseline to left / top of glyph
uint32_t advance; // Amount to advance to next glyph
};
// -----------------------------------------
class Font {
public:
Font(const std::string& name);
virtual ~Font() {}
inline std::string name() const { return m_name; }
inline uint32_t size() const { return m_size; }
inline std::shared_ptr<Texture> texture() const { return m_texture; }
inline std::shared_ptr<Character> get(unsigned char c) const { return m_characterList.at(c); }
inline std::shared_ptr<Character> operator[](unsigned char c) const { return m_characterList.at(c); }
private:
void parseFont(const std::string& font);
const std::string findAction(const std::string& line);
const std::vector<std::string> findColumns(const std::string& line);
const std::string findValue(const std::string& key, const std::vector<std::string>& columns);
std::string m_name;
uint32_t m_size;
std::shared_ptr<Texture> m_texture;
std::unordered_map<unsigned char, std::shared_ptr<Character>> m_characterList;
};
// -----------------------------------------
class FontManager final : public Singleton<FontManager> {
public:
FontManager(s);
virtual ~FontManager();
void add(const std::string& name, std::shared_ptr<Font> font);
std::shared_ptr<Font> load(const std::string& name);
std::shared_ptr<Font> get(const std::string& name);
bool exists(const std::string& name);
void remove(const std::string& name);
void remove(std::shared_ptr<Font> font);
private:
std::unordered_map<std::string, std::shared_ptr<Font>> m_fontList;
};
// -----------------------------------------
const LogStream& operator<<(const LogStream& stream, const glm::ivec2& value);
}
#endif // FONT_H
// FontManager fm;
// Font f = fm.load("path/to/font");
// Font f2("path/to/font");
// Character c = f['a'];
// Look into using signed distance fields for texture map generation ? anti-aliasing for text
// https://youtu.be/d8cfgcJR9Tk
-339
View File
@@ -1,339 +0,0 @@
#include <algorithm> // std::copy
#include <utility> // std::move
#include "nlohmann/json.hpp"
#include "inferno/assert.h"
#include "inferno/io/file.h"
#include "inferno/io/gltffile.h"
#include "inferno/io/log.h"
#include "inferno/render/gltf.h"
#include "inferno/util/integer.h"
namespace Inferno {
Gltf::Gltf(const std::string& path)
: m_path(std::move(path))
{
auto gltf = GltfFile::read(path);
ASSERT(gltf.first, "Gltf model invalid JSON content '{}'", path);
json json = json::parse(gltf.first.get());
// Add binary data from .glb files
if (gltf.second) {
m_model.data.emplace(0, std::move(gltf.second));
}
// Properties
// Asset
// ---------------------------------
ASSERT(Json::hasProperty(json, "asset"), "GlTF model missing required property 'asset'");
auto asset = json["asset"];
ASSERT(asset.is_object(), "Gltf model invalid property type 'asset'");
parseAsset(&m_model.asset, asset);
// Scene
// ---------------------------------
if (Json::hasProperty(json, "scenes")) {
auto scenes = json["scenes"];
ASSERT(scenes.is_array(), "Gltf model invalid property type 'scenes'");
for (auto& [key, object] : scenes.items()) {
glTF::Scene scene;
parseScene(&scene, key, object);
m_model.scenes.emplace_back(std::move(scene));
}
}
// Node
// ---------------------------------
if (Json::hasProperty(json, "nodes")) {
auto nodes = json["nodes"];
ASSERT(nodes.is_array(), "Gltf model invalid property type 'nodes'");
for (auto& [key, object] : nodes.items()) {
glTF::Node node;
parseNode(&node, key, object);
m_model.nodes.emplace_back(std::move(node));
}
}
// Mesh
// ---------------------------------
if (Json::hasProperty(json, "meshes")) {
auto meshes = json["meshes"];
ASSERT(meshes.is_array(), "Gltf model invalid property type 'meshes'");
for (auto& [key, object] : meshes.items()) {
glTF::Mesh mesh;
parseMesh(&mesh, key, object);
m_model.meshes.emplace_back(std::move(mesh));
}
}
// Accessor
// ---------------------------------
if (Json::hasProperty(json, "accessors")) {
auto accessors = json["accessors"];
ASSERT(accessors.is_array(), "Gltf model invalid property type 'accessors'");
for (auto& [key, object] : accessors.items()) {
glTF::Accessor accessor;
parseAccessor(&accessor, key, object);
m_model.accessors.emplace_back(std::move(accessor));
}
}
// Bufferview
// ---------------------------------
if (Json::hasProperty(json, "bufferViews")) {
auto bufferViews = json["bufferViews"];
ASSERT(bufferViews.is_array(), "Gltf model invalid property type 'bufferViews'");
for (auto& [key, object] : bufferViews.items()) {
glTF::BufferView bufferView;
parseBufferView(&bufferView, key, object);
m_model.bufferViews.emplace_back(std::move(bufferView));
}
}
// Buffer
// ---------------------------------
if (Json::hasProperty(json, "buffers")) {
auto buffers = json["buffers"];
ASSERT(buffers.is_array(), "Gltf model invalid property type 'buffers'");
for (auto& [key, object] : buffers.items()) {
glTF::Buffer buffer;
parseBuffer(&buffer, key, object, &m_model.data);
m_model.buffers.emplace_back(std::move(buffer));
}
}
}
Gltf::~Gltf()
{
}
void Gltf::parseAsset(glTF::Asset* asset, const json& object)
{
auto copyright = Json::parseStringProperty(object, "copyright", false);
auto generator = Json::parseStringProperty(object, "generator", false);
auto version = Json::parseStringProperty(object, "version", true);
ASSERT(version, "GlTF model missing required property 'version'");
ASSERT(version.value().compare("2.0") == 0, "GlTF version unsupported '{}'", version.value());
auto minVersion = Json::parseStringProperty(object, "minVersion", false);
if (copyright) asset->copyright = copyright.value();
if (generator) asset->generator = generator.value();
if (version) asset->version = version.value();
if (minVersion) asset->minVersion = minVersion.value();
}
void Gltf::parseScene(glTF::Scene* scene, const std::string& key, const json& object)
{
auto nodes = Json::parseFloatArrayProperty(object, "nodes", false);
ASSERT(!nodes || nodes.value().size() > 0, "Gltf scene '{}' empty 'nodes' property", key);
auto name = Json::parseStringProperty(object, "name", false);
scene->name = name ? name.value() : key;
}
void Gltf::parseNode(glTF::Node* node, const std::string& key, const json& object)
{
auto camera = Json::parseUnsignedProperty(object, "camera", false);
auto children = Json::parseUnsignedArrayProperty(object, "children", false);
ASSERT(!children || children.value().size() > 0, "Gltf node '{}' empty property 'children'", key);
auto skin = Json::parseUnsignedProperty(object, "skin", false);
auto matrix = Json::parseFloatArrayProperty(object, "matrix", false);
ASSERT(!matrix || matrix.value().size() == 16, "Gltf node '{}' property 'matrix' invalid size", key);
auto mesh = Json::parseUnsignedProperty(object, "mesh", false);
auto rotation = Json::parseFloatArrayProperty(object, "rotation", false);
ASSERT(!rotation || rotation.value().size() == 4, "Gltf node '{}' property 'rotation' invalid size", key);
auto scale = Json::parseFloatArrayProperty(object, "scale", false);
ASSERT(!scale || scale.value().size() == 3, "Gltf node '{}' property 'scale' invalid size", key);
auto translation = Json::parseFloatArrayProperty(object, "translation", false);
ASSERT(!translation || translation.value().size() == 3, "Gltf node '{}' property 'translation' invalid size", key);
auto weights = Json::parseFloatArrayProperty(object, "weights", false);
ASSERT(!weights || weights.value().size() > 0, "Gltf node '{}' empty property 'weights'", key);
auto name = Json::parseStringProperty(object, "name", false);
if (camera) node->camera = camera.value();
if (children) node->children = children.value();
if (skin) node->skin = skin.value();
if (matrix) std::copy(matrix.value().begin(), matrix.value().end(), node->matrix.begin());
if (mesh) node->mesh = mesh.value();
if (rotation) std::copy(rotation.value().begin(), rotation.value().end(), node->rotation.begin());
if (scale) std::copy(scale.value().begin(), scale.value().end(), node->scale.begin());
if (translation) std::copy(translation.value().begin(), translation.value().end(), node->translation.begin());
if (weights) node->weights = weights.value();
node->name = name ? name.value() : key;
}
void Gltf::parsePrimitive(glTF::Primitive* primitive, const std::string& key, const json& object)
{
auto attributes = Json::parseUnsignedObjectProperty(object, "attributes", true);
ASSERT(attributes && attributes.value().size() > 0, "Gltf primitive '{}' empty property 'attributes'", key);
auto indices = Json::parseUnsignedProperty(object, "indices", false);
auto material = Json::parseUnsignedProperty(object, "material", false);
auto mode = Json::parseUnsignedProperty(object, "mode", false);
if (Json::hasProperty(object, "targets")) {
auto targets = object["targets"];
ASSERT(targets.is_array(), "Gltf primitive '{}' property 'targets' invalid type", key);
for (auto& targetObject : targets) {
std::map<std::string, uint32_t> target;
for (auto& [key, propertyValue] : targetObject.items()) {
auto value = Json::getPropertyValue<uint32_t>(propertyValue, json::value_t::number_unsigned);
if (value) target.emplace(std::move(key), value.value());
}
ASSERT(target.size() > 0, "Gltf primitive '{}' empty 'target' object", key);
primitive->targets.emplace_back(std::move(target));
}
}
if (attributes) primitive->attributes = attributes.value();
if (indices) primitive->indices = indices.value();
if (material) primitive->material = material.value();
if (mode) primitive->mode = static_cast<unsigned char>(mode.value());
}
void Gltf::parseMesh(glTF::Mesh* mesh, const std::string& key, const json& object)
{
ASSERT(Json::hasProperty(object, "primitives"), "Gltf mesh '{}' missing required property 'primitives'", key);
auto primitives = object["primitives"];
ASSERT(primitives.is_array(), "Gltf mesh '{}' property 'primitives' invalid type", key);
for (auto& primitiveObject : primitives) {
glTF::Primitive primitive;
parsePrimitive(&primitive, key, primitiveObject);
mesh->primitives.emplace_back(std::move(primitive));
}
auto weights = Json::parseFloatArrayProperty(object, "weights", false);
ASSERT(!weights || weights.value().size() > 0, "Gltf mesh '{}' empty property 'weights'", key);
auto name = Json::parseStringProperty(object, "name", false);
if (weights) mesh->weights = weights.value();
mesh->name = name ? name.value() : key;
}
void Gltf::parseAccessor(glTF::Accessor* accessor, const std::string& key, const json& object)
{
auto bufferView = Json::parseUnsignedProperty(object, "bufferView", false);
auto byteOffset = Json::parseUnsignedProperty(object, "byteOffset", false);
auto componentType = Json::parseUnsignedProperty(object, "componentType", true);
ASSERT(componentType, "Gltf accessor '{}' missing required property 'componentType'", key);
auto normalized = Json::parseBoolProperty(object, "normalized", false);
auto count = Json::parseUnsignedProperty(object, "count", true);
ASSERT(count, "Gltf accessor '{}' missing required property 'count'", key);
auto type = Json::parseStringProperty(object, "type", true);
ASSERT(type, "Gltf accessor '{}' missing required property 'type'", key);
auto max = Json::parseFloatArrayProperty(object, "max", false);
ASSERT(!max || max.value().size() > 0, "Gltf accessor '{}' empty property 'max'", key);
auto min = Json::parseFloatArrayProperty(object, "min", false);
ASSERT(!min || min.value().size() > 0, "Gltf accessor '{}' empty property 'min'", key);
auto name = Json::parseStringProperty(object, "name", false);
if (bufferView) accessor->bufferView = bufferView.value();
if (byteOffset) accessor->byteOffset = byteOffset.value();
if (normalized) accessor->normalized = normalized.value();
if (count) accessor->count = count.value();
if (type) accessor->type = type.value();
if (max) accessor->max = max.value();
if (min) accessor->min = min.value();
accessor->name = name ? name.value() : key;
}
void Gltf::parseBufferView(glTF::BufferView* bufferView, const std::string& key, const json& object)
{
auto buffer = Json::parseUnsignedProperty(object, "buffer", false);
ASSERT(buffer, "Gltf bufferView '{}' missing required property 'buffer'", key);
auto byteOffset = Json::parseUnsignedProperty(object, "byteOffset", false);
auto byteLength = Json::parseUnsignedProperty(object, "byteLength", true);
ASSERT(byteLength, "Gltf bufferView '{}' missing required property 'byteLength'", key);
auto byteStride = Json::parseUnsignedProperty(object, "byteStride", false);
auto target = Json::parseUnsignedProperty(object, "target", false);
auto name = Json::parseStringProperty(object, "name", false);
if (buffer) bufferView->buffer = buffer.value();
if (byteOffset) bufferView->byteOffset = byteOffset.value();
if (byteLength) bufferView->byteLength = byteLength.value();
if (byteStride) bufferView->byteStride = byteStride.value();
if (target) bufferView->target = target.value();
bufferView->name = name ? name.value() : key;
}
void Gltf::parseBuffer(glTF::Buffer* buffer, const std::string& key, const json& object, std::map<uint32_t, std::shared_ptr<char[]>>* data)
{
auto uri = Json::parseStringProperty(object, "uri", false);
// Load external binary data
if (uri) {
ASSERT(uri.value().find("data:", 0) == std::string::npos, "GltfFile embedded binary data is unsupported");
data->emplace(std::stou(key), File::raw("assets/gltf/" + uri.value()));
}
auto byteLength = Json::parseUnsignedProperty(object, "byteLength", true);
ASSERT(byteLength, "Gltf buffer '{}' missing required property 'byteLength'", key);
auto name = Json::parseStringProperty(object, "name", false);
if (uri) buffer->uri = uri.value();
if (byteLength) buffer->byteLength = byteLength.value();
buffer->name = name ? name.value() : key;
}
} // namespace Inferno
-152
View File
@@ -1,152 +0,0 @@
#ifndef GLTF_H
#define GLTF_H
#include <cstdint> // uint32_t
#include <memory> // std::shared_ptr
#include <string> // std::string
#include <unordered_map> // std::unordered_map
#include <vector> // std::vector
#include "inferno/singleton.h"
#include "inferno/util/json.h"
namespace Inferno {
namespace glTF {
// Type specifications
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#objects
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#asset
struct Asset {
std::string copyright;
std::string generator;
std::string version; // Required
std::string minVersion;
};
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#scenes
struct Scene {
std::vector<uint32_t> nodes;
std::string name;
};
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#nodes-and-hierarchy
struct Node {
uint32_t camera;
std::vector<uint32_t> children;
uint32_t skin;
std::array<float, 16> matrix { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; // Identity matrix
uint32_t mesh;
std::array<float, 4> rotation { 0, 0, 0, 1 };
std::array<float, 3> scale { 1, 1, 1 };
std::array<float, 3> translation { 0, 0, 0 };
std::vector<float> weights;
std::string name;
};
struct Primitive {
std::map<std::string, uint32_t> attributes; // Required
uint32_t indices;
uint32_t material;
unsigned char mode { 4 };
std::vector<std::map<std::string, uint32_t>> targets;
};
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#meshes
struct Mesh {
std::vector<Primitive> primitives; // Required
std::vector<float> weights;
std::string name;
};
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#accessors
struct Accessor {
uint32_t bufferView;
uint32_t byteOffset { 0 };
uint32_t componentType; // Required
bool normalized { false };
uint32_t count; // Required
std::string type; // Required
std::vector<float> max;
std::vector<float> min;
std::string name;
};
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#buffers-and-buffer-views
struct BufferView {
uint32_t buffer; // Required
uint32_t byteOffset { 0 };
uint32_t byteLength; // Required
uint32_t byteStride;
uint32_t target;
std::string name;
};
struct Buffer {
std::string uri;
uint32_t byteLength; // Required
std::string name;
};
struct Model {
Asset asset;
std::vector<Scene> scenes;
std::vector<Node> nodes;
std::vector<Mesh> meshes;
std::vector<Accessor> accessors;
std::vector<BufferView> bufferViews;
std::vector<Buffer> buffers;
std::map<uint32_t, std::shared_ptr<char[]>> data;
};
} // namespace glTF
// -----------------------------------------
class Gltf {
public:
Gltf(const std::string& path);
virtual ~Gltf();
inline const glTF::Model& model() const { return m_model; }
private:
static void parseAsset(glTF::Asset* asset, const json& object);
static void parseScene(glTF::Scene* scene, const std::string& key, const json& object);
static void parseNode(glTF::Node* node, const std::string& key, const json& object);
static void parsePrimitive(glTF::Primitive* primitive, const std::string& key, const json& object);
static void parseMesh(glTF::Mesh* mesh, const std::string& key, const json& object);
static void parseAccessor(glTF::Accessor* accessor, const std::string& key, const json& object);
static void parseBufferView(glTF::BufferView* bufferView, const std::string& key, const json& object);
static void parseBuffer(glTF::Buffer* buffer, const std::string& key, const json& object, std::map<uint32_t, std::shared_ptr<char[]>>* data);
std::string m_path;
glTF::Model m_model;
};
// -----------------------------------------
class GltfManager final : Singleton<GltfManager> {
public:
GltfManager(s) {}
virtual ~GltfManager() {}
void add(const std::string& path, std::shared_ptr<Gltf> gltf);
std::shared_ptr<Gltf> load(const std::string& path);
std::shared_ptr<Gltf> get(const std::string& path);
bool exists(const std::string& path);
void remove(const std::string& path);
void remove(std::shared_ptr<Gltf> gltf);
private:
std::unordered_map<std::string, std::shared_ptr<Gltf>> m_gltfList;
};
} // namespace Inferno
#endif // GLTF_H
-443
View File
@@ -1,443 +0,0 @@
#include <algorithm> // std::min
#include <utility> // std::move
#include "glad/glad.h"
#include "inferno/assert.h"
#include "inferno/render/buffer.h"
#include "inferno/render/renderer.h"
#include "inferno/render/shader.h"
#include "inferno/render/texture.h"
namespace Inferno {
void RenderCommand::initialize()
{
setDepthTest(true);
// Enable transparency
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
info() << "RenderCommand initialized";
}
void RenderCommand::destroy()
{
}
void RenderCommand::clear()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void RenderCommand::clearColor(const glm::vec4& color)
{
glClearColor(color.r, color.g, color.b, color.a);
}
void RenderCommand::drawIndexed(const VertexArray& vertexArray, uint32_t indexCount)
{
uint32_t count = indexCount ? indexCount : vertexArray.getIndexBuffer()->getCount();
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, nullptr);
}
void RenderCommand::setViewport(int32_t x, int32_t y, uint32_t width, uint32_t height)
{
glViewport(x, y, width, height);
}
void RenderCommand::setDepthTest(bool enabled)
{
// Set z-buffer / depth buffer
enabled ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);
}
bool RenderCommand::depthTest()
{
unsigned char depthTest = GL_FALSE;
glGetBooleanv(GL_DEPTH_TEST, &depthTest);
return depthTest == GL_TRUE;
}
int32_t RenderCommand::textureUnitAmount()
{
int32_t amount = 0;
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &amount);
return amount;
}
// -----------------------------------------
uint32_t Renderer::m_supportedTextureUnitPerBatch = 0;
void Renderer::initialize()
{
// Get amount of texture units supported by the GPU
uint32_t constTextureUnitCount = textureUnitPerBatch;
uint32_t gpuTextureUnitCount = RenderCommand::textureUnitAmount();
m_supportedTextureUnitPerBatch = std::min(constTextureUnitCount, gpuTextureUnitCount);
// Texture unit 0 is reserved for no texture
m_textureUnits[0] = nullptr;
// Create texture unit samplers
int32_t samplers[textureUnitPerBatch];
for (uint32_t i = 0; i < textureUnitPerBatch; i++) {
samplers[i] = i;
}
// Create shader
loadShader();
m_shader->bind();
m_shader->setInt("u_textures", samplers, textureUnitPerBatch);
m_shader->unbind();
// Create vertex array
m_vertexArray = std::make_shared<VertexArray>();
}
void Renderer::destroy()
{
}
uint32_t Renderer::addTextureUnit(std::shared_ptr<Texture> texture)
{
if (texture == nullptr) {
return 0;
}
// Create a new batch if the texture unit limit has been reached
if (m_textureUnitIndex >= m_supportedTextureUnitPerBatch) {
nextBatch();
}
// If texure was already added
for (uint32_t i = 1; i < m_textureUnitIndex; i++) {
if (m_textureUnits[i] == texture) {
return i;
}
}
// Add texture
uint32_t textureUnitIndex = m_textureUnitIndex;
m_textureUnits[textureUnitIndex] = texture;
m_textureUnitIndex++;
return textureUnitIndex;
}
void Renderer::bind()
{
m_shader->bind();
for (uint32_t i = 1; i < m_textureUnitIndex; i++) {
m_textureUnits[i]->bind(i);
}
m_vertexArray->bind();
}
void Renderer::unbind()
{
m_vertexArray->unbind();
for (uint32_t i = 1; i < m_textureUnitIndex; i++) {
m_textureUnits[i]->unbind();
}
m_shader->unbind();
}
// -----------------------------------------
Renderer2D::Renderer2D(s)
{
Renderer::initialize();
// CPU
// ---------------------------------
// Create array for storing quads vertices
m_vertexBufferBase = std::make_unique<QuadVertex[]>(vertexCount);
m_vertexBufferPtr = m_vertexBufferBase.get();
// Set default quad vertex positions
m_vertexPositions[0] = { -0.5f, -0.5f, 0.0f, 1.0f };
m_vertexPositions[1] = { 0.5f, -0.5f, 0.0f, 1.0f };
m_vertexPositions[2] = { 0.5f, 0.5f, 0.0f, 1.0f };
m_vertexPositions[3] = { -0.5f, 0.5f, 0.0f, 1.0f };
// Generate indices
uint32_t* indices = new uint32_t[indexCount];
uint32_t offset = 0;
for (uint32_t i = 0; i < indexCount; i += indexPerQuad) {
indices[i + 0] = offset + 0;
indices[i + 1] = offset + 1;
indices[i + 2] = offset + 2;
indices[i + 3] = offset + 2;
indices[i + 4] = offset + 3;
indices[i + 5] = offset + 0;
offset += vertexPerQuad;
}
// GPU
// ---------------------------------
// Create vertex buffer
auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(QuadVertex) * vertexCount);
vertexBuffer->setLayout({
{ BufferElementType::Vec3, "a_position" },
{ BufferElementType::Vec4, "a_color" },
{ BufferElementType::Vec2, "a_textureCoordinates" },
{ BufferElementType::Float, "a_textureIndex" },
});
m_vertexArray->addVertexBuffer(vertexBuffer);
// Create index buffer
auto indexBuffer = std::make_shared<IndexBuffer>(indices, sizeof(uint32_t) * indexCount);
m_vertexArray->setIndexBuffer(indexBuffer);
delete[] indices;
info() << "Renderer2D initialized";
}
Renderer2D::~Renderer2D()
{
Renderer::destroy();
}
void Renderer2D::beginScene(glm::mat4 cameraProjectionView)
{
m_shader->bind();
m_shader->setFloat("u_projectionView", cameraProjectionView);
m_shader->unbind();
}
void Renderer2D::endScene()
{
nextBatch();
}
void Renderer2D::drawQuad(const TransformComponent& transform, glm::vec4 color)
{
drawQuad(transform, color, nullptr);
}
void Renderer2D::drawQuad(const TransformComponent& transform, glm::mat4 color)
{
drawQuad(transform, color, nullptr);
}
void Renderer2D::drawQuad(const TransformComponent& transform, glm::vec4 color, std::shared_ptr<Texture> texture)
{
drawQuad(transform, glm::mat4(color, color, color, color), texture);
}
void Renderer2D::drawQuad(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture)
{
// Create a new batch if the quad limit has been reached
if (m_quadIndex >= quadCount) {
nextBatch();
}
constexpr glm::vec2 textureCoordinates[] = {
{ 0.0f, 0.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f }, { 0.0f, 1.0f }
};
uint32_t textureUnitIndex = addTextureUnit(texture);
// Add the quads 4 vertices
for (uint32_t i = 0; i < vertexPerQuad; i++) {
m_vertexBufferPtr->position = transform.transform * m_vertexPositions[i];
m_vertexBufferPtr->color = color[i];
m_vertexBufferPtr->textureCoordinates = textureCoordinates[i];
m_vertexBufferPtr->textureIndex = (float)textureUnitIndex;
m_vertexBufferPtr++;
}
m_quadIndex++;
}
void Renderer2D::loadShader()
{
m_shader = ShaderManager::the().load("assets/glsl/batch-quad");
}
void Renderer2D::flush()
{
if (m_quadIndex == 0) {
return;
}
// Upload vertex data to GPU
m_vertexArray->getVertexBuffers().at(0)->uploadData(
m_vertexBufferBase.get(),
m_quadIndex * vertexPerQuad * sizeof(QuadVertex));
bind();
// Render
RenderCommand::drawIndexed(*m_vertexArray, m_quadIndex * indexPerQuad);
unbind();
}
void Renderer2D::startBatch()
{
m_quadIndex = 0;
m_vertexBufferPtr = m_vertexBufferBase.get();
m_textureUnitIndex = 1;
}
void Renderer2D::nextBatch()
{
flush();
startBatch();
}
// -----------------------------------------
RendererCharacter::RendererCharacter(s)
{
Renderer::initialize();
// CPU
// ---------------------------------
// Create array for storing quads vertices
m_vertexBufferBase = std::make_unique<CharacterVertex[]>(vertexCount);
m_vertexBufferPtr = m_vertexBufferBase.get();
// Generate indices
uint32_t* indices = new uint32_t[indexCount];
uint32_t offset = 0;
for (uint32_t i = 0; i < indexCount; i += indexPerQuad) {
indices[i + 0] = offset + 0;
indices[i + 1] = offset + 1;
indices[i + 2] = offset + 2;
indices[i + 3] = offset + 2;
indices[i + 4] = offset + 3;
indices[i + 5] = offset + 0;
offset += vertexPerQuad;
}
// GPU
// ---------------------------------
// Create vertex buffer
auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(CharacterVertex) * vertexCount);
vertexBuffer->setLayout({
{ BufferElementType::Vec3, "a_position" },
{ BufferElementType::Vec4, "a_color" },
{ BufferElementType::Vec2, "a_textureCoordinates" },
{ BufferElementType::Float, "a_textureIndex" },
{ BufferElementType::Float, "a_width" },
{ BufferElementType::Float, "a_edge" },
{ BufferElementType::Float, "a_borderWidth" },
{ BufferElementType::Float, "a_borderEdge" },
{ BufferElementType::Vec4, "a_borderColor" },
{ BufferElementType::Float, "a_offset" },
});
m_vertexArray->addVertexBuffer(vertexBuffer);
// Create index buffer
auto indexBuffer = std::make_shared<IndexBuffer>(indices, sizeof(uint32_t) * indexCount);
m_vertexArray->setIndexBuffer(indexBuffer);
delete[] indices;
info() << "RendererCharacter initialized";
}
RendererCharacter::~RendererCharacter()
{
Renderer::destroy();
}
void RendererCharacter::beginScene()
{
}
void RendererCharacter::endScene()
{
nextBatch();
}
void RendererCharacter::drawCharacter(std::array<CharacterVertex, vertexPerQuad>& characterQuad, std::shared_ptr<Texture> texture)
{
// Create a new batch if the quad limit has been reached
if (m_quadIndex >= quadCount) {
nextBatch();
}
uint32_t textureUnitIndex = addTextureUnit(texture);
// Add the quads 4 vertices
for (uint32_t i = 0; i < vertexPerQuad; i++) {
m_vertexBufferPtr->quad.position = characterQuad[i].quad.position;
m_vertexBufferPtr->quad.color = characterQuad[i].quad.color;
m_vertexBufferPtr->quad.textureCoordinates = characterQuad[i].quad.textureCoordinates;
m_vertexBufferPtr->quad.textureIndex = (float)textureUnitIndex;
m_vertexBufferPtr->width = characterQuad[i].width;
m_vertexBufferPtr->edge = characterQuad[i].edge;
m_vertexBufferPtr->borderWidth = characterQuad[i].borderWidth;
m_vertexBufferPtr->borderEdge = characterQuad[i].borderEdge;
m_vertexBufferPtr->borderColor = characterQuad[i].borderColor;
m_vertexBufferPtr->offset = characterQuad[i].offset;
m_vertexBufferPtr++;
}
m_quadIndex++;
}
void RendererCharacter::loadShader()
{
m_shader = ShaderManager::the().load("assets/glsl/batch-font");
}
void RendererCharacter::flush()
{
if (m_quadIndex == 0) {
return;
}
// Upload vertex data to GPU
m_vertexArray->getVertexBuffers().at(0)->uploadData(
m_vertexBufferBase.get(),
m_quadIndex * vertexPerQuad * sizeof(CharacterVertex));
bind();
// Render
bool depthTest = RenderCommand::depthTest();
RenderCommand::setDepthTest(false);
RenderCommand::drawIndexed(*m_vertexArray, m_quadIndex * indexPerQuad);
RenderCommand::setDepthTest(depthTest);
unbind();
}
void RendererCharacter::startBatch()
{
m_quadIndex = 0;
m_vertexBufferPtr = m_vertexBufferBase.get();
m_textureUnitIndex = 1;
}
void RendererCharacter::nextBatch()
{
flush();
startBatch();
}
}
-165
View File
@@ -1,165 +0,0 @@
#ifndef RENDERER_H
#define RENDERER_H
#include <cstdint> // int32_t, uint32_t
#include <memory> // std::shared_ptr, std::unique_ptr, std::make_shared, std::make_unique
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
#include "glm/ext/vector_float2.hpp" // glm::vec2
#include "glm/ext/vector_float3.hpp" // glm::vec3
#include "glm/ext/vector_float4.hpp" // glm::vec4
#include "inferno/component/transformcomponent.h"
#include "inferno/singleton.h"
namespace Inferno {
class Shader;
class Texture;
class VertexArray;
struct QuadVertex {
glm::vec3 position { 0.0f, 0.0f, 0.0f };
glm::vec4 color { 1.0f, 1.0f, 1.0f, 1.0f };
glm::vec2 textureCoordinates { 0.0f, 0.0f };
float textureIndex = 0; // @Todo get int to pass to fragment correctly
};
struct CharacterVertex {
QuadVertex quad;
// Font
float width = 0.44f;
float edge = 0.15f;
// Outline
float borderWidth = 0.7f;
float borderEdge = 0.1f;
glm::vec4 borderColor { 1.0f, 1.0f, 1.0f, 1.0f };
// Dropshadow
float offset = 0.0f;
};
// -----------------------------------------
class RenderCommand {
public:
static void initialize();
static void destroy();
static void clear();
static void clearColor(const glm::vec4& color);
static void drawIndexed(const VertexArray& vertexArray, uint32_t indexCount = 0);
static void setViewport(int32_t x, int32_t y, uint32_t width, uint32_t height);
static void setDepthTest(bool enabled);
static bool depthTest();
static int32_t textureUnitAmount();
};
// -----------------------------------------
class Renderer {
public:
static const uint32_t vertexPerQuad = 4;
static const uint32_t indexPerQuad = 6;
static const uint32_t textureUnitPerBatch = 32;
protected:
Renderer() {}
void initialize();
void destroy();
uint32_t addTextureUnit(std::shared_ptr<Texture> texture);
void bind();
void unbind();
virtual void loadShader() = 0;
virtual void flush() = 0;
virtual void startBatch() = 0;
virtual void nextBatch() = 0;
uint32_t m_quadIndex = 0;
// Texture units
static uint32_t m_supportedTextureUnitPerBatch;
uint32_t m_textureUnitIndex = 1;
std::array<std::shared_ptr<Texture>, textureUnitPerBatch> m_textureUnits;
// GPU objects
std::shared_ptr<Shader> m_shader;
std::shared_ptr<VertexArray> m_vertexArray;
};
// -----------------------------------------
class Renderer2D final
: public Renderer
, public Singleton<Renderer2D> {
public:
Renderer2D(s);
virtual ~Renderer2D();
using Singleton<Renderer2D>::initialize;
using Singleton<Renderer2D>::destroy;
static const uint32_t quadCount = 1000;
static const uint32_t vertexCount = quadCount * vertexPerQuad;
static const uint32_t indexCount = quadCount * indexPerQuad;
void beginScene(glm::mat4 cameraProjectionView);
void endScene();
void drawQuad(const TransformComponent& transform, glm::vec4 color);
void drawQuad(const TransformComponent& transform, glm::mat4 color);
void drawQuad(const TransformComponent& transform, glm::vec4 color, std::shared_ptr<Texture> texture);
void drawQuad(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture);
private:
void loadShader() override;
void flush() override;
void startBatch() override;
void nextBatch() override;
// CPU quad vertices
std::unique_ptr<QuadVertex[]> m_vertexBufferBase;
QuadVertex* m_vertexBufferPtr { nullptr };
// Default quad vertex positions
glm::vec4 m_vertexPositions[vertexPerQuad];
};
// -----------------------------------------
class RendererCharacter final
: public Renderer
, public Singleton<RendererCharacter> {
public:
RendererCharacter(s);
virtual ~RendererCharacter();
using Singleton<RendererCharacter>::initialize;
using Singleton<RendererCharacter>::destroy;
static const uint32_t quadCount = 1000;
static const uint32_t vertexCount = quadCount * vertexPerQuad;
static const uint32_t indexCount = quadCount * indexPerQuad;
void beginScene();
void endScene();
void drawCharacter(std::array<CharacterVertex, vertexPerQuad>& characterQuad, std::shared_ptr<Texture> texture);
private:
void loadShader() override;
void flush() override;
void startBatch() override;
void nextBatch() override;
// CPU quad vertices
std::unique_ptr<CharacterVertex[]> m_vertexBufferBase;
CharacterVertex* m_vertexBufferPtr { nullptr };
};
}
#endif // RENDERER_H
-270
View File
@@ -1,270 +0,0 @@
#include <utility> // std::move
#include <vector> // std::vector
#include "glad/glad.h"
#include "glm/gtc/type_ptr.hpp" // glm::value_ptr
#include "inferno/assert.h"
#include "inferno/core.h"
#include "inferno/io/file.h"
#include "inferno/io/log.h"
#include "inferno/render/shader.h"
namespace Inferno {
Shader::Shader(const std::string& name)
: m_name(std::move(name)),
m_id(0)
{
// Get file contents
std::string vertexSrc = File::read(name + ".vert");
std::string fragmentSrc = File::read(name + ".frag");
// Compile shaders
uint32_t vertexID = compileShader(GL_VERTEX_SHADER, vertexSrc.c_str());
uint32_t fragmentID = compileShader(GL_FRAGMENT_SHADER, fragmentSrc.c_str());
// Link shaders
if (vertexID > 0 && fragmentID > 0) {
m_id = linkShader(vertexID, fragmentID);
}
// Clear resources
else if (vertexID > 0) glDeleteShader(vertexID);
else if (fragmentID > 0) glDeleteShader(fragmentID);
}
Shader::~Shader()
{
if (m_id > 0) {
glDeleteProgram(m_id);
m_id = 0;
}
}
int32_t Shader::findUniform(const std::string& name) const
{
int32_t location = glGetUniformLocation(m_id, name.c_str());
ASSERT(location != -1, "Shader could not find uniform '{}'", name);
return location;
}
void Shader::setInt(const std::string& name, int value)
{
// Set uniform int
glUniform1i(findUniform(name), value);
}
void Shader::setInt(const std::string& name, int* values, uint32_t count)
{
// Set uniform int array
glUniform1iv(findUniform(name), count, values);
}
void Shader::setFloat(const std::string& name, float value) const
{
// Set uniform float
glUniform1f(findUniform(name), value);
}
void Shader::setFloat(const std::string& name, float v1, float v2, float v3, float v4) const
{
// Set uniform vec4 data
glUniform4f(findUniform(name), v1, v2, v3, v4);
}
void Shader::setFloat(const std::string& name, glm::vec2 value) const
{
// Set uniform vec2 data
glUniform2f(findUniform(name), value.x, value.y);
}
void Shader::setFloat(const std::string& name, glm::vec3 value) const
{
// Set uniform vec3 data
glUniform3f(findUniform(name), value.x, value.y, value.z);
}
void Shader::setFloat(const std::string& name, glm::vec4 value) const
{
// Set uniform vec4 data
glUniform4f(findUniform(name), value.x, value.y, value.z, value.w);
}
void Shader::setFloat(const std::string& name, glm::mat3 matrix) const
{
// Set uniform mat3 data
glUniformMatrix3fv(findUniform(name), 1, GL_FALSE, glm::value_ptr(matrix));
}
void Shader::setFloat(const std::string& name, glm::mat4 matrix) const
{
// Set uniform mat4 data
glUniformMatrix4fv(findUniform(name), 1, GL_FALSE, glm::value_ptr(matrix));
}
void Shader::bind() const
{
glUseProgram(m_id);
}
void Shader::unbind() const
{
glUseProgram(0);
}
uint32_t Shader::compileShader(int32_t type, const char* source) const
{
// Create new shader
uint32_t shader = 0;
shader = glCreateShader(type);
// Attach shader source to shader object
glShaderSource(shader, 1, &source, nullptr);
// Compile shader
glCompileShader(shader);
// Check compilation status
if (checkStatus(shader) == GL_TRUE) {
return shader;
}
// On fail
glDeleteShader(shader);
return 0;
}
uint32_t Shader::linkShader(uint32_t vertex, uint32_t fragment) const
{
// Create new shader program
uint32_t shaderProgram = 0;
shaderProgram = glCreateProgram();
// Attach both shaders to the shader program
glAttachShader(shaderProgram, vertex);
glAttachShader(shaderProgram, fragment);
// Setup vertex attributes
glBindAttribLocation(shaderProgram, 0, "a_position");
// Link the shaders
glLinkProgram(shaderProgram);
// Clear resources
glDeleteShader(vertex);
glDeleteShader(fragment);
// Check linking status
if (checkStatus(shaderProgram, true) == GL_TRUE) {
return shaderProgram;
}
// On fail
glDeleteProgram(shaderProgram);
return 0;
}
int32_t Shader::checkStatus(uint32_t check, bool isProgram) const
{
int32_t success;
int32_t maxLength = 0;
std::vector<char> infoLog;
// Get the compilation/linking status
!isProgram
? glGetShaderiv(check, GL_COMPILE_STATUS, &success)
: glGetProgramiv(check, GL_LINK_STATUS, &success);
if (success != GL_TRUE) {
// Get max length of the log including \0 terminator
!isProgram
? glGetShaderiv(check, GL_INFO_LOG_LENGTH, &maxLength)
: glGetProgramiv(check, GL_INFO_LOG_LENGTH, &maxLength);
// Reserve data for the log
infoLog.reserve(maxLength);
// Retrieve the error message
!isProgram
? glGetShaderInfoLog(check, maxLength, nullptr, &infoLog[0])
: glGetProgramInfoLog(check, maxLength, nullptr, &infoLog[0]);
warn() << "Shader " << infoLog.data();
}
ASSERT(success == GL_TRUE, "Shader program creation failed!");
return success;
}
// -----------------------------------------
ShaderManager::ShaderManager(s)
{
info() << "ShaderManager initialized";
}
ShaderManager::~ShaderManager()
{
}
void ShaderManager::add(const std::string& name, std::shared_ptr<Shader> shader)
{
// Construct (key, value) pair and insert it into the unordered_map
m_shaderList.emplace(std::move(name), std::move(shader));
}
std::shared_ptr<Shader> ShaderManager::load(const std::string& name)
{
if (exists(name)) {
return get(name);
}
std::shared_ptr<Shader> shader = std::make_shared<Shader>(name);
add(name, shader);
return get(name);
}
std::shared_ptr<Shader> ShaderManager::load(const std::string& vertexSource,
const std::string& fragmentSource)
{
std::string name = computeName(vertexSource, fragmentSource);
return load(name);
}
std::shared_ptr<Shader> ShaderManager::get(const std::string& name)
{
return exists(name) ? m_shaderList.at(name) : nullptr;
}
bool ShaderManager::exists(const std::string& name)
{
return m_shaderList.find(name) != m_shaderList.end();
}
void ShaderManager::remove(const std::string& name)
{
if (exists(name)) {
m_shaderList.erase(name);
}
}
void ShaderManager::remove(std::shared_ptr<Shader> shader)
{
if (exists(shader->name())) {
m_shaderList.erase(shader->name());
}
}
std::string ShaderManager::computeName(const std::string& vertexSource,
const std::string& fragmentSource)
{
auto vertexPos = vertexSource.find_last_of('.');
auto fragmentPos = fragmentSource.find_last_of('.');
ASSERT(vertexPos != std::string::npos, "Shader did not have file extension: '{}'", vertexSource);
ASSERT(fragmentPos != std::string::npos, "Shader did not have file extension: '{}'", fragmentSource);
auto vertexName = vertexSource.substr(0, vertexPos);
auto fragmentName = vertexSource.substr(0, fragmentPos);
ASSERT(vertexName == fragmentName, "Shader names did not match: {} {}", vertexSource, fragmentSource);
return vertexName;
}
}
-76
View File
@@ -1,76 +0,0 @@
#ifndef SHADER_H
#define SHADER_H
#include <cstdint> // int32_t, uint32_t
#include <memory> // std::shared_ptr
#include <string> // std::string
#include <unordered_map> // std::unordered_map
#include "glm/glm.hpp"
#include "inferno/singleton.h"
namespace Inferno {
class Shader {
public:
Shader(const std::string& name);
virtual ~Shader();
int32_t findUniform(const std::string& name) const;
void setInt(const std::string& name, int value);
void setInt(const std::string& name, int* values, uint32_t count);
void setFloat(const std::string& name, float value) const;
void setFloat(const std::string& name, float v1, float v2, float v3, float v4) const;
void setFloat(const std::string& name, glm::vec2 value) const;
void setFloat(const std::string& name, glm::vec3 value) const;
void setFloat(const std::string& name, glm::vec4 value) const;
void setFloat(const std::string& name, glm::mat3 matrix) const;
void setFloat(const std::string& name, glm::mat4 matrix) const;
void bind() const;
void unbind() const;
inline std::string name() const { return m_name; }
inline uint32_t id() const { return m_id; }
protected:
uint32_t compileShader(int32_t type, const char* shaderSource) const;
uint32_t linkShader(uint32_t vertex, uint32_t fragment) const;
int32_t checkStatus(uint32_t check, bool isProgram = false) const;
private:
std::string m_name;
uint32_t m_id;
};
// -----------------------------------------
class ShaderManager final : public Singleton<ShaderManager> {
public:
ShaderManager(s);
virtual ~ShaderManager();
void add(const std::string& name, std::shared_ptr<Shader> shader);
std::shared_ptr<Shader> load(const std::string& name);
std::shared_ptr<Shader> load(const std::string& vertexSource,
const std::string& fragmentSource);
std::shared_ptr<Shader> get(const std::string& name);
bool exists(const std::string& name);
void remove(const std::string& name);
void remove(std::shared_ptr<Shader> shader);
protected:
std::string computeName(const std::string& vertexSource,
const std::string& fragmentSource);
private:
std::unordered_map<std::string, std::shared_ptr<Shader>> m_shaderList;
};
}
#endif // SHADER_H
-156
View File
@@ -1,156 +0,0 @@
#include <climits> // UINT_MAX
#include <memory> // std::shared_ptr
#include <utility> // std::move
#include "glad/glad.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb/stb_image.h"
#include "inferno/assert.h"
#include "inferno/render/texture.h"
namespace Inferno {
Texture::Texture(const std::string& path)
: m_path(std::move(path))
{
int width;
int height;
int channels;
// Load image data
stbi_set_flip_vertically_on_load(1);
unsigned char* data = stbi_load(path.c_str(), &width, &height, &channels, STBI_default);
ASSERT(data, "Failed to load image: '{}'", path);
m_width = width;
m_height = height;
if (channels == 4) {
m_internalFormat = GL_RGBA8;
m_dataFormat = GL_RGBA;
}
else if (channels == 3) {
m_internalFormat = GL_RGB8;
m_dataFormat = GL_RGB;
}
create(data);
// Clean resources
stbi_image_free(data);
}
Texture::~Texture()
{
glDeleteTextures(1, &m_id);
}
void Texture::bind(uint32_t unit) const
{
// Set active unit
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, m_id);
// Reset unit
glActiveTexture(GL_TEXTURE0);
}
void Texture::unbind() const
{
glBindTexture(GL_TEXTURE_2D, 0);
}
void Texture::create(unsigned char* data)
{
m_id = UINT_MAX;
// Create texture object
glGenTextures(1, &m_id);
// Bind texture object
glBindTexture(GL_TEXTURE_2D, m_id);
// Set unpacking of pixel data to byte-alignment,
// this prevents alignment issues when using a single byte for color
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Generate texture
glTexImage2D(
GL_TEXTURE_2D, // Texture target
0, // Midmap level, base starts at level 0
m_internalFormat, // Texture format
m_width, m_height, // Image width/height
0, // Always 0 (legacy)
m_dataFormat, // Texture source format
GL_UNSIGNED_BYTE, // Texture source datatype
data); // Image data
// Set the texture wrapping / filtering options
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // X
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Y
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Minify
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Magnify
// Automatically generate all mipmap levels
glGenerateMipmap(GL_TEXTURE_2D);
// Unbind texture object
glBindTexture(GL_TEXTURE_2D, 0);
}
// -----------------------------------------
TextureManager::TextureManager(s)
{
info() << "TextureManager initialized";
}
TextureManager::~TextureManager()
{
}
void TextureManager::add(const std::string& path, std::shared_ptr<Texture> texture)
{
// Construct (key, value) pair and insert it into the unordered_map
m_textureList.emplace(std::move(path), std::move(texture));
}
std::shared_ptr<Texture> TextureManager::load(const std::string& path)
{
if (exists(path)) {
return get(path);
}
std::shared_ptr<Texture> texture = std::make_shared<Texture>(path);
add(path, texture);
return get(path);
}
std::shared_ptr<Texture> TextureManager::get(const std::string& path)
{
return exists(path) ? m_textureList.at(path) : nullptr;
}
bool TextureManager::exists(const std::string& path)
{
return m_textureList.find(path) != m_textureList.end();
}
void TextureManager::remove(const std::string& path)
{
if (exists(path)) {
m_textureList.erase(path);
}
}
void TextureManager::remove(std::shared_ptr<Texture> texture)
{
if (exists(texture->path())) {
m_textureList.erase(texture->path());
}
}
}
-61
View File
@@ -1,61 +0,0 @@
#ifndef TEXTURE_H
#define TEXTURE_H
#include <cstdint> // uint32_t
#include <memory> // std::shared_ptr
#include <string> // std::string
#include <unordered_map> // std::unordered_map
#include "inferno/singleton.h"
namespace Inferno {
class Texture {
public:
Texture(const std::string& path);
virtual ~Texture();
void bind(uint32_t unit = 0) const;
void unbind() const;
inline std::string path() const { return m_path; }
inline uint32_t width() const { return m_width; }
inline uint32_t height() const { return m_height; }
inline uint32_t id() const { return m_id; }
inline uint32_t internalFormat() const { return m_internalFormat; }
inline uint32_t dataFormat() const { return m_dataFormat; }
protected:
void create(unsigned char* data);
private:
std::string m_path;
uint32_t m_width;
uint32_t m_height;
uint32_t m_id;
uint32_t m_internalFormat;
uint32_t m_dataFormat;
};
// -----------------------------------------
class TextureManager final : public Singleton<TextureManager> {
public:
TextureManager(s);
virtual ~TextureManager();
void add(const std::string& path, std::shared_ptr<Texture> texture);
std::shared_ptr<Texture> load(const std::string& path);
std::shared_ptr<Texture> get(const std::string& path);
bool exists(const std::string& path);
void remove(const std::string& path);
void remove(std::shared_ptr<Texture> texture);
private:
std::unordered_map<std::string, std::shared_ptr<Texture>> m_textureList;
};
}
#endif // TEXTURE_H
-122
View File
@@ -1,122 +0,0 @@
#include "inferno/assert.h"
#include "inferno/component/cameracomponent.h"
#include "inferno/component/luascriptcomponent.h"
#include "inferno/component/nativescriptcomponent.h"
#include "inferno/component/spritecomponent.h"
#include "inferno/component/tagcomponent.h"
#include "inferno/scene/scene.h"
#include "inferno/script/cameracontroller.h"
#include "inferno/script/nativescript.h"
#include "inferno/system/camerasystem.h"
#include "inferno/system/rendersystem.h"
#include "inferno/system/scriptsystem.h"
#include "inferno/system/transformsystem.h"
namespace Inferno {
void Scene::initialize()
{
// Initialize
// ---------------------------------
m_registry = std::make_shared<entt::registry>();
TransformSystem::initialize();
TransformSystem::the().setRegistry(m_registry);
CameraSystem::initialize();
CameraSystem::the().setRegistry(m_registry);
RenderSystem::initialize();
RenderSystem::the().setRegistry(m_registry);
ScriptSystem::initialize();
ScriptSystem::the().setScene(this);
// Load assets
// ---------------------------------
m_texture = TextureManager::the().load("assets/gfx/test.png");
m_texture2 = TextureManager::the().load("assets/gfx/test-inverted.png");
// Construct entities
// ---------------------------------
uint32_t camera = createEntity("Camera Entity");
auto& cameraTransform = getComponent<TransformComponent>(camera);
cameraTransform.rotate.z = -1.0f;
cameraTransform.translate.z = 1.0f;
addComponent<CameraComponent>(camera, CameraType::Perspective);
// addComponent<NativeScriptComponent>(camera).bind<CameraController>();
addComponent<LuaScriptComponent>(camera, "assets/lua/cameracontroller.lua");
uint32_t quad = createEntity("Quad");
addComponent<SpriteComponent>(quad, glm::vec4 { 1.0f, 1.0f, 1.0f, 1.0f }, m_texture);
uint32_t quad2 = createEntity("Quad 2");
auto& quad2Transform = getComponent<TransformComponent>(quad2);
quad2Transform.translate.x = 1.1f;
addComponent<SpriteComponent>(quad2, glm::vec4 { 0.5f, 0.6f, 0.8f, 1.0f }, m_texture);
uint32_t quad3 = createEntity("Quad 3");
auto& quad3Transform = getComponent<TransformComponent>(quad3);
quad3Transform.translate.x = 2.2f;
addComponent<SpriteComponent>(quad3, glm::vec4 { 1.0f, 1.0f, 1.0f, 1.0f }, m_texture2);
info() << "Scene initialized";
}
void Scene::update(float deltaTime)
{
ScriptSystem::the().update(deltaTime);
TransformSystem::the().update();
CameraSystem::the().update();
}
void Scene::render()
{
RenderSystem::the().render();
}
void Scene::destroy()
{
ScriptSystem::destroy();
RenderSystem::destroy();
CameraSystem::destroy();
TransformSystem::destroy();
}
uint32_t Scene::createEntity(const std::string& name)
{
uint32_t entity = static_cast<uint32_t>(m_registry->create());
addComponent<TagComponent>(entity, name.empty() ? "Unnamed Entity" : name);
addComponent<TransformComponent>(entity);
return entity;
}
void Scene::destroyEntity(uint32_t entity)
{
ScriptSystem::the().cleanup(entity);
m_registry->destroy(entt::entity { entity });
}
glm::mat4 Scene::cameraProjectionView()
{
return CameraSystem::the().projectionView();
}
void Scene::validEntity(uint32_t entity) const
{
ASSERT(m_registry->valid(entt::entity {entity}), "Entity is not valid");
}
// ----------------------------------------
const LogStream& operator<<(const LogStream& stream, entt::entity entity)
{
return stream << static_cast<uint32_t>(entity);
}
}
-84
View File
@@ -1,84 +0,0 @@
#ifndef SCENE_H
#define SCENE_H
#include <cstdint> // uint32_t
#include <memory> // std::shared_ptr
#include "entt/entity/registry.hpp" // entt::entity, entt::registry
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
#include "inferno/io/log.h"
namespace Inferno {
class Camera;
class Texture;
class Scene {
public:
void initialize();
void update(float deltaTime);
void render();
void destroy();
uint32_t createEntity(const std::string& name = "");
void destroyEntity(uint32_t entity);
glm::mat4 cameraProjectionView();
void validEntity(uint32_t entity) const;
template<typename... T>
[[nodiscard]] bool hasComponent(uint32_t entity) const
{
validEntity(entity);
return m_registry->has<T...>(entt::entity { entity });
}
template<typename... T>
[[nodiscard]] bool anyComponent(uint32_t entity) const
{
validEntity(entity);
return m_registry->any<T...>(entt::entity { entity });
}
// @Todo Should replace be allowed? could trigger memory leaks with nativescript
template<typename T, typename... P>
T& addComponent(uint32_t entity, P&&... parameters) const
{
validEntity(entity);
return m_registry->emplace_or_replace<T>(entt::entity { entity }, std::forward<P>(parameters)...);
};
template<typename T>
size_t removeComponent(uint32_t entity) const
{
validEntity(entity);
return m_registry->remove_if_exists<T>(entt::entity { entity });
}
// @Todo Should replace be allowed? could trigger memory leaks with nativescript
template<typename T, typename... P>
T& getComponent(uint32_t entity, P&&... parameters) const
{
validEntity(entity);
return m_registry->get_or_emplace<T>(entt::entity { entity }, std::forward<P>(parameters)...);
}
// const entt::registry& registry() const { return m_registry; }
std::shared_ptr<entt::registry> registry() const { return m_registry; }
private:
std::shared_ptr<Texture> m_texture;
std::shared_ptr<Texture> m_texture2;
std::shared_ptr<entt::registry> m_registry;
};
// -----------------------------------------
const LogStream& operator<<(const LogStream& stream, entt::entity handle);
}
#endif // SCENE_H
@@ -1,122 +0,0 @@
#include "glm/ext/matrix_transform.hpp" // glm::radians
#include "inferno/component/cameracomponent.h"
#include "inferno/component/transformcomponent.h"
#include "inferno/io/input.h"
#include "inferno/keycodes.h"
#include "inferno/script/cameracontroller.h"
namespace Inferno {
void CameraController::updateOrthographic(float deltaTime)
{
// Update camera rotation
float cameraRotateSpeed = ROTATE_SPEED * deltaTime;
if (Input::isKeyPressed(keyCode("GLFW_KEY_Q"))) {
transform->rotate.z -= cameraRotateSpeed;
}
if (Input::isKeyPressed(keyCode("GLFW_KEY_E"))) {
transform->rotate.z += cameraRotateSpeed;
}
if (transform->rotate.z > 180.0f) {
transform->rotate.z -= 360.0f;
}
else if (transform->rotate.z <= -180.0f) {
transform->rotate.z += 360.0f;
}
// Update camera translation
float cameraTranslateSpeed = TRANSLATE_SPEED * deltaTime;
// WASD movement
if (Input::isKeyPressed(keyCode("GLFW_KEY_W"))) {
transform->translate.x += -sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
transform->translate.y += cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
}
if (Input::isKeyPressed(keyCode("GLFW_KEY_S"))) {
transform->translate.x -= -sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
transform->translate.y -= cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
}
if (Input::isKeyPressed(keyCode("GLFW_KEY_A"))) {
transform->translate.x -= cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
transform->translate.y -= sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
}
if (Input::isKeyPressed(keyCode("GLFW_KEY_D"))) {
transform->translate.x += cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
transform->translate.y += sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
}
// Update camera zoom
float zoomSpeed = ZOOM_SENSITIVITY * deltaTime;
if (Input::isKeyPressed(keyCode("GLFW_KEY_EQUAL"))) {
m_camera->zoomLevel -= zoomSpeed;
}
if (Input::isKeyPressed(keyCode("GLFW_KEY_MINUS"))) {
m_camera->zoomLevel += zoomSpeed;
}
m_camera->zoomLevel = std::max(m_camera->zoomLevel, 0.25f);
m_camera->zoomLevel = std::min(m_camera->zoomLevel, 10.0f);
}
void CameraController::updatePerspective(float deltaTime)
{
// Get mouse movement offset compared to last frame
float xOffset = Input::getXOffset() * MOUSE_SENSITIVITY;
float yOffset = Input::getYOffset() * MOUSE_SENSITIVITY;
m_camera->yaw += xOffset;
m_camera->pitch += yOffset;
// Prevent gimbal lock
if (m_camera->pitch > 89.0f) m_camera->pitch = 89.0f;
if (m_camera->pitch < -89.0f) m_camera->pitch = -89.0f;
// Update camera rotation, by calculating direction vector via yaw and pitch
transform->rotate = {
cos(glm::radians(m_camera->pitch)) * cos(glm::radians(m_camera->yaw)),
sin(glm::radians(m_camera->pitch)),
cos(glm::radians(m_camera->pitch)) * sin(glm::radians(m_camera->yaw))
};
transform->rotate = glm::normalize(transform->rotate);
// The direction vector is based on
// Camera direction (z): normalize(position - target)
// Right axis (x): normalize(cross(up, direction))
// Up axis (y): cross(direction, right)
// Source: https://learnopengl.com/img/getting-started/camera_axes.png
// Cross = combination of two vectors in 3D space,
// where result is always perpendicular to both of the vectors
// Update camera translation
float cameraSpeed = TRANSLATE_SPEED * deltaTime;
// WASD movement
if (Input::isKeyPressed(keyCode("GLFW_KEY_W"))) {
transform->translate += transform->rotate * cameraSpeed;
}
if (Input::isKeyPressed(keyCode("GLFW_KEY_S"))) {
transform->translate -= transform->rotate * cameraSpeed;
}
if (Input::isKeyPressed(keyCode("GLFW_KEY_A"))) {
transform->translate -= glm::normalize(glm::cross(transform->rotate, m_camera->up)) * cameraSpeed;
}
if (Input::isKeyPressed(keyCode("GLFW_KEY_D"))) {
transform->translate += glm::normalize(glm::cross(transform->rotate, m_camera->up)) * cameraSpeed;
}
// Up / down movement
if (Input::isKeyPressed(keyCode("GLFW_KEY_SPACE"))) {
transform->translate.y += cameraSpeed;
}
if (Input::isKeyPressed(keyCode("GLFW_KEY_LEFT_SHIFT"))) {
transform->translate.y -= cameraSpeed;
}
}
}
@@ -1,39 +0,0 @@
#ifndef CAMERA_CONTROLLER_H
#define CAMERA_CONTROLLER_H
#include "inferno/script/nativescript.h"
#define TRANSLATE_SPEED 2.5f
#define ROTATE_SPEED 90.0f
#define ZOOM_SENSITIVITY 2.5f
#define MOUSE_SENSITIVITY 0.25f
namespace Inferno {
struct CameraComponent;
class CameraController final : public NativeScript {
public:
virtual void update(float deltaTime) override
{
m_camera = &getComponent<CameraComponent>();
if (m_camera->type == CameraType::Orthographic) {
updateOrthographic(deltaTime);
}
else if (m_camera->type == CameraType::Perspective) {
updatePerspective(deltaTime);
}
}
void updateOrthographic(float deltaTime);
void updatePerspective(float deltaTime);
private:
CameraComponent* m_camera { nullptr };
};
}
#endif // CAMERA_CONTROLLER_H
-79
View File
@@ -1,79 +0,0 @@
#include "sol/unsafe_function_result.hpp"
#include "inferno/component/cameracomponent.h"
#include "inferno/component/spritecomponent.h"
#include "inferno/component/tagcomponent.h"
#include "inferno/component/transformcomponent.h"
#include "inferno/io/file.h"
#include "inferno/scene/scene.h"
#include "inferno/script/luascript.h"
#include "inferno/script/registration.h"
namespace Inferno {
void LuaScript::initialize()
{
// Type registration
// ---------------------------------
Registration::fill(m_state);
// Load libraries
// ---------------------------------
m_state.open_libraries(sol::lib::base, sol::lib::math);
// Component get functions
// ---------------------------------
m_state.set_function("getTagComponent", [this]() -> TagComponent* {
return &m_scene->getComponent<TagComponent>(m_entity);
});
m_state.set_function("getTransformComponent", [this]() -> TransformComponent* {
return &m_scene->getComponent<TransformComponent>(m_entity);
});
m_state.set_function("getCameraComponent", [this]() -> CameraComponent* {
return &m_scene->getComponent<CameraComponent>(m_entity);
});
m_state.set_function("getSpriteComponent", [this]() -> SpriteComponent* {
return &m_scene->getComponent<SpriteComponent>(m_entity);
});
// Load and Initialize script
// ---------------------------------
loadScript();
callFunction("LuaScript", "initialize");
}
void LuaScript::destroy()
{
callFunction("LuaScript", "destroy");
}
void LuaScript::update(float deltaTime)
{
m_state["LuaScript"]["transform"] = &m_scene->getComponent<TransformComponent>(m_entity);
callFunction("LuaScript", "update", deltaTime);
}
void LuaScript::loadScript()
{
std::string script = File::read(m_path);
auto result = m_state.script(script.c_str(),
[](lua_State*, sol::protected_function_result pfr) { return pfr; });
ASSERT(result.valid(), "LuaScript {}", ((sol::error)result).what());
}
sol::table LuaScript::getTable(const char* name)
{
sol::table table = m_state[name];
ASSERT(table.valid(), "LuaScript table does not exist");
return table;
}
}
-57
View File
@@ -1,57 +0,0 @@
#ifndef LUA_SCRIPT_H
#define LUA_SCRIPT_H
#include <cstdint> // uint32_t
#include <string> // std::string
#define SOL_ALL_SAFETIES_ON 1
#include "sol/protected_function.hpp"
#include "sol/protected_function_result.hpp"
#include "sol/state.hpp"
#include "sol/table.hpp"
#include "inferno/assert.h"
namespace Inferno {
struct TransformComponent;
class Scene;
class LuaScript {
public:
void initialize();
void destroy();
void update(float deltaTime);
void loadScript();
private:
sol::table getTable(const char* name);
template<typename... P>
void callFunction(const char* table, const char* function, P&&... parameters)
{
sol::table solTable = getTable(table);
sol::protected_function solFunction = solTable[function];
// Only call function if it exists
if (solFunction.valid()) {
sol::protected_function_result result = solFunction(solTable, parameters...);
ASSERT(result.valid(), "Lua function {}", ((sol::error)result).what());
}
}
sol::state m_state;
std::string m_path = "";
Scene* m_scene { nullptr };
uint32_t m_entity { 0 };
TransformComponent* transform { nullptr };
friend class ScriptSystem;
};
}
#endif // LUA_SCRIPT_H
-36
View File
@@ -1,36 +0,0 @@
#ifndef NATIVE_SCRIPT_H
#define NATIVE_SCRIPT_H
#include "inferno/scene/scene.h"
namespace Inferno {
struct TransformComponent;
class NativeScript {
public:
virtual ~NativeScript() {}
protected:
virtual void initialize() {}
virtual void destroy() {}
virtual void update(float deltaTime) { (void)deltaTime; }
template<typename T>
T& getComponent() const
{
return m_scene->getComponent<T>(m_entity);
}
TransformComponent* transform { nullptr };
private:
Scene* m_scene { nullptr };
uint32_t m_entity { 0 };
friend class ScriptSystem;
};
}
#endif // NATIVE_SCRIPT_H
-122
View File
@@ -1,122 +0,0 @@
#include "glm/ext/vector_float2.hpp" // glm::vec2
#include "glm/ext/vector_float3.hpp" // glm::vec3
#include "glm/ext/vector_float4.hpp" // glm::vec4
#include "glm/ext/matrix_transform.hpp" // glm::radians
#include "inferno/component/cameracomponent.h"
#include "inferno/component/spritecomponent.h"
#include "inferno/component/tagcomponent.h"
#include "inferno/component/transformcomponent.h"
#include "inferno/io/input.h"
#include "inferno/keycodes.h"
#include "inferno/script/registration.h"
namespace Inferno {
void Registration::fill(sol::state_view &state)
{
glm(state);
component(state);
input(state);
}
void Registration::glm(sol::state_view& state)
{
auto glm = state["glm"].get_or_create<sol::table>();
auto vec2 = glm.new_usertype<glm::vec2>(
"vec2",
sol::call_constructor, sol::constructors<glm::vec2(), glm::vec2(glm::vec2), glm::vec2(float), glm::vec2(float, float)>(),
"x", &glm::vec2::x, "y", &glm::vec2::y,
"r", &glm::vec2::r, "g", &glm::vec2::g,
"s", &glm::vec2::s, "t", &glm::vec2::t,
"__add", addition<glm::vec2, float>(),
"__sub", subtraction<glm::vec2, float>(),
"__mul", multiplication<glm::vec2, float>(),
"__div", division<glm::vec2, float>(),
"__tostring", string<glm::vec2>
);
auto vec3 = glm.new_usertype<glm::vec3>(
"vec3",
sol::call_constructor, sol::constructors<glm::vec3(), glm::vec3(glm::vec3), glm::vec3(float), glm::vec3(float, float, float)>(),
"x", &glm::vec3::x, "y", &glm::vec3::y, "z", &glm::vec3::z,
"r", &glm::vec3::r, "g", &glm::vec3::g, "b", &glm::vec3::b,
"s", &glm::vec3::s, "t", &glm::vec3::t, "p", &glm::vec3::p,
"__add", addition<glm::vec3, float>(),
"__sub", subtraction<glm::vec3, float>(),
"__mul", multiplication<glm::vec3, float>(),
"__div", division<glm::vec3, float>(),
"__tostring", string<glm::vec3>
);
auto vec4 = glm.new_usertype<glm::vec4>(
"vec4",
sol::call_constructor, sol::constructors<glm::vec4(), glm::vec4(glm::vec4), glm::vec4(float), glm::vec4(float, float, float, float)>(),
"x", &glm::vec4::x, "y", &glm::vec4::y, "z", &glm::vec4::z, "w", &glm::vec4::w,
"r", &glm::vec4::r, "g", &glm::vec4::g, "b", &glm::vec4::b, "a", &glm::vec4::a,
"s", &glm::vec4::s, "t", &glm::vec4::t, "p", &glm::vec4::p, "q", &glm::vec4::q,
"__add", addition<glm::vec4, float>(),
"__sub", subtraction<glm::vec4, float>(),
"__mul", multiplication<glm::vec4, float>(),
"__div", division<glm::vec4, float>(),
"__tostring", string<glm::vec4>
);
glm.set_function("radians", sol::overload(
[](float v) { return glm::radians(v); },
[](const glm::vec2& v) { return glm::radians(v); },
[](const glm::vec3& v) { return glm::radians(v); },
[](const glm::vec4& v) { return glm::radians(v); }
));
glm.set_function("normalize", sol::overload(
[](const glm::vec2& v) { return glm::normalize(v); },
[](const glm::vec3& v) { return glm::normalize(v); },
[](const glm::vec4& v) { return glm::normalize(v); }
));
glm.set_function("cross", [](const glm::vec3& x, const glm::vec3& y) { return glm::cross(x, y); });
}
void Registration::component(sol::state_view& state)
{
auto tagComponent = state.new_usertype<TagComponent>("TagComponent", sol::no_constructor);
tagComponent["tag"] = &TagComponent::tag;
auto transformComponent = state.new_usertype<TransformComponent>("TransformComponent", sol::no_constructor);
transformComponent["translate"] = &TransformComponent::translate;
transformComponent["rotate"] = &TransformComponent::rotate;
transformComponent["scale"] = &TransformComponent::scale;
transformComponent["transform"] = &TransformComponent::transform;
transformComponent["__tostring"] = &string<TransformComponent>;
auto cameraType = state.new_enum("CameraType",
"Orthographic", CameraType::Orthographic,
"Perspective", CameraType::Perspective);
auto cameraComponent = state.new_usertype<CameraComponent>("CameraComponent", sol::no_constructor);
cameraComponent["type"] = &CameraComponent::type;
cameraComponent["zoomLevel"] = &CameraComponent::zoomLevel;
cameraComponent["rotateAxis"] = &CameraComponent::rotateAxis;
cameraComponent["fov"] = &CameraComponent::fov;
cameraComponent["pitch"] = &CameraComponent::pitch;
cameraComponent["yaw"] = &CameraComponent::yaw;
cameraComponent["up"] = &CameraComponent::up;
cameraComponent["projection"] = &CameraComponent::projection;
auto spriteComponent = state.new_usertype<SpriteComponent>("SpriteComponent", sol::no_constructor);
spriteComponent["color"] = &SpriteComponent::color;
spriteComponent["texture"] = &SpriteComponent::texture;
}
void Registration::input(sol::state_view& state)
{
state.set_function("keyCode", &keyCode);
auto input = state.new_usertype<Input>("Input", sol::no_constructor);
input["isKeyPressed"] = &Input::isKeyPressed;
input["getXOffset"] = &Input::getXOffset;
input["getYOffset"] = &Input::getYOffset;
}
}
-71
View File
@@ -1,71 +0,0 @@
#ifndef REGISTRATION_H
#define REGISTRATION_H
#include "sol/overload.hpp" // sol::overload
#include "sol/state_view.hpp" // sol::state_view
#include "inferno/io/log.h"
namespace Inferno {
class Registration final {
public:
static void fill(sol::state_view& state);
private:
static void glm(sol::state_view& state);
static void component(sol::state_view& state);
static void input(sol::state_view& state);
template<typename T, typename V>
static auto addition()
{
return sol::overload(
[](const T& lhs, const T& rhs) { return lhs + rhs; },
[](const T& lhs, const V& rhs) { return lhs + rhs; },
[](const V& lhs, const T& rhs) { return lhs + rhs; }
);
}
template<typename T, typename V>
static auto subtraction()
{
return sol::overload(
[](const T& lhs, const T& rhs) { return lhs - rhs; },
[](const T& lhs, const V& rhs) { return lhs - rhs; },
[](const V& lhs, const T& rhs) { return lhs - rhs; }
);
}
template<typename T, typename V>
static auto multiplication()
{
return sol::overload(
[](const T& lhs, const T& rhs) { return lhs * rhs; },
[](const T& lhs, const V& rhs) { return lhs * rhs; },
[](const V& lhs, const T& rhs) { return lhs * rhs; }
);
}
template<typename T, typename V>
static auto division()
{
return sol::overload(
[](const T& lhs, const T& rhs) { return lhs / rhs; },
[](const T& lhs, const V& rhs) { return lhs / rhs; },
[](const V& lhs, const T& rhs) { return lhs / rhs; }
);
}
template<typename T>
static std::string string(const T& t)
{
std::string result;
str(&result) << t;
return result;
}
};
}
#endif // REGISTRATION_H
-91
View File
@@ -1,91 +0,0 @@
#include <cstdint> // uint32_t
#include <string> // std::string
#include "inferno/io/file.h"
#include "inferno/io/log.h"
#include "inferno/settings.h"
#include "inferno/util/json.h"
#include "inferno/window.h"
namespace Inferno {
const char* Settings::m_path { "assets/settings.json" };
SettingsProperties Settings::m_properties {};
void Settings::initialize()
{
Settings::load();
info() << "Settings initialized";
Settings::save();
}
void Settings::destroy()
{
}
bool Settings::load()
{
json object;
if (!File::ioRead(&object, m_path)) {
warn() << "Settings invalid formatting, using default values";
return false;
}
auto settings = Json::getPropertyValue<SettingsProperties>(object, json::value_t::object);
if (settings) {
m_properties = settings.value();
}
return true;
}
bool Settings::save()
{
json object = m_properties;
if (!File::ioWrite(&object, m_path)) {
warn() << "Settings could not be saved";
return false;
}
info() << "Settings saved";
return true;
}
// -----------------------------------------
void to_json(json& object, const SettingsProperties& settings)
{
object = json {
{ "window", settings.window }
};
}
void from_json(const json& object, SettingsProperties& settings)
{
if (Json::hasProperty(object, "window")) object.at("window").get_to(settings.window);
}
void to_json(json& object, const WindowProperties& window)
{
object = json {
{ "title", window.title },
{ "width", window.width },
{ "height", window.height },
{ "fullscreen", window.fullscreen },
{ "vsync", window.vsync },
};
}
void from_json(const json& object, WindowProperties& window)
{
if (Json::hasProperty(object, "title")) object.at("title").get_to(window.title);
if (Json::hasProperty(object, "width")) object.at("width").get_to(window.width);
if (Json::hasProperty(object, "height")) object.at("height").get_to(window.height);
if (Json::hasProperty(object, "fullscreen")) object.at("fullscreen").get_to(window.fullscreen);
if (Json::hasProperty(object, "vsync")) object.at("vsync").get_to(window.vsync);
}
}
-40
View File
@@ -1,40 +0,0 @@
#ifndef SETTINGS_H
#define SETTINGS_H
#include "inferno/util/json.h"
#include "inferno/window.h"
namespace Inferno {
struct SettingsProperties {
WindowProperties window;
};
class Settings {
public:
static void initialize();
static void destroy();
static bool load();
static bool save();
static inline SettingsProperties& get() { return m_properties; }
private:
static const char* m_path;
static SettingsProperties m_properties;
};
// -----------------------------------------
// nlohmann::json arbitrary type conversion functions
void to_json(json& object, const SettingsProperties& settings);
void from_json(const json& object, SettingsProperties& settings);
void to_json(json& object, const WindowProperties& window);
void from_json(const json& object, WindowProperties& window);
}
#endif // SETTINGS_H
-55
View File
@@ -1,55 +0,0 @@
#ifndef SINGLETON_H
#define SINGLETON_H
#include "inferno/assert.h"
namespace Inferno {
template<typename T>
class Singleton {
// Application is allowed to access its Singleton instance for early setting
friend class Application;
public:
static inline void initialize()
{
ASSERT(!s_instance, "Singleton already exists!");
s_instance = new T { s {} };
}
static inline void destroy()
{
ASSERT(s_instance, "Singleton does not exist!");
delete s_instance;
s_instance = nullptr;
}
static inline T& the()
{
ASSERT(s_instance, "Singleton does not exist!");
return *s_instance;
}
// Remove copy constructor and copy assignment operator
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(Singleton&&) = delete;
protected:
Singleton() {}
// Constructor token
struct s {};
private:
static T* s_instance;
};
template<typename T>
T* Singleton<T>::s_instance = nullptr;
} // namespace Inferno
#endif // SINGLETON_H
@@ -1,97 +0,0 @@
#include "glm/ext/matrix_clip_space.hpp" // glm::perspective, glm::ortho
#include "glm/ext/matrix_transform.hpp" // glm::radians, glm::lookAt
#include "inferno/application.h"
#include "inferno/assert.h"
#include "inferno/component/cameracomponent.h"
#include "inferno/component/transformcomponent.h"
#include "inferno/io/input.h"
#include "inferno/io/log.h"
#include "inferno/system/camerasystem.h"
#include "inferno/window.h"
namespace Inferno {
CameraSystem::CameraSystem(s)
{
info() << "CameraSystem initialized";
}
CameraSystem::~CameraSystem()
{
}
void CameraSystem::update()
{
auto view = m_registry->view<TransformComponent, CameraComponent>();
for (auto [entity, transform, camera] : view.each()) {
if (camera.type == CameraType::Orthographic) {
updateOrthographic(transform, camera);
}
else if (camera.type == CameraType::Perspective) {
updatePerspective(transform, camera);
}
}
}
glm::mat4 CameraSystem::projectionView()
{
auto view = m_registry->view<TransformComponent, CameraComponent>();
for (auto [entity, transform, camera] : view.each()) {
return camera.projection * transform.transform;
}
ASSERT_NOT_REACHED();
return glm::mat4 { 1.0f };
}
void CameraSystem::updateOrthographic(TransformComponent& transform, CameraComponent& camera)
{
// Update camera matrix
// Local space -> World space: model matrix
// Is done in Object::update()
// World space -> View space: view matrix
transform.transform = {
glm::translate(glm::mat4(1.0f), transform.translate) *
glm::rotate(glm::mat4(1.0f), glm::radians(transform.rotate.z), camera.rotateAxis)
};
transform.transform = { glm::inverse(transform.transform) };
// View space -> Clip space: projection matrix
float aspectRatio = Application::the().getWindow().getAspect();
camera.projection = {
glm::ortho(-aspectRatio * camera.zoomLevel, aspectRatio * camera.zoomLevel,
-camera.zoomLevel, camera.zoomLevel, -1.0f, 1.0f)
};
// Clip space -> Screen space: viewport transform
// Is done in the fragment shader using the settings of glViewport
}
void CameraSystem::updatePerspective(TransformComponent& transform, CameraComponent& camera)
{
// Update camera matrix
// Local space -> World space: model matrix
// Is done in Object::update()
// World space -> View space: view matrix
transform.transform = { glm::lookAt(transform.translate, transform.translate + transform.rotate, camera.up) };
// View space -> Clip space: projection matrix
float aspect = Application::the().getWindow().getAspect();
camera.projection = { glm::perspective(glm::radians(camera.fov), aspect, NEAR_PLANE, FAR_PLANE) };
// Clip space -> Screen space: viewport transform
// Is done in the fragment shader using the settings of glViewport
// Souce: https://learnopengl.com/img/getting-started/coordinate_systems.png
}
}
-39
View File
@@ -1,39 +0,0 @@
#ifndef CAMERA_SYSTEM_H
#define CAMERA_SYSTEM_H
#include <memory> //std::shared_ptr
#include "entt/entity/registry.hpp" // entt::entity, entt::registry
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
#include "inferno/singleton.h"
#define NEAR_PLANE 0.1f
#define FAR_PLANE 100.0f
namespace Inferno {
struct TransformComponent;
struct CameraComponent;
class CameraSystem final : public Singleton<CameraSystem> {
public:
CameraSystem(s);
virtual ~CameraSystem();
void update();
glm::mat4 projectionView();
void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; };
private:
void updateOrthographic(TransformComponent& transform, CameraComponent& camera);
void updatePerspective(TransformComponent& transform, CameraComponent& camera);
std::shared_ptr<entt::registry> m_registry;
};
}
#endif // CAMERA_SYSTEM_H
@@ -1,30 +0,0 @@
#include "glm/ext/matrix_transform.hpp" // glm::translate, glm::rotate, glm::scale, glm::radians
#include "inferno/assert.h"
#include "inferno/component/spritecomponent.h"
#include "inferno/component/transformcomponent.h"
#include "inferno/io/log.h"
#include "inferno/render/renderer.h"
#include "inferno/system/rendersystem.h"
namespace Inferno {
RenderSystem::RenderSystem(s)
{
info() << "RenderSystem initialized";
}
RenderSystem::~RenderSystem()
{
}
void RenderSystem::render()
{
auto group = m_registry->group<TransformComponent, SpriteComponent>();
for (auto [entity, transform, sprite] : group.each()) {
Renderer2D::the().drawQuad(transform, sprite.color, sprite.texture);
}
}
}
-28
View File
@@ -1,28 +0,0 @@
#ifndef RENDER_SYSTEM_H
#define RENDER_SYSTEM_H
#include <memory> //std::shared_ptr
#include "entt/entity/registry.hpp" // entt::entity, entt::registry
#include "inferno/render/renderer.h"
#include "inferno/singleton.h"
namespace Inferno {
class RenderSystem final : public Singleton<RenderSystem> {
public:
RenderSystem(s);
virtual ~RenderSystem();
void render();
void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; };
private:
std::shared_ptr<entt::registry> m_registry;
};
}
#endif // RENDER_SYSTEM_H

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