Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc33b5d481 | ||
|
|
67bb6a5671 | ||
|
|
3ff8838e01 | ||
|
|
3ae6ecae8a | ||
|
|
6b6c588378 | ||
|
|
9145f90c1d | ||
|
|
b9043dbb4b | ||
|
|
b6e68eccec | ||
|
|
d16fade497 | ||
|
|
b8e4d9ef3f | ||
|
|
03e8210165 | ||
|
|
dcf2a85208 | ||
|
|
b2ed951b1e | ||
|
|
d63dfe2f9f | ||
|
|
faacdca424 | ||
|
|
b5f3cae5ba | ||
|
|
1d5f5a1ad8 | ||
|
|
3cd2fab637 | ||
|
|
c5ed219ad2 | ||
|
|
4dbac7ee38 | ||
|
|
a5b7a49447 | ||
|
|
fd72f6610e | ||
|
|
21319b93ad | ||
|
|
cd36841039 | ||
|
|
538d0b5ce7 | ||
|
|
5f6a5f48dd | ||
|
|
c06b06ed62 | ||
|
|
5721b4249c | ||
|
|
95a64be4cd | ||
|
|
79b4f1c3d1 | ||
|
|
a266a27f88 | ||
|
|
08969e32d1 | ||
|
|
2793956be4 | ||
|
|
51c5874318 | ||
|
|
d01a4429ca | ||
|
|
d22effdfa3 | ||
|
|
52611beeab | ||
|
|
fd8973d10d | ||
|
|
bc3f2c9db5 | ||
|
|
0dd7a05d46 | ||
|
|
c607ebcc72 | ||
|
|
15b71f8387 | ||
|
|
6e5f82913e | ||
|
|
d02d5a528b | ||
|
|
574f2a8b5a | ||
|
|
2b0635ed69 | ||
|
|
649d196577 | ||
|
|
f47babe5cf | ||
|
|
efae5b9adb | ||
|
|
a1b02c2e3a | ||
|
|
e926d3ce4a | ||
|
|
4c479cfb64 | ||
|
|
cf0a20e208 | ||
|
|
55af11d831 | ||
|
|
26cd35d679 | ||
|
|
6972128ad2 | ||
|
|
c858ef3b1d | ||
|
|
3d22334be9 | ||
|
|
9d26f20bde | ||
|
|
0305b2c464 | ||
|
|
17e3a8a5eb | ||
|
|
85b222984d | ||
|
|
124479876b | ||
|
|
aec1a80623 | ||
|
|
ae8bb46a7d | ||
|
|
1dcb25ea5e | ||
|
|
10a5b70520 | ||
|
|
67b4eb0cc0 | ||
|
|
e1d88a1872 | ||
|
|
3db5845bb4 | ||
|
|
c7a8f92970 | ||
|
|
892be89728 | ||
|
|
c2c5777566 | ||
|
|
aedb1a5fc9 | ||
|
|
2ab555af5e | ||
|
|
01e5179ec7 | ||
|
|
324da69bb2 | ||
|
|
f44c82d06e | ||
|
|
8a03d84580 | ||
|
|
f61f402116 | ||
|
|
470f90fbdd | ||
|
|
6302bb4ae1 | ||
|
|
b72da1278d | ||
|
|
3da83e9cea | ||
|
|
766f24d6b9 | ||
|
|
722bdd82b1 | ||
|
|
4af037a7fb | ||
|
|
2f1c6b5e75 | ||
|
|
478dccd3df | ||
|
|
edc0ef7203 | ||
|
|
6b0095dadf | ||
|
|
4468b1ffb9 | ||
|
|
90bfd30f7f | ||
|
|
ed935e50cd | ||
|
|
8b11e51109 | ||
|
|
da757365d0 |
@@ -14,14 +14,17 @@ AlignTrailingComments: true
|
|||||||
AllowAllArgumentsOnNextLine: false
|
AllowAllArgumentsOnNextLine: false
|
||||||
AllowAllConstructorInitializersOnNextLine: true
|
AllowAllConstructorInitializersOnNextLine: true
|
||||||
AllowAllParametersOfDeclarationOnNextLine: false
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
|
||||||
AlwaysBreakTemplateDeclarations: Yes
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
IndentPPDirectives: BeforeHash
|
||||||
|
|
||||||
BraceWrapping:
|
BraceWrapping:
|
||||||
AfterEnum: false
|
AfterEnum: false
|
||||||
AfterFunction: true
|
AfterFunction: true
|
||||||
BeforeCatch: true
|
BeforeCatch: true
|
||||||
BeforeElse: true
|
BeforeElse: true
|
||||||
|
BeforeLambdaBody: false
|
||||||
SplitEmptyRecord: false
|
SplitEmptyRecord: false
|
||||||
BreakBeforeBraces: Custom
|
BreakBeforeBraces: Custom
|
||||||
BreakInheritanceList: BeforeComma
|
BreakInheritanceList: BeforeComma
|
||||||
@@ -29,7 +32,8 @@ BreakInheritanceList: BeforeComma
|
|||||||
SpaceAfterTemplateKeyword: false
|
SpaceAfterTemplateKeyword: false
|
||||||
SpaceInEmptyBlock: false
|
SpaceInEmptyBlock: false
|
||||||
NamespaceIndentation: None
|
NamespaceIndentation: None
|
||||||
Standard: c++11
|
FixNamespaceComments: true
|
||||||
|
Standard: c++20
|
||||||
TabWidth: 4
|
TabWidth: 4
|
||||||
UseTab: AlignWithSpaces
|
UseTab: AlignWithSpaces
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -1,21 +1,24 @@
|
|||||||
[submodule "inferno/vendor/glfw"]
|
[submodule "inferno/vendor/glfw"]
|
||||||
path = inferno/vendor/glfw
|
path = vendor/glfw
|
||||||
url = https://github.com/glfw/glfw
|
url = https://github.com/glfw/glfw
|
||||||
[submodule "inferno/vendor/glm"]
|
[submodule "inferno/vendor/glm"]
|
||||||
path = inferno/vendor/glm
|
path = vendor/glm
|
||||||
url = https://github.com/g-truc/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"]
|
[submodule "inferno/vendor/entt"]
|
||||||
path = inferno/vendor/entt
|
path = vendor/entt
|
||||||
url = https://github.com/skypjack/entt
|
url = https://github.com/skypjack/entt
|
||||||
[submodule "inferno/vendor/lua/lua"]
|
[submodule "inferno/vendor/lua/lua"]
|
||||||
path = inferno/vendor/lua/lua
|
path = vendor/lua/lua
|
||||||
url = https://github.com/lua/lua
|
url = https://github.com/lua/lua
|
||||||
[submodule "inferno/vendor/sol2"]
|
[submodule "inferno/vendor/sol2"]
|
||||||
path = inferno/vendor/sol2
|
path = vendor/sol2
|
||||||
url = https://github.com/ThePhD/sol2
|
url = https://github.com/ThePhD/sol2
|
||||||
[submodule "inferno/vendor/stb/stb"]
|
[submodule "inferno/vendor/stb/stb"]
|
||||||
path = inferno/vendor/stb/stb
|
path = vendor/stb/stb
|
||||||
url = https://github.com/nothings/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
|
||||||
|
|||||||
@@ -1,115 +1,92 @@
|
|||||||
# User config between these lines
|
|
||||||
# ------------------------------------------
|
# ------------------------------------------
|
||||||
|
# User config between these lines
|
||||||
|
|
||||||
# Set engine name
|
# Set engine name
|
||||||
set(ENGINE "inferno")
|
set(ENGINE "inferno")
|
||||||
# Set project name
|
|
||||||
set(GAME "game")
|
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||||
# Set debugging, ON/OFF
|
set(INFERNO_STANDALONE TRUE)
|
||||||
set(DEBUG "ON")
|
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
|
cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
|
||||||
add_custom_target(run
|
project(${ENGINE} CXX C)
|
||||||
COMMAND ${GAME}
|
|
||||||
)
|
|
||||||
|
|
||||||
# ------------------------------------------
|
# ------------------------------------------
|
||||||
|
# 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)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
# Check if the build should include debugging symbols
|
# ------------------------------------------
|
||||||
option(DEBUG "" ${DEBUG})
|
# Engine dependencies target
|
||||||
if(DEBUG)
|
|
||||||
# cmake -DDEBUG=on .. && make
|
|
||||||
message("--- Debug ---")
|
|
||||||
set(CMAKE_BUILD_TYPE "Debug")
|
|
||||||
|
|
||||||
# -Og = Optimizations that do not interfere with debugging
|
# Add engine target to project
|
||||||
# -Wall = All warnings about contructions that are easily avoidable
|
add_subdirectory("vendor")
|
||||||
# -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")
|
|
||||||
|
|
||||||
# -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()
|
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,14 +7,13 @@ Inferno game engine project.
|
|||||||
** Clone
|
** Clone
|
||||||
|
|
||||||
#+BEGIN_SRC sh
|
#+BEGIN_SRC sh
|
||||||
$ git clone https://gitlab.com/riyyi/inferno
|
$ git clone https://github.com/riyyi/inferno
|
||||||
$ cd inferno
|
$ cd inferno
|
||||||
$ git submodule init
|
$ git submodule update --init --recursive
|
||||||
$ git submodule update
|
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
Or
|
Or
|
||||||
#+BEGIN_SRC sh
|
#+BEGIN_SRC sh
|
||||||
$ git clone --recursive https://gitlab.com/riyyi/inferno
|
$ git clone --recursive https://github.com/riyyi/inferno
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
** Update
|
** Update
|
||||||
@@ -34,13 +33,14 @@ Or
|
|||||||
|
|
||||||
* Libraries
|
* Libraries
|
||||||
|
|
||||||
|
- [[https://github.com/assimp/assimp][assimp]]
|
||||||
# - [[https://github.com/bulletphysics/bullet3][Bullet]]
|
# - [[https://github.com/bulletphysics/bullet3][Bullet]]
|
||||||
- [[https://github.com/skypjack/entt][EnTT]]
|
- [[https://github.com/skypjack/entt][EnTT]]
|
||||||
- [[https://github.com/Dav1dde/glad][glad]]
|
- [[https://github.com/Dav1dde/glad][glad]]
|
||||||
- [[https://github.com/glfw/glfw][GLFW]]
|
- [[https://github.com/glfw/glfw][GLFW]]
|
||||||
- [[https://github.com/g-truc/glm][GLM]]
|
- [[https://github.com/g-truc/glm][GLM]]
|
||||||
- [[https://github.com/nlohmann/json][JSON]]
|
|
||||||
- [[https://github.com/lua/lua][Lua]]
|
- [[https://github.com/lua/lua][Lua]]
|
||||||
|
- [[https://github.com/riyyi/ruc][ruc]]
|
||||||
- [[https://github.com/ThePhD/sol2][sol3]]
|
- [[https://github.com/ThePhD/sol2][sol3]]
|
||||||
- [[https://github.com/nothings/stb][stb]]
|
- [[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://www.glfw.org/docs/latest/build_guide.html#build_link_cmake_source][Build GLFW using CMake]]
|
||||||
- [[https://learnopengl.com][Learn OpenGL]]
|
- [[https://learnopengl.com][Learn OpenGL]]
|
||||||
- [[https://www.youtube.com/playlist?list=PLlrATfBNZ98dC-V-N3m0Go4deliWHPFwT][Game Engine]] by The Cherno
|
- [[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]]
|
||||||
|
|||||||
@@ -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)
|
||||||
@@ -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.
|
||||||
@@ -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
|
||||||
|
After Width: | Height: | Size: 135 KiB |
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 87 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
@@ -4,14 +4,14 @@ layout(location = 0) out vec4 color;
|
|||||||
|
|
||||||
in vec4 v_color;
|
in vec4 v_color;
|
||||||
in vec2 v_textureCoordinates;
|
in vec2 v_textureCoordinates;
|
||||||
in flat float v_textureIndex;
|
in flat uint v_textureIndex;
|
||||||
|
|
||||||
uniform sampler2D u_textures[32];
|
uniform sampler2D u_textures[32];
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec4 textureColor = v_color;
|
vec4 textureColor = v_color;
|
||||||
switch(int(v_textureIndex)) {
|
switch(v_textureIndex) {
|
||||||
case 0: break; // Texture unit 0 is reserved for no texture
|
case 0: break; // Texture unit 0 is reserved for no texture
|
||||||
case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break;
|
case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break;
|
||||||
case 2: textureColor *= texture(u_textures[2], v_textureCoordinates); break;
|
case 2: textureColor *= texture(u_textures[2], v_textureCoordinates); break;
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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 = 0) in vec3 a_position;
|
||||||
layout(location = 1) in vec4 a_color;
|
layout(location = 1) in vec4 a_color;
|
||||||
layout(location = 2) in vec2 a_textureCoordinates;
|
layout(location = 2) in uint a_textureIndex;
|
||||||
layout(location = 3) in float a_textureIndex;
|
|
||||||
|
|
||||||
out vec4 v_color;
|
out vec4 v_color;
|
||||||
out vec2 v_textureCoordinates;
|
out vec3 v_textureCoordinates;
|
||||||
out flat float v_textureIndex;
|
out flat uint v_textureIndex;
|
||||||
|
|
||||||
uniform mat4 u_projectionView;
|
uniform mat4 u_projectionView;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
v_color = a_color;
|
v_color = a_color;
|
||||||
v_textureCoordinates = a_textureCoordinates;
|
v_textureCoordinates = a_position;
|
||||||
v_textureIndex = a_textureIndex;
|
v_textureIndex = a_textureIndex;
|
||||||
// Vclip = Camera projection * Camera view * Model transform * Vlocal
|
// Vclip = Camera projection * Camera view * Model transform * Vlocal
|
||||||
gl_Position = u_projectionView * vec4(a_position, 1.0f);
|
gl_Position = u_projectionView * vec4(a_position, 1.0f);
|
||||||
@@ -4,7 +4,7 @@ layout(location = 0) out vec4 color;
|
|||||||
|
|
||||||
in vec4 v_color;
|
in vec4 v_color;
|
||||||
in vec2 v_textureCoordinates;
|
in vec2 v_textureCoordinates;
|
||||||
in flat float v_textureIndex;
|
in flat uint v_textureIndex;
|
||||||
in float v_width;
|
in float v_width;
|
||||||
in float v_edge;
|
in float v_edge;
|
||||||
in float v_borderWidth;
|
in float v_borderWidth;
|
||||||
@@ -25,8 +25,9 @@ float alpha(float textureAlpha)
|
|||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec4 textureColor = v_color;
|
vec4 textureColor = v_color;
|
||||||
switch(int(v_textureIndex)) {
|
switch(v_textureIndex) {
|
||||||
case 0: break; // Texture unit 0 is reserved for no texture
|
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.a = alpha(texture(u_textures[1], v_textureCoordinates).a); break;
|
||||||
// case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break;
|
// case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break;
|
||||||
case 2: textureColor.a = alpha(texture(u_textures[2], v_textureCoordinates).a); break;
|
case 2: textureColor.a = alpha(texture(u_textures[2], v_textureCoordinates).a); break;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
layout(location = 0) in vec3 a_position;
|
layout(location = 0) in vec3 a_position;
|
||||||
layout(location = 1) in vec4 a_color;
|
layout(location = 1) in vec4 a_color;
|
||||||
layout(location = 2) in vec2 a_textureCoordinates;
|
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 = 4) in float a_width;
|
||||||
layout(location = 5) in float a_edge;
|
layout(location = 5) in float a_edge;
|
||||||
layout(location = 6) in float a_borderWidth;
|
layout(location = 6) in float a_borderWidth;
|
||||||
@@ -13,7 +13,7 @@ layout(location = 9) in float a_offset;
|
|||||||
|
|
||||||
out vec4 v_color;
|
out vec4 v_color;
|
||||||
out vec2 v_textureCoordinates;
|
out vec2 v_textureCoordinates;
|
||||||
out flat float v_textureIndex;
|
out flat uint v_textureIndex;
|
||||||
out float v_width;
|
out float v_width;
|
||||||
out float v_edge;
|
out float v_edge;
|
||||||
out float v_borderWidth;
|
out float v_borderWidth;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"fullscreen": "windowed",
|
"fullscreen": "windowed",
|
||||||
"height": 720,
|
"height": 720,
|
||||||
"title": "Inferno",
|
"title": "Inferno",
|
||||||
"vsync": true,
|
"vsync": false,
|
||||||
"width": 1280
|
"width": 1280
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
file(COPY ${CMAKE_CURRENT_LIST_DIR}/../assets DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#+TITLE: Documentation
|
||||||
|
#+AUTHOR: Riyyi
|
||||||
|
#+LANGUAGE: en
|
||||||
|
#+OPTIONS: toc:nil
|
||||||
|
|
||||||
|
Topics:
|
||||||
|
|
||||||
|
- [[./shaders.org][Shaders]]
|
||||||
|
- [[./references.org][References]]
|
||||||
@@ -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]]
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#+TITLE: Shaders
|
||||||
|
#+AUTHOR: Riyyi
|
||||||
|
#+LANGUAGE: en
|
||||||
|
#+OPTIONS: toc:nil
|
||||||
|
|
||||||
|
Topics:
|
||||||
|
|
||||||
|
- [[./memory-layout.org][Memory Layout]]
|
||||||
@@ -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})
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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[]);
|
||||||
@@ -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();
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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 << " }";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||