Compare commits

...
34 Commits
Author SHA1 Message Date
Riyyi 124479876b Engine: Make event handle functions virtual 2022-09-26 14:19:49 +02:00
Riyyi aec1a80623 Engine: Rename getWindow() => window() 2022-09-26 14:18:34 +02:00
Riyyi ae8bb46a7d Engine+Example: Improve entrypoint via manual singleton 2022-09-26 13:07:05 +02:00
Riyyi 1dcb25ea5e CMake: Change include directories to use relative path 2022-09-26 13:00:00 +02:00
Riyyi 10a5b70520 Engine: Comment out text-area test code 2022-09-26 13:00:00 +02:00
Riyyi 67b4eb0cc0 Scene: Load text-areas from JSON 2022-09-26 13:00:00 +02:00
Riyyi e1d88a1872 Component: Add ability to load TextAreaComponent from JSON 2022-09-26 13:00:00 +02:00
Riyyi 3db5845bb4 Scene: Load quads from JSON 2022-09-26 13:00:00 +02:00
Riyyi c7a8f92970 Component: Add ability to read SpriteComponent from JSON 2022-09-26 13:00:00 +02:00
Riyyi 892be89728 Scene: Load camera from JSON 2022-09-26 13:00:00 +02:00
Riyyi c2c5777566 Component: Add ability to read TransformComponent from JSON 2022-09-26 13:00:00 +02:00
Riyyi aedb1a5fc9 Everywhere: Add copyright headers 2022-09-26 13:00:00 +02:00
Riyyi 2ab555af5e Engine: Remove unused utility classes 2022-09-26 13:00:00 +02:00
Riyyi 01e5179ec7 Engine: Update std::stou, remove need for intToHex() 2022-09-26 13:00:00 +02:00
Riyyi 324da69bb2 Engine: Remove unnecessary unused warning suppressions 2022-09-26 13:00:00 +02:00
Riyyi f44c82d06e Engine: Add function for finding key names 2022-09-26 13:00:00 +02:00
Riyyi 8a03d84580 Engine: Switch inferno/io/log.h => ruc/format/log.h 2022-09-26 13:00:00 +02:00
Riyyi f61f402116 Engine: Switch to ruc::File 2022-09-26 13:00:00 +02:00
Riyyi 470f90fbdd Engine: Switch inferno core.h => ruc core.h 2022-09-26 13:00:00 +02:00
Riyyi 6302bb4ae1 Engine: Make sure glad gets included before GLFW in context 2022-09-26 13:00:00 +02:00
Riyyi b72da1278d Engine: Run clang-format 2022-09-26 13:00:00 +02:00
Riyyi 3da83e9cea Meta: Bump C++ version to 20 in .clang-format 2022-09-26 13:00:00 +02:00
Riyyi 766f24d6b9 Engine: Switch to ASSERT macro to ruc's VERIFY 2022-09-26 13:00:00 +02:00
Riyyi 722bdd82b1 Engine: Change include guards to #pragma once 2022-09-26 13:00:00 +02:00
Riyyi 4af037a7fb Engine: Switch to ruc's singleton 2022-09-26 13:00:00 +02:00
Riyyi 2f1c6b5e75 Engine: Make it compile again 2022-09-26 13:00:00 +02:00
Riyyi 478dccd3df Meta+CMake: Add ruc library 2022-09-26 13:00:00 +02:00
Riyyi edc0ef7203 Everywhere: Update work in progress 2022-09-16 20:22:08 +02:00
Riyyi 6b0095dadf CMake: Move source directory to project root 2022-09-16 20:15:49 +02:00
Riyyi 4468b1ffb9 CMake: Move vendor directory to the project root 2022-09-16 19:16:53 +02:00
Riyyi 90bfd30f7f CMake: Move engine source compilation to separate file 2022-09-16 17:12:57 +02:00
Riyyi ed935e50cd CMake: Automatically build examples during standalone compilation 2022-09-16 12:46:44 +02:00
Riyyi 8b11e51109 CMake: Restructure main file, move example to its own directory 2022-09-16 12:41:08 +02:00
Riyyi da757365d0 CMake: Exclude unnecessary lua files from compilation 2022-09-16 11:14:09 +02:00
165 changed files with 6214 additions and 5950 deletions
+5 -1
View File
@@ -14,14 +14,17 @@ AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortLambdasOnASingleLine: All
AlwaysBreakTemplateDeclarations: Yes
IndentPPDirectives: BeforeHash
BraceWrapping:
AfterEnum: false
AfterFunction: true
BeforeCatch: true
BeforeElse: true
BeforeLambdaBody: false
SplitEmptyRecord: false
BreakBeforeBraces: Custom
BreakInheritanceList: BeforeComma
@@ -29,7 +32,8 @@ BreakInheritanceList: BeforeComma
SpaceAfterTemplateKeyword: false
SpaceInEmptyBlock: false
NamespaceIndentation: None
Standard: c++11
FixNamespaceComments: true
Standard: c++20
TabWidth: 4
UseTab: AlignWithSpaces
...
+10 -7
View File
@@ -1,21 +1,24 @@
[submodule "inferno/vendor/glfw"]
path = inferno/vendor/glfw
path = vendor/glfw
url = https://github.com/glfw/glfw
[submodule "inferno/vendor/glm"]
path = inferno/vendor/glm
path = vendor/glm
url = https://github.com/g-truc/glm
[submodule "inferno/vendor/json"]
path = inferno/vendor/json
path = vendor/json
url = https://github.com/nlohmann/json
[submodule "inferno/vendor/entt"]
path = inferno/vendor/entt
path = vendor/entt
url = https://github.com/skypjack/entt
[submodule "inferno/vendor/lua/lua"]
path = inferno/vendor/lua/lua
path = vendor/lua/lua
url = https://github.com/lua/lua
[submodule "inferno/vendor/sol2"]
path = inferno/vendor/sol2
path = vendor/sol2
url = https://github.com/ThePhD/sol2
[submodule "inferno/vendor/stb/stb"]
path = inferno/vendor/stb/stb
path = vendor/stb/stb
url = https://github.com/nothings/stb
[submodule "vendor/ruc"]
path = vendor/ruc
url = https://github.com/Riyyi/ruc
+59 -99
View File
@@ -1,115 +1,75 @@
# User config between these lines
# ------------------------------------------
# User config between these lines
# Set engine name
set(ENGINE "inferno")
# Set project name
set(GAME "game")
# Set debugging, ON/OFF
set(DEBUG "ON")
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(INFERNO_STANDALONE TRUE)
endif()
# Options
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
option(INFERNO_BUILD_EXAMPLES "Build the Inferno example programs" ${INFERNO_STANDALONE})
# ------------------------------------------
# Add 'make run' target
add_custom_target(run
COMMAND ${GAME}
)
cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
project(${ENGINE} CXX C)
# ------------------------------------------
# Setup C++ compiler
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Compiler flags used for all build types
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -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
# 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)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og -g -pg")
# -Og = Optimizations that do not interfere with debugging
# -g = Produce debugging information in OS's native format
# -pg = Generate profile information for analysis with gprof
# $ gprof <PROJECT> gmon.out > profile-data.txt
elseif(${CMAKE_BUILD_TYPE} STREQUAL Release)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
# -O3 = Optimizations that increase compilation time and performance
endif()
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Check if the build should include debugging symbols
option(DEBUG "" ${DEBUG})
if(DEBUG)
# cmake -DDEBUG=on .. && make
message("--- Debug ---")
set(CMAKE_BUILD_TYPE "Debug")
# ------------------------------------------
# Engine dependencies target
# -Og = Optimizations that do not interfere with debugging
# -Wall = All warnings about contructions that are easily avoidable
# -Wextra = Extra warning flags not covered by -Wall
# -g = Produce debugging information in OS's native format
# -pg = Generate profile information for analysis with gprof
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og -Wall -Wextra -g -pg")
# gprof <GAME> gmon.out > profile-data.txt
else()
# cmake -DDEBUG=off .. && make
message("--- Release ---")
set(CMAKE_BUILD_TYPE "Release")
# Add engine target to project
add_subdirectory("vendor")
# -O3 = Optimizations that increases compilation time and performance
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
# ------------------------------------------
# Engine target
# Add engine target to project
add_subdirectory("src")
# ------------------------------------------
# Examples target
if (INFERNO_BUILD_EXAMPLES)
# Add examples target to project
add_subdirectory("example")
endif()
# Include all headers
include_directories(
"${ENGINE}/src"
"${ENGINE}/vendor/entt/src"
"${ENGINE}/vendor/glad/include"
"${ENGINE}/vendor/glfw/include"
"${ENGINE}/vendor/glm"
"${ENGINE}/vendor/json/include"
"${ENGINE}/vendor/lua"
"${ENGINE}/vendor/sol2/include"
"${ENGINE}/vendor/stb"
)
# Define engine source files
file(GLOB_RECURSE GLAD "${ENGINE}/vendor/glad/*.c")
file(GLOB LUA "${ENGINE}/vendor/lua/lua/*.c")
list(REMOVE_ITEM LUA "${CMAKE_SOURCE_DIR}/${ENGINE}/vendor/lua/lua/lua.c") # Do not compile stand-alone main()
file(GLOB_RECURSE ENGINE_SOURCES "${ENGINE}/src/${ENGINE}/*.cpp")
set(ENGINE_SOURCES ${GLAD} ${LUA} ${ENGINE_SOURCES})
# Define game source files
file(GLOB_RECURSE GAME_SOURCES "${GAME}/src/*.cpp")
set(GAME_SOURCES ${GAME_SOURCES})
# ------------------------------------------
project(${ENGINE})
set(CMAKE_CXX_STANDARD 17)
# GLFW options
set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
# Add GLFW target to project
add_subdirectory(${ENGINE}/vendor/glfw)
add_library(${ENGINE} STATIC ${ENGINE_SOURCES})
target_link_libraries(${ENGINE} glfw)
# ------------------------------------------
project(${GAME})
set(CMAKE_CXX_STANDARD 17)
add_executable(${GAME} ${GAME_SOURCES})
target_link_libraries(${GAME} ${ENGINE})
# ------------------------------------------
target_precompile_headers(${ENGINE} PRIVATE
"$<$<COMPILE_LANGUAGE:CXX>:<algorithm$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<array$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<csignal$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<cstddef$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<cstdint$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<functional$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<iostream$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<memory$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<ostream$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<sstream$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<string$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<string_view$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<unordered_map$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<utility$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<vector$<ANGLE-R>>"
)
target_precompile_headers(${GAME} REUSE_FROM ${ENGINE})
+1
View File
@@ -41,6 +41,7 @@ Or
- [[https://github.com/g-truc/glm][GLM]]
- [[https://github.com/nlohmann/json][JSON]]
- [[https://github.com/lua/lua][Lua]]
- [[https://github.com/riyyi/ruc][ruc]]
- [[https://github.com/ThePhD/sol2][sol3]]
- [[https://github.com/nothings/stb][stb]]
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

+1
View File
@@ -27,6 +27,7 @@ void main()
vec4 textureColor = v_color;
switch(int(v_textureIndex)) {
case 0: break; // Texture unit 0 is reserved for no texture
// case 1: textureColor.a = 1; break;
case 1: textureColor.a = alpha(texture(u_textures[1], v_textureCoordinates).a); break;
// case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break;
case 2: textureColor.a = alpha(texture(u_textures[2], v_textureCoordinates).a); break;
+3
View File
@@ -33,4 +33,7 @@ void main()
v_borderColor = a_borderColor;
v_offset = a_offset;
gl_Position = vec4(a_position, 1.0f);
// Vclip = Camera projection * Camera view * Model transform * Vlocal
// gl_Position = u_projectionView * vec4(a_position, 1.0f);
}
+50
View File
@@ -0,0 +1,50 @@
{
"init": "assets/lua/scene1-init.lua",
"camera": {
"name": "Camera",
"translate": [ 0.0, 0.0, 1.0 ],
"rotate": [ 0.0, 0.0, -1.0 ],
"scale": [ 1.0, 1.0, 1.0 ],
"type": "perspective",
"script": {
"type": "lua",
"name": "assets/lua/cameracontroller.lua"
}
},
"quad": [
{
"name": "Quad",
"translate": [ 0.0, 0.0, 0.0 ],
"rotate": [ 0.0, 0.0, 0.0 ],
"scale": [ 1.0, 1.0, 1.0 ],
"color": [ 1.0, 1.0, 1.0, 1.0 ],
"texture": "assets/gfx/test.png"
},
{
"name": "Quad 2",
"translate": [ 1.1, 0.0, 0.0 ],
"rotate": [ 0.0, 0.0, 0.0 ],
"scale": [ 1.0, 1.0, 1.0 ],
"color": [ 0.5, 0.6, 0.8, 1.0 ],
"texture": "assets/gfx/test.png"
},
{
"name": "Quad 3",
"translate": [ 2.2, 0.0, 0.0 ],
"rotate": [ 0.0, 0.0, 0.0 ],
"scale": [ 1.0, 1.0, 1.0 ],
"color": [ 1.0, 1.0, 1.0, 1.0 ],
"texture": "assets/gfx/test-inverted.png"
}
],
"text": [
{
"name": "Text",
"content": "HelloWorld!",
"font": "assets/fnt/dejavu-sans",
"font-size": 0,
"width": 150,
"lines": 3
}
]
}
+28
View File
@@ -0,0 +1,28 @@
# ------------------------------------------
# User config between these lines
# Set project name
set(GAME "game")
# ------------------------------------------
project(${GAME} CXX)
# Define game source files
file(GLOB_RECURSE GAME_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_executable(${GAME} ${GAME_SOURCES})
target_include_directories(${GAME} PRIVATE
"src"
"${CMAKE_SOURCE_DIR}/src"
"${CMAKE_SOURCE_DIR}/vendor/ruc/src")
target_link_libraries(${GAME} ${ENGINE})
target_precompile_headers(${GAME} REUSE_FROM ${ENGINE})
# ------------------------------------------
# Add 'make run' target
add_custom_target(run
COMMAND ${GAME}
)
+29
View File
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include "game.h"
Game::Game()
: Application()
{
}
Game::~Game()
{
}
void Game::update()
{
}
void Game::render()
{
}
Inferno::Application* Inferno::createApplication(int argc, char* argv[])
{
return new Game;
}
+19
View File
@@ -0,0 +1,19 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include "inferno.h"
#include "inferno/entrypoint.h"
class Game final : public Inferno::Application {
public:
Game();
~Game();
void update() override;
void render() override;
};
Inferno::Application* Inferno::createApplication(int argc, char* argv[]);
-15
View File
@@ -1,15 +0,0 @@
#include "inferno.h"
#include "inferno/entrypoint.h"
class Game : public Inferno::Application
{
public:
Game() : Application({}) {}
~Game() {}
};
Inferno::Application& Inferno::createApplication()
{
Game::initialize();
return Game::the();
}
-210
View File
@@ -1,210 +0,0 @@
#include "inferno/application.h"
#include "inferno/assert.h"
#include "inferno/core.h"
#include "inferno/event/applicationevent.h"
#include "inferno/event/event.h"
#include "inferno/event/keyevent.h"
#include "inferno/event/mouseevent.h"
#include "inferno/keycodes.h"
#include "inferno/io/input.h"
#include "inferno/io/log.h"
#include "inferno/render/buffer.h"
#include "inferno/render/context.h"
#include "inferno/render/font.h"
#include "inferno/render/renderer.h"
#include "inferno/render/shader.h"
#include "inferno/render/texture.h"
#include "inferno/scene/scene.h"
#include "inferno/settings.h"
#include "inferno/time.h"
#include "inferno/window.h"
namespace Inferno {
Application::Application(s)
{
// Set singleton instance early
s_instance = this;
// Initialize
Settings::initialize();
m_window = std::make_unique<Window>();
m_window->setEventCallback(NF_BIND_EVENT(Application::onEvent));
Input::initialize();
ShaderManager::initialize();
TextureManager::initialize();
RenderCommand::initialize();
Renderer2D::initialize();
RendererCharacter::initialize();
FontManager::initialize();
m_scene = std::make_shared<Scene>();
m_scene->initialize();
// Load assets
m_font = FontManager::the().load("assets/fnt/dejavu-sans");
}
Application::~Application()
{
m_scene->destroy();
FontManager::destroy();
RendererCharacter::destroy();
Renderer2D::destroy();
RenderCommand::destroy();
TextureManager::destroy();
ShaderManager::destroy();
// Input::destroy();
Settings::destroy();
}
int Application::run()
{
dbg() << "Application startup";
std::array<CharacterVertex, Renderer::vertexPerQuad> character;
// character.at(0).quad.textureCoordinates = { 0.0f, 0.0f }; // bottom left
// character.at(1).quad.textureCoordinates = { 1.0f, 0.0f };
// character.at(2).quad.textureCoordinates = { 1.0f, 1.0f }; // top right
// character.at(3).quad.textureCoordinates = { 0.0f, 1.0f };
auto f = FontManager::the().get("assets/fnt/dejavu-sans");
auto c = f->get('5');
// dbg() << c->position << " " << c->size;
uint32_t textureWidth = f->texture()->width();
uint32_t textureHeight = f->texture()->height();
ASSERT(textureWidth == textureHeight, "Invalid font texture!");
float quadWidth = (c->size.x / (float)textureWidth) - 0.04; // @Todo something wrong with the width
float quadHeight = c->size.y / (float)textureHeight;
character.at(0).quad.position = { -quadWidth, -quadHeight, 0.0f }; // bottom left
character.at(1).quad.position = { quadWidth, -quadHeight, 0.0f }; // bottom right
character.at(2).quad.position = { quadWidth, quadHeight, 0.0f }; // top right
character.at(3).quad.position = { -quadWidth, quadHeight, 0.0f }; // top left
glm::vec2 x {
1 - (textureWidth - c->position.x) / (float)textureWidth,
1 - (textureWidth - c->position.x - c->size.x) / (float)textureWidth
};
glm::vec2 y {
(textureHeight - c->position.y - c->size.y) / (float)textureHeight,
(textureHeight - c->position.y) / (float)textureHeight
};
// dbg() < y;
character.at(0).quad.textureCoordinates = { x.x, y.x };
character.at(1).quad.textureCoordinates = { x.y, y.x };
character.at(2).quad.textureCoordinates = { x.y, y.y };
character.at(3).quad.textureCoordinates = { x.x, y.y };
// pos
// texcoords
//
// width
// edge
// borderwidth
// borderedge
// bordercolor
// offset
while (!m_window->shouldClose()) {
float time = Time::time();
float deltaTime = time - m_lastFrameTime;
m_lastFrameTime = time;
// dbg() << "Frametime " << deltaTime * 1000 << "ms";
// Update
Input::update();
m_window->update();
m_scene->update(deltaTime);
// Render
RenderCommand::clearColor({ 0.2f, 0.3f, 0.3f, 1.0f });
RenderCommand::clear();
Renderer2D::the().beginScene(m_scene->cameraProjectionView()); // camera, lights, environment
RendererCharacter::the().beginScene();
m_scene->render();
RendererCharacter::the().drawCharacter(character, f->texture());
Renderer2D::the().endScene();
RendererCharacter::the().endScene();
m_window->render();
}
dbg() << "Application shutdown";
return m_status;
}
void Application::onEvent(Event& e)
{
EventDispatcher dispatcher(e);
dispatcher.dispatch<WindowCloseEvent>(NF_BIND_EVENT(Application::onWindowClose));
dispatcher.dispatch<WindowResizeEvent>(NF_BIND_EVENT(Application::onWindowResize));
dispatcher.dispatch<KeyPressEvent>(NF_BIND_EVENT(Application::onKeyPress));
dispatcher.dispatch<MousePositionEvent>(NF_BIND_EVENT(Application::onMousePosition));
}
bool Application::onWindowClose(WindowCloseEvent& e)
{
// Suppress unused warning
(void)e;
info() << "WindowCloseEvent triggered";
m_window->setShouldClose(true);
return true;
}
bool Application::onWindowResize(WindowResizeEvent& e)
{
// Suppress unused warning
(void)e;
infoln("WindowResizeEvent {}x{} triggered", e.getWidth(), e.getHeight());
RenderCommand::setViewport(0, 0, e.getWidth(), e.getHeight());
return true;
}
bool Application::onKeyPress(KeyPressEvent& e)
{
// Suppress unused warning
(void)e;
infoln("KeyPressEvent {} ({}) triggered",
Input::getKeyName(e.getKey()),
e.getKey());
// Stop the main loop on 'Escape' keypress
if (e.getKey() == keyCode("GLFW_KEY_ESCAPE")) {
m_window->setShouldClose(true);
}
return true;
}
bool Application::onMousePosition(MousePositionEvent& e)
{
return Input::onMousePosition(e);
}
}
-89
View File
@@ -1,89 +0,0 @@
#ifndef APPLICATION_H
#define APPLICATION_H
#include <memory> // std::unique_ptr, std::shared_ptr
#include "inferno/singleton.h"
namespace Inferno {
class Event;
class Font;
class KeyPressEvent;
class MousePositionEvent;
class Scene;
class Window;
class WindowCloseEvent;
class WindowResizeEvent;
class Application : public Singleton<Application> {
public:
Application(s);
virtual ~Application();
int run();
void onEvent(Event& e);
bool onWindowClose(WindowCloseEvent& e);
bool onWindowResize(WindowResizeEvent& e);
bool onKeyPress(KeyPressEvent& e);
bool onMousePosition(MousePositionEvent& e);
inline void setStatus(int status) { m_status = status; }
inline Window& getWindow() const { return *m_window; }
private:
int m_status { 0 };
float m_lastFrameTime { 0.0f };
std::unique_ptr<Window> m_window;
std::shared_ptr<Scene> m_scene;
//
std::shared_ptr<Font> m_font;
//
};
// To be defined in the game
extern Application& createApplication();
}
#endif // APPLICATION_H
// C++17 features used:
// - std::string:view, log.h
// - std::shared_ptr array management, renderer.h
// OpenGL 4.5 features used:
// -
// Gameplan
// v Entrypoint
// v Logging
// v Events
// v Window
// v Settings loader (json)
// v Input polling
// v OpenGL context
// - GPUDriver (?)
// v Renderer
// v Buffers
// ~ Shader
// - Schene (camera, lights, environment)
// - Texture loading
// - Model loading
// - Entity Component System
// - Serialization
// - Level format
// - Tools (Tiled?)
// - Scripting (Lua)
// - Global object access can be done in 3 ways:
// - Singleton, static, extern
// @Todo
// - Settings should contain all file paths (ex: shaders)
// - RefPtr<>
// - Rename Application::get() to Application::the() for singleton
-64
View File
@@ -1,64 +0,0 @@
#ifndef ASSERT_H
#define ASSERT_H
#include <csignal> // raise
#include <cstdint> // uint32_t
#include "inferno/core.h"
#include "inferno/io/log.h"
#ifndef NDEBUG
#define NF_ENABLE_ASSERTS
#endif
// Asserts
#ifdef NF_ENABLE_ASSERTS
// Check if SIGTRAP is available
#ifdef SIGTRAP
#define ABORT_SIGNAL SIGTRAP
#else
#define ABORT_SIGNAL SIGABRT
#endif
// Non-standard function macro
#ifdef GCC
#define FUNCTION_MACRO __PRETTY_FUNCTION__
#elif MSVC
#define FUNCTION_MACRO __FUNCSIG__
#else
#define FUNCTION_MACRO __func__
#endif
// ##__VA_ARGS__ is a non-standard GCC extension, C++20 introduces __VA_OPT__
// https://stackoverflow.com/questions/52891546/what-does-va-args-mean
#define ASSERT(expr, ...) static_cast<bool>(expr) ? (void)0 : Inferno::__assert_fail(#expr, __FILE__, __LINE__, FUNCTION_MACRO, ##__VA_ARGS__)
#define ASSERT_NOT_REACHED() ASSERT(false)
#else
#define ASSERT(expr, ...)
#define ASSERT_NOT_REACHED() CRASH()
#endif
#define CRASH() raise(SIGABRT)
namespace Inferno {
#ifdef NF_ENABLE_ASSERTS
template<typename... P>
inline void __assert_fail(const char* assertion, const char* file, uint32_t line, const char* function, P&&... parameters)
{
dangerln(false, "ASSERTION `{}' FAILED.", assertion);
if (sizeof...(P) > 0) {
dbg(false) << " ";
dbgln(Log::Danger, false, std::forward<P>(parameters)...);
}
danger() << "\n " << file << ":" << line << " in " << function;
raise(ABORT_SIGNAL);
}
#endif
}
#endif // ASSERT_H
@@ -1,32 +0,0 @@
#ifndef CAMERA_COMPONENT_H
#define CAMERA_COMPONENT_H
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
#include "glm/ext/vector_float3.hpp" // glm::vec3
namespace Inferno {
enum CameraType {
Orthographic,
Perspective,
};
struct CameraComponent {
CameraType type = CameraType::Perspective;
// Orthographic
float zoomLevel = 1.0f;
glm::vec3 rotateAxis { 0.0f, 0.0f, 1.0f };
// Perspective
float fov = 90.0f;
float pitch = 0.0f;
float yaw = -90.0f;
glm::vec3 up { 0.0f, 1.0f, 0.0f };
glm::mat4 projection { 1.0f }; // Identity matrix
};
}
#endif // CAMERA_COMPONENT_H
@@ -1,22 +0,0 @@
#ifndef LUA_SCRIPT_COMPONENT_H
#define LUA_SCRIPT_COMPONENT_H
#include <string> // std::string
#include <utility> // std::move
namespace Inferno {
class LuaScript;
struct LuaScriptComponent {
LuaScript* instance { nullptr };
std::string path;
// Dont allow manually setting instance during construction
LuaScriptComponent() {}
LuaScriptComponent(const std::string& path)
: path(std::move(path)) {}
};
}
#endif // LUA_SCRIPT_COMPONENT_H
@@ -1,33 +0,0 @@
#ifndef NATIVE_SCRIPT_COMPONENT_H
#define NATIVE_SCRIPT_COMPONENT_H
#include "inferno/assert.h"
#include "inferno/script/nativescript.h"
namespace Inferno {
struct NativeScriptComponent {
NativeScript* instance { nullptr };
NativeScript* (*initialize)();
// Dont allow manually setting instance during construction
NativeScriptComponent() {}
template<typename T>
void bind()
{
ASSERT(instance == nullptr, "NativeScript already bound");
initialize = []() { return static_cast<NativeScript*>(new T()); };
}
void destroy() {
ASSERT(instance, "Attempting to destroy an uninitialized NativeScript");
delete instance;
instance = nullptr;
}
};
}
#endif // NATIVE_SCRIPT_COMPONENT_H
@@ -1,19 +0,0 @@
#ifndef SPRITE_COMPONENT_H
#define SPRITE_COMPONENT_H
#include <memory> // std::shared_ptr
#include "glm/ext/vector_float4.hpp" // glm::vec4
#include "inferno/render/texture.h"
namespace Inferno {
struct SpriteComponent {
glm::vec4 color { 1.0f };
std::shared_ptr<Texture> texture;
};
}
#endif // SPRITE_COMPONENT_H
@@ -1,21 +0,0 @@
#ifndef TAG_COMPONENT_H
#define TAG_COMPONENT_H
#include <string> // std::string
#include <utility> // std::move
namespace Inferno {
struct TagComponent {
std::string tag;
TagComponent() = default;
TagComponent(const std::string& tag)
: tag(std::move(tag)) {}
operator const std::string&() const { return tag; }
};
}
#endif // TAG_COMPONENT_H
@@ -1,47 +0,0 @@
#include "inferno/component/transformcomponent.h"
namespace Inferno {
const LogStream& operator<<(const LogStream& stream, const glm::vec2& value)
{
return stream << "{ "
<< (value.x >= 0.0f ? " " : "") << value.x << ", "
<< (value.y >= 0.0f ? " " : "") << value.y
<< " }";
}
const LogStream& operator<<(const LogStream& stream, const glm::vec3& value)
{
return stream << "{ "
<< (value.x >= 0.0f ? " " : "") << value.x << ", "
<< (value.y >= 0.0f ? " " : "") << value.y << ", "
<< (value.z >= 0.0f ? " " : "") << value.z
<< " }";
}
const LogStream& operator<<(const LogStream& stream, const glm::vec4& value)
{
return stream << "{ "
<< (value.x >= 0.0f ? " " : "") << value.x << ", "
<< (value.y >= 0.0f ? " " : "") << value.y << ", "
<< (value.z >= 0.0f ? " " : "") << value.z << ", "
<< (value.w >= 0.0f ? " " : "") << value.w
<< " }";
}
const LogStream& operator<<(const LogStream& stream, const glm::mat4& value)
{
return stream << "mat4 "
<< value[0] << "\n " << value[1] << "\n "
<< value[2] << "\n " << value[3];
}
const LogStream& operator<<(const LogStream& stream, const TransformComponent& value)
{
return stream << "transform "
<< value.translate << " t\n "
<< value.rotate << " r\n "
<< value.scale << " s";
}
}
@@ -1,27 +0,0 @@
#ifndef TRANSFORM_COMPONENT_H
#define TRANSFORM_COMPONENT_H
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
#include "glm/ext/vector_float3.hpp" // glm::vec3
#include "inferno/io/log.h"
namespace Inferno {
struct TransformComponent {
glm::vec3 translate { 0.0f, 0.0f, 0.0f };
glm::vec3 rotate { 0.0f, 0.0f, 0.0f } ;
glm::vec3 scale { 1.0f, 1.0f, 1.0f };
glm::mat4 transform { 1.0f }; // Identity matrix
};
// -----------------------------------------
const LogStream& operator<<(const LogStream& stream, const glm::vec2& value);
const LogStream& operator<<(const LogStream& stream, const glm::vec3& value);
const LogStream& operator<<(const LogStream& stream, const glm::vec4& value);
const LogStream& operator<<(const LogStream& stream, const glm::mat4& value);
const LogStream& operator<<(const LogStream& stream, const TransformComponent& value);
}
#endif // TRANSFORM_COMPONENT_H
-21
View File
@@ -1,21 +0,0 @@
#ifndef CORE_H
#define CORE_H
#include <functional> // std::bind
#define BIT(x) (1 << x)
#define NF_BIND_EVENT(f) std::bind(&f, this, std::placeholders::_1)
// Compiler
#if defined(__clang__)
#define GCC
#elif defined(__INTEL_COMPILER) // Supports some GCC extensions
#define GCC
#elif defined(__GNUG__) || (defined(__GNUC__) && defined(__cplusplus))
#define GCC
#elif defined(_MSC_VER)
#define MSVC
#endif
#endif // CORE_H
-27
View File
@@ -1,27 +0,0 @@
/*
* `m_` for member variables,
* `s_` for static variables,
* `g_` for global variables.
*/
#ifndef ENTRYPOINT_H
#define ENTRYPOINT_H
#include "inferno/application.h"
int main(int argc, char* argv[])
{
// Suppress unused warning
(void)argc;
(void)argv;
auto& app = Inferno::createApplication();
int status = app.run();
app.destroy();
return status;
}
#endif // ENTRYPOINT_H
@@ -1,42 +0,0 @@
#ifndef APPLICATIONEVENT_H
#define APPLICATIONEVENT_H
#include <sstream> // std::stringstream
#include "inferno/event/event.h"
namespace Inferno {
class WindowCloseEvent : public Event {
public:
EVENT_CLASS_TYPE(WindowClose)
EVENT_CLASS_CATEGORY(ApplicationEventCategory)
};
class WindowResizeEvent : public Event {
public:
WindowResizeEvent(int width, int height) :
m_width(width), m_height(height) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "WindowResize: " << m_width << "x" << m_height;
return ss.str();
}
// -----------------------------------------
inline int getWidth() const { return m_width; }
inline int getHeight() const { return m_height; }
EVENT_CLASS_TYPE(WindowResize)
EVENT_CLASS_CATEGORY(ApplicationEventCategory)
private:
int m_width;
int m_height;
};
}
#endif // APPLICATIONEVENT_H
-111
View File
@@ -1,111 +0,0 @@
#ifndef EVENT_H
#define EVENT_H
#include <ostream> // std::ostream
#include "inferno/core.h"
namespace Inferno {
enum class EventType {
None = 0,
WindowClose,
WindowResize,
KeyPress,
KeyRelease,
KeyRepeat,
MouseButtonPress,
MouseButtonRelease,
MousePosition,
MouseScroll,
JoystickConnected,
JoystickDisconnected,
};
enum EventCategory {
None = 0,
ApplicationEventCategory = BIT(0),
InputEventCategory = BIT(1),
KeyEventCategory = BIT(2),
MouseEventCategory = BIT(3),
MouseButtonEventCategory = BIT(4),
JoystickEventCatergory = BIT(5),
};
class Event {
// EventDispatcher is allowed to access Event private/protected members
friend class EventDispatcher;
public:
virtual ~Event() {}
virtual std::string toString() const { return getName(); }
inline bool inCategory(EventCategory category)
{
return getCategoryFlags() & category;
}
// -----------------------------------------
// Getter function templates
virtual char getCategoryFlags() const = 0;
virtual const char* getName() const = 0;
virtual EventType getType() const = 0;
private:
bool handled = false;
};
class EventDispatcher {
public:
EventDispatcher(Event& e) : m_event(e) {}
// Easily dispatch all type of Events, call with:
// dispatch<T>(std::bind(&F, this, std::placeholders::_1));
// T is the type of Event
// F is the function to call, signature: bool name(T& e);
template<typename T, typename F>
bool dispatch(const F& function)
{
// If <constructed> type is same as member variable type
if (T::getTypeStatic() == m_event.getType()) {
// Call the function
m_event.handled = function(static_cast<T& >(m_event));
return true;
}
return false;
}
private:
Event& m_event;
};
// Add class type functions macro
#define EVENT_CLASS_TYPE(type) \
virtual const char* getName() const override { return #type; } \
virtual EventType getType() const override { return getTypeStatic(); } \
static inline EventType getTypeStatic() { return EventType::type; }
// Add class catergory function macro
#define EVENT_CLASS_CATEGORY(category) \
virtual char getCategoryFlags() const override { return category; }
// Make Events easily printable
inline std::ostream& operator<<(std::ostream& os, const Event& e)
{
return os << e.toString();
}
}
#endif // EVENT_H
-56
View File
@@ -1,56 +0,0 @@
#ifndef JOYSTICKEVENT_H
#define JOYSTICKEVENT_H
#include <sstream> // std::stringstream
#include "inferno/event/event.h"
namespace Inferno {
class JoystickEvent : public Event {
public:
inline int getID() const { return m_id; }
EVENT_CLASS_CATEGORY(InputEventCategory | JoystickEventCatergory)
protected:
JoystickEvent(int id) :
m_id(id) {}
private:
int m_id;
};
class JoystickConnectedEvent : public JoystickEvent {
public:
JoystickConnectedEvent(int id) :
JoystickEvent(id) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "JoystickConnected: " << getID();
return ss.str();
}
EVENT_CLASS_TYPE(JoystickConnected)
};
class JoystickDisconnectedEvent : public JoystickEvent {
public:
JoystickDisconnectedEvent(int id) :
JoystickEvent(id) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "JoystickDisconnected: " << getID();
return ss.str();
}
EVENT_CLASS_TYPE(JoystickDisconnected)
};
}
#endif // JOYSTICKEVENT_H
-71
View File
@@ -1,71 +0,0 @@
#ifndef KEYEVENT_H
#define KEYEVENT_H
#include <sstream> // std::stringstream
#include "inferno/event/event.h"
namespace Inferno {
class KeyEvent : public Event {
public:
inline int getKey() const { return m_key; }
EVENT_CLASS_CATEGORY(InputEventCategory | KeyEventCategory)
protected:
KeyEvent(int key) :
m_key(key) {}
private:
int m_key;
};
class KeyPressEvent : public KeyEvent {
public:
KeyPressEvent(int key) :
KeyEvent(key) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "KeyPress: " << getKey();
return ss.str();
}
EVENT_CLASS_TYPE(KeyPress)
};
class KeyReleaseEvent : public KeyEvent {
public:
KeyReleaseEvent(int key) :
KeyEvent(key) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "KeyRelease: " << getKey();
return ss.str();
}
EVENT_CLASS_TYPE(KeyPress)
};
class KeyRepeatEvent : public KeyEvent {
public:
KeyRepeatEvent(int key) :
KeyEvent(key) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "KeyRepeat: " << getKey();
return ss.str();
}
EVENT_CLASS_TYPE(KeyPress)
};
}
#endif // KEYEVENT_H
-106
View File
@@ -1,106 +0,0 @@
#ifndef MOUSEEVENT_H
#define MOUSEEVENT_H
#include <sstream> // std::stringstream
#include "inferno/event/event.h"
namespace Inferno {
class MouseButtonEvent : public Event {
public:
inline int getButton() const { return m_button; }
EVENT_CLASS_CATEGORY(InputEventCategory | MouseEventCategory | MouseButtonEventCategory)
protected:
MouseButtonEvent(int button) :
m_button(button) {}
private:
int m_button;
};
class MouseButtonPressEvent : public MouseButtonEvent {
public:
MouseButtonPressEvent(int button) :
MouseButtonEvent(button) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "MouseButtonPressed: " << getButton();
return ss.str();
}
EVENT_CLASS_TYPE(MouseButtonPress)
};
class MouseButtonReleaseEvent : public MouseButtonEvent {
public:
MouseButtonReleaseEvent(int button) :
MouseButtonEvent(button) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "MouseButtonReleased: " << getButton();
return ss.str();
}
EVENT_CLASS_TYPE(MouseButtonRelease)
};
class MousePositionEvent : public Event {
public:
MousePositionEvent(float xPos, float yPos) :
m_xPos(xPos), m_yPos(yPos) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "MousePosition: " << m_xPos << "x" << m_yPos;
return ss.str();
}
// -----------------------------------------
inline float getXPos() const { return m_xPos; }
inline float getYPos() const { return m_yPos; }
EVENT_CLASS_TYPE(MousePosition)
EVENT_CLASS_CATEGORY(InputEventCategory | MouseEventCategory)
private:
float m_xPos;
float m_yPos;
};
class MouseScrollEvent : public Event {
public:
MouseScrollEvent(float xOffset, float yOffset) :
m_xOffset(xOffset), m_yOffset(yOffset) {}
virtual std::string toString() const override
{
std::stringstream ss;
ss << "MouseScroll: " << m_xOffset << ":" << m_yOffset;
return ss.str();
}
// -----------------------------------------
inline float getXOffset() const { return m_xOffset; }
inline float getYOffset() const { return m_yOffset; }
EVENT_CLASS_TYPE(MouseScroll)
EVENT_CLASS_CATEGORY(InputEventCategory | MouseEventCategory)
private:
float m_xOffset;
float m_yOffset;
};
}
#endif // MOUSEEVENT_H
-47
View File
@@ -1,47 +0,0 @@
#include <ios> // std::ios
#include <memory> // std::make_unique
#include "inferno/assert.h"
#include "inferno/io/file.h"
namespace Inferno {
std::shared_ptr<char[]> File::raw(const std::string& path)
{
// Create input stream object and open file
std::ifstream file(path);
ASSERT(file.is_open(), "File could not open '{}'", path);
// Get length of the file
int32_t length = File::length(path, file);
// Allocate memory filled with zeros
auto buffer = std::shared_ptr<char[]>(new char[length + 1]);
// Fill buffer with file contents
file.read(buffer.get(), length);
file.close();
// Null termination
buffer[length] = '\0';
return buffer;
}
std::string File::read(const std::string &path)
{
// Create string from the buffer and return
return std::string(raw(path).get());
}
int32_t File::length(const std::string& path, std::ifstream& file)
{
file.seekg(0, std::ios::end);
int32_t length = file.tellg();
file.seekg(0, std::ios::beg);
ASSERT(length != -1, "File could not determine length '{}'", path);
return length;
}
}
-65
View File
@@ -1,65 +0,0 @@
#ifndef FILE_H
#define FILE_H
#include <fstream> // std::ifstream, std::ofstream
#include <iomanip> // std::setfill, std::setw
#include <memory> // std::shared_ptr
#include <string> // std::string
#include "inferno/assert.h"
#include "inferno/core.h"
#include "inferno/io/log.h"
namespace Inferno {
class File {
public:
static std::shared_ptr<char[]> raw(const std::string& path);
static std::string read(const std::string& path);
static int32_t length(const std::string& path, std::ifstream& file);
template<typename T>
static bool ioRead(T* t, const std::string& path)
{
std::ifstream file(path);
ASSERT(file.is_open(), "File could not open '{}'", path);
if (!file.is_open()) {
return false;
}
try {
file >> *t;
}
catch (...) {
return false;
}
return true;
}
template<typename T>
static bool ioWrite(T* t, const std::string& path)
{
std::ofstream file (path);
ASSERT(file.is_open(), "File could not open! {}", path);
if (!file.is_open()) {
return false;
}
try {
// Write file with single tabs, nicely formatted
file << std::setfill ('\t') << std::setw(1) << *t << std::endl;
}
catch (...) {
return false;
}
return true;
}
};
}
#endif // FILE_H
-103
View File
@@ -1,103 +0,0 @@
#include <cstring> // strcmp ??
#include <fstream> // std::ifstream
#include <ios> // std::ios
#include "inferno/assert.h"
#include "inferno/io/file.h"
#include "inferno/io/gltffile.h"
#include "inferno/io/log.h"
#include "inferno/util/string.h"
#include "inferno/util/json.h"
namespace Inferno {
std::pair<std::shared_ptr<char[]>, std::shared_ptr<char[]>> GltfFile::read(const std::string& path)
{
std::string extension = path.substr(path.find_first_of("."));
if (extension.compare(".glb") == 0) {
return glb(path);
}
else if (extension.compare(".gltf") == 0) {
return { File::raw(path), nullptr };
}
ASSERT(false, "GltfFile unknown file extension!");
return {};
}
std::pair<std::shared_ptr<char[]>, std::shared_ptr<char[]>> GltfFile::glb(const std::string& path)
{
// Create input stream object and open file
std::ifstream glb(path, std::ios::in | std::ios::binary);
ASSERT(glb.is_open(), "GltfFile could not open '{}'", path);
constexpr uint32_t size = 4;
constexpr uint32_t header = 12;
constexpr uint32_t json = 27; // Minimum valid glTF has an asset property with version specifier
// Get the actual length of the file
uint32_t length = static_cast<uint32_t>(File::length(path, glb));
ASSERT(length > header + json, "GltfFile too small to be valid '{}'", path);
// Read header
char magic[size];
char version[size];
char fileLength[size];
glb.read(magic, size);
glb.seekg(size * 1);
glb.read(version, size);
glb.seekg(size * 2);
glb.read(fileLength, size);
// Validate header
uint32_t magicInt = *reinterpret_cast<uint32_t*>(magic);
ASSERT(magicInt == 0x46546c67, "Gltf invalid header magic '{}'", magic);
uint32_t versionInt = *reinterpret_cast<uint32_t*>(version);
ASSERT(versionInt == 2, "Gltf unsupported version '{}'", versionInt);
uint32_t fileLengthInt = *reinterpret_cast<uint32_t*>(fileLength);
ASSERT(fileLengthInt == length, "Gltf file and reported byte size mismatch '{}' '{}'", length, fileLengthInt);
// Read JSON data
auto jsonChunk = readChunk(glb, header, 0x4e4f534a);
ASSERT(jsonChunk.second >= json, "Gltf file invalid JSON content length '{}'", jsonChunk.second);
// Read binary data
auto binaryChunk = readChunk(glb, header + size * 2 + jsonChunk.second, 0x004e4942);
glb.close();
return { jsonChunk.first, binaryChunk.first };
}
std::pair<std::shared_ptr<char[]>, uint32_t> GltfFile::readChunk(std::ifstream& ifstream, uint32_t offset, uint32_t type)
{
constexpr uint32_t size = 4;
char chunkLength[size];
char chunkType[size];
ifstream.seekg(offset);
ifstream.read(chunkLength, size);
ifstream.seekg(offset + size * 1);
ifstream.read(chunkType, size);
uint32_t chunkTypeInt = *reinterpret_cast<uint32_t*>(chunkType);
ASSERT(chunkTypeInt == type, "Gltf invalid chunk type '{}' != '{}'", chunkType, intToHex(type));
uint32_t chunkLengthInt = *reinterpret_cast<uint32_t*>(chunkLength);
// Allocate memory filled with zeros
std::shared_ptr<char[]> chunkData(new char[chunkLengthInt + 1]);
ifstream.seekg(offset + size * 2);
ifstream.read(chunkData.get(), chunkLengthInt);
chunkData.get()[chunkLengthInt] = '\0';
return { chunkData, chunkLengthInt };
}
} // namespace Inferno
-22
View File
@@ -1,22 +0,0 @@
#ifndef GLTF_FILE_H
#define GLTF_FILE_H
#include <cstdint> // uint32_t
#include <memory> // std::shared_ptr
#include <string> // std::string
#include <utility> // std::pair
namespace Inferno {
class GltfFile {
public:
static std::pair<std::shared_ptr<char[]>, std::shared_ptr<char[]>> read(const std::string& path);
private:
static std::pair<std::shared_ptr<char[]>, std::shared_ptr<char[]>> glb(const std::string& path);
static std::pair<std::shared_ptr<char[]>, uint32_t> readChunk(std::ifstream& ifstream, uint32_t offset, uint32_t type);
};
} // namespace Inferno
#endif // GLTF_FILE_H
-92
View File
@@ -1,92 +0,0 @@
#include "GLFW/glfw3.h"
#include "inferno/application.h"
#include "inferno/event/mouseevent.h"
#include "inferno/io/input.h"
#include "inferno/io/log.h"
#include "inferno/window.h"
namespace Inferno {
bool Input::m_firstMousePos = true;
float Input::m_xPosLast = 0.0f;
float Input::m_yPosLast = 0.0f;
float Input::m_xOffset = 0.0f;
float Input::m_yOffset = 0.0f;
void Input::initialize()
{
// Set cursor in the middle of the screen
m_xPosLast = Application::the().getWindow().getWidth() / 2.0f;
m_yPosLast = Application::the().getWindow().getHeight() / 2.0f;
info() << "Input initialized";
}
void Input::update()
{
// Stop infinite mouse movement
m_xOffset = 0.0f;
m_yOffset = 0.0f;
}
bool Input::onMousePosition(MousePositionEvent& e)
{
// Prevent weird jump on first cursor window enter
if(m_firstMousePos) {
m_firstMousePos = false;
m_xPosLast = e.getXPos();
m_yPosLast = e.getYPos();
}
m_xOffset = e.getXPos() - m_xPosLast;
// Reversed since y-coordinates range from bottom to top
m_yOffset = m_yPosLast - e.getYPos();
m_xPosLast = e.getXPos();
m_yPosLast = e.getYPos();
return true;
}
bool Input::isKeyPressed(int key)
{
GLFWwindow* w = Application::the().getWindow().getWindow();
return glfwGetKey(w, key) == GLFW_PRESS;
}
bool Input::isMouseButtonPressed(int button)
{
GLFWwindow* w = Application::the().getWindow().getWindow();
return glfwGetMouseButton(w, button) == GLFW_PRESS;
}
std::pair<float, float> Input::getMousePosition()
{
GLFWwindow* w = Application::the().getWindow().getWindow();
double xPos;
double yPos;
glfwGetCursorPos(w, &xPos, &yPos);
return { (float)xPos, (float)yPos };
}
float Input::getMouseX()
{
return getMousePosition().first;
}
float Input::getMouseY()
{
return getMousePosition().second;
}
const char* Input::getKeyName(int key)
{
return glfwGetKeyName(key, getKeyScancode(key));
}
int Input::getKeyScancode(int key)
{
return glfwGetKeyScancode(key);
}
}
-39
View File
@@ -1,39 +0,0 @@
#ifndef INPUT_H
#define INPUT_H
#include <utility> // std::pair
namespace Inferno {
class MousePositionEvent;
class Input {
public:
static void initialize();
static void update();
static bool onMousePosition(MousePositionEvent& e);
static bool isKeyPressed(int key);
static bool isMouseButtonPressed(int button);
static std::pair<float, float> getMousePosition();
static float getMouseX();
static float getMouseY();
static const char* getKeyName(int key);
static int getKeyScancode(int key);
static inline float getXOffset() { return m_xOffset; }
static inline float getYOffset() { return m_yOffset; }
private:
static bool m_firstMousePos;
static float m_xPosLast;
static float m_yPosLast;
static float m_xOffset;
static float m_yOffset;
};
}
#endif // INPUT_H
-320
View File
@@ -1,320 +0,0 @@
#include "inferno/assert.h"
#include "inferno/io/log.h"
#include <cstddef> // size_t
#include <cstdio> // fwrite, snprintf
#include <cstdlib> // malloc, free
#include <cstring> // memcpy, strlen
#include <string> // std::string
#include <string_view> // std::string_view
namespace Inferno {
BufferedLogStream::~BufferedLogStream()
{
// Free buffer memory
if (m_capacity > sizeof(m_buffer.stack)) {
free(m_buffer.heap);
}
}
void BufferedLogStream::grow(size_t bytes) const
{
// Bitwise & ~ example, we use 127 as binary starts at 0
// 0b001111111 127 ~
// 0b100000100 260 &
// -----------
// 0b110000000 384
// 0b100000100 260 &
// -----------
// 0b100000000 256
// Buffer is increased in chunks of 128 bytes
size_t newCapacity = (m_count + bytes + BUFFER_SIZE - 1) & ~(BUFFER_SIZE - 1);
unsigned char* newBuffer = static_cast<unsigned char*>(malloc(newCapacity));
// Copy the non-heap data into the new buffer
if (m_capacity <= sizeof(m_buffer.stack)) {
memcpy(newBuffer, m_buffer.stack, m_count);
}
// Copy old heap-buffer data into the new buffer, free old heap-buffer
else if (m_buffer.heap) {
memcpy(newBuffer, m_buffer.heap, m_count);
free(m_buffer.heap);
}
m_buffer.heap = newBuffer;
m_capacity = newCapacity;
}
// -----------------------------------------
DebugLogStream::~DebugLogStream()
{
if (m_type != Log::None) {
const char* clear = "\033[0m";
write(clear, strlen(clear));
}
if (m_newline) {
char newline = '\n';
write(&newline, 1);
}
fwrite(buffer(), 1, count(), stdout);
}
void DebugLogStream::color() const
{
const char* color = "";
if (m_type == Log::Info) {
color = "\x1B[34m";
}
else if (m_type == Log::Warn) {
color = "\x1B[33m";
}
else if (m_type == Log::Danger) {
color = "\x1B[31m";
}
else if (m_type == Log::Success) {
color = "\x1B[32m";
}
else if (m_type == Log::Comment) {
color = "\x1B[37m";
}
write(color, strlen(color));
}
// -----------------------------------------
StringLogStream::~StringLogStream()
{
char terminator = '\0';
write(&terminator, 1);
*m_fill = std::string(reinterpret_cast<char*>(buffer()));
}
// -----------------------------------------
const LogStream& operator<<(const LogStream& stream, const char* value)
{
if (value == nullptr) {
stream.write("(null)", 6);
return stream;
}
stream.write(value, strlen(value));
return stream;
}
const LogStream& operator<<(const LogStream& stream, const unsigned char* value)
{
if (value == nullptr) {
stream.write("(null)", 6);
return stream;
}
stream.write(value, strlen((const char*)value));
return stream;
}
const LogStream& operator<<(const LogStream& stream, const std::string& value)
{
stream.write(value.c_str(), value.length());
return stream;
}
const LogStream& operator<<(const LogStream& stream, const std::string_view& value)
{
stream.write(value.data(), value.length());
return stream;
}
const LogStream& operator<<(const LogStream& stream, char value)
{
stream.write(&value, 1);
return stream;
}
const LogStream& operator<<(const LogStream& stream, unsigned char value)
{
stream.write(&value, 1);
return stream;
}
const LogStream& operator<<(const LogStream& stream, int value)
{
// return stream << std::to_string(value);
char buffer[32];
snprintf(buffer, sizeof(buffer), "%d", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, long int value)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%ld", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, long long int value)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%lld", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, unsigned int value)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%u", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, long unsigned int value)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%lu", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, long long unsigned int value)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%llu", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, double value)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%.4f", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, float value)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%.4f", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, const void* value)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%p", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, bool value)
{
return stream << (value ? "true": "false");
}
const LogStream& operator<<(const LogStream& stream, Log value)
{
switch (value) {
case Log::None:
return stream << "Log";
case Log::Info:
return stream << "Info";
case Log::Warn:
return stream << "Warn";
case Log::Danger:
return stream << "Danger";
case Log::Success:
return stream << "Success";
case Log::Comment:
return stream << "Comment";
default:
ASSERT_NOT_REACHED();
return stream;
}
}
// -----------------------------------------
DebugLogStream dbg()
{
return {};
}
DebugLogStream dbg(bool newline)
{
return DebugLogStream(newline);
}
DebugLogStream info()
{
return DebugLogStream(Log::Info);
}
DebugLogStream warn()
{
return DebugLogStream(Log::Warn);
}
DebugLogStream danger()
{
return DebugLogStream(Log::Danger);
}
DebugLogStream success()
{
return DebugLogStream(Log::Success);
}
DebugLogStream comment()
{
return DebugLogStream(Log::Comment);
}
DebugLogStream info(bool newline)
{
return DebugLogStream(Log::Info, newline);
}
DebugLogStream warn(bool newline)
{
return DebugLogStream(Log::Warn, newline);
}
DebugLogStream danger(bool newline)
{
return DebugLogStream(Log::Danger, newline);
}
DebugLogStream success(bool newline)
{
return DebugLogStream(Log::Success, newline);
}
DebugLogStream comment(bool newline)
{
return DebugLogStream(Log::Comment, newline);
}
// -----------------------------------------
void dbgln(Log type, bool newline)
{
(void)type, DebugLogStream(newline);
}
void dbgln(Log type, bool newline, const char* format)
{
DebugLogStream(type, newline) << format;
}
// -----------------------------------------
StringLogStream str(std::string* fill)
{
return StringLogStream(fill);
}
}
-224
View File
@@ -1,224 +0,0 @@
#ifndef LOG_H
#define LOG_H
#include <cstddef> // size_t
#include <cstring> // memcpy
#include <string> // std::string
#include <string_view> // std::string_view
#include <utility> // std::forward
#define BUFFER_SIZE 128
namespace Inferno {
enum class Log {
None,
Info,
Warn,
Danger,
Success,
Comment,
};
// -----------------------------------------
class LogStream {
public:
LogStream() {}
virtual ~LogStream() {}
virtual void write(const char* characters, int length) const = 0;
virtual void write(const unsigned char* characters, int length) const = 0;
};
// -----------------------------------------
class BufferedLogStream : public LogStream {
public:
BufferedLogStream() {}
virtual ~BufferedLogStream();
inline virtual void write(const char* characters, int length) const override
{
write(reinterpret_cast<const unsigned char*>(characters), length);
}
inline virtual void write(const unsigned char* characters, int length) const override
{
size_t newSize = m_count + length;
if (newSize > m_capacity) {
grow(length);
}
// Append to buffer
memcpy(buffer() + m_count, characters, length);
m_count = newSize;
}
protected:
inline unsigned char* buffer() const
{
if (m_capacity <= sizeof(m_buffer.stack)) {
return m_buffer.stack;
}
return m_buffer.heap;
}
inline bool empty() const { return m_count == 0; }
inline size_t count() const { return m_count; }
private:
void grow(size_t bytes) const;
mutable size_t m_count { 0 };
mutable size_t m_capacity { BUFFER_SIZE };
union {
mutable unsigned char* heap { nullptr };
mutable unsigned char stack[BUFFER_SIZE];
} m_buffer;
};
// -----------------------------------------
class DebugLogStream final : public BufferedLogStream {
public:
DebugLogStream()
: m_newline(true), m_type(Log::None) {}
DebugLogStream(bool newline)
: m_newline(newline), m_type(Log::None) {}
DebugLogStream(Log type)
: m_newline(true), m_type(type) { color(); }
DebugLogStream(Log type, bool newline)
: m_newline(newline), m_type(type) { color(); }
virtual ~DebugLogStream() override;
void color() const;
private:
bool m_newline;
Log m_type;
};
// -----------------------------------------
class StringLogStream final : public BufferedLogStream {
public:
StringLogStream(std::string* fill)
: m_fill(fill) {}
virtual ~StringLogStream() override;
private:
std::string* m_fill { nullptr };
};
// -----------------------------------------
const LogStream& operator<<(const LogStream& stream, const char* value);
const LogStream& operator<<(const LogStream& stream, const unsigned char* value);
const LogStream& operator<<(const LogStream& stream, const std::string& value);
const LogStream& operator<<(const LogStream& stream, const std::string_view& value);
const LogStream& operator<<(const LogStream& stream, char value);
const LogStream& operator<<(const LogStream& stream, unsigned char value);
const LogStream& operator<<(const LogStream& stream, int value);
const LogStream& operator<<(const LogStream& stream, long int value);
const LogStream& operator<<(const LogStream& stream, long long int value);
const LogStream& operator<<(const LogStream& stream, unsigned int value);
const LogStream& operator<<(const LogStream& stream, long unsigned int value);
const LogStream& operator<<(const LogStream& stream, long long unsigned int value);
const LogStream& operator<<(const LogStream& stream, double value);
const LogStream& operator<<(const LogStream& stream, float value);
const LogStream& operator<<(const LogStream& stream, const void* value);
const LogStream& operator<<(const LogStream& stream, bool value);
const LogStream& operator<<(const LogStream& stream, Log value);
// -----------------------------------------
DebugLogStream dbg();
DebugLogStream info();
DebugLogStream warn();
DebugLogStream danger();
DebugLogStream success();
DebugLogStream comment();
DebugLogStream dbg(bool newline);
DebugLogStream info(bool newline);
DebugLogStream warn(bool newline);
DebugLogStream danger(bool newline);
DebugLogStream success(bool newline);
DebugLogStream comment(bool newline);
// -----------------------------------------
template<typename... P> void dbgln(const char* format, P&&... parameters) { dbgln(Log::None, true, format, std::forward<P>(parameters)...); }
template<typename... P> void infoln(const char* format, P&&... parameters) { dbgln(Log::Info, true, format, std::forward<P>(parameters)...); }
template<typename... P> void warnln(const char* format, P&&... parameters) { dbgln(Log::Warn, true, format, std::forward<P>(parameters)...); }
template<typename... P> void dangerln(const char* format, P&&... parameters) { dbgln(Log::Danger, true, format, std::forward<P>(parameters)...); }
template<typename... P> void successln(const char* format, P&&... parameters) { dbgln(Log::Success, true, format, std::forward<P>(parameters)...); }
template<typename... P> void commentln(const char* format, P&&... parameters) { dbgln(Log::Comment, true, format, std::forward<P>(parameters)...); }
template<typename... P> void dbgln(const std::string& format, P&&... parameters) { dbgln(Log::None, true, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void infoln(const std::string& format, P&&... parameters) { dbgln(Log::Info, true, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void warnln(const std::string& format, P&&... parameters) { dbgln(Log::Warn, true, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void dangerln(const std::string& format, P&&... parameters) { dbgln(Log::Danger, true, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void successln(const std::string& format, P&&... parameters) { dbgln(Log::Success, true, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void commentln(const std::string& format, P&&... parameters) { dbgln(Log::Comment, true, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void dbgln(const std::string_view& format, P&&... parameters) { dbgln(Log::None, true, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void infoln(const std::string_view& format, P&&... parameters) { dbgln(Log::Info, true, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void warnln(const std::string_view& format, P&&... parameters) { dbgln(Log::Warn, true, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void dangerln(const std::string_view& format, P&&... parameters) { dbgln(Log::Danger, true, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void successln(const std::string_view& format, P&&... parameters) { dbgln(Log::Success, true, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void commentln(const std::string_view& format, P&&... parameters) { dbgln(Log::Comment, true, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void dbgln(bool newline, const char* format, P&&... parameters) { dbgln(Log::None, newline, format, std::forward<P>(parameters)...); }
template<typename... P> void infoln(bool newline, const char* format, P&&... parameters) { dbgln(Log::Info, newline, format, std::forward<P>(parameters)...); }
template<typename... P> void warnln(bool newline, const char* format, P&&... parameters) { dbgln(Log::Warn, newline, format, std::forward<P>(parameters)...); }
template<typename... P> void dangerln(bool newline, const char* format, P&&... parameters) { dbgln(Log::Danger, newline, format, std::forward<P>(parameters)...); }
template<typename... P> void successln(bool newline, const char* format, P&&... parameters) { dbgln(Log::Success, newline, format, std::forward<P>(parameters)...); }
template<typename... P> void commentln(bool newline, const char* format, P&&... parameters) { dbgln(Log::Comment, newline, format, std::forward<P>(parameters)...); }
template<typename... P> void dbgln(bool newline, const std::string& format, P&&... parameters) { dbgln(Log::None, newline, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void infoln(bool newline, const std::string& format, P&&... parameters) { dbgln(Log::Info, newline, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void warnln(bool newline, const std::string& format, P&&... parameters) { dbgln(Log::Warn, newline, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void dangerln(bool newline, const std::string& format, P&&... parameters) { dbgln(Log::Danger, newline, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void successln(bool newline, const std::string& format, P&&... parameters) { dbgln(Log::Success, newline, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void commentln(bool newline, const std::string& format, P&&... parameters) { dbgln(Log::Comment, newline, format.c_str(), std::forward<P>(parameters)...); }
template<typename... P> void dbgln(bool newline, const std::string_view& format, P&&... parameters) { dbgln(Log::None, newline, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void infoln(bool newline, const std::string_view& format, P&&... parameters) { dbgln(Log::Info, newline, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void warnln(bool newline, const std::string_view& format, P&&... parameters) { dbgln(Log::Warn, newline, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void dangerln(bool newline, const std::string_view& format, P&&... parameters) { dbgln(Log::Danger, newline, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void successln(bool newline, const std::string_view& format, P&&... parameters) { dbgln(Log::Success, newline, format.data(), std::forward<P>(parameters)...); }
template<typename... P> void commentln(bool newline, const std::string_view& format, P&&... parameters) { dbgln(Log::Comment, newline, format.data(), std::forward<P>(parameters)...); }
// -----------------------------------------
void dbgln(Log type, bool newline);
void dbgln(Log type, bool newline, const char* format);
// https://en.cppreference.com/w/cpp/language/parameter_pack#Example
template<typename T, typename... P>
void dbgln(Log type, bool newline, const char* format, T value, P&&... parameters)
{
std::string_view view { format };
for(uint32_t i = 0; format[i] != '\0'; i++) {
if (format[i] == '{' && format[i + 1] == '}') {
DebugLogStream(type, false) << view.substr(0, i) << value;
dbgln(type, newline, format + i + 2, parameters...);
return;
}
}
}
// -----------------------------------------
StringLogStream str(std::string* fill);
}
#endif // LOG_H
-143
View File
@@ -1,143 +0,0 @@
#include <string> // std::string
#include <unordered_map> // std::unordered_map
#include "GLFW/glfw3.h"
#include "inferno/assert.h"
#include "inferno/keycodes.h"
namespace Inferno {
static std::unordered_map<std::string, int> keys ({
{ MAP_KEY(GLFW_KEY_UNKNOWN) },
{ MAP_KEY(GLFW_KEY_SPACE) },
{ MAP_KEY(GLFW_KEY_APOSTROPHE) },
{ MAP_KEY(GLFW_KEY_COMMA) },
{ MAP_KEY(GLFW_KEY_MINUS) },
{ MAP_KEY(GLFW_KEY_PERIOD) },
{ MAP_KEY(GLFW_KEY_SLASH) },
{ MAP_KEY(GLFW_KEY_0) },
{ MAP_KEY(GLFW_KEY_1) },
{ MAP_KEY(GLFW_KEY_2) },
{ MAP_KEY(GLFW_KEY_3) },
{ MAP_KEY(GLFW_KEY_4) },
{ MAP_KEY(GLFW_KEY_5) },
{ MAP_KEY(GLFW_KEY_6) },
{ MAP_KEY(GLFW_KEY_7) },
{ MAP_KEY(GLFW_KEY_8) },
{ MAP_KEY(GLFW_KEY_9) },
{ MAP_KEY(GLFW_KEY_SEMICOLON) },
{ MAP_KEY(GLFW_KEY_EQUAL) },
{ MAP_KEY(GLFW_KEY_A) },
{ MAP_KEY(GLFW_KEY_B) },
{ MAP_KEY(GLFW_KEY_C) },
{ MAP_KEY(GLFW_KEY_D) },
{ MAP_KEY(GLFW_KEY_E) },
{ MAP_KEY(GLFW_KEY_F) },
{ MAP_KEY(GLFW_KEY_G) },
{ MAP_KEY(GLFW_KEY_H) },
{ MAP_KEY(GLFW_KEY_I) },
{ MAP_KEY(GLFW_KEY_J) },
{ MAP_KEY(GLFW_KEY_K) },
{ MAP_KEY(GLFW_KEY_L) },
{ MAP_KEY(GLFW_KEY_M) },
{ MAP_KEY(GLFW_KEY_N) },
{ MAP_KEY(GLFW_KEY_O) },
{ MAP_KEY(GLFW_KEY_P) },
{ MAP_KEY(GLFW_KEY_Q) },
{ MAP_KEY(GLFW_KEY_R) },
{ MAP_KEY(GLFW_KEY_S) },
{ MAP_KEY(GLFW_KEY_T) },
{ MAP_KEY(GLFW_KEY_U) },
{ MAP_KEY(GLFW_KEY_V) },
{ MAP_KEY(GLFW_KEY_W) },
{ MAP_KEY(GLFW_KEY_X) },
{ MAP_KEY(GLFW_KEY_Y) },
{ MAP_KEY(GLFW_KEY_Z) },
{ MAP_KEY(GLFW_KEY_LEFT_BRACKET) },
{ MAP_KEY(GLFW_KEY_BACKSLASH) },
{ MAP_KEY(GLFW_KEY_RIGHT_BRACKET) },
{ MAP_KEY(GLFW_KEY_GRAVE_ACCENT) },
{ MAP_KEY(GLFW_KEY_WORLD_1) },
{ MAP_KEY(GLFW_KEY_WORLD_2) },
{ MAP_KEY(GLFW_KEY_ESCAPE) },
{ MAP_KEY(GLFW_KEY_ENTER) },
{ MAP_KEY(GLFW_KEY_TAB) },
{ MAP_KEY(GLFW_KEY_BACKSPACE) },
{ MAP_KEY(GLFW_KEY_INSERT) },
{ MAP_KEY(GLFW_KEY_DELETE) },
{ MAP_KEY(GLFW_KEY_RIGHT) },
{ MAP_KEY(GLFW_KEY_LEFT) },
{ MAP_KEY(GLFW_KEY_DOWN) },
{ MAP_KEY(GLFW_KEY_UP) },
{ MAP_KEY(GLFW_KEY_PAGE_UP) },
{ MAP_KEY(GLFW_KEY_PAGE_DOWN) },
{ MAP_KEY(GLFW_KEY_HOME) },
{ MAP_KEY(GLFW_KEY_END) },
{ MAP_KEY(GLFW_KEY_CAPS_LOCK) },
{ MAP_KEY(GLFW_KEY_SCROLL_LOCK) },
{ MAP_KEY(GLFW_KEY_NUM_LOCK) },
{ MAP_KEY(GLFW_KEY_PRINT_SCREEN) },
{ MAP_KEY(GLFW_KEY_PAUSE) },
{ MAP_KEY(GLFW_KEY_F1) },
{ MAP_KEY(GLFW_KEY_F2) },
{ MAP_KEY(GLFW_KEY_F3) },
{ MAP_KEY(GLFW_KEY_F4) },
{ MAP_KEY(GLFW_KEY_F5) },
{ MAP_KEY(GLFW_KEY_F6) },
{ MAP_KEY(GLFW_KEY_F7) },
{ MAP_KEY(GLFW_KEY_F8) },
{ MAP_KEY(GLFW_KEY_F9) },
{ MAP_KEY(GLFW_KEY_F10) },
{ MAP_KEY(GLFW_KEY_F11) },
{ MAP_KEY(GLFW_KEY_F12) },
{ MAP_KEY(GLFW_KEY_F13) },
{ MAP_KEY(GLFW_KEY_F14) },
{ MAP_KEY(GLFW_KEY_F15) },
{ MAP_KEY(GLFW_KEY_F16) },
{ MAP_KEY(GLFW_KEY_F17) },
{ MAP_KEY(GLFW_KEY_F18) },
{ MAP_KEY(GLFW_KEY_F19) },
{ MAP_KEY(GLFW_KEY_F20) },
{ MAP_KEY(GLFW_KEY_F21) },
{ MAP_KEY(GLFW_KEY_F22) },
{ MAP_KEY(GLFW_KEY_F23) },
{ MAP_KEY(GLFW_KEY_F24) },
{ MAP_KEY(GLFW_KEY_F25) },
{ MAP_KEY(GLFW_KEY_KP_0) },
{ MAP_KEY(GLFW_KEY_KP_1) },
{ MAP_KEY(GLFW_KEY_KP_2) },
{ MAP_KEY(GLFW_KEY_KP_3) },
{ MAP_KEY(GLFW_KEY_KP_4) },
{ MAP_KEY(GLFW_KEY_KP_5) },
{ MAP_KEY(GLFW_KEY_KP_6) },
{ MAP_KEY(GLFW_KEY_KP_7) },
{ MAP_KEY(GLFW_KEY_KP_8) },
{ MAP_KEY(GLFW_KEY_KP_9) },
{ MAP_KEY(GLFW_KEY_KP_DECIMAL) },
{ MAP_KEY(GLFW_KEY_KP_DIVIDE) },
{ MAP_KEY(GLFW_KEY_KP_MULTIPLY) },
{ MAP_KEY(GLFW_KEY_KP_SUBTRACT) },
{ MAP_KEY(GLFW_KEY_KP_ADD) },
{ MAP_KEY(GLFW_KEY_KP_ENTER) },
{ MAP_KEY(GLFW_KEY_KP_EQUAL) },
{ MAP_KEY(GLFW_KEY_LEFT_SHIFT) },
{ MAP_KEY(GLFW_KEY_LEFT_CONTROL) },
{ MAP_KEY(GLFW_KEY_LEFT_ALT) },
{ MAP_KEY(GLFW_KEY_LEFT_SUPER) },
{ MAP_KEY(GLFW_KEY_RIGHT_SHIFT) },
{ MAP_KEY(GLFW_KEY_RIGHT_CONTROL) },
{ MAP_KEY(GLFW_KEY_RIGHT_ALT) },
{ MAP_KEY(GLFW_KEY_RIGHT_SUPER) },
{ MAP_KEY(GLFW_KEY_MENU) },
});
// -----------------------------------------
int keyCode(const char* name)
{
ASSERT(keys.find(name) != keys.end(), "keyCode could not find '{}'", name);
return keys.at(name);
}
}
-12
View File
@@ -1,12 +0,0 @@
#ifndef INPUTCODES_H
#define INPUTCODES_H
#define MAP_KEY(key) #key, key
namespace Inferno {
int keyCode(const char* name);
}
#endif // INPUTCODES_H
-298
View File
@@ -1,298 +0,0 @@
#include "glad/glad.h"
#include "inferno/assert.h"
#include "inferno/core.h"
#include "inferno/io/log.h"
#include "inferno/render/buffer.h"
namespace Inferno {
// -----------------------------------------
BufferElement::BufferElement(BufferElementType type, std::string name, bool normalized) :
m_type(type),
m_name(name),
m_size(BufferElement::getTypeSize(type)),
m_normalized(normalized)
{
}
uint32_t BufferElement::getTypeSize() const
{
return BufferElement::getTypeSize(m_type);
}
uint32_t BufferElement::getTypeCount() const
{
return BufferElement::getTypeCount(m_type);
}
uint32_t BufferElement::getTypeGL() const
{
return BufferElement::getTypeGL(m_type);
}
uint32_t BufferElement::getTypeSize(const BufferElementType type)
{
switch (type) {
case BufferElementType::None: return 0;
case BufferElementType::Bool: return sizeof(bool);
case BufferElementType::Bool2: return sizeof(bool) * 2;
case BufferElementType::Bool3: return sizeof(bool) * 3;
case BufferElementType::Bool4: return sizeof(bool) * 4;
case BufferElementType::Int: return sizeof(int32_t);
case BufferElementType::Int2: return sizeof(int32_t) * 2;
case BufferElementType::Int3: return sizeof(int32_t) * 3;
case BufferElementType::Int4: return sizeof(int32_t) * 4;
case BufferElementType::Uint: return sizeof(uint32_t);
case BufferElementType::Uint2: return sizeof(uint32_t) * 2;
case BufferElementType::Uint3: return sizeof(uint32_t) * 3;
case BufferElementType::Uint4: return sizeof(uint32_t) * 4;
case BufferElementType::Float: return sizeof(float);
case BufferElementType::Vec2: return sizeof(float) * 2;
case BufferElementType::Vec3: return sizeof(float) * 3;
case BufferElementType::Vec4: return sizeof(float) * 4;
case BufferElementType::Double: return sizeof(double);
case BufferElementType::Double2: return sizeof(double);
case BufferElementType::Double3: return sizeof(double);
case BufferElementType::Double4: return sizeof(double);
case BufferElementType::Mat2: return sizeof(float) * 2 * 2;
case BufferElementType::Mat3: return sizeof(float) * 3 * 3;
case BufferElementType::Mat4: return sizeof(float) * 4 * 4;
case BufferElementType::DoubleMat2: return sizeof(double) * 2 * 2;
case BufferElementType::DoubleMat3: return sizeof(double) * 3 * 3;
case BufferElementType::DoubleMat4: return sizeof(double) * 4 * 4;
};
ASSERT(false, "BufferElement unknown BufferElementType size!");
return 0;
}
uint32_t BufferElement::getTypeCount(const BufferElementType type)
{
switch (type) {
case BufferElementType::None: return 0;
case BufferElementType::Bool: return 1;
case BufferElementType::Bool2: return 2;
case BufferElementType::Bool3: return 3;
case BufferElementType::Bool4: return 4;
case BufferElementType::Int: return 1;
case BufferElementType::Int2: return 2;
case BufferElementType::Int3: return 3;
case BufferElementType::Int4: return 4;
case BufferElementType::Uint: return 1;
case BufferElementType::Uint2: return 2;
case BufferElementType::Uint3: return 3;
case BufferElementType::Uint4: return 4;
case BufferElementType::Float: return 1;
case BufferElementType::Vec2: return 2;
case BufferElementType::Vec3: return 3;
case BufferElementType::Vec4: return 4;
case BufferElementType::Double: return 1;
case BufferElementType::Double2: return 2;
case BufferElementType::Double3: return 3;
case BufferElementType::Double4: return 4;
case BufferElementType::Mat2: return 2 * 2;
case BufferElementType::Mat3: return 3 * 3;
case BufferElementType::Mat4: return 4 * 4;
case BufferElementType::DoubleMat2: return 2 * 2;
case BufferElementType::DoubleMat3: return 3 * 3;
case BufferElementType::DoubleMat4: return 4 * 4;
};
ASSERT(false, "BufferElement unknown BufferElementType count!");
return 0;
}
uint32_t BufferElement::getTypeGL(const BufferElementType type)
{
switch (type) {
case BufferElementType::None: return GL_NONE;
case BufferElementType::Bool: return GL_BOOL;
case BufferElementType::Bool2: return GL_BOOL;
case BufferElementType::Bool3: return GL_BOOL;
case BufferElementType::Bool4: return GL_BOOL;
case BufferElementType::Int: return GL_INT;
case BufferElementType::Int2: return GL_INT;
case BufferElementType::Int3: return GL_INT;
case BufferElementType::Int4: return GL_INT;
case BufferElementType::Uint: return GL_UNSIGNED_INT;
case BufferElementType::Uint2: return GL_UNSIGNED_INT;
case BufferElementType::Uint3: return GL_UNSIGNED_INT;
case BufferElementType::Uint4: return GL_UNSIGNED_INT;
case BufferElementType::Float: return GL_FLOAT;
case BufferElementType::Vec2: return GL_FLOAT;
case BufferElementType::Vec3: return GL_FLOAT;
case BufferElementType::Vec4: return GL_FLOAT;
case BufferElementType::Double: return GL_DOUBLE;
case BufferElementType::Double2: return GL_DOUBLE;
case BufferElementType::Double3: return GL_DOUBLE;
case BufferElementType::Double4: return GL_DOUBLE;
case BufferElementType::Mat2: return GL_FLOAT;
case BufferElementType::Mat3: return GL_FLOAT;
case BufferElementType::Mat4: return GL_FLOAT;
case BufferElementType::DoubleMat2: return GL_DOUBLE;
case BufferElementType::DoubleMat3: return GL_DOUBLE;
case BufferElementType::DoubleMat4: return GL_DOUBLE;
};
ASSERT(false, "BufferElement unknown BufferElementType GL!");
return 0;
}
// -----------------------------------------
BufferLayout::BufferLayout(const std::initializer_list<BufferElement>& elements)
: m_elements(elements)
{
calculateOffsetsAndStride();
}
void BufferLayout::calculateOffsetsAndStride()
{
m_stride = 0;
for (auto& element : m_elements) {
element.setOffset(m_stride);
m_stride += element.getSize();
}
}
// -----------------------------------------
VertexBuffer::VertexBuffer(size_t size)
{
glGenBuffers(1, &m_id);
bind();
// Reserve data on the GPU
glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_DYNAMIC_DRAW);
unbind();
}
VertexBuffer::VertexBuffer(float* vertices, size_t size)
{
glGenBuffers(1, &m_id);
bind();
// Upload data to the GPU
glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);
unbind();
}
VertexBuffer::~VertexBuffer()
{
glDeleteBuffers(1, &m_id);
}
void VertexBuffer::bind() const
{
glBindBuffer(GL_ARRAY_BUFFER, m_id);
}
void VertexBuffer::unbind() const
{
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void VertexBuffer::uploadData(const void* data, uint32_t size)
{
bind();
// Upload data to the GPU
glBufferSubData(GL_ARRAY_BUFFER, 0, size, data);
unbind();
}
// -----------------------------------------
IndexBuffer::IndexBuffer(uint32_t* indices, size_t size) :
m_count(size / sizeof(uint32_t))
{
glCreateBuffers(1, &m_id);
bind();
// Upload data to the GPU
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, indices, GL_STATIC_DRAW);
unbind();
}
IndexBuffer::~IndexBuffer()
{
glDeleteBuffers(1, &m_id);
}
void IndexBuffer::bind() const
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_id);
}
void IndexBuffer::unbind() const
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
// -----------------------------------------
VertexArray::VertexArray()
{
glCreateVertexArrays(1, &m_id);
}
VertexArray::~VertexArray()
{
glDeleteVertexArrays(1, &m_id);
}
void VertexArray::bind() const
{
glBindVertexArray(m_id);
}
void VertexArray::unbind() const
{
glBindVertexArray(0);
}
void VertexArray::addVertexBuffer(std::shared_ptr<VertexBuffer> vertexBuffer)
{
const auto& layout = vertexBuffer->getLayout();
ASSERT(layout.getElements().size(), "VertexBuffer has no layout");
bind();
vertexBuffer->bind();
uint32_t index = 0;
for (const auto& element : layout) {
glEnableVertexAttribArray(index);
glVertexAttribPointer(
index,
element.getTypeCount(),
element.getTypeGL(),
element.getNormalized() ? GL_TRUE : GL_FALSE,
layout.getStride(),
reinterpret_cast<const void*>(element.getOffset()));
index++;
}
m_vertexBuffers.push_back(std::move(vertexBuffer));
unbind();
vertexBuffer->unbind();
}
void VertexArray::setIndexBuffer(std::shared_ptr<IndexBuffer> indexBuffer)
{
bind();
indexBuffer->bind();
m_indexBuffer = std::move(indexBuffer);
unbind();
indexBuffer->unbind();
}
}
-148
View File
@@ -1,148 +0,0 @@
#ifndef BUFFER_H
#define BUFFER_H
#include <cstddef> // size_t
#include <cstdint> // int32_t, uint32_t
#include <memory> // std::shared_ptr
#include <string> // std::string
#include <vector> // std::vector
namespace Inferno {
// https://www.khronos.org/opengl/wiki/Data_Type_(GLSL)
enum class BufferElementType {
None = 0,
Bool, Bool2, Bool3, Bool4, // bvec
Int, Int2, Int3, Int4, // ivec
Uint, Uint2, Uint3, Uint4, // uvec
Float, Vec2, Vec3, Vec4, // vec
Double, Double2, Double3, Double4, // dvec
Mat2, Mat3, Mat4, // mat
DoubleMat2, DoubleMat3, DoubleMat4, // dmat
};
// -----------------------------------------
// Describes one element of the BufferLayout
class BufferElement {
public:
BufferElement(BufferElementType type, std::string name, bool normalized = false);
uint32_t getTypeSize() const;
uint32_t getTypeCount() const;
uint32_t getTypeGL() const;
static uint32_t getTypeSize(const BufferElementType type);
static uint32_t getTypeCount(const BufferElementType type);
static uint32_t getTypeGL(const BufferElementType type);
inline BufferElementType getType() const{ return m_type; }
inline std::string getName() const { return m_name; }
inline uint32_t getSize() const { return m_size; }
inline uint32_t getOffset() const { return m_offset; }
inline bool getNormalized() const { return m_normalized; }
inline void setType(const BufferElementType& type) { m_type = type; }
inline void setName(const std::string& name) { m_name = name; }
inline void setSize(const uint32_t& size) { m_size = size; }
inline void setOffset(const uint32_t& offset) { m_offset = offset; }
inline void setNormalized(const bool& normalized) { m_normalized = normalized; }
private:
BufferElementType m_type;
std::string m_name;
uint32_t m_size { 0 };
uint32_t m_offset { 0 };
bool m_normalized { false };
};
// -----------------------------------------
// Layout that describes raw vertex data
class BufferLayout {
public:
BufferLayout() {}
BufferLayout(const std::initializer_list<BufferElement>& elements);
inline const std::vector<BufferElement>& getElements() const { return m_elements; }
inline uint32_t getStride() const { return m_stride; }
// Iterators
inline std::vector<BufferElement>::iterator begin() { return m_elements.begin(); }
inline std::vector<BufferElement>::iterator end() { return m_elements.end(); }
inline std::vector<BufferElement>::const_iterator begin() const { return m_elements.begin(); }
inline std::vector<BufferElement>::const_iterator end() const { return m_elements.end(); }
protected:
void calculateOffsetsAndStride();
private:
std::vector<BufferElement> m_elements;
uint32_t m_stride { 0 };
};
// -----------------------------------------
// GPU memory which holds raw vertex data
class VertexBuffer {
public:
VertexBuffer(size_t size);
VertexBuffer(float* vertices, size_t size);
~VertexBuffer();
void bind() const;
void unbind() const;
void uploadData(const void* data, uint32_t size);
inline const BufferLayout& getLayout() const { return m_layout; }
inline void setLayout(const BufferLayout& layout) { m_layout = layout; }
private:
uint32_t m_id { 0 };
BufferLayout m_layout;
};
// -----------------------------------------
// Vertices order of rendering
class IndexBuffer {
public:
IndexBuffer(uint32_t* indices, size_t size);
~IndexBuffer();
void bind() const;
void unbind() const;
inline uint32_t getCount() const { return m_count; }
private:
uint32_t m_id { 0 };
uint32_t m_count { 0 };
};
// -----------------------------------------
// Array that holds the vertex attributes configuration
class VertexArray {
public:
VertexArray();
~VertexArray();
void bind() const;
void unbind() const;
void addVertexBuffer(std::shared_ptr<VertexBuffer> vertexBuffer);
void setIndexBuffer(std::shared_ptr<IndexBuffer> indexBuffer);
inline const std::vector<std::shared_ptr<VertexBuffer>>& getVertexBuffers() const { return m_vertexBuffers; }
inline std::shared_ptr<IndexBuffer> getIndexBuffer() const { return m_indexBuffer; }
private:
uint32_t m_id { 0 };
std::vector<std::shared_ptr<VertexBuffer>> m_vertexBuffers;
std::shared_ptr<IndexBuffer> m_indexBuffer;
};
}
#endif // BUFFER_H
-52
View File
@@ -1,52 +0,0 @@
#include "glad/glad.h"
#include "GLFW/glfw3.h"
#include "inferno/assert.h"
#include "inferno/core.h"
#include "inferno/io/log.h"
#include "inferno/render/context.h"
#include "inferno/window.h"
namespace Inferno {
Context::Context(GLFWwindow* window) :
m_window(window)
{
ASSERT(window, "Context window is nullptr!");
}
void Context::initialize()
{
Context::setCurrent();
// Initialize glad
int glad = gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
ASSERT(glad, "Failed to initialize glad!");
// Log OpenGL properties
comment() << "OpenGL Info:";
comment() << " Vendor: " << glGetString(GL_VENDOR);
comment() << " Renderer: " << glGetString(GL_RENDERER);
comment() << " Version: " << glGetString(GL_VERSION);
// Check OpenGL version
ASSERT(GLVersion.major > 4 || (GLVersion.major == 4 && GLVersion.minor >= 5),
"Inferno requires at least OpenGL version 4.5!");
}
void Context::destroy()
{
}
void Context::render()
{
glfwSwapBuffers(m_window);
}
void Context::setCurrent()
{
// Set current OpenGL context to this window
glfwMakeContextCurrent(m_window);
}
}
-25
View File
@@ -1,25 +0,0 @@
#ifndef CONTEXT_H
#define CONTEXT_H
struct GLFWwindow;
namespace Inferno {
class Context {
public:
Context(GLFWwindow* window);
void initialize();
void destroy();
void render();
void setCurrent();
private:
GLFWwindow* m_window { nullptr };
};
}
#endif // CONTEXT_H
-163
View File
@@ -1,163 +0,0 @@
#include <limits> // std::numeric_limits
#include <string> // std::getline, std::stoi
#include <utility> // std::move
#include "inferno/assert.h"
#include "inferno/io/file.h"
#include "inferno/render/font.h"
#include "inferno/render/texture.h"
#include "inferno/util/integer.h"
namespace Inferno {
Font::Font(const std::string& name)
: m_name(std::move(name))
{
std::string path = name + ".fnt";
std::string image = name + ".png";
std::string font = File::read(path);
parseFont(font);
m_texture = std::make_shared<Texture>(image);
}
void Font::parseFont(const std::string& font)
{
std::istringstream iss(font);
for (std::string line; std::getline(iss, line);) {
if (findAction(line).compare("info") != 0 &&
findAction(line).compare("char") != 0) {
continue;
}
const std::vector<std::string> columns = findColumns(line);
// Info
if (findAction(line).compare("info") == 0) {
m_size = std::stou(findValue("size", columns));
continue;
}
// Character
unsigned char id = std::stoi(findValue("id", columns));
Character character = {
{ std::stou(findValue("x", columns)), std::stou(findValue("y", columns)) },
{ std::stou(findValue("width", columns)), std::stou(findValue("height", columns)) },
{ std::stoi(findValue("xoffset", columns)), std::stoi(findValue("yoffset", columns)) },
std::stou(findValue("xadvance", columns))
};
m_characterList.emplace(id, std::make_shared<Character>(character));
}
}
const std::string Font::findAction(const std::string& line)
{
return line.substr(0, line.find(" "));
}
const std::vector<std::string> Font::findColumns(const std::string& line)
{
std::vector<std::string> elements;
size_t index = 0;
size_t find = 0;
size_t findFirstNotOf = 0;
// Loop over line characters
while (find != std::string::npos) {
find = line.find(" ", index);
findFirstNotOf = line.find_first_not_of(" ", index);
// Add element
if (find > findFirstNotOf) {
elements.push_back(line.substr(index, find - findFirstNotOf));
index += 1 + find - findFirstNotOf;
}
// Skip double spaces
else {
index = findFirstNotOf;
}
}
ASSERT(!elements.empty(), "Font file did not find any columns");
return elements;
}
const std::string Font::findValue(const std::string& key, const std::vector<std::string>& columns)
{
size_t find = 0;
// Loop over columns
for (auto& column : columns) {
find = column.find(key + "=");
if (find != std::string::npos) {
return column.substr(key.length() + 1);
}
}
ASSERT(false, "Font file did not contain key '{}'", key);
return "";
}
// -----------------------------------------
FontManager::FontManager(s)
{
info() << "FontManager initialized";
}
FontManager::~FontManager()
{
}
void FontManager::add(const std::string& name, std::shared_ptr<Font> font)
{
// Construct (key, value) pair and insert it into the unordered_map
m_fontList.emplace(std::move(name), std::move(font));
}
std::shared_ptr<Font> FontManager::load(const std::string& name)
{
if (exists(name)) {
return get(name);
}
std::shared_ptr<Font> font = std::make_shared<Font>(name);
add(name, font);
return get(name);
}
std::shared_ptr<Font> FontManager::get(const std::string& name)
{
return exists(name) ? m_fontList.at(name) : nullptr;
}
bool FontManager::exists(const std::string& name)
{
return m_fontList.find(name) != m_fontList.end();
}
void FontManager::remove(const std::string& name)
{
if (exists(name)) {
m_fontList.erase(name);
}
}
void FontManager::remove(std::shared_ptr<Font> font)
{
if (exists(font->name())) {
m_fontList.erase(font->name());
}
}
// -----------------------------------------
const LogStream& operator<<(const LogStream& stream, const glm::ivec2& value)
{
return stream << "{ " << value.x << ", " << value.y << " }";
}
}
-87
View File
@@ -1,87 +0,0 @@
#ifndef FONT_H
#define FONT_H
#include <cstdint> // uint32_t
#include <memory> // std::shared_ptr
#include <string> // std::string
#include <unordered_map> // std::unordered_map
#include <vector> // std::vector
#include "glm/ext/vector_uint2.hpp" // glm::uvec2
#include "glm/ext/vector_int2.hpp" // glm::ivec2
#include "inferno/io/log.h"
#include "inferno/singleton.h"
namespace Inferno {
class Texture;
struct Character {
glm::uvec2 position; // Position
glm::uvec2 size; // Width/height
glm::ivec2 offset; // Offset from baseline to left / top of glyph
uint32_t advance; // Amount to advance to next glyph
};
// -----------------------------------------
class Font {
public:
Font(const std::string& name);
virtual ~Font() {}
inline std::string name() const { return m_name; }
inline uint32_t size() const { return m_size; }
inline std::shared_ptr<Texture> texture() const { return m_texture; }
inline std::shared_ptr<Character> get(unsigned char c) const { return m_characterList.at(c); }
inline std::shared_ptr<Character> operator[](unsigned char c) const { return m_characterList.at(c); }
private:
void parseFont(const std::string& font);
const std::string findAction(const std::string& line);
const std::vector<std::string> findColumns(const std::string& line);
const std::string findValue(const std::string& key, const std::vector<std::string>& columns);
std::string m_name;
uint32_t m_size;
std::shared_ptr<Texture> m_texture;
std::unordered_map<unsigned char, std::shared_ptr<Character>> m_characterList;
};
// -----------------------------------------
class FontManager final : public Singleton<FontManager> {
public:
FontManager(s);
virtual ~FontManager();
void add(const std::string& name, std::shared_ptr<Font> font);
std::shared_ptr<Font> load(const std::string& name);
std::shared_ptr<Font> get(const std::string& name);
bool exists(const std::string& name);
void remove(const std::string& name);
void remove(std::shared_ptr<Font> font);
private:
std::unordered_map<std::string, std::shared_ptr<Font>> m_fontList;
};
// -----------------------------------------
const LogStream& operator<<(const LogStream& stream, const glm::ivec2& value);
}
#endif // FONT_H
// FontManager fm;
// Font f = fm.load("path/to/font");
// Font f2("path/to/font");
// Character c = f['a'];
// Look into using signed distance fields for texture map generation ? anti-aliasing for text
// https://youtu.be/d8cfgcJR9Tk
-443
View File
@@ -1,443 +0,0 @@
#include <algorithm> // std::min
#include <utility> // std::move
#include "glad/glad.h"
#include "inferno/assert.h"
#include "inferno/render/buffer.h"
#include "inferno/render/renderer.h"
#include "inferno/render/shader.h"
#include "inferno/render/texture.h"
namespace Inferno {
void RenderCommand::initialize()
{
setDepthTest(true);
// Enable transparency
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
info() << "RenderCommand initialized";
}
void RenderCommand::destroy()
{
}
void RenderCommand::clear()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void RenderCommand::clearColor(const glm::vec4& color)
{
glClearColor(color.r, color.g, color.b, color.a);
}
void RenderCommand::drawIndexed(const VertexArray& vertexArray, uint32_t indexCount)
{
uint32_t count = indexCount ? indexCount : vertexArray.getIndexBuffer()->getCount();
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, nullptr);
}
void RenderCommand::setViewport(int32_t x, int32_t y, uint32_t width, uint32_t height)
{
glViewport(x, y, width, height);
}
void RenderCommand::setDepthTest(bool enabled)
{
// Set z-buffer / depth buffer
enabled ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);
}
bool RenderCommand::depthTest()
{
unsigned char depthTest = GL_FALSE;
glGetBooleanv(GL_DEPTH_TEST, &depthTest);
return depthTest == GL_TRUE;
}
int32_t RenderCommand::textureUnitAmount()
{
int32_t amount = 0;
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &amount);
return amount;
}
// -----------------------------------------
uint32_t Renderer::m_supportedTextureUnitPerBatch = 0;
void Renderer::initialize()
{
// Get amount of texture units supported by the GPU
uint32_t constTextureUnitCount = textureUnitPerBatch;
uint32_t gpuTextureUnitCount = RenderCommand::textureUnitAmount();
m_supportedTextureUnitPerBatch = std::min(constTextureUnitCount, gpuTextureUnitCount);
// Texture unit 0 is reserved for no texture
m_textureUnits[0] = nullptr;
// Create texture unit samplers
int32_t samplers[textureUnitPerBatch];
for (uint32_t i = 0; i < textureUnitPerBatch; i++) {
samplers[i] = i;
}
// Create shader
loadShader();
m_shader->bind();
m_shader->setInt("u_textures", samplers, textureUnitPerBatch);
m_shader->unbind();
// Create vertex array
m_vertexArray = std::make_shared<VertexArray>();
}
void Renderer::destroy()
{
}
uint32_t Renderer::addTextureUnit(std::shared_ptr<Texture> texture)
{
if (texture == nullptr) {
return 0;
}
// Create a new batch if the texture unit limit has been reached
if (m_textureUnitIndex >= m_supportedTextureUnitPerBatch) {
nextBatch();
}
// If texure was already added
for (uint32_t i = 1; i < m_textureUnitIndex; i++) {
if (m_textureUnits[i] == texture) {
return i;
}
}
// Add texture
uint32_t textureUnitIndex = m_textureUnitIndex;
m_textureUnits[textureUnitIndex] = texture;
m_textureUnitIndex++;
return textureUnitIndex;
}
void Renderer::bind()
{
m_shader->bind();
for (uint32_t i = 1; i < m_textureUnitIndex; i++) {
m_textureUnits[i]->bind(i);
}
m_vertexArray->bind();
}
void Renderer::unbind()
{
m_vertexArray->unbind();
for (uint32_t i = 1; i < m_textureUnitIndex; i++) {
m_textureUnits[i]->unbind();
}
m_shader->unbind();
}
// -----------------------------------------
Renderer2D::Renderer2D(s)
{
Renderer::initialize();
// CPU
// ---------------------------------
// Create array for storing quads vertices
m_vertexBufferBase = std::make_unique<QuadVertex[]>(vertexCount);
m_vertexBufferPtr = m_vertexBufferBase.get();
// Set default quad vertex positions
m_vertexPositions[0] = { -0.5f, -0.5f, 0.0f, 1.0f };
m_vertexPositions[1] = { 0.5f, -0.5f, 0.0f, 1.0f };
m_vertexPositions[2] = { 0.5f, 0.5f, 0.0f, 1.0f };
m_vertexPositions[3] = { -0.5f, 0.5f, 0.0f, 1.0f };
// Generate indices
uint32_t* indices = new uint32_t[indexCount];
uint32_t offset = 0;
for (uint32_t i = 0; i < indexCount; i += indexPerQuad) {
indices[i + 0] = offset + 0;
indices[i + 1] = offset + 1;
indices[i + 2] = offset + 2;
indices[i + 3] = offset + 2;
indices[i + 4] = offset + 3;
indices[i + 5] = offset + 0;
offset += vertexPerQuad;
}
// GPU
// ---------------------------------
// Create vertex buffer
auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(QuadVertex) * vertexCount);
vertexBuffer->setLayout({
{ BufferElementType::Vec3, "a_position" },
{ BufferElementType::Vec4, "a_color" },
{ BufferElementType::Vec2, "a_textureCoordinates" },
{ BufferElementType::Float, "a_textureIndex" },
});
m_vertexArray->addVertexBuffer(vertexBuffer);
// Create index buffer
auto indexBuffer = std::make_shared<IndexBuffer>(indices, sizeof(uint32_t) * indexCount);
m_vertexArray->setIndexBuffer(indexBuffer);
delete[] indices;
info() << "Renderer2D initialized";
}
Renderer2D::~Renderer2D()
{
Renderer::destroy();
}
void Renderer2D::beginScene(glm::mat4 cameraProjectionView)
{
m_shader->bind();
m_shader->setFloat("u_projectionView", cameraProjectionView);
m_shader->unbind();
}
void Renderer2D::endScene()
{
nextBatch();
}
void Renderer2D::drawQuad(const TransformComponent& transform, glm::vec4 color)
{
drawQuad(transform, color, nullptr);
}
void Renderer2D::drawQuad(const TransformComponent& transform, glm::mat4 color)
{
drawQuad(transform, color, nullptr);
}
void Renderer2D::drawQuad(const TransformComponent& transform, glm::vec4 color, std::shared_ptr<Texture> texture)
{
drawQuad(transform, glm::mat4(color, color, color, color), texture);
}
void Renderer2D::drawQuad(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture)
{
// Create a new batch if the quad limit has been reached
if (m_quadIndex >= quadCount) {
nextBatch();
}
constexpr glm::vec2 textureCoordinates[] = {
{ 0.0f, 0.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f }, { 0.0f, 1.0f }
};
uint32_t textureUnitIndex = addTextureUnit(texture);
// Add the quads 4 vertices
for (uint32_t i = 0; i < vertexPerQuad; i++) {
m_vertexBufferPtr->position = transform.transform * m_vertexPositions[i];
m_vertexBufferPtr->color = color[i];
m_vertexBufferPtr->textureCoordinates = textureCoordinates[i];
m_vertexBufferPtr->textureIndex = (float)textureUnitIndex;
m_vertexBufferPtr++;
}
m_quadIndex++;
}
void Renderer2D::loadShader()
{
m_shader = ShaderManager::the().load("assets/glsl/batch-quad");
}
void Renderer2D::flush()
{
if (m_quadIndex == 0) {
return;
}
// Upload vertex data to GPU
m_vertexArray->getVertexBuffers().at(0)->uploadData(
m_vertexBufferBase.get(),
m_quadIndex * vertexPerQuad * sizeof(QuadVertex));
bind();
// Render
RenderCommand::drawIndexed(*m_vertexArray, m_quadIndex * indexPerQuad);
unbind();
}
void Renderer2D::startBatch()
{
m_quadIndex = 0;
m_vertexBufferPtr = m_vertexBufferBase.get();
m_textureUnitIndex = 1;
}
void Renderer2D::nextBatch()
{
flush();
startBatch();
}
// -----------------------------------------
RendererCharacter::RendererCharacter(s)
{
Renderer::initialize();
// CPU
// ---------------------------------
// Create array for storing quads vertices
m_vertexBufferBase = std::make_unique<CharacterVertex[]>(vertexCount);
m_vertexBufferPtr = m_vertexBufferBase.get();
// Generate indices
uint32_t* indices = new uint32_t[indexCount];
uint32_t offset = 0;
for (uint32_t i = 0; i < indexCount; i += indexPerQuad) {
indices[i + 0] = offset + 0;
indices[i + 1] = offset + 1;
indices[i + 2] = offset + 2;
indices[i + 3] = offset + 2;
indices[i + 4] = offset + 3;
indices[i + 5] = offset + 0;
offset += vertexPerQuad;
}
// GPU
// ---------------------------------
// Create vertex buffer
auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(CharacterVertex) * vertexCount);
vertexBuffer->setLayout({
{ BufferElementType::Vec3, "a_position" },
{ BufferElementType::Vec4, "a_color" },
{ BufferElementType::Vec2, "a_textureCoordinates" },
{ BufferElementType::Float, "a_textureIndex" },
{ BufferElementType::Float, "a_width" },
{ BufferElementType::Float, "a_edge" },
{ BufferElementType::Float, "a_borderWidth" },
{ BufferElementType::Float, "a_borderEdge" },
{ BufferElementType::Vec4, "a_borderColor" },
{ BufferElementType::Float, "a_offset" },
});
m_vertexArray->addVertexBuffer(vertexBuffer);
// Create index buffer
auto indexBuffer = std::make_shared<IndexBuffer>(indices, sizeof(uint32_t) * indexCount);
m_vertexArray->setIndexBuffer(indexBuffer);
delete[] indices;
info() << "RendererCharacter initialized";
}
RendererCharacter::~RendererCharacter()
{
Renderer::destroy();
}
void RendererCharacter::beginScene()
{
}
void RendererCharacter::endScene()
{
nextBatch();
}
void RendererCharacter::drawCharacter(std::array<CharacterVertex, vertexPerQuad>& characterQuad, std::shared_ptr<Texture> texture)
{
// Create a new batch if the quad limit has been reached
if (m_quadIndex >= quadCount) {
nextBatch();
}
uint32_t textureUnitIndex = addTextureUnit(texture);
// Add the quads 4 vertices
for (uint32_t i = 0; i < vertexPerQuad; i++) {
m_vertexBufferPtr->quad.position = characterQuad[i].quad.position;
m_vertexBufferPtr->quad.color = characterQuad[i].quad.color;
m_vertexBufferPtr->quad.textureCoordinates = characterQuad[i].quad.textureCoordinates;
m_vertexBufferPtr->quad.textureIndex = (float)textureUnitIndex;
m_vertexBufferPtr->width = characterQuad[i].width;
m_vertexBufferPtr->edge = characterQuad[i].edge;
m_vertexBufferPtr->borderWidth = characterQuad[i].borderWidth;
m_vertexBufferPtr->borderEdge = characterQuad[i].borderEdge;
m_vertexBufferPtr->borderColor = characterQuad[i].borderColor;
m_vertexBufferPtr->offset = characterQuad[i].offset;
m_vertexBufferPtr++;
}
m_quadIndex++;
}
void RendererCharacter::loadShader()
{
m_shader = ShaderManager::the().load("assets/glsl/batch-font");
}
void RendererCharacter::flush()
{
if (m_quadIndex == 0) {
return;
}
// Upload vertex data to GPU
m_vertexArray->getVertexBuffers().at(0)->uploadData(
m_vertexBufferBase.get(),
m_quadIndex * vertexPerQuad * sizeof(CharacterVertex));
bind();
// Render
bool depthTest = RenderCommand::depthTest();
RenderCommand::setDepthTest(false);
RenderCommand::drawIndexed(*m_vertexArray, m_quadIndex * indexPerQuad);
RenderCommand::setDepthTest(depthTest);
unbind();
}
void RendererCharacter::startBatch()
{
m_quadIndex = 0;
m_vertexBufferPtr = m_vertexBufferBase.get();
m_textureUnitIndex = 1;
}
void RendererCharacter::nextBatch()
{
flush();
startBatch();
}
}
-165
View File
@@ -1,165 +0,0 @@
#ifndef RENDERER_H
#define RENDERER_H
#include <cstdint> // int32_t, uint32_t
#include <memory> // std::shared_ptr, std::unique_ptr, std::make_shared, std::make_unique
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
#include "glm/ext/vector_float2.hpp" // glm::vec2
#include "glm/ext/vector_float3.hpp" // glm::vec3
#include "glm/ext/vector_float4.hpp" // glm::vec4
#include "inferno/component/transformcomponent.h"
#include "inferno/singleton.h"
namespace Inferno {
class Shader;
class Texture;
class VertexArray;
struct QuadVertex {
glm::vec3 position { 0.0f, 0.0f, 0.0f };
glm::vec4 color { 1.0f, 1.0f, 1.0f, 1.0f };
glm::vec2 textureCoordinates { 0.0f, 0.0f };
float textureIndex = 0; // @Todo get int to pass to fragment correctly
};
struct CharacterVertex {
QuadVertex quad;
// Font
float width = 0.44f;
float edge = 0.15f;
// Outline
float borderWidth = 0.7f;
float borderEdge = 0.1f;
glm::vec4 borderColor { 1.0f, 1.0f, 1.0f, 1.0f };
// Dropshadow
float offset = 0.0f;
};
// -----------------------------------------
class RenderCommand {
public:
static void initialize();
static void destroy();
static void clear();
static void clearColor(const glm::vec4& color);
static void drawIndexed(const VertexArray& vertexArray, uint32_t indexCount = 0);
static void setViewport(int32_t x, int32_t y, uint32_t width, uint32_t height);
static void setDepthTest(bool enabled);
static bool depthTest();
static int32_t textureUnitAmount();
};
// -----------------------------------------
class Renderer {
public:
static const uint32_t vertexPerQuad = 4;
static const uint32_t indexPerQuad = 6;
static const uint32_t textureUnitPerBatch = 32;
protected:
Renderer() {}
void initialize();
void destroy();
uint32_t addTextureUnit(std::shared_ptr<Texture> texture);
void bind();
void unbind();
virtual void loadShader() = 0;
virtual void flush() = 0;
virtual void startBatch() = 0;
virtual void nextBatch() = 0;
uint32_t m_quadIndex = 0;
// Texture units
static uint32_t m_supportedTextureUnitPerBatch;
uint32_t m_textureUnitIndex = 1;
std::array<std::shared_ptr<Texture>, textureUnitPerBatch> m_textureUnits;
// GPU objects
std::shared_ptr<Shader> m_shader;
std::shared_ptr<VertexArray> m_vertexArray;
};
// -----------------------------------------
class Renderer2D final
: public Renderer
, public Singleton<Renderer2D> {
public:
Renderer2D(s);
virtual ~Renderer2D();
using Singleton<Renderer2D>::initialize;
using Singleton<Renderer2D>::destroy;
static const uint32_t quadCount = 1000;
static const uint32_t vertexCount = quadCount * vertexPerQuad;
static const uint32_t indexCount = quadCount * indexPerQuad;
void beginScene(glm::mat4 cameraProjectionView);
void endScene();
void drawQuad(const TransformComponent& transform, glm::vec4 color);
void drawQuad(const TransformComponent& transform, glm::mat4 color);
void drawQuad(const TransformComponent& transform, glm::vec4 color, std::shared_ptr<Texture> texture);
void drawQuad(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture);
private:
void loadShader() override;
void flush() override;
void startBatch() override;
void nextBatch() override;
// CPU quad vertices
std::unique_ptr<QuadVertex[]> m_vertexBufferBase;
QuadVertex* m_vertexBufferPtr { nullptr };
// Default quad vertex positions
glm::vec4 m_vertexPositions[vertexPerQuad];
};
// -----------------------------------------
class RendererCharacter final
: public Renderer
, public Singleton<RendererCharacter> {
public:
RendererCharacter(s);
virtual ~RendererCharacter();
using Singleton<RendererCharacter>::initialize;
using Singleton<RendererCharacter>::destroy;
static const uint32_t quadCount = 1000;
static const uint32_t vertexCount = quadCount * vertexPerQuad;
static const uint32_t indexCount = quadCount * indexPerQuad;
void beginScene();
void endScene();
void drawCharacter(std::array<CharacterVertex, vertexPerQuad>& characterQuad, std::shared_ptr<Texture> texture);
private:
void loadShader() override;
void flush() override;
void startBatch() override;
void nextBatch() override;
// CPU quad vertices
std::unique_ptr<CharacterVertex[]> m_vertexBufferBase;
CharacterVertex* m_vertexBufferPtr { nullptr };
};
}
#endif // RENDERER_H
-270
View File
@@ -1,270 +0,0 @@
#include <utility> // std::move
#include <vector> // std::vector
#include "glad/glad.h"
#include "glm/gtc/type_ptr.hpp" // glm::value_ptr
#include "inferno/assert.h"
#include "inferno/core.h"
#include "inferno/io/file.h"
#include "inferno/io/log.h"
#include "inferno/render/shader.h"
namespace Inferno {
Shader::Shader(const std::string& name)
: m_name(std::move(name)),
m_id(0)
{
// Get file contents
std::string vertexSrc = File::read(name + ".vert");
std::string fragmentSrc = File::read(name + ".frag");
// Compile shaders
uint32_t vertexID = compileShader(GL_VERTEX_SHADER, vertexSrc.c_str());
uint32_t fragmentID = compileShader(GL_FRAGMENT_SHADER, fragmentSrc.c_str());
// Link shaders
if (vertexID > 0 && fragmentID > 0) {
m_id = linkShader(vertexID, fragmentID);
}
// Clear resources
else if (vertexID > 0) glDeleteShader(vertexID);
else if (fragmentID > 0) glDeleteShader(fragmentID);
}
Shader::~Shader()
{
if (m_id > 0) {
glDeleteProgram(m_id);
m_id = 0;
}
}
int32_t Shader::findUniform(const std::string& name) const
{
int32_t location = glGetUniformLocation(m_id, name.c_str());
ASSERT(location != -1, "Shader could not find uniform '{}'", name);
return location;
}
void Shader::setInt(const std::string& name, int value)
{
// Set uniform int
glUniform1i(findUniform(name), value);
}
void Shader::setInt(const std::string& name, int* values, uint32_t count)
{
// Set uniform int array
glUniform1iv(findUniform(name), count, values);
}
void Shader::setFloat(const std::string& name, float value) const
{
// Set uniform float
glUniform1f(findUniform(name), value);
}
void Shader::setFloat(const std::string& name, float v1, float v2, float v3, float v4) const
{
// Set uniform vec4 data
glUniform4f(findUniform(name), v1, v2, v3, v4);
}
void Shader::setFloat(const std::string& name, glm::vec2 value) const
{
// Set uniform vec2 data
glUniform2f(findUniform(name), value.x, value.y);
}
void Shader::setFloat(const std::string& name, glm::vec3 value) const
{
// Set uniform vec3 data
glUniform3f(findUniform(name), value.x, value.y, value.z);
}
void Shader::setFloat(const std::string& name, glm::vec4 value) const
{
// Set uniform vec4 data
glUniform4f(findUniform(name), value.x, value.y, value.z, value.w);
}
void Shader::setFloat(const std::string& name, glm::mat3 matrix) const
{
// Set uniform mat3 data
glUniformMatrix3fv(findUniform(name), 1, GL_FALSE, glm::value_ptr(matrix));
}
void Shader::setFloat(const std::string& name, glm::mat4 matrix) const
{
// Set uniform mat4 data
glUniformMatrix4fv(findUniform(name), 1, GL_FALSE, glm::value_ptr(matrix));
}
void Shader::bind() const
{
glUseProgram(m_id);
}
void Shader::unbind() const
{
glUseProgram(0);
}
uint32_t Shader::compileShader(int32_t type, const char* source) const
{
// Create new shader
uint32_t shader = 0;
shader = glCreateShader(type);
// Attach shader source to shader object
glShaderSource(shader, 1, &source, nullptr);
// Compile shader
glCompileShader(shader);
// Check compilation status
if (checkStatus(shader) == GL_TRUE) {
return shader;
}
// On fail
glDeleteShader(shader);
return 0;
}
uint32_t Shader::linkShader(uint32_t vertex, uint32_t fragment) const
{
// Create new shader program
uint32_t shaderProgram = 0;
shaderProgram = glCreateProgram();
// Attach both shaders to the shader program
glAttachShader(shaderProgram, vertex);
glAttachShader(shaderProgram, fragment);
// Setup vertex attributes
glBindAttribLocation(shaderProgram, 0, "a_position");
// Link the shaders
glLinkProgram(shaderProgram);
// Clear resources
glDeleteShader(vertex);
glDeleteShader(fragment);
// Check linking status
if (checkStatus(shaderProgram, true) == GL_TRUE) {
return shaderProgram;
}
// On fail
glDeleteProgram(shaderProgram);
return 0;
}
int32_t Shader::checkStatus(uint32_t check, bool isProgram) const
{
int32_t success;
int32_t maxLength = 0;
std::vector<char> infoLog;
// Get the compilation/linking status
!isProgram
? glGetShaderiv(check, GL_COMPILE_STATUS, &success)
: glGetProgramiv(check, GL_LINK_STATUS, &success);
if (success != GL_TRUE) {
// Get max length of the log including \0 terminator
!isProgram
? glGetShaderiv(check, GL_INFO_LOG_LENGTH, &maxLength)
: glGetProgramiv(check, GL_INFO_LOG_LENGTH, &maxLength);
// Reserve data for the log
infoLog.reserve(maxLength);
// Retrieve the error message
!isProgram
? glGetShaderInfoLog(check, maxLength, nullptr, &infoLog[0])
: glGetProgramInfoLog(check, maxLength, nullptr, &infoLog[0]);
warn() << "Shader " << infoLog.data();
}
ASSERT(success == GL_TRUE, "Shader program creation failed!");
return success;
}
// -----------------------------------------
ShaderManager::ShaderManager(s)
{
info() << "ShaderManager initialized";
}
ShaderManager::~ShaderManager()
{
}
void ShaderManager::add(const std::string& name, std::shared_ptr<Shader> shader)
{
// Construct (key, value) pair and insert it into the unordered_map
m_shaderList.emplace(std::move(name), std::move(shader));
}
std::shared_ptr<Shader> ShaderManager::load(const std::string& name)
{
if (exists(name)) {
return get(name);
}
std::shared_ptr<Shader> shader = std::make_shared<Shader>(name);
add(name, shader);
return get(name);
}
std::shared_ptr<Shader> ShaderManager::load(const std::string& vertexSource,
const std::string& fragmentSource)
{
std::string name = computeName(vertexSource, fragmentSource);
return load(name);
}
std::shared_ptr<Shader> ShaderManager::get(const std::string& name)
{
return exists(name) ? m_shaderList.at(name) : nullptr;
}
bool ShaderManager::exists(const std::string& name)
{
return m_shaderList.find(name) != m_shaderList.end();
}
void ShaderManager::remove(const std::string& name)
{
if (exists(name)) {
m_shaderList.erase(name);
}
}
void ShaderManager::remove(std::shared_ptr<Shader> shader)
{
if (exists(shader->name())) {
m_shaderList.erase(shader->name());
}
}
std::string ShaderManager::computeName(const std::string& vertexSource,
const std::string& fragmentSource)
{
auto vertexPos = vertexSource.find_last_of('.');
auto fragmentPos = fragmentSource.find_last_of('.');
ASSERT(vertexPos != std::string::npos, "Shader did not have file extension: '{}'", vertexSource);
ASSERT(fragmentPos != std::string::npos, "Shader did not have file extension: '{}'", fragmentSource);
auto vertexName = vertexSource.substr(0, vertexPos);
auto fragmentName = vertexSource.substr(0, fragmentPos);
ASSERT(vertexName == fragmentName, "Shader names did not match: {} {}", vertexSource, fragmentSource);
return vertexName;
}
}
-76
View File
@@ -1,76 +0,0 @@
#ifndef SHADER_H
#define SHADER_H
#include <cstdint> // int32_t, uint32_t
#include <memory> // std::shared_ptr
#include <string> // std::string
#include <unordered_map> // std::unordered_map
#include "glm/glm.hpp"
#include "inferno/singleton.h"
namespace Inferno {
class Shader {
public:
Shader(const std::string& name);
virtual ~Shader();
int32_t findUniform(const std::string& name) const;
void setInt(const std::string& name, int value);
void setInt(const std::string& name, int* values, uint32_t count);
void setFloat(const std::string& name, float value) const;
void setFloat(const std::string& name, float v1, float v2, float v3, float v4) const;
void setFloat(const std::string& name, glm::vec2 value) const;
void setFloat(const std::string& name, glm::vec3 value) const;
void setFloat(const std::string& name, glm::vec4 value) const;
void setFloat(const std::string& name, glm::mat3 matrix) const;
void setFloat(const std::string& name, glm::mat4 matrix) const;
void bind() const;
void unbind() const;
inline std::string name() const { return m_name; }
inline uint32_t id() const { return m_id; }
protected:
uint32_t compileShader(int32_t type, const char* shaderSource) const;
uint32_t linkShader(uint32_t vertex, uint32_t fragment) const;
int32_t checkStatus(uint32_t check, bool isProgram = false) const;
private:
std::string m_name;
uint32_t m_id;
};
// -----------------------------------------
class ShaderManager final : public Singleton<ShaderManager> {
public:
ShaderManager(s);
virtual ~ShaderManager();
void add(const std::string& name, std::shared_ptr<Shader> shader);
std::shared_ptr<Shader> load(const std::string& name);
std::shared_ptr<Shader> load(const std::string& vertexSource,
const std::string& fragmentSource);
std::shared_ptr<Shader> get(const std::string& name);
bool exists(const std::string& name);
void remove(const std::string& name);
void remove(std::shared_ptr<Shader> shader);
protected:
std::string computeName(const std::string& vertexSource,
const std::string& fragmentSource);
private:
std::unordered_map<std::string, std::shared_ptr<Shader>> m_shaderList;
};
}
#endif // SHADER_H
-156
View File
@@ -1,156 +0,0 @@
#include <climits> // UINT_MAX
#include <memory> // std::shared_ptr
#include <utility> // std::move
#include "glad/glad.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb/stb_image.h"
#include "inferno/assert.h"
#include "inferno/render/texture.h"
namespace Inferno {
Texture::Texture(const std::string& path)
: m_path(std::move(path))
{
int width;
int height;
int channels;
// Load image data
stbi_set_flip_vertically_on_load(1);
unsigned char* data = stbi_load(path.c_str(), &width, &height, &channels, STBI_default);
ASSERT(data, "Failed to load image: '{}'", path);
m_width = width;
m_height = height;
if (channels == 4) {
m_internalFormat = GL_RGBA8;
m_dataFormat = GL_RGBA;
}
else if (channels == 3) {
m_internalFormat = GL_RGB8;
m_dataFormat = GL_RGB;
}
create(data);
// Clean resources
stbi_image_free(data);
}
Texture::~Texture()
{
glDeleteTextures(1, &m_id);
}
void Texture::bind(uint32_t unit) const
{
// Set active unit
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, m_id);
// Reset unit
glActiveTexture(GL_TEXTURE0);
}
void Texture::unbind() const
{
glBindTexture(GL_TEXTURE_2D, 0);
}
void Texture::create(unsigned char* data)
{
m_id = UINT_MAX;
// Create texture object
glGenTextures(1, &m_id);
// Bind texture object
glBindTexture(GL_TEXTURE_2D, m_id);
// Set unpacking of pixel data to byte-alignment,
// this prevents alignment issues when using a single byte for color
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Generate texture
glTexImage2D(
GL_TEXTURE_2D, // Texture target
0, // Midmap level, base starts at level 0
m_internalFormat, // Texture format
m_width, m_height, // Image width/height
0, // Always 0 (legacy)
m_dataFormat, // Texture source format
GL_UNSIGNED_BYTE, // Texture source datatype
data); // Image data
// Set the texture wrapping / filtering options
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // X
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Y
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Minify
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Magnify
// Automatically generate all mipmap levels
glGenerateMipmap(GL_TEXTURE_2D);
// Unbind texture object
glBindTexture(GL_TEXTURE_2D, 0);
}
// -----------------------------------------
TextureManager::TextureManager(s)
{
info() << "TextureManager initialized";
}
TextureManager::~TextureManager()
{
}
void TextureManager::add(const std::string& path, std::shared_ptr<Texture> texture)
{
// Construct (key, value) pair and insert it into the unordered_map
m_textureList.emplace(std::move(path), std::move(texture));
}
std::shared_ptr<Texture> TextureManager::load(const std::string& path)
{
if (exists(path)) {
return get(path);
}
std::shared_ptr<Texture> texture = std::make_shared<Texture>(path);
add(path, texture);
return get(path);
}
std::shared_ptr<Texture> TextureManager::get(const std::string& path)
{
return exists(path) ? m_textureList.at(path) : nullptr;
}
bool TextureManager::exists(const std::string& path)
{
return m_textureList.find(path) != m_textureList.end();
}
void TextureManager::remove(const std::string& path)
{
if (exists(path)) {
m_textureList.erase(path);
}
}
void TextureManager::remove(std::shared_ptr<Texture> texture)
{
if (exists(texture->path())) {
m_textureList.erase(texture->path());
}
}
}
-61
View File
@@ -1,61 +0,0 @@
#ifndef TEXTURE_H
#define TEXTURE_H
#include <cstdint> // uint32_t
#include <memory> // std::shared_ptr
#include <string> // std::string
#include <unordered_map> // std::unordered_map
#include "inferno/singleton.h"
namespace Inferno {
class Texture {
public:
Texture(const std::string& path);
virtual ~Texture();
void bind(uint32_t unit = 0) const;
void unbind() const;
inline std::string path() const { return m_path; }
inline uint32_t width() const { return m_width; }
inline uint32_t height() const { return m_height; }
inline uint32_t id() const { return m_id; }
inline uint32_t internalFormat() const { return m_internalFormat; }
inline uint32_t dataFormat() const { return m_dataFormat; }
protected:
void create(unsigned char* data);
private:
std::string m_path;
uint32_t m_width;
uint32_t m_height;
uint32_t m_id;
uint32_t m_internalFormat;
uint32_t m_dataFormat;
};
// -----------------------------------------
class TextureManager final : public Singleton<TextureManager> {
public:
TextureManager(s);
virtual ~TextureManager();
void add(const std::string& path, std::shared_ptr<Texture> texture);
std::shared_ptr<Texture> load(const std::string& path);
std::shared_ptr<Texture> get(const std::string& path);
bool exists(const std::string& path);
void remove(const std::string& path);
void remove(std::shared_ptr<Texture> texture);
private:
std::unordered_map<std::string, std::shared_ptr<Texture>> m_textureList;
};
}
#endif // TEXTURE_H
-122
View File
@@ -1,122 +0,0 @@
#include "inferno/assert.h"
#include "inferno/component/cameracomponent.h"
#include "inferno/component/luascriptcomponent.h"
#include "inferno/component/nativescriptcomponent.h"
#include "inferno/component/spritecomponent.h"
#include "inferno/component/tagcomponent.h"
#include "inferno/scene/scene.h"
#include "inferno/script/cameracontroller.h"
#include "inferno/script/nativescript.h"
#include "inferno/system/camerasystem.h"
#include "inferno/system/rendersystem.h"
#include "inferno/system/scriptsystem.h"
#include "inferno/system/transformsystem.h"
namespace Inferno {
void Scene::initialize()
{
// Initialize
// ---------------------------------
m_registry = std::make_shared<entt::registry>();
TransformSystem::initialize();
TransformSystem::the().setRegistry(m_registry);
CameraSystem::initialize();
CameraSystem::the().setRegistry(m_registry);
RenderSystem::initialize();
RenderSystem::the().setRegistry(m_registry);
ScriptSystem::initialize();
ScriptSystem::the().setScene(this);
// Load assets
// ---------------------------------
m_texture = TextureManager::the().load("assets/gfx/test.png");
m_texture2 = TextureManager::the().load("assets/gfx/test-inverted.png");
// Construct entities
// ---------------------------------
uint32_t camera = createEntity("Camera Entity");
auto& cameraTransform = getComponent<TransformComponent>(camera);
cameraTransform.rotate.z = -1.0f;
cameraTransform.translate.z = 1.0f;
addComponent<CameraComponent>(camera, CameraType::Perspective);
// addComponent<NativeScriptComponent>(camera).bind<CameraController>();
addComponent<LuaScriptComponent>(camera, "assets/lua/cameracontroller.lua");
uint32_t quad = createEntity("Quad");
addComponent<SpriteComponent>(quad, glm::vec4 { 1.0f, 1.0f, 1.0f, 1.0f }, m_texture);
uint32_t quad2 = createEntity("Quad 2");
auto& quad2Transform = getComponent<TransformComponent>(quad2);
quad2Transform.translate.x = 1.1f;
addComponent<SpriteComponent>(quad2, glm::vec4 { 0.5f, 0.6f, 0.8f, 1.0f }, m_texture);
uint32_t quad3 = createEntity("Quad 3");
auto& quad3Transform = getComponent<TransformComponent>(quad3);
quad3Transform.translate.x = 2.2f;
addComponent<SpriteComponent>(quad3, glm::vec4 { 1.0f, 1.0f, 1.0f, 1.0f }, m_texture2);
info() << "Scene initialized";
}
void Scene::update(float deltaTime)
{
ScriptSystem::the().update(deltaTime);
TransformSystem::the().update();
CameraSystem::the().update();
}
void Scene::render()
{
RenderSystem::the().render();
}
void Scene::destroy()
{
ScriptSystem::destroy();
RenderSystem::destroy();
CameraSystem::destroy();
TransformSystem::destroy();
}
uint32_t Scene::createEntity(const std::string& name)
{
uint32_t entity = static_cast<uint32_t>(m_registry->create());
addComponent<TagComponent>(entity, name.empty() ? "Unnamed Entity" : name);
addComponent<TransformComponent>(entity);
return entity;
}
void Scene::destroyEntity(uint32_t entity)
{
ScriptSystem::the().cleanup(entity);
m_registry->destroy(entt::entity { entity });
}
glm::mat4 Scene::cameraProjectionView()
{
return CameraSystem::the().projectionView();
}
void Scene::validEntity(uint32_t entity) const
{
ASSERT(m_registry->valid(entt::entity {entity}), "Entity is not valid");
}
// ----------------------------------------
const LogStream& operator<<(const LogStream& stream, entt::entity entity)
{
return stream << static_cast<uint32_t>(entity);
}
}
-84
View File
@@ -1,84 +0,0 @@
#ifndef SCENE_H
#define SCENE_H
#include <cstdint> // uint32_t
#include <memory> // std::shared_ptr
#include "entt/entity/registry.hpp" // entt::entity, entt::registry
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
#include "inferno/io/log.h"
namespace Inferno {
class Camera;
class Texture;
class Scene {
public:
void initialize();
void update(float deltaTime);
void render();
void destroy();
uint32_t createEntity(const std::string& name = "");
void destroyEntity(uint32_t entity);
glm::mat4 cameraProjectionView();
void validEntity(uint32_t entity) const;
template<typename... T>
[[nodiscard]] bool hasComponent(uint32_t entity) const
{
validEntity(entity);
return m_registry->has<T...>(entt::entity { entity });
}
template<typename... T>
[[nodiscard]] bool anyComponent(uint32_t entity) const
{
validEntity(entity);
return m_registry->any<T...>(entt::entity { entity });
}
// @Todo Should replace be allowed? could trigger memory leaks with nativescript
template<typename T, typename... P>
T& addComponent(uint32_t entity, P&&... parameters) const
{
validEntity(entity);
return m_registry->emplace_or_replace<T>(entt::entity { entity }, std::forward<P>(parameters)...);
};
template<typename T>
size_t removeComponent(uint32_t entity) const
{
validEntity(entity);
return m_registry->remove_if_exists<T>(entt::entity { entity });
}
// @Todo Should replace be allowed? could trigger memory leaks with nativescript
template<typename T, typename... P>
T& getComponent(uint32_t entity, P&&... parameters) const
{
validEntity(entity);
return m_registry->get_or_emplace<T>(entt::entity { entity }, std::forward<P>(parameters)...);
}
// const entt::registry& registry() const { return m_registry; }
std::shared_ptr<entt::registry> registry() const { return m_registry; }
private:
std::shared_ptr<Texture> m_texture;
std::shared_ptr<Texture> m_texture2;
std::shared_ptr<entt::registry> m_registry;
};
// -----------------------------------------
const LogStream& operator<<(const LogStream& stream, entt::entity handle);
}
#endif // SCENE_H
@@ -1,122 +0,0 @@
#include "glm/ext/matrix_transform.hpp" // glm::radians
#include "inferno/component/cameracomponent.h"
#include "inferno/component/transformcomponent.h"
#include "inferno/io/input.h"
#include "inferno/keycodes.h"
#include "inferno/script/cameracontroller.h"
namespace Inferno {
void CameraController::updateOrthographic(float deltaTime)
{
// Update camera rotation
float cameraRotateSpeed = ROTATE_SPEED * deltaTime;
if (Input::isKeyPressed(keyCode("GLFW_KEY_Q"))) {
transform->rotate.z -= cameraRotateSpeed;
}
if (Input::isKeyPressed(keyCode("GLFW_KEY_E"))) {
transform->rotate.z += cameraRotateSpeed;
}
if (transform->rotate.z > 180.0f) {
transform->rotate.z -= 360.0f;
}
else if (transform->rotate.z <= -180.0f) {
transform->rotate.z += 360.0f;
}
// Update camera translation
float cameraTranslateSpeed = TRANSLATE_SPEED * deltaTime;
// WASD movement
if (Input::isKeyPressed(keyCode("GLFW_KEY_W"))) {
transform->translate.x += -sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
transform->translate.y += cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
}
if (Input::isKeyPressed(keyCode("GLFW_KEY_S"))) {
transform->translate.x -= -sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
transform->translate.y -= cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
}
if (Input::isKeyPressed(keyCode("GLFW_KEY_A"))) {
transform->translate.x -= cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
transform->translate.y -= sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
}
if (Input::isKeyPressed(keyCode("GLFW_KEY_D"))) {
transform->translate.x += cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
transform->translate.y += sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
}
// Update camera zoom
float zoomSpeed = ZOOM_SENSITIVITY * deltaTime;
if (Input::isKeyPressed(keyCode("GLFW_KEY_EQUAL"))) {
m_camera->zoomLevel -= zoomSpeed;
}
if (Input::isKeyPressed(keyCode("GLFW_KEY_MINUS"))) {
m_camera->zoomLevel += zoomSpeed;
}
m_camera->zoomLevel = std::max(m_camera->zoomLevel, 0.25f);
m_camera->zoomLevel = std::min(m_camera->zoomLevel, 10.0f);
}
void CameraController::updatePerspective(float deltaTime)
{
// Get mouse movement offset compared to last frame
float xOffset = Input::getXOffset() * MOUSE_SENSITIVITY;
float yOffset = Input::getYOffset() * MOUSE_SENSITIVITY;
m_camera->yaw += xOffset;
m_camera->pitch += yOffset;
// Prevent gimbal lock
if (m_camera->pitch > 89.0f) m_camera->pitch = 89.0f;
if (m_camera->pitch < -89.0f) m_camera->pitch = -89.0f;
// Update camera rotation, by calculating direction vector via yaw and pitch
transform->rotate = {
cos(glm::radians(m_camera->pitch)) * cos(glm::radians(m_camera->yaw)),
sin(glm::radians(m_camera->pitch)),
cos(glm::radians(m_camera->pitch)) * sin(glm::radians(m_camera->yaw))
};
transform->rotate = glm::normalize(transform->rotate);
// The direction vector is based on
// Camera direction (z): normalize(position - target)
// Right axis (x): normalize(cross(up, direction))
// Up axis (y): cross(direction, right)
// Source: https://learnopengl.com/img/getting-started/camera_axes.png
// Cross = combination of two vectors in 3D space,
// where result is always perpendicular to both of the vectors
// Update camera translation
float cameraSpeed = TRANSLATE_SPEED * deltaTime;
// WASD movement
if (Input::isKeyPressed(keyCode("GLFW_KEY_W"))) {
transform->translate += transform->rotate * cameraSpeed;
}
if (Input::isKeyPressed(keyCode("GLFW_KEY_S"))) {
transform->translate -= transform->rotate * cameraSpeed;
}
if (Input::isKeyPressed(keyCode("GLFW_KEY_A"))) {
transform->translate -= glm::normalize(glm::cross(transform->rotate, m_camera->up)) * cameraSpeed;
}
if (Input::isKeyPressed(keyCode("GLFW_KEY_D"))) {
transform->translate += glm::normalize(glm::cross(transform->rotate, m_camera->up)) * cameraSpeed;
}
// Up / down movement
if (Input::isKeyPressed(keyCode("GLFW_KEY_SPACE"))) {
transform->translate.y += cameraSpeed;
}
if (Input::isKeyPressed(keyCode("GLFW_KEY_LEFT_SHIFT"))) {
transform->translate.y -= cameraSpeed;
}
}
}
@@ -1,39 +0,0 @@
#ifndef CAMERA_CONTROLLER_H
#define CAMERA_CONTROLLER_H
#include "inferno/script/nativescript.h"
#define TRANSLATE_SPEED 2.5f
#define ROTATE_SPEED 90.0f
#define ZOOM_SENSITIVITY 2.5f
#define MOUSE_SENSITIVITY 0.25f
namespace Inferno {
struct CameraComponent;
class CameraController final : public NativeScript {
public:
virtual void update(float deltaTime) override
{
m_camera = &getComponent<CameraComponent>();
if (m_camera->type == CameraType::Orthographic) {
updateOrthographic(deltaTime);
}
else if (m_camera->type == CameraType::Perspective) {
updatePerspective(deltaTime);
}
}
void updateOrthographic(float deltaTime);
void updatePerspective(float deltaTime);
private:
CameraComponent* m_camera { nullptr };
};
}
#endif // CAMERA_CONTROLLER_H
-79
View File
@@ -1,79 +0,0 @@
#include "sol/unsafe_function_result.hpp"
#include "inferno/component/cameracomponent.h"
#include "inferno/component/spritecomponent.h"
#include "inferno/component/tagcomponent.h"
#include "inferno/component/transformcomponent.h"
#include "inferno/io/file.h"
#include "inferno/scene/scene.h"
#include "inferno/script/luascript.h"
#include "inferno/script/registration.h"
namespace Inferno {
void LuaScript::initialize()
{
// Type registration
// ---------------------------------
Registration::fill(m_state);
// Load libraries
// ---------------------------------
m_state.open_libraries(sol::lib::base, sol::lib::math);
// Component get functions
// ---------------------------------
m_state.set_function("getTagComponent", [this]() -> TagComponent* {
return &m_scene->getComponent<TagComponent>(m_entity);
});
m_state.set_function("getTransformComponent", [this]() -> TransformComponent* {
return &m_scene->getComponent<TransformComponent>(m_entity);
});
m_state.set_function("getCameraComponent", [this]() -> CameraComponent* {
return &m_scene->getComponent<CameraComponent>(m_entity);
});
m_state.set_function("getSpriteComponent", [this]() -> SpriteComponent* {
return &m_scene->getComponent<SpriteComponent>(m_entity);
});
// Load and Initialize script
// ---------------------------------
loadScript();
callFunction("LuaScript", "initialize");
}
void LuaScript::destroy()
{
callFunction("LuaScript", "destroy");
}
void LuaScript::update(float deltaTime)
{
m_state["LuaScript"]["transform"] = &m_scene->getComponent<TransformComponent>(m_entity);
callFunction("LuaScript", "update", deltaTime);
}
void LuaScript::loadScript()
{
std::string script = File::read(m_path);
auto result = m_state.script(script.c_str(),
[](lua_State*, sol::protected_function_result pfr) { return pfr; });
ASSERT(result.valid(), "LuaScript {}", ((sol::error)result).what());
}
sol::table LuaScript::getTable(const char* name)
{
sol::table table = m_state[name];
ASSERT(table.valid(), "LuaScript table does not exist");
return table;
}
}
-57
View File
@@ -1,57 +0,0 @@
#ifndef LUA_SCRIPT_H
#define LUA_SCRIPT_H
#include <cstdint> // uint32_t
#include <string> // std::string
#define SOL_ALL_SAFETIES_ON 1
#include "sol/protected_function.hpp"
#include "sol/protected_function_result.hpp"
#include "sol/state.hpp"
#include "sol/table.hpp"
#include "inferno/assert.h"
namespace Inferno {
struct TransformComponent;
class Scene;
class LuaScript {
public:
void initialize();
void destroy();
void update(float deltaTime);
void loadScript();
private:
sol::table getTable(const char* name);
template<typename... P>
void callFunction(const char* table, const char* function, P&&... parameters)
{
sol::table solTable = getTable(table);
sol::protected_function solFunction = solTable[function];
// Only call function if it exists
if (solFunction.valid()) {
sol::protected_function_result result = solFunction(solTable, parameters...);
ASSERT(result.valid(), "Lua function {}", ((sol::error)result).what());
}
}
sol::state m_state;
std::string m_path = "";
Scene* m_scene { nullptr };
uint32_t m_entity { 0 };
TransformComponent* transform { nullptr };
friend class ScriptSystem;
};
}
#endif // LUA_SCRIPT_H
-36
View File
@@ -1,36 +0,0 @@
#ifndef NATIVE_SCRIPT_H
#define NATIVE_SCRIPT_H
#include "inferno/scene/scene.h"
namespace Inferno {
struct TransformComponent;
class NativeScript {
public:
virtual ~NativeScript() {}
protected:
virtual void initialize() {}
virtual void destroy() {}
virtual void update(float deltaTime) { (void)deltaTime; }
template<typename T>
T& getComponent() const
{
return m_scene->getComponent<T>(m_entity);
}
TransformComponent* transform { nullptr };
private:
Scene* m_scene { nullptr };
uint32_t m_entity { 0 };
friend class ScriptSystem;
};
}
#endif // NATIVE_SCRIPT_H
-122
View File
@@ -1,122 +0,0 @@
#include "glm/ext/vector_float2.hpp" // glm::vec2
#include "glm/ext/vector_float3.hpp" // glm::vec3
#include "glm/ext/vector_float4.hpp" // glm::vec4
#include "glm/ext/matrix_transform.hpp" // glm::radians
#include "inferno/component/cameracomponent.h"
#include "inferno/component/spritecomponent.h"
#include "inferno/component/tagcomponent.h"
#include "inferno/component/transformcomponent.h"
#include "inferno/io/input.h"
#include "inferno/keycodes.h"
#include "inferno/script/registration.h"
namespace Inferno {
void Registration::fill(sol::state_view &state)
{
glm(state);
component(state);
input(state);
}
void Registration::glm(sol::state_view& state)
{
auto glm = state["glm"].get_or_create<sol::table>();
auto vec2 = glm.new_usertype<glm::vec2>(
"vec2",
sol::call_constructor, sol::constructors<glm::vec2(), glm::vec2(glm::vec2), glm::vec2(float), glm::vec2(float, float)>(),
"x", &glm::vec2::x, "y", &glm::vec2::y,
"r", &glm::vec2::r, "g", &glm::vec2::g,
"s", &glm::vec2::s, "t", &glm::vec2::t,
"__add", addition<glm::vec2, float>(),
"__sub", subtraction<glm::vec2, float>(),
"__mul", multiplication<glm::vec2, float>(),
"__div", division<glm::vec2, float>(),
"__tostring", string<glm::vec2>
);
auto vec3 = glm.new_usertype<glm::vec3>(
"vec3",
sol::call_constructor, sol::constructors<glm::vec3(), glm::vec3(glm::vec3), glm::vec3(float), glm::vec3(float, float, float)>(),
"x", &glm::vec3::x, "y", &glm::vec3::y, "z", &glm::vec3::z,
"r", &glm::vec3::r, "g", &glm::vec3::g, "b", &glm::vec3::b,
"s", &glm::vec3::s, "t", &glm::vec3::t, "p", &glm::vec3::p,
"__add", addition<glm::vec3, float>(),
"__sub", subtraction<glm::vec3, float>(),
"__mul", multiplication<glm::vec3, float>(),
"__div", division<glm::vec3, float>(),
"__tostring", string<glm::vec3>
);
auto vec4 = glm.new_usertype<glm::vec4>(
"vec4",
sol::call_constructor, sol::constructors<glm::vec4(), glm::vec4(glm::vec4), glm::vec4(float), glm::vec4(float, float, float, float)>(),
"x", &glm::vec4::x, "y", &glm::vec4::y, "z", &glm::vec4::z, "w", &glm::vec4::w,
"r", &glm::vec4::r, "g", &glm::vec4::g, "b", &glm::vec4::b, "a", &glm::vec4::a,
"s", &glm::vec4::s, "t", &glm::vec4::t, "p", &glm::vec4::p, "q", &glm::vec4::q,
"__add", addition<glm::vec4, float>(),
"__sub", subtraction<glm::vec4, float>(),
"__mul", multiplication<glm::vec4, float>(),
"__div", division<glm::vec4, float>(),
"__tostring", string<glm::vec4>
);
glm.set_function("radians", sol::overload(
[](float v) { return glm::radians(v); },
[](const glm::vec2& v) { return glm::radians(v); },
[](const glm::vec3& v) { return glm::radians(v); },
[](const glm::vec4& v) { return glm::radians(v); }
));
glm.set_function("normalize", sol::overload(
[](const glm::vec2& v) { return glm::normalize(v); },
[](const glm::vec3& v) { return glm::normalize(v); },
[](const glm::vec4& v) { return glm::normalize(v); }
));
glm.set_function("cross", [](const glm::vec3& x, const glm::vec3& y) { return glm::cross(x, y); });
}
void Registration::component(sol::state_view& state)
{
auto tagComponent = state.new_usertype<TagComponent>("TagComponent", sol::no_constructor);
tagComponent["tag"] = &TagComponent::tag;
auto transformComponent = state.new_usertype<TransformComponent>("TransformComponent", sol::no_constructor);
transformComponent["translate"] = &TransformComponent::translate;
transformComponent["rotate"] = &TransformComponent::rotate;
transformComponent["scale"] = &TransformComponent::scale;
transformComponent["transform"] = &TransformComponent::transform;
transformComponent["__tostring"] = &string<TransformComponent>;
auto cameraType = state.new_enum("CameraType",
"Orthographic", CameraType::Orthographic,
"Perspective", CameraType::Perspective);
auto cameraComponent = state.new_usertype<CameraComponent>("CameraComponent", sol::no_constructor);
cameraComponent["type"] = &CameraComponent::type;
cameraComponent["zoomLevel"] = &CameraComponent::zoomLevel;
cameraComponent["rotateAxis"] = &CameraComponent::rotateAxis;
cameraComponent["fov"] = &CameraComponent::fov;
cameraComponent["pitch"] = &CameraComponent::pitch;
cameraComponent["yaw"] = &CameraComponent::yaw;
cameraComponent["up"] = &CameraComponent::up;
cameraComponent["projection"] = &CameraComponent::projection;
auto spriteComponent = state.new_usertype<SpriteComponent>("SpriteComponent", sol::no_constructor);
spriteComponent["color"] = &SpriteComponent::color;
spriteComponent["texture"] = &SpriteComponent::texture;
}
void Registration::input(sol::state_view& state)
{
state.set_function("keyCode", &keyCode);
auto input = state.new_usertype<Input>("Input", sol::no_constructor);
input["isKeyPressed"] = &Input::isKeyPressed;
input["getXOffset"] = &Input::getXOffset;
input["getYOffset"] = &Input::getYOffset;
}
}
-71
View File
@@ -1,71 +0,0 @@
#ifndef REGISTRATION_H
#define REGISTRATION_H
#include "sol/overload.hpp" // sol::overload
#include "sol/state_view.hpp" // sol::state_view
#include "inferno/io/log.h"
namespace Inferno {
class Registration final {
public:
static void fill(sol::state_view& state);
private:
static void glm(sol::state_view& state);
static void component(sol::state_view& state);
static void input(sol::state_view& state);
template<typename T, typename V>
static auto addition()
{
return sol::overload(
[](const T& lhs, const T& rhs) { return lhs + rhs; },
[](const T& lhs, const V& rhs) { return lhs + rhs; },
[](const V& lhs, const T& rhs) { return lhs + rhs; }
);
}
template<typename T, typename V>
static auto subtraction()
{
return sol::overload(
[](const T& lhs, const T& rhs) { return lhs - rhs; },
[](const T& lhs, const V& rhs) { return lhs - rhs; },
[](const V& lhs, const T& rhs) { return lhs - rhs; }
);
}
template<typename T, typename V>
static auto multiplication()
{
return sol::overload(
[](const T& lhs, const T& rhs) { return lhs * rhs; },
[](const T& lhs, const V& rhs) { return lhs * rhs; },
[](const V& lhs, const T& rhs) { return lhs * rhs; }
);
}
template<typename T, typename V>
static auto division()
{
return sol::overload(
[](const T& lhs, const T& rhs) { return lhs / rhs; },
[](const T& lhs, const V& rhs) { return lhs / rhs; },
[](const V& lhs, const T& rhs) { return lhs / rhs; }
);
}
template<typename T>
static std::string string(const T& t)
{
std::string result;
str(&result) << t;
return result;
}
};
}
#endif // REGISTRATION_H
-91
View File
@@ -1,91 +0,0 @@
#include <cstdint> // uint32_t
#include <string> // std::string
#include "inferno/io/file.h"
#include "inferno/io/log.h"
#include "inferno/settings.h"
#include "inferno/util/json.h"
#include "inferno/window.h"
namespace Inferno {
const char* Settings::m_path { "assets/settings.json" };
SettingsProperties Settings::m_properties {};
void Settings::initialize()
{
Settings::load();
info() << "Settings initialized";
Settings::save();
}
void Settings::destroy()
{
}
bool Settings::load()
{
json object;
if (!File::ioRead(&object, m_path)) {
warn() << "Settings invalid formatting, using default values";
return false;
}
auto settings = Json::getPropertyValue<SettingsProperties>(object, json::value_t::object);
if (settings) {
m_properties = settings.value();
}
return true;
}
bool Settings::save()
{
json object = m_properties;
if (!File::ioWrite(&object, m_path)) {
warn() << "Settings could not be saved";
return false;
}
info() << "Settings saved";
return true;
}
// -----------------------------------------
void to_json(json& object, const SettingsProperties& settings)
{
object = json {
{ "window", settings.window }
};
}
void from_json(const json& object, SettingsProperties& settings)
{
if (Json::hasProperty(object, "window")) object.at("window").get_to(settings.window);
}
void to_json(json& object, const WindowProperties& window)
{
object = json {
{ "title", window.title },
{ "width", window.width },
{ "height", window.height },
{ "fullscreen", window.fullscreen },
{ "vsync", window.vsync },
};
}
void from_json(const json& object, WindowProperties& window)
{
if (Json::hasProperty(object, "title")) object.at("title").get_to(window.title);
if (Json::hasProperty(object, "width")) object.at("width").get_to(window.width);
if (Json::hasProperty(object, "height")) object.at("height").get_to(window.height);
if (Json::hasProperty(object, "fullscreen")) object.at("fullscreen").get_to(window.fullscreen);
if (Json::hasProperty(object, "vsync")) object.at("vsync").get_to(window.vsync);
}
}
-40
View File
@@ -1,40 +0,0 @@
#ifndef SETTINGS_H
#define SETTINGS_H
#include "inferno/util/json.h"
#include "inferno/window.h"
namespace Inferno {
struct SettingsProperties {
WindowProperties window;
};
class Settings {
public:
static void initialize();
static void destroy();
static bool load();
static bool save();
static inline SettingsProperties& get() { return m_properties; }
private:
static const char* m_path;
static SettingsProperties m_properties;
};
// -----------------------------------------
// nlohmann::json arbitrary type conversion functions
void to_json(json& object, const SettingsProperties& settings);
void from_json(const json& object, SettingsProperties& settings);
void to_json(json& object, const WindowProperties& window);
void from_json(const json& object, WindowProperties& window);
}
#endif // SETTINGS_H
-55
View File
@@ -1,55 +0,0 @@
#ifndef SINGLETON_H
#define SINGLETON_H
#include "inferno/assert.h"
namespace Inferno {
template<typename T>
class Singleton {
// Application is allowed to access its Singleton instance for early setting
friend class Application;
public:
static inline void initialize()
{
ASSERT(!s_instance, "Singleton already exists!");
s_instance = new T { s {} };
}
static inline void destroy()
{
ASSERT(s_instance, "Singleton does not exist!");
delete s_instance;
s_instance = nullptr;
}
static inline T& the()
{
ASSERT(s_instance, "Singleton does not exist!");
return *s_instance;
}
// Remove copy constructor and copy assignment operator
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(Singleton&&) = delete;
protected:
Singleton() {}
// Constructor token
struct s {};
private:
static T* s_instance;
};
template<typename T>
T* Singleton<T>::s_instance = nullptr;
} // namespace Inferno
#endif // SINGLETON_H
@@ -1,97 +0,0 @@
#include "glm/ext/matrix_clip_space.hpp" // glm::perspective, glm::ortho
#include "glm/ext/matrix_transform.hpp" // glm::radians, glm::lookAt
#include "inferno/application.h"
#include "inferno/assert.h"
#include "inferno/component/cameracomponent.h"
#include "inferno/component/transformcomponent.h"
#include "inferno/io/input.h"
#include "inferno/io/log.h"
#include "inferno/system/camerasystem.h"
#include "inferno/window.h"
namespace Inferno {
CameraSystem::CameraSystem(s)
{
info() << "CameraSystem initialized";
}
CameraSystem::~CameraSystem()
{
}
void CameraSystem::update()
{
auto view = m_registry->view<TransformComponent, CameraComponent>();
for (auto [entity, transform, camera] : view.each()) {
if (camera.type == CameraType::Orthographic) {
updateOrthographic(transform, camera);
}
else if (camera.type == CameraType::Perspective) {
updatePerspective(transform, camera);
}
}
}
glm::mat4 CameraSystem::projectionView()
{
auto view = m_registry->view<TransformComponent, CameraComponent>();
for (auto [entity, transform, camera] : view.each()) {
return camera.projection * transform.transform;
}
ASSERT_NOT_REACHED();
return glm::mat4 { 1.0f };
}
void CameraSystem::updateOrthographic(TransformComponent& transform, CameraComponent& camera)
{
// Update camera matrix
// Local space -> World space: model matrix
// Is done in Object::update()
// World space -> View space: view matrix
transform.transform = {
glm::translate(glm::mat4(1.0f), transform.translate) *
glm::rotate(glm::mat4(1.0f), glm::radians(transform.rotate.z), camera.rotateAxis)
};
transform.transform = { glm::inverse(transform.transform) };
// View space -> Clip space: projection matrix
float aspectRatio = Application::the().getWindow().getAspect();
camera.projection = {
glm::ortho(-aspectRatio * camera.zoomLevel, aspectRatio * camera.zoomLevel,
-camera.zoomLevel, camera.zoomLevel, -1.0f, 1.0f)
};
// Clip space -> Screen space: viewport transform
// Is done in the fragment shader using the settings of glViewport
}
void CameraSystem::updatePerspective(TransformComponent& transform, CameraComponent& camera)
{
// Update camera matrix
// Local space -> World space: model matrix
// Is done in Object::update()
// World space -> View space: view matrix
transform.transform = { glm::lookAt(transform.translate, transform.translate + transform.rotate, camera.up) };
// View space -> Clip space: projection matrix
float aspect = Application::the().getWindow().getAspect();
camera.projection = { glm::perspective(glm::radians(camera.fov), aspect, NEAR_PLANE, FAR_PLANE) };
// Clip space -> Screen space: viewport transform
// Is done in the fragment shader using the settings of glViewport
// Souce: https://learnopengl.com/img/getting-started/coordinate_systems.png
}
}
-39
View File
@@ -1,39 +0,0 @@
#ifndef CAMERA_SYSTEM_H
#define CAMERA_SYSTEM_H
#include <memory> //std::shared_ptr
#include "entt/entity/registry.hpp" // entt::entity, entt::registry
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
#include "inferno/singleton.h"
#define NEAR_PLANE 0.1f
#define FAR_PLANE 100.0f
namespace Inferno {
struct TransformComponent;
struct CameraComponent;
class CameraSystem final : public Singleton<CameraSystem> {
public:
CameraSystem(s);
virtual ~CameraSystem();
void update();
glm::mat4 projectionView();
void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; };
private:
void updateOrthographic(TransformComponent& transform, CameraComponent& camera);
void updatePerspective(TransformComponent& transform, CameraComponent& camera);
std::shared_ptr<entt::registry> m_registry;
};
}
#endif // CAMERA_SYSTEM_H
@@ -1,30 +0,0 @@
#include "glm/ext/matrix_transform.hpp" // glm::translate, glm::rotate, glm::scale, glm::radians
#include "inferno/assert.h"
#include "inferno/component/spritecomponent.h"
#include "inferno/component/transformcomponent.h"
#include "inferno/io/log.h"
#include "inferno/render/renderer.h"
#include "inferno/system/rendersystem.h"
namespace Inferno {
RenderSystem::RenderSystem(s)
{
info() << "RenderSystem initialized";
}
RenderSystem::~RenderSystem()
{
}
void RenderSystem::render()
{
auto group = m_registry->group<TransformComponent, SpriteComponent>();
for (auto [entity, transform, sprite] : group.each()) {
Renderer2D::the().drawQuad(transform, sprite.color, sprite.texture);
}
}
}
-28
View File
@@ -1,28 +0,0 @@
#ifndef RENDER_SYSTEM_H
#define RENDER_SYSTEM_H
#include <memory> //std::shared_ptr
#include "entt/entity/registry.hpp" // entt::entity, entt::registry
#include "inferno/render/renderer.h"
#include "inferno/singleton.h"
namespace Inferno {
class RenderSystem final : public Singleton<RenderSystem> {
public:
RenderSystem(s);
virtual ~RenderSystem();
void render();
void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; };
private:
std::shared_ptr<entt::registry> m_registry;
};
}
#endif // RENDER_SYSTEM_H
-103
View File
@@ -1,103 +0,0 @@
#include "entt/entity/registry.hpp" // entt::entity, entt::registry
#include "inferno/assert.h"
#include "inferno/component/luascriptcomponent.h"
#include "inferno/component/nativescriptcomponent.h"
#include "inferno/component/transformcomponent.h"
#include "inferno/io/log.h"
#include "inferno/scene/scene.h"
#include "inferno/script/luascript.h"
#include "inferno/script/nativescript.h"
#include "inferno/system/scriptsystem.h"
namespace Inferno {
ScriptSystem::ScriptSystem(s)
{
info() << "ScriptSystem initialized";
}
ScriptSystem::~ScriptSystem()
{
auto nativeScriptView = m_scene->registry()->view<NativeScriptComponent>();
for (auto entity : nativeScriptView) {
cleanup(nativeScriptView.get<NativeScriptComponent>(entity));
}
auto luaScriptView = m_scene->registry()->view<LuaScriptComponent>();
for (auto entity : luaScriptView) {
cleanup(luaScriptView.get<LuaScriptComponent>(entity));
}
}
void ScriptSystem::update(float deltaTime)
{
// @Todo figure out why group doesn't work here
auto nativeScriptView = m_scene->registry()->view<TransformComponent, NativeScriptComponent>();
for (auto [entity, transform, nativeScript] : nativeScriptView.each()) {
// Create native script if not initialized
if (!nativeScript.instance) {
nativeScript.instance = nativeScript.initialize();
nativeScript.instance->transform = &transform;
nativeScript.instance->m_scene = m_scene;
nativeScript.instance->m_entity = static_cast<uint32_t>(entity);
nativeScript.instance->initialize();
}
nativeScript.instance->transform = &transform;
nativeScript.instance->update(deltaTime);
}
auto luaScriptView = m_scene->registry()->view<TransformComponent, LuaScriptComponent>();
for (auto [entity, transform, luaScript] : luaScriptView.each()) {
// Create Lua script if not initialized
if (!luaScript.instance) {
luaScript.instance = new LuaScript();
luaScript.instance->transform = &transform;
luaScript.instance->m_scene = m_scene;
luaScript.instance->m_entity = static_cast<uint32_t>(entity);
luaScript.instance->m_path = luaScript.path;
luaScript.instance->initialize();
}
luaScript.instance->update(deltaTime);
}
}
void ScriptSystem::cleanup(uint32_t entity)
{
if (m_scene->hasComponent<NativeScriptComponent>(entity)) {
auto& nativeScript = m_scene->getComponent<NativeScriptComponent>(entity);
cleanup(nativeScript);
}
if (m_scene->hasComponent<LuaScriptComponent>(entity)) {
auto& luaScript = m_scene->getComponent<LuaScriptComponent>(entity);
cleanup(luaScript);
}
}
void ScriptSystem::cleanup(NativeScriptComponent& nativeScript)
{
if (nativeScript.instance) {
nativeScript.instance->destroy();
nativeScript.destroy();
}
}
void ScriptSystem::cleanup(LuaScriptComponent& luaScript)
{
if (luaScript.instance) {
luaScript.instance->destroy();
delete luaScript.instance;
}
}
}
-34
View File
@@ -1,34 +0,0 @@
#ifndef SCRIPT_SYSTEM_H
#define SCRIPT_SYSTEM_H
#include <cstdint> // uint32_t
#include "inferno/singleton.h"
namespace Inferno {
struct NativeScriptComponent;
struct LuaScriptComponent;
class Scene;
class ScriptSystem final : public Singleton<ScriptSystem> {
public:
ScriptSystem(s);
virtual ~ScriptSystem();
void update(float deltaTime);
void cleanup(uint32_t entity);
void cleanup(NativeScriptComponent& nativeScript);
void cleanup(LuaScriptComponent& luaScript);
void setScene(Scene* scene) { m_scene = scene; }
private:
Scene* m_scene { nullptr };
};
}
#endif // SCRIPT_SYSTEM_H
@@ -1,43 +0,0 @@
#include "glm/ext/matrix_transform.hpp" // glm::translate, glm::rotate, glm::scale, glm::radians
#include "inferno/assert.h"
#include "inferno/component/transformcomponent.h"
#include "inferno/io/log.h"
#include "inferno/system/transformsystem.h"
namespace Inferno {
TransformSystem::TransformSystem(s)
{
info() << "TransformSystem initialized";
}
TransformSystem::~TransformSystem()
{
}
void TransformSystem::update()
{
auto view = m_registry->view<TransformComponent>();
for (auto entity : view) {
auto& component = view.get<TransformComponent>(entity);
// Identity matrix
component.transform = glm::mat4(1.0f);
// Translate
component.transform = glm::translate(component.transform, component.translate);
// Rotate
component.transform = glm::rotate(component.transform, glm::radians(component.rotate.x), {1.0, 0.0, 0.0});
component.transform = glm::rotate(component.transform, glm::radians(component.rotate.y), {0.0, 1.0, 0.0});
component.transform = glm::rotate(component.transform, glm::radians(component.rotate.z), {0.0, 0.0, 1.0});
// Scale
component.transform = glm::scale(component.transform, component.scale);
}
}
}
@@ -1,26 +0,0 @@
#ifndef TRANSFORM_SYSTEM_H
#define TRANSFORM_SYSTEM_H
#include <memory> //std::shared_ptr
#include "entt/entity/registry.hpp" // entt::entity, entt::registry
#include "inferno/singleton.h"
namespace Inferno {
class TransformSystem final : public Singleton<TransformSystem> {
public:
TransformSystem(s);
virtual ~TransformSystem();
void update();
void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; };
private:
std::shared_ptr<entt::registry> m_registry;
};
}
#endif // TRANSFORM_SYSTEM_H
-12
View File
@@ -1,12 +0,0 @@
#include "GLFW/glfw3.h"
#include "inferno/time.h"
namespace Inferno {
float Time::time()
{
return static_cast<float>(glfwGetTime());
}
}
-13
View File
@@ -1,13 +0,0 @@
#ifndef TIME_H
#define TIME_H
namespace Inferno {
class Time {
public:
static float time();
};
}
#endif // TIME_H
-27
View File
@@ -1,27 +0,0 @@
#ifndef INTEGER_UTIL_H
#define INTEGER_UTIL_H
#include <limits> // std::numeric_limits
#include <string> // std::string, std::stoul
#include "inferno/assert.h"
namespace std {
// Can't believe this is not in the standard library
inline uint32_t stou(const std::string& string)
{
unsigned long size = std::stoul(string);
ASSERT(size <= std::numeric_limits<uint32_t>::max(), "String util not in uint32_t range '{}'", string);
return static_cast<uint32_t>(size);
}
inline uint32_t stou(const char* string)
{
return stou(std::string(string));
}
} // namespace std
#endif // INTEGER_UTIL_H
-22
View File
@@ -1,22 +0,0 @@
#ifndef STRING_UTIL_H
#define STRING_UTIL_H
#include <iomanip> // std::setfill, std::setw
#include <sstream> // std::stringstream
namespace Inferno {
template<typename T>
std::string intToHex(T i)
{
std::stringstream stream;
stream << "0x"
<< std::setfill('0') << std::setw(sizeof(T) * 2)
<< std::hex << i;
return stream.str();
}
} // namespace Inferno
#endif // STRING_UTIL_H
-261
View File
@@ -1,261 +0,0 @@
#include <csignal> // signal
#include "GLFW/glfw3.h"
#include "inferno/application.h"
#include "inferno/assert.h"
#include "inferno/core.h"
#include "inferno/event/applicationevent.h"
#include "inferno/event/keyevent.h"
#include "inferno/event/mouseevent.h"
#include "inferno/io/input.h"
#include "inferno/io/log.h"
#include "inferno/keycodes.h"
#include "inferno/render/context.h"
#include "inferno/render/renderer.h"
#include "inferno/settings.h"
#include "inferno/window.h"
namespace Inferno {
unsigned char Window::s_windowCount = 0;
Window::Window()
{
m_properties = {
Settings::get().window.title,
Settings::get().window.width,
Settings::get().window.height,
Settings::get().window.fullscreen,
Settings::get().window.vsync,
};
this->initialize();
}
Window::~Window()
{
this->destroy();
}
// -----------------------------------------
void Window::initialize()
{
std::string title = m_properties.title;
uint32_t width = m_properties.width;
uint32_t height = m_properties.height;
bool vsync = m_properties.vsync;
// Only init once
if (s_windowCount == 0) {
glfwInit();
}
// Set window properties
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
// Create GLFW window
m_window = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);
s_windowCount++;
ASSERT(m_window, "Failed to create GLFW window!");
// Set windowed/fullscreen/borderless
this->setWindowMonitor();
// Associate the wrapper to the window
glfwSetWindowUserPointer(m_window, this);
// Create graphics context
m_context = std::make_shared<Context>(m_window);
m_context->initialize();
// Set vsync, viewport
setVSync(vsync);
RenderCommand::setViewport(0, 0, width, height);
// Signal callbacks
signal(SIGINT, Window::signalCallback);
signal(SIGTERM, Window::signalCallback);
// Error callback
glfwSetErrorCallback([](int error, const char* description) {
dbgln("GLFW Error {}: {}", error, description);
});
// Window close callback
glfwSetWindowCloseCallback(m_window, [](GLFWwindow* window) {
Window& w = *(Window*)glfwGetWindowUserPointer(window);
WindowCloseEvent event;
w.m_eventCallback(event);
});
// Window resize callback
glfwSetWindowSizeCallback(m_window, [](GLFWwindow* window, int width, int height) {
Window& w = *(Window*)glfwGetWindowUserPointer(window);
w.m_properties.width = width;
w.m_properties.height = height;
WindowResizeEvent event(width, height);
w.m_eventCallback(event);
});
// Keyboard callback
glfwSetKeyCallback(m_window, [](GLFWwindow* window, int key, int scanCode, int action, int mods) {
// Suppress unused warning
(void)scanCode;
(void)mods;
Window& w = *(Window*)glfwGetWindowUserPointer(window);
switch (action) {
case GLFW_PRESS: {
KeyPressEvent event(key);
w.m_eventCallback(event);
break;
}
case GLFW_RELEASE: {
KeyReleaseEvent event(key);
w.m_eventCallback(event);
break;
}
case GLFW_REPEAT: {
KeyRepeatEvent event(key);
w.m_eventCallback(event);
break;
}
}
});
// Mouse button callback
glfwSetMouseButtonCallback(m_window, [](GLFWwindow* window, int button, int action, int mods) {
// Suppress unused warning
(void)mods;
Window& w = *(Window*)glfwGetWindowUserPointer(window);
switch (action) {
case GLFW_PRESS: {
MouseButtonPressEvent event(button);
w.m_eventCallback(event);
break;
}
case GLFW_RELEASE: {
MouseButtonReleaseEvent event(button);
w.m_eventCallback(event);
break;
}
}
});
// Mouse position callback
glfwSetCursorPosCallback(m_window, [](GLFWwindow* window, double xPos, double yPos) {
Window& w = *(Window*)glfwGetWindowUserPointer(window);
MousePositionEvent event(xPos, yPos);
w.m_eventCallback(event);
});
// Mouse scroll callback
glfwSetScrollCallback(m_window, [](GLFWwindow* window, double xOffset, double yOffset) {
Window& w = *(Window*)glfwGetWindowUserPointer(window);
MouseScrollEvent event(xOffset, yOffset);
w.m_eventCallback(event);
});
}
void Window::destroy()
{
m_context->destroy();
glfwDestroyWindow(m_window);
s_windowCount--;
if (s_windowCount == 0) {
glfwTerminate();
}
}
void Window::update()
{
glfwPollEvents();
// Capture cursor in window and hide it
if (!Input::isKeyPressed(keyCode("GLFW_KEY_LEFT_SUPER"))) {
glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
}
else {
glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
}
void Window::render()
{
m_context->render();
}
// -----------------------------------------
void Window::signalCallback(int signal)
{
Application::the().setStatus(signal);
if (signal == SIGINT || signal == SIGTERM) {
WindowCloseEvent e;
Application::the().getWindow().m_eventCallback(e);
}
}
void Window::setWindowMonitor() const
{
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
int xPos = 0;
int yPos = 0;
unsigned int width = m_properties.width;
unsigned int height = m_properties.height;
int refresh = GLFW_DONT_CARE;
std::string fullscreen = m_properties.fullscreen;
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
if (fullscreen.compare("fullscreen") == 0) {
refresh = mode->refreshRate;
}
else if (fullscreen.compare("borderless") == 0) {
width = mode->width;
height = mode->height;
refresh = mode->refreshRate;
}
// Default window state is windowed
else {
monitor = nullptr;
// Put window in the center of the monitor
xPos = (mode->width - width) / 2;
yPos = (mode->height - height) / 2;
}
glfwSetWindowMonitor(m_window, monitor, xPos, yPos, width, height, refresh);
}
void Window::setVSync(bool enabled)
{
enabled ? glfwSwapInterval(GL_TRUE) : glfwSwapInterval(GL_FALSE);
m_properties.vsync = enabled;
}
void Window::setShouldClose(bool close) const
{
glfwSetWindowShouldClose(m_window, close ? GL_TRUE : GL_FALSE);
}
bool Window::shouldClose() const {
return glfwWindowShouldClose(m_window);
}
}
-66
View File
@@ -1,66 +0,0 @@
#ifndef WINDOW_H
#define WINDOW_H
#include <cstdint> // uint32_t
#include <functional> // std::function
#include <memory> // std::shared_ptr
#include <string> // std::string
struct GLFWwindow;
namespace Inferno {
class Context;
class Event;
struct WindowProperties {
std::string title { "Inferno" };
uint32_t width = 1280;
uint32_t height = 720;
std::string fullscreen { "windowed" }; // windowed/fullscreen/borderless
bool vsync = true;
};
class Window {
public:
Window();
virtual ~Window();
// -----------------------------------------
void initialize();
void destroy();
void update();
void render();
// -----------------------------------------
static void signalCallback(int signal);
void setWindowMonitor() const;
void setVSync(bool enabled);
void setShouldClose(bool close) const;
bool shouldClose() const;
inline float getAspect() const { return static_cast<float>(m_properties.width) / static_cast<float>(m_properties.height); }
inline uint32_t getWidth() const { return m_properties.width; }
inline uint32_t getHeight() const { return m_properties.height; }
inline GLFWwindow* getWindow() const { return m_window; }
inline std::shared_ptr<Context> getContext() const { return m_context; }
inline void setEventCallback(const std::function<void(Event&)>& callback) { m_eventCallback = callback; }
private:
WindowProperties m_properties;
GLFWwindow* m_window;
std::shared_ptr<Context> m_context;
std::function<void(Event&)> m_eventCallback;
static unsigned char s_windowCount;
};
}
#endif // WINDOW_H
+8 -8
View File
@@ -9,9 +9,12 @@
scriptPath="$(cd -P -- "$(dirname -- "$0")" && pwd -P)"
cd "$scriptPath/.." || exit 1
green=$(tput setf 2)
red=$(tput setf 4)
nc=$(tput sgr0)
# Get all files staged for commit
files="$(git --no-pager diff --cached --name-only)"
green="$(tput setf 2)"
red="$(tput setf 4)"
nc="$(tput sgr0)"
failures=0
@@ -21,7 +24,7 @@ lint-shell-script.sh
for linter in $linters; do
echo "Running script/$linter"
if "script/$linter"; then
if "script/$linter" "$files"; then
echo "[${green}PASS${nc}]: script/$linter"
else
echo "[${red}FAIL${nc}]: script/$linter"
@@ -29,12 +32,9 @@ for linter in $linters; do
fi
done
# Get all files staged for commit
files="$(git diff --cached --name-only)"
echo "Running script/lint-clang-format.sh"
# shellcheck disable=SC2086
if script/lint-clang-format.sh && git diff --exit-code $files; then
if script/lint-clang-format.sh "$files" && git diff --exit-code $files; then
echo "[${green}PASS${nc}]: script/lint-clang-format.sh"
else
echo "[${red}FAIL${nc}]: script/lint-clang-format.sh"
+2 -1
View File
@@ -24,7 +24,8 @@ else
exit 1
fi
files=$(git ls-files -- '*.cpp' '*.h' ':!:inferno/vendor')
files="${1:-$(git --no-pager diff --cached --name-only)}"
files="$(echo "$files" | grep -E '\.(cpp|h)$')"
if [ -z "$files" ]; then
echo "No .cpp or .h files to check."
+2 -1
View File
@@ -15,7 +15,8 @@ if ! command -v shellcheck > /dev/null 2>&1; then
exit 1
fi
files=$(git ls-files -- '*.sh' ':!:inferno/vendor')
files="${1:-$(git --no-pager diff --cached --name-only)}"
files="$(echo "$files" | grep -E '\.sh$')"
if [ -z "$files" ]; then
echo "No .sh files to check."
+24 -13
View File
@@ -7,23 +7,24 @@
scriptName="$(basename "$0")"
help() {
b=$(tput bold)
u=$(tput smul)
nc=$(tput sgr0)
b="$(tput bold)"
u="$(tput smul)"
red="$(tput setf 4)"
n="$(tput sgr0)"
help() {
cat << EOF
${b}NAME${nc}
${b}NAME${n}
${scriptName} - manage pre-commit hooks
${b}SYNOPSIS${nc}
${b}${scriptName}${nc} ${u}COMMAND${nc}
${b}SYNOPSIS${n}
${b}${scriptName}${n} ${u}COMMAND${n}
${b}COMMANDS${nc}
${b}install${nc}
${b}COMMANDS${n}
${b}install${n}
Install all pre-commit hooks.
${b}remove${nc}
${b}remove${n}
Remove all pre-commit hooks.
EOF
}
@@ -31,8 +32,18 @@ EOF
# Exit if no option is provided
[ "$#" -eq 0 ] && help && exit 1
if [ ! -d ".git" ]; then
echo "${b}${red}Error:${n} please run this script from the project root." >&2
exit 1
fi
currentDir="$(pwd -P)"
# Get the path from the project root to the script
subDir="$(dirname -- "$0")"
# Get the full path to this script while handling spaces and symlinks correctly
scriptPath="$(cd -P -- "$(dirname -- "$0")" && pwd -P)"
scriptPath="$(cd -P -- "$subDir" && pwd -P)"
cd "$scriptPath/.." || exit 1
hooks="
@@ -42,7 +53,7 @@ lint-ci.sh
install() {
echo "Installing pre-commit hooks"
preCommit=".git/hooks/pre-commit"
preCommit="$currentDir/.git/hooks/pre-commit"
if ! test -f "$preCommit"; then
touch "$preCommit"
chmod +x "$preCommit"
@@ -51,7 +62,7 @@ install() {
for hook in $hooks; do
sed -Ei "/$hook/d" "$preCommit"
sed -Ei "\$ a script/$hook" "$preCommit"
sed -Ei "\$ a $subDir/$hook" "$preCommit"
done
}
+35
View File
@@ -0,0 +1,35 @@
file(GLOB_RECURSE ENGINE_SOURCES "${ENGINE}/*.cpp")
add_library(${ENGINE} ${ENGINE_SOURCES})
target_include_directories(${ENGINE} PRIVATE
"."
"../vendor/entt/src"
"../vendor/glad/include"
"../vendor/glfw/include"
"../vendor/glm"
"../vendor/json/include"
"../vendor/lua"
"../vendor/ruc/src"
"../vendor/sol2/include"
"../vendor/stb")
target_link_libraries(${ENGINE} ${ENGINE}-dependencies)
# ------------------------------------------
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>>"
)
+1 -6
View File
@@ -1,5 +1,4 @@
#ifndef INFERNO_H
#define INFERNO_H
#pragma once
// For use by the game
@@ -8,9 +7,5 @@
#include "inferno/core.h"
#include "inferno/application.h"
#include "inferno/assert.h"
#include "inferno/io/log.h"
// -----------------------------------------
#endif // INFERNO_H
+233
View File
@@ -0,0 +1,233 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include "glm/gtc/type_ptr.hpp" // glm::make_mat4
#include "ruc/format/log.h"
#include "ruc/meta/assert.h"
#include "inferno/application.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/io/gltffile.h"
#include "inferno/io/input.h"
#include "inferno/keycodes.h"
#include "inferno/render/buffer.h"
#include "inferno/render/context.h"
#include "inferno/render/font.h"
// #include "inferno/render/gltf.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_instance = nullptr;
Application::Application()
{
// Set singleton instance
VERIFY(!s_instance, "reinstantiation of Application");
s_instance = this;
// Initialize
Settings::initialize();
m_window = std::make_unique<Window>();
m_window->setEventCallback(NF_BIND_EVENT(Application::onEvent));
Input::initialize();
RenderCommand::initialize();
m_scene = std::make_shared<Scene>();
m_scene->initialize();
// Load assets
// m_font = FontManager::the().load("assets/fnt/dejavu-sans");
// auto bla = GlTFFile::read("assets/gltf/box.glb");
// ruc::success("@{}@", bla.first.get());
// auto bla2 = GlTFFile::read("assets/gltf/boxtextured.glb");
// ruc::info("@{}@", bla2.first.get());
// auto bla3 = GlTFFile::read("assets/gltf/guinea-pig-cage-fleece.glb");
// ruc::warn("@{}@", bla3.first.get());
// Gltf model = Gltf("assets/gltf/box.glb");
// Gltf model = Gltf("assets/gltf/animatedmorphcube.glb");
// Gltf model = Gltf("assets/gltf/reciprocatingsaw.glb");
// Gltf model = Gltf("assets/gltf/triangle-without-indices.gltf");
}
Application::~Application()
{
m_scene->destroy();
FontManager::destroy();
RendererCharacter::destroy();
Renderer2D::destroy();
RenderCommand::destroy();
TextureManager::destroy();
ShaderManager::destroy();
// Input::destroy();
Settings::destroy();
s_instance = nullptr;
}
int Application::run()
{
ruc::debug("Application startup");
#if 0
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');
// ruc::debug(c->position << " " << c->size);
uint32_t textureWidth = f->texture()->width();
uint32_t textureHeight = f->texture()->height();
VERIFY(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
};
// ruc::debug(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
#endif
while (!m_window->shouldClose()) {
float time = Time::time();
float deltaTime = time - m_lastFrameTime;
m_lastFrameTime = time;
// ruc::debug("Frametime " << deltaTime * 1000 << "ms");
// Update
update();
Input::update();
m_window->update();
m_scene->update(deltaTime);
// Render
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();
}
ruc::debug("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;
ruc::info("WindowCloseEvent");
m_window->setShouldClose(true);
return true;
}
bool Application::onWindowResize(WindowResizeEvent& e)
{
ruc::info("WindowResizeEvent {}x{}", e.getWidth(), e.getHeight());
RenderCommand::setViewport(0, 0, e.getWidth(), e.getHeight());
return true;
}
bool Application::onKeyPress(KeyPressEvent& e)
{
ruc::info("KeyPressEvent {:3} {}", e.getKey(), keyName(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)
{
// ruc::info("MousePositionEvent {:.0}x{:.0}", e.getXPos(), e.getYPos());
return Input::onMousePosition(e);
}
} // namespace Inferno
+112
View File
@@ -0,0 +1,112 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <memory> // std::unique_ptr, std::shared_ptr
#include "ruc/singleton.h"
namespace Inferno {
class Event;
class Font;
class KeyPressEvent;
class MousePositionEvent;
class Scene;
class Window;
class WindowCloseEvent;
class WindowResizeEvent;
class Application {
public:
virtual ~Application();
virtual void update() = 0;
virtual void render() = 0;
int run();
void onEvent(Event& e);
virtual bool onWindowClose(WindowCloseEvent& e);
virtual bool onWindowResize(WindowResizeEvent& e);
virtual bool onKeyPress(KeyPressEvent& e);
virtual bool onMousePosition(MousePositionEvent& e);
inline void setStatus(int status) { m_status = status; }
inline Window& window() const { return *m_window; }
static Application& the() { return *s_instance; }
protected:
Application();
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;
//
static Application* s_instance;
};
// To be defined in the game
extern Application* createApplication(int argc, char* argv[]);
} // namespace Inferno
// C++17 features used:
// - std::string_view -> log.h
// - std::shared_ptr array management -> renderer.h
// - EnTT library
// - structured binding -> render.cpp, camera.cpp
// - std::optional -> textareasystem.cpp
// OpenGL 4.5 features used:
// -
// Cmake 3.16 features used:
// - Precompiled headers
// Gameplan
// - GPUDriver (?)
// v Renderer
// v Buffers
// ~ Shader
// - Schene (camera, lights, environment)
// - Model loading
// - Serialization
// - Level format
// - Tools (Tiled?)
// - Global object access can be done in 4 ways:
// - Singleton, static class, extern, regular global
// @Todo
// - RefPtr<>
// - keycodes.h stringify helper in code.h (util/types.h, util/defines.h)
// https://github.com/SerenityOS/serenity/blob/master/Kernel/Assertions.h#L29
// - Call delete on pointers that make the singletons, so valgrind will say "All heap blocks were freed -- no leaks are possible", in "HEAP SUMMARY"
// - TagComponent, string -> char[]
// - Move Gltf parsing and json helper to /parser directory
// - Initialize primitive types, raw pointers are uninitialized, so need to be explicitly initialized to nullptr
// - Run clang-format on every file
// profiling: 1:33:08 - JS bytecode VM part 7
// $ valgrind --tool=callgrind <executable>
// $ kcachegrind callgrind.out.<number>
// GUI
// Framebuffer on entire screen, manage every individual pixel
// - classes: Window, Button, Label
// - event loop: select based
+35
View File
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#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
};
} // namespace Inferno
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#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))
{
}
};
} // namespace Inferno
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "ruc/meta/assert.h"
#include "inferno/script/nativescript.h"
namespace Inferno {
struct NativeScriptComponent {
NativeScript* instance { nullptr };
NativeScript* (*initialize)() { nullptr };
// Dont allow manually setting instance during construction
NativeScriptComponent() {}
template<typename T>
void bind()
{
VERIFY(instance == nullptr, "NativeScript already bound");
initialize = []() { return static_cast<NativeScript*>(new T()); };
}
void destroy()
{
VERIFY(instance, "Attempting to destroy an uninitialized NativeScript");
delete instance;
instance = nullptr;
}
};
} // namespace Inferno
+48
View File
@@ -0,0 +1,48 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include "inferno/component/spritecomponent.h"
#include "inferno/render/texture.h"
namespace Inferno {
void fromJson(const ruc::Json& json, SpriteComponent& value)
{
VERIFY(json.type() == ruc::Json::Type::Object);
if (json.exists("color")) {
json.at("color").getTo(value.color);
}
if (json.exists("texture") && json.at("texture").type() == ruc::Json::Type::String) {
value.texture = TextureManager::the().load(json.at("texture").asString());
}
}
} // namespace Inferno
namespace glm {
void toJson(ruc::Json& json, const vec4& value)
{
json = ruc::Json {
{ value.r, value.g, value.b, value.a },
};
}
void fromJson(const ruc::Json& json, vec4& value)
{
VERIFY(json.type() == ruc::Json::Type::Array);
auto& values = json.asArray();
VERIFY(values.size() == 4, "glm::vec4 expects 4 values, not {}", values.size());
value.r = values.at(0).get<float>();
value.g = values.at(1).get<float>();
value.b = values.at(2).get<float>();
value.a = values.at(3).get<float>();
}
} // namespace glm
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <memory> // std::shared_ptr
#include "glm/ext/vector_float4.hpp" // glm::vec4
#include "ruc/json/json.h"
#include "inferno/render/texture.h"
namespace Inferno {
struct SpriteComponent {
glm::vec4 color { 1.0f };
std::shared_ptr<Texture> texture;
};
void fromJson(const ruc::Json& json, SpriteComponent& value);
} // namespace Inferno
namespace glm {
void toJson(ruc::Json& json, const vec4& value);
void fromJson(const ruc::Json& json, vec4& value);
} // namespace glm
+26
View File
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#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; }
};
} // namespace Inferno
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include "ruc/json/json.h"
#include "inferno/component/textareacomponent.h"
namespace Inferno {
void fromJson(const ruc::Json& json, TextAreaComponent& value)
{
VERIFY(json.type() == ruc::Json::Type::Object);
if (json.exists("content") && json.at("content").type() == ruc::Json::Type::String) {
json.at("content").getTo(value.content);
}
if (json.exists("font") && json.at("font").type() == ruc::Json::Type::String) {
json.at("font").getTo(value.font);
}
if (json.exists("font-size") && json.at("font-size").type() == ruc::Json::Type::Number) {
json.at("font-size").getTo(value.fontSize);
}
if (json.exists("width") && json.at("width").type() == ruc::Json::Type::Number) {
json.at("width").getTo(value.width);
}
if (json.exists("lines") && json.at("lines").type() == ruc::Json::Type::Number) {
json.at("lines").getTo(value.width);
}
}
} // namespace Inferno
+46
View File
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <cstdint> // uint32_t
#include <string> // std::string
#include <utility> // std::move
#include "glm/ext/vector_float4.hpp" // glm::vec4
#include "ruc/json/json.h"
namespace Inferno {
struct TextAreaComponent {
std::string content;
std::string font;
uint32_t fontSize { 0 };
uint32_t width { 0 };
uint32_t lines { 0 };
#if 0
TextAreaComponent() {}
TextAreaComponent(const std::string& content, const std::string& font,
uint32_t fontSize, uint32_t width, uint32_t lines)
: content(std::move(content))
, font(std::move(font))
, fontSize(fontSize)
, width(width)
, lines(lines)
{
}
#endif
// booleans?
// glm::vec4 outlineColor { 1.0f, 1.0f, 1.0f, 1.0f };
// glow?
// float dropShadow { 0.0f };
};
void fromJson(const ruc::Json& json, TextAreaComponent& value);
} // namespace Inferno
@@ -0,0 +1,90 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include "ruc/format/format.h"
#include "ruc/json/json.h"
#include "inferno/component/transformcomponent.h"
namespace Inferno {
void fromJson(const ruc::Json& json, TransformComponent& value)
{
VERIFY(json.type() == ruc::Json::Type::Object);
if (json.exists("translate")) {
json.at("translate").getTo(value.translate);
}
if (json.exists("rotate")) {
json.at("rotate").getTo(value.rotate);
}
if (json.exists("scale")) {
json.at("scale").getTo(value.scale);
}
}
} // namespace Inferno
namespace glm {
void toJson(ruc::Json& json, const vec3& value)
{
json = ruc::Json {
{ value.x, value.y, value.z },
};
}
void fromJson(const ruc::Json& json, vec3& value)
{
VERIFY(json.type() == ruc::Json::Type::Array);
auto& values = json.asArray();
VERIFY(values.size() == 3, "glm::vec3 expects 3 values, not {}", values.size());
value.x = values.at(0).get<float>();
value.y = values.at(1).get<float>();
value.z = values.at(2).get<float>();
}
} // namespace glm
void ruc::format::Formatter<glm::vec2>::format(Builder& builder, glm::vec2 value) const
{
return Formatter<std::vector<float>>::format(builder, { value.x, value.y });
}
void ruc::format::Formatter<glm::vec3>::format(Builder& builder, glm::vec3 value) const
{
return Formatter<std::vector<float>>::format(builder, { value.x, value.y, value.z });
}
void ruc::format::Formatter<glm::vec4>::format(Builder& builder, glm::vec4 value) const
{
return Formatter<std::vector<float>>::format(builder, { value.x, value.y, value.z, value.w });
}
void ruc::format::Formatter<glm::mat4>::format(Builder& builder, glm::mat4 value) const
{
builder.putString("mat4 ");
Formatter<glm::vec4>::format(builder, value[0]);
builder.putString("\n ");
Formatter<glm::vec4>::format(builder, value[1]);
builder.putString("\n ");
Formatter<glm::vec4>::format(builder, value[2]);
builder.putString("\n ");
return Formatter<glm::vec4>::format(builder, value[3]);
}
void ruc::format::Formatter<Inferno::TransformComponent>::format(Builder& builder, Inferno::TransformComponent value) const
{
builder.putString("transform ");
Formatter<glm::vec3>::format(builder, value.translate);
builder.putString(" t\n ");
Formatter<glm::vec3>::format(builder, value.rotate);
builder.putString(" r\n ");
Formatter<glm::vec3>::format(builder, value.scale);
builder.putString(" s");
}
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
#include "glm/ext/vector_float3.hpp" // glm::vec3
#include "ruc/format/format.h"
#include "ruc/json/json.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
};
void fromJson(const ruc::Json& json, TransformComponent& value);
} // namespace Inferno
namespace glm {
void toJson(ruc::Json& json, const vec3& value);
void fromJson(const ruc::Json& json, vec3& value);
} // namespace glm
template<>
struct ruc::format::Formatter<glm::vec2> : Formatter<std::vector<float>> {
void format(Builder& builder, glm::vec2 value) const;
};
template<>
struct ruc::format::Formatter<glm::vec3> : Formatter<std::vector<float>> {
void format(Builder& builder, glm::vec3 value) const;
};
template<>
struct ruc::format::Formatter<glm::vec4> : Formatter<std::vector<float>> {
void format(Builder& builder, glm::vec4 value) const;
};
template<>
struct ruc::format::Formatter<glm::mat4> : Formatter<glm::vec4> {
void format(Builder& builder, glm::mat4 value) const;
};
template<>
struct ruc::format::Formatter<Inferno::TransformComponent> : Formatter<glm::vec3> {
void format(Builder& builder, Inferno::TransformComponent value) const;
};
+14
View File
@@ -0,0 +1,14 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <functional> // std::bind, std::placeholders
// @Todo figure out lambda's and replace std::bind
// https://github.com/TheCherno/Hazel/pull/277
// variadic args in lambdas were added in C++17
#define NF_BIND_EVENT(f) std::bind(&f, this, std::placeholders::_1)
+26
View File
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
/*
* `m_` for member variables,
* `s_` for static variables,
* `g_` for global variables.
*/
#pragma once
#include "inferno/application.h"
int main(int argc, char* argv[]) // NOLINT(misc-definitions-in-headers)
{
auto* app = Inferno::createApplication(argc, argv);
int status = app->run();
delete app;
return status;
}
+48
View File
@@ -0,0 +1,48 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#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;
};
} // namespace Inferno
+117
View File
@@ -0,0 +1,117 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <ostream> // std::ostream
#include "ruc/meta/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 category 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();
}
} // namespace Inferno
+65
View File
@@ -0,0 +1,65 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#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)
};
} // namespace Inferno

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