Browse Source

Engine: Run clang-format

master
Riyyi 2 years ago
parent
commit
b72da1278d
  1. 292
      src/inferno/application.cpp
  2. 80
      src/inferno/application.h
  3. 112
      src/inferno/assert.h
  4. 40
      src/inferno/component/cameracomponent.h
  5. 20
      src/inferno/component/luascriptcomponent.h
  6. 43
      src/inferno/component/nativescriptcomponent.h
  7. 8
      src/inferno/component/spritecomponent.h
  8. 16
      src/inferno/component/tagcomponent.h
  9. 36
      src/inferno/component/textareacomponent.h
  10. 76
      src/inferno/component/transformcomponent.cpp
  11. 22
      src/inferno/component/transformcomponent.h
  12. 63
      src/inferno/event/applicationevent.h
  13. 92
      src/inferno/event/joystickevent.h
  14. 124
      src/inferno/event/keyevent.h
  15. 198
      src/inferno/event/mouseevent.h
  16. 74
      src/inferno/io/file.cpp
  17. 88
      src/inferno/io/file.h
  18. 134
      src/inferno/io/gltffile.cpp
  19. 14
      src/inferno/io/gltffile.h
  20. 136
      src/inferno/io/input.cpp
  21. 56
      src/inferno/io/input.h
  22. 526
      src/inferno/io/log.cpp
  23. 264
      src/inferno/io/log.h
  24. 256
      src/inferno/keycodes.cpp
  25. 2
      src/inferno/keycodes.h
  26. 581
      src/inferno/render/buffer.cpp
  27. 208
      src/inferno/render/buffer.h
  28. 80
      src/inferno/render/context.cpp
  29. 20
      src/inferno/render/context.h
  30. 237
      src/inferno/render/font.cpp
  31. 86
      src/inferno/render/font.h
  32. 10
      src/inferno/render/framebuffer.h
  33. 18
      src/inferno/render/gltf.cpp
  34. 56
      src/inferno/render/gltf.h
  35. 675
      src/inferno/render/renderer.cpp
  36. 276
      src/inferno/render/renderer.h
  37. 446
      src/inferno/render/shader.cpp
  38. 114
      src/inferno/render/shader.h
  39. 242
      src/inferno/render/texture.cpp
  40. 90
      src/inferno/render/texture.h
  41. 212
      src/inferno/scene/scene.cpp
  42. 126
      src/inferno/scene/scene.h
  43. 224
      src/inferno/script/cameracontroller.cpp
  44. 38
      src/inferno/script/cameracontroller.h
  45. 128
      src/inferno/script/luascript.cpp
  46. 54
      src/inferno/script/luascript.h
  47. 38
      src/inferno/script/nativescript.h
  48. 209
      src/inferno/script/registration.cpp
  49. 98
      src/inferno/script/registration.h
  50. 146
      src/inferno/settings.cpp
  51. 38
      src/inferno/settings.h
  52. 86
      src/inferno/singleton.h
  53. 127
      src/inferno/system/camerasystem.cpp
  54. 28
      src/inferno/system/camerasystem.h
  55. 26
      src/inferno/system/rendersystem.cpp
  56. 18
      src/inferno/system/rendersystem.h
  57. 126
      src/inferno/system/scriptsystem.cpp
  58. 30
      src/inferno/system/scriptsystem.h
  59. 168
      src/inferno/system/textareasystem.cpp
  60. 26
      src/inferno/system/textareasystem.h
  61. 46
      src/inferno/system/transformsystem.cpp
  62. 18
      src/inferno/system/transformsystem.h
  63. 10
      src/inferno/time.cpp
  64. 8
      src/inferno/time.h
  65. 22
      src/inferno/util/integer.h
  66. 10
      src/inferno/util/json.h
  67. 18
      src/inferno/util/string.h
  68. 393
      src/inferno/window.cpp
  69. 74
      src/inferno/window.h

292
src/inferno/application.cpp

@ -25,196 +25,196 @@
namespace Inferno { namespace Inferno {
Application::Application(s) Application::Application(s)
{ {
// Initialize // 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();
Settings::initialize(); // Load assets
m_window = std::make_unique<Window>(); m_font = FontManager::the().load("assets/fnt/dejavu-sans");
m_window->setEventCallback(NF_BIND_EVENT(Application::onEvent));
Input::initialize(); // auto bla = GlTFFile::read("assets/gltf/box.glb");
RenderCommand::initialize(); // success() << "@" << bla.first.get() << "@";
// auto bla2 = GlTFFile::read("assets/gltf/boxtextured.glb");
// info() << "@" << bla2.first.get() << "@";
// auto bla3 = GlTFFile::read("assets/gltf/guinea-pig-cage-fleece.glb");
// warn() << "@" << bla3.first.get() << "@";
m_scene = std::make_shared<Scene>(); // Gltf model = Gltf("assets/gltf/box.glb");
m_scene->initialize();
// Load assets // Gltf model = Gltf("assets/gltf/animatedmorphcube.glb");
// Gltf model = Gltf("assets/gltf/reciprocatingsaw.glb");
m_font = FontManager::the().load("assets/fnt/dejavu-sans"); // Gltf model = Gltf("assets/gltf/triangle-without-indices.gltf");
}
// auto bla = GlTFFile::read("assets/gltf/box.glb"); Application::~Application()
// success() << "@" << bla.first.get() << "@"; {
// auto bla2 = GlTFFile::read("assets/gltf/boxtextured.glb"); m_scene->destroy();
// info() << "@" << bla2.first.get() << "@";
// auto bla3 = GlTFFile::read("assets/gltf/guinea-pig-cage-fleece.glb");
// warn() << "@" << bla3.first.get() << "@";
// Gltf model = Gltf("assets/gltf/box.glb"); FontManager::destroy();
RendererCharacter::destroy();
Renderer2D::destroy();
RenderCommand::destroy();
TextureManager::destroy();
ShaderManager::destroy();
// Input::destroy();
// Gltf model = Gltf("assets/gltf/animatedmorphcube.glb"); Settings::destroy();
// Gltf model = Gltf("assets/gltf/reciprocatingsaw.glb"); }
// Gltf model = Gltf("assets/gltf/triangle-without-indices.gltf"); int Application::run()
} {
dbg() << "Application startup";
Application::~Application()
{
m_scene->destroy();
FontManager::destroy(); std::array<CharacterVertex, Renderer::vertexPerQuad> character;
RendererCharacter::destroy();
Renderer2D::destroy();
RenderCommand::destroy();
TextureManager::destroy();
ShaderManager::destroy();
// Input::destroy();
Settings::destroy(); // 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 };
int Application::run() auto f = FontManager::the().get("assets/fnt/dejavu-sans");
{ auto c = f->get('5');
dbg() << "Application startup"; // dbg() << c->position << " " << c->size;
std::array<CharacterVertex, Renderer::vertexPerQuad> character; uint32_t textureWidth = f->texture()->width();
uint32_t textureHeight = f->texture()->height();
VERIFY(textureWidth == textureHeight, "Invalid font texture!");
// character.at(0).quad.textureCoordinates = { 0.0f, 0.0f }; // bottom left float quadWidth = (c->size.x / (float)textureWidth) - 0.04; // @Todo something wrong with the width
// character.at(1).quad.textureCoordinates = { 1.0f, 0.0f }; float quadHeight = c->size.y / (float)textureHeight;
// 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"); character.at(0).quad.position = { -quadWidth, -quadHeight, 0.0f }; // bottom left
auto c = f->get('5'); character.at(1).quad.position = { quadWidth, -quadHeight, 0.0f }; // bottom right
// dbg() << c->position << " " << c->size; character.at(2).quad.position = { quadWidth, quadHeight, 0.0f }; // top right
character.at(3).quad.position = { -quadWidth, quadHeight, 0.0f }; // top left
uint32_t textureWidth = f->texture()->width(); glm::vec2 x {
uint32_t textureHeight = f->texture()->height(); 1 - (textureWidth - c->position.x) / (float)textureWidth,
VERIFY(textureWidth == textureHeight, "Invalid font texture!"); 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;
float quadWidth = (c->size.x / (float)textureWidth) - 0.04; // @Todo something wrong with the width character.at(0).quad.textureCoordinates = { x.x, y.x };
float quadHeight = c->size.y / (float)textureHeight; 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 };
character.at(0).quad.position = { -quadWidth, -quadHeight, 0.0f }; // bottom left // pos
character.at(1).quad.position = { quadWidth, -quadHeight, 0.0f }; // bottom right // texcoords
character.at(2).quad.position = { quadWidth, quadHeight, 0.0f }; // top right //
character.at(3).quad.position = { -quadWidth, quadHeight, 0.0f }; // top left // width
// edge
// borderwidth
// borderedge
// bordercolor
// offset
glm::vec2 x { while (!m_window->shouldClose()) {
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 }; float time = Time::time();
character.at(1).quad.textureCoordinates = { x.y, y.x }; float deltaTime = time - m_lastFrameTime;
character.at(2).quad.textureCoordinates = { x.y, y.y }; m_lastFrameTime = time;
character.at(3).quad.textureCoordinates = { x.x, y.y }; // dbg() << "Frametime " << deltaTime * 1000 << "ms";
// pos // Update
// texcoords
//
// width
// edge
// borderwidth
// borderedge
// bordercolor
// offset
while (!m_window->shouldClose()) { Input::update();
m_window->update();
m_scene->update(deltaTime);
float time = Time::time(); // Render
float deltaTime = time - m_lastFrameTime;
m_lastFrameTime = time;
// dbg() << "Frametime " << deltaTime * 1000 << "ms";
// Update RenderCommand::clearColor({ 0.2f, 0.3f, 0.3f, 1.0f });
RenderCommand::clear();
Input::update(); Renderer2D::the().beginScene(m_scene->cameraProjectionView()); // camera, lights, environment
m_window->update(); RendererCharacter::the().beginScene();
m_scene->update(deltaTime);
m_scene->render();
// RendererCharacter::the().drawCharacter(character, f->texture());
// Render Renderer2D::the().endScene();
RendererCharacter::the().endScene();
RenderCommand::clearColor({ 0.2f, 0.3f, 0.3f, 1.0f }); m_window->render();
RenderCommand::clear(); }
Renderer2D::the().beginScene(m_scene->cameraProjectionView()); // camera, lights, environment dbg() << "Application shutdown";
RendererCharacter::the().beginScene();
m_scene->render(); return m_status;
// RendererCharacter::the().drawCharacter(character, f->texture()); }
Renderer2D::the().endScene(); void Application::onEvent(Event& e)
RendererCharacter::the().endScene(); {
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));
}
m_window->render(); bool Application::onWindowClose(WindowCloseEvent& e)
} {
// Suppress unused warning
(void)e;
dbg() << "Application shutdown"; info() << "WindowCloseEvent triggered";
infoln("{}Event triggered", e.toString());
return m_status; m_window->setShouldClose(true);
}
void Application::onEvent(Event& e) return true;
{ }
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) bool Application::onWindowResize(WindowResizeEvent& e)
{ {
// Suppress unused warning // Suppress unused warning
(void)e; (void)e;
info() << "WindowCloseEvent triggered"; infoln("WindowResizeEvent {}x{} triggered", e.getWidth(), e.getHeight());
infoln("{}Event triggered", e.toString());
m_window->setShouldClose(true); RenderCommand::setViewport(0, 0, e.getWidth(), e.getHeight());
return true; return true;
} }
bool Application::onWindowResize(WindowResizeEvent& e) bool Application::onKeyPress(KeyPressEvent& e)
{ {
// Suppress unused warning // Suppress unused warning
(void)e; (void)e;
infoln("WindowResizeEvent {}x{} triggered", e.getWidth(), e.getHeight()); infoln("KeyPressEvent {} ({}) triggered",
Input::getKeyName(e.getKey()),
e.getKey());
RenderCommand::setViewport(0, 0, e.getWidth(), e.getHeight()); // Stop the main loop on 'Escape' keypress
if (e.getKey() == keyCode("GLFW_KEY_ESCAPE")) {
return true; m_window->setShouldClose(true);
} }
bool Application::onKeyPress(KeyPressEvent& e) return true;
{ }
// 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);
bool Application::onMousePosition(MousePositionEvent& e) }
{
return Input::onMousePosition(e);
}
} // namespace Inferno } // namespace Inferno

80
src/inferno/application.h

@ -6,46 +6,46 @@
namespace Inferno { namespace Inferno {
class Event; class Event;
class Font; class Font;
class KeyPressEvent; class KeyPressEvent;
class MousePositionEvent; class MousePositionEvent;
class Scene; class Scene;
class Window; class Window;
class WindowCloseEvent; class WindowCloseEvent;
class WindowResizeEvent; class WindowResizeEvent;
class Application : public ruc::Singleton<Application> { class Application : public ruc::Singleton<Application> {
public: public:
Application(s); Application(s);
virtual ~Application(); virtual ~Application();
int run(); int run();
void onEvent(Event& e); void onEvent(Event& e);
bool onWindowClose(WindowCloseEvent& e); bool onWindowClose(WindowCloseEvent& e);
bool onWindowResize(WindowResizeEvent& e); bool onWindowResize(WindowResizeEvent& e);
bool onKeyPress(KeyPressEvent& e); bool onKeyPress(KeyPressEvent& e);
bool onMousePosition(MousePositionEvent& e); bool onMousePosition(MousePositionEvent& e);
inline void setStatus(int status) { m_status = status; } inline void setStatus(int status) { m_status = status; }
inline Window& getWindow() const { return *m_window; } inline Window& getWindow() const { return *m_window; }
private: private:
int m_status { 0 }; int m_status { 0 };
float m_lastFrameTime { 0.0f }; float m_lastFrameTime { 0.0f };
std::unique_ptr<Window> m_window; std::unique_ptr<Window> m_window;
std::shared_ptr<Scene> m_scene; std::shared_ptr<Scene> m_scene;
// //
std::shared_ptr<Font> m_font; std::shared_ptr<Font> m_font;
// //
}; };
// To be defined in the game // To be defined in the game
extern Application& createApplication(); extern Application& createApplication();
} // namespace Inferno } // namespace Inferno

112
src/inferno/assert.h

@ -33,7 +33,7 @@
#endif #endif
// ##__VA_ARGS__ is a non-standard GCC extension, C++20 introduces __VA_OPT__ // ##__VA_ARGS__ is a non-standard GCC extension, C++20 introduces __VA_OPT__
// https://stackoverflow.com/questions/52891546/what-does-va-args-mean // 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(expr, ...) (static_cast<bool>(expr) ? (void)0 : Inferno::__assert_fail(#expr, __FILE__, __LINE__, FUNCTION_MACRO, ##__VA_ARGS__))
#define ASSERT_NOT_REACHED() ASSERT(false) #define ASSERT_NOT_REACHED() ASSERT(false)
#else #else
@ -51,63 +51,63 @@ inline void __crash()
asm volatile("int $0x03"); asm volatile("int $0x03");
} }
// FIXME: Doesnt print to stderr // FIXME: Doesnt print to stderr
#ifdef NF_ENABLE_ASSERTS #ifdef NF_ENABLE_ASSERTS
template<typename... P> template<typename... P>
inline void __assert_fail(const char* assertion, const char* file, uint32_t line, const char* function, P&&... parameters) inline void __assert_fail(const char* assertion, const char* file, uint32_t line, const char* function, P&&... parameters)
{ {
(void)function; (void)function;
// Get the line that caused the error // Get the line that caused the error
std::ifstream source(file); std::ifstream source(file);
std::string content; std::string content;
if (source.is_open()) { if (source.is_open()) {
for (uint32_t i = 0; std::getline(source, content); ++i) { for (uint32_t i = 0; std::getline(source, content); ++i) {
if (i == line - 1) { if (i == line - 1) {
break; break;
}
}
}
// Replace tab indentation with spaces
size_t tabs = content.find_first_not_of('\t');
if (tabs > 0 && tabs < content.size()) {
content = std::string(tabs * 4, ' ') + content.substr(tabs);
}
// Find the assertion in the line
size_t column = content.find_first_of(assertion);
size_t assertionLength = strlen(assertion);
if (column == std::string::npos) {
column = content.find_first_not_of(' ');
assertionLength = content.length() - column;
}
// Error message
dbgln(false, "\033[0;1m{}:{}:{}: ", file, line, column + 1);
dangerln(false, "error: ");
dbgln(false, "assertion failed");
if (sizeof...(P) > 0) {
dbgln(false, ": ");
dbgln(Log::None, false, std::forward<P>(parameters)...);
} }
// Code line
dbgln("\n {} | {}\033[31;1m{}\033[0m{}", line,
content.substr(0, column), // Whitespace at front
content.substr(column, assertionLength), // Error portion
content.substr(column + assertionLength)); // Rest of the line
// Arrow pointer
dbgln(" {} | {}\033[31;1m^{}\033[0m",
std::string(std::to_string(line).length(), ' '), // Line number spacing
std::string(column, ' '), // Content spacing
std::string(assertionLength - 1, '~')); // Arrow pointer
fflush(stdout); // FIXME: stdout is buffered, strerr is not so wouldnt need this
CRASH();
} }
#endif }
// Replace tab indentation with spaces
size_t tabs = content.find_first_not_of('\t');
if (tabs > 0 && tabs < content.size()) {
content = std::string(tabs * 4, ' ') + content.substr(tabs);
}
// Find the assertion in the line
size_t column = content.find_first_of(assertion);
size_t assertionLength = strlen(assertion);
if (column == std::string::npos) {
column = content.find_first_not_of(' ');
assertionLength = content.length() - column;
}
// Error message
dbgln(false, "\033[0;1m{}:{}:{}: ", file, line, column + 1);
dangerln(false, "error: ");
dbgln(false, "assertion failed");
if (sizeof...(P) > 0) {
dbgln(false, ": ");
dbgln(Log::None, false, std::forward<P>(parameters)...);
}
// Code line
dbgln("\n {} | {}\033[31;1m{}\033[0m{}", line,
content.substr(0, column), // Whitespace at front
content.substr(column, assertionLength), // Error portion
content.substr(column + assertionLength)); // Rest of the line
// Arrow pointer
dbgln(" {} | {}\033[31;1m^{}\033[0m",
std::string(std::to_string(line).length(), ' '), // Line number spacing
std::string(column, ' '), // Content spacing
std::string(assertionLength - 1, '~')); // Arrow pointer
fflush(stdout); // FIXME: stdout is buffered, strerr is not so wouldnt need this
CRASH();
} }
#endif
} // namespace Inferno
// https://github.com/scottt/debugbreak // https://github.com/scottt/debugbreak

40
src/inferno/component/cameracomponent.h

@ -5,25 +5,25 @@
namespace Inferno { namespace Inferno {
enum CameraType { enum CameraType {
Orthographic, Orthographic,
Perspective, Perspective,
}; };
struct CameraComponent { struct CameraComponent {
CameraType type = CameraType::Perspective; CameraType type = CameraType::Perspective;
// Orthographic // Orthographic
float zoomLevel = 1.0f; float zoomLevel = 1.0f;
glm::vec3 rotateAxis { 0.0f, 0.0f, 1.0f }; glm::vec3 rotateAxis { 0.0f, 0.0f, 1.0f };
// Perspective // Perspective
float fov = 90.0f; float fov = 90.0f;
float pitch = 0.0f; float pitch = 0.0f;
float yaw = -90.0f; float yaw = -90.0f;
glm::vec3 up { 0.0f, 1.0f, 0.0f }; glm::vec3 up { 0.0f, 1.0f, 0.0f };
glm::mat4 projection { 1.0f }; // Identity matrix glm::mat4 projection { 1.0f }; // Identity matrix
}; };
} // namespace Inferno } // namespace Inferno

20
src/inferno/component/luascriptcomponent.h

@ -5,15 +5,17 @@
namespace Inferno { namespace Inferno {
class LuaScript; class LuaScript;
struct LuaScriptComponent { struct LuaScriptComponent {
LuaScript* instance { nullptr }; LuaScript* instance { nullptr };
std::string path; std::string path;
// Dont allow manually setting instance during construction // Dont allow manually setting instance during construction
LuaScriptComponent() {} LuaScriptComponent() {}
LuaScriptComponent(const std::string& path) LuaScriptComponent(const std::string& path)
: path(std::move(path)) {} : path(std::move(path))
}; {
}
};
} // namespace Inferno } // namespace Inferno

43
src/inferno/component/nativescriptcomponent.h

@ -6,26 +6,27 @@
namespace Inferno { namespace Inferno {
struct NativeScriptComponent { struct NativeScriptComponent {
NativeScript* instance { nullptr }; NativeScript* instance { nullptr };
NativeScript* (*initialize)(); NativeScript* (*initialize)();
// Dont allow manually setting instance during construction // Dont allow manually setting instance during construction
NativeScriptComponent() {} NativeScriptComponent() {}
template<typename T> template<typename T>
void bind() void bind()
{ {
VERIFY(instance == nullptr, "NativeScript already bound"); VERIFY(instance == nullptr, "NativeScript already bound");
initialize = []() { return static_cast<NativeScript*>(new T()); }; initialize = []() { return static_cast<NativeScript*>(new T()); };
} }
void destroy() { void destroy()
VERIFY(instance, "Attempting to destroy an uninitialized NativeScript"); {
delete instance; VERIFY(instance, "Attempting to destroy an uninitialized NativeScript");
instance = nullptr; delete instance;
} instance = nullptr;
}; }
};
} // namespace Inferno } // namespace Inferno

8
src/inferno/component/spritecomponent.h

@ -8,9 +8,9 @@
namespace Inferno { namespace Inferno {
struct SpriteComponent { struct SpriteComponent {
glm::vec4 color { 1.0f }; glm::vec4 color { 1.0f };
std::shared_ptr<Texture> texture; std::shared_ptr<Texture> texture;
}; };
} // namespace Inferno } // namespace Inferno

16
src/inferno/component/tagcomponent.h

@ -5,14 +5,16 @@
namespace Inferno { namespace Inferno {
struct TagComponent { struct TagComponent {
std::string tag; std::string tag;
TagComponent() = default; TagComponent() = default;
TagComponent(const std::string& tag) TagComponent(const std::string& tag)
: tag(std::move(tag)) {} : tag(std::move(tag))
{
}
operator const std::string&() const { return tag; } operator const std::string&() const { return tag; }
}; };
} // namespace Inferno } // namespace Inferno

36
src/inferno/component/textareacomponent.h

@ -8,22 +8,28 @@
namespace Inferno { namespace Inferno {
struct TextAreaComponent { struct TextAreaComponent {
std::string content { "" }; std::string content { "" };
std::string font { "" }; std::string font { "" };
uint32_t fontSize { 0 }; uint32_t fontSize { 0 };
uint32_t width { 0 }; uint32_t width { 0 };
uint32_t lines { 0 }; uint32_t lines { 0 };
TextAreaComponent() {} TextAreaComponent() {}
TextAreaComponent(const std::string& content, const std::string& font, TextAreaComponent(const std::string& content, const std::string& font,
uint32_t fontSize, uint32_t width, uint32_t lines) uint32_t fontSize, uint32_t width, uint32_t lines)
: content(std::move(content)), font(std::move(font)), fontSize(fontSize), width(width), lines(lines) {} : content(std::move(content))
, font(std::move(font))
, fontSize(fontSize)
, width(width)
, lines(lines)
{
}
// booleans? // booleans?
// glm::vec4 outlineColor { 1.0f, 1.0f, 1.0f, 1.0f }; // glm::vec4 outlineColor { 1.0f, 1.0f, 1.0f, 1.0f };
// glow? // glow?
// float dropShadow { 0.0f }; // float dropShadow { 0.0f };
}; };
} // namespace Inferno } // namespace Inferno

76
src/inferno/component/transformcomponent.cpp

@ -2,46 +2,46 @@
namespace Inferno { namespace Inferno {
const LogStream& operator<<(const LogStream& stream, const glm::vec2& value) const LogStream& operator<<(const LogStream& stream, const glm::vec2& value)
{ {
return stream << "{ " return stream << "{ "
<< (value.x >= 0.0f ? " " : "") << value.x << ", " << (value.x >= 0.0f ? " " : "") << value.x << ", "
<< (value.y >= 0.0f ? " " : "") << value.y << (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) const LogStream& operator<<(const LogStream& stream, const glm::vec3& value)
{ {
return stream << "{ " return stream << "{ "
<< (value.x >= 0.0f ? " " : "") << value.x << ", " << (value.x >= 0.0f ? " " : "") << value.x << ", "
<< (value.y >= 0.0f ? " " : "") << value.y << ", " << (value.y >= 0.0f ? " " : "") << value.y << ", "
<< (value.z >= 0.0f ? " " : "") << value.z << ", " << (value.z >= 0.0f ? " " : "") << value.z
<< (value.w >= 0.0f ? " " : "") << value.w << " }";
<< " }"; }
}
const LogStream& operator<<(const LogStream& stream, const glm::mat4& value) const LogStream& operator<<(const LogStream& stream, const glm::vec4& value)
{ {
return stream << "mat4 " return stream << "{ "
<< value[0] << "\n " << value[1] << "\n " << (value.x >= 0.0f ? " " : "") << value.x << ", "
<< value[2] << "\n " << value[3]; << (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 TransformComponent& value) const LogStream& operator<<(const LogStream& stream, const glm::mat4& value)
{ {
return stream << "transform " return stream << "mat4 "
<< value.translate << " t\n " << value[0] << "\n " << value[1] << "\n "
<< value.rotate << " r\n " << value[2] << "\n " << value[3];
<< value.scale << " s"; }
}
const LogStream& operator<<(const LogStream& stream, const TransformComponent& value)
{
return stream << "transform "
<< value.translate << " t\n "
<< value.rotate << " r\n "
<< value.scale << " s";
} }
} // namespace Inferno

22
src/inferno/component/transformcomponent.h

@ -7,18 +7,18 @@
namespace Inferno { namespace Inferno {
struct TransformComponent { struct TransformComponent {
glm::vec3 translate { 0.0f, 0.0f, 0.0f }; glm::vec3 translate { 0.0f, 0.0f, 0.0f };
glm::vec3 rotate { 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::vec3 scale { 1.0f, 1.0f, 1.0f };
glm::mat4 transform { 1.0f }; // Identity matrix 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::vec2& value);
const LogStream& operator<<(const LogStream& stream, const glm::vec3& 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::vec4& value);
const LogStream& operator<<(const LogStream& stream, const glm::mat4& value); const LogStream& operator<<(const LogStream& stream, const glm::mat4& value);
const LogStream& operator<<(const LogStream& stream, const TransformComponent& value); const LogStream& operator<<(const LogStream& stream, const TransformComponent& value);
} // namespace Inferno } // namespace Inferno

63
src/inferno/event/applicationevent.h

@ -6,34 +6,37 @@
namespace Inferno { namespace Inferno {
class WindowCloseEvent : public Event { class WindowCloseEvent : public Event {
public: public:
EVENT_CLASS_TYPE(WindowClose) EVENT_CLASS_TYPE(WindowClose)
EVENT_CLASS_CATEGORY(ApplicationEventCategory) EVENT_CLASS_CATEGORY(ApplicationEventCategory)
}; };
class WindowResizeEvent : public Event { class WindowResizeEvent : public Event {
public: public:
WindowResizeEvent(int width, int height) : WindowResizeEvent(int width, int height)
m_width(width), m_height(height) {} : m_width(width)
, m_height(height)
virtual std::string toString() const override {
{ }
std::stringstream ss;
ss << "WindowResize: " << m_width << "x" << m_height; virtual std::string toString() const override
return ss.str(); {
} 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) inline int getWidth() const { return m_width; }
EVENT_CLASS_CATEGORY(ApplicationEventCategory) inline int getHeight() const { return m_height; }
private: EVENT_CLASS_TYPE(WindowResize)
int m_width; EVENT_CLASS_CATEGORY(ApplicationEventCategory)
int m_height;
}; private:
int m_width;
int m_height;
};
} // namespace Inferno } // namespace Inferno

92
src/inferno/event/joystickevent.h

@ -6,48 +6,54 @@
namespace Inferno { namespace Inferno {
class JoystickEvent : public Event { class JoystickEvent : public Event {
public: public:
inline int getID() const { return m_id; } inline int getID() const { return m_id; }
EVENT_CLASS_CATEGORY(InputEventCategory | JoystickEventCatergory) EVENT_CLASS_CATEGORY(InputEventCategory | JoystickEventCatergory)
protected: protected:
JoystickEvent(int id) : JoystickEvent(int id)
m_id(id) {} : m_id(id)
{
private: }
int m_id;
}; private:
int m_id;
class JoystickConnectedEvent : public JoystickEvent { };
public:
JoystickConnectedEvent(int id) : class JoystickConnectedEvent : public JoystickEvent {
JoystickEvent(id) {} public:
JoystickConnectedEvent(int id)
virtual std::string toString() const override : JoystickEvent(id)
{ {
std::stringstream ss; }
ss << "JoystickConnected: " << getID();
return ss.str(); virtual std::string toString() const override
} {
std::stringstream ss;
EVENT_CLASS_TYPE(JoystickConnected) ss << "JoystickConnected: " << getID();
}; return ss.str();
}
class JoystickDisconnectedEvent : public JoystickEvent {
public: EVENT_CLASS_TYPE(JoystickConnected)
JoystickDisconnectedEvent(int id) : };
JoystickEvent(id) {}
class JoystickDisconnectedEvent : public JoystickEvent {
virtual std::string toString() const override public:
{ JoystickDisconnectedEvent(int id)
std::stringstream ss; : JoystickEvent(id)
ss << "JoystickDisconnected: " << getID(); {
return ss.str(); }
}
virtual std::string toString() const override
EVENT_CLASS_TYPE(JoystickDisconnected) {
}; std::stringstream ss;
ss << "JoystickDisconnected: " << getID();
return ss.str();
}
EVENT_CLASS_TYPE(JoystickDisconnected)
};
} // namespace Inferno } // namespace Inferno

124
src/inferno/event/keyevent.h

@ -6,63 +6,71 @@
namespace Inferno { namespace Inferno {
class KeyEvent : public Event { class KeyEvent : public Event {
public: public:
inline int getKey() const { return m_key; } inline int getKey() const { return m_key; }
EVENT_CLASS_CATEGORY(InputEventCategory | KeyEventCategory) EVENT_CLASS_CATEGORY(InputEventCategory | KeyEventCategory)
protected: protected:
KeyEvent(int key) : KeyEvent(int key)
m_key(key) {} : m_key(key)
{
private: }
int m_key;
}; private:
int m_key;
class KeyPressEvent : public KeyEvent { };
public:
KeyPressEvent(int key) : class KeyPressEvent : public KeyEvent {
KeyEvent(key) {} public:
KeyPressEvent(int key)
virtual std::string toString() const override : KeyEvent(key)
{ {
std::stringstream ss; }
ss << "KeyPress: " << getKey();
return ss.str(); virtual std::string toString() const override
} {
std::stringstream ss;
EVENT_CLASS_TYPE(KeyPress) ss << "KeyPress: " << getKey();
}; return ss.str();
}
class KeyReleaseEvent : public KeyEvent {
public: EVENT_CLASS_TYPE(KeyPress)
KeyReleaseEvent(int key) : };
KeyEvent(key) {}
class KeyReleaseEvent : public KeyEvent {
virtual std::string toString() const override public:
{ KeyReleaseEvent(int key)
std::stringstream ss; : KeyEvent(key)
ss << "KeyRelease: " << getKey(); {
return ss.str(); }
}
virtual std::string toString() const override
EVENT_CLASS_TYPE(KeyPress) {
}; std::stringstream ss;
ss << "KeyRelease: " << getKey();
class KeyRepeatEvent : public KeyEvent { return ss.str();
public: }
KeyRepeatEvent(int key) :
KeyEvent(key) {} EVENT_CLASS_TYPE(KeyPress)
};
virtual std::string toString() const override
{ class KeyRepeatEvent : public KeyEvent {
std::stringstream ss; public:
ss << "KeyRepeat: " << getKey(); KeyRepeatEvent(int key)
return ss.str(); : KeyEvent(key)
} {
}
EVENT_CLASS_TYPE(KeyPress)
}; virtual std::string toString() const override
{
std::stringstream ss;
ss << "KeyRepeat: " << getKey();
return ss.str();
}
EVENT_CLASS_TYPE(KeyPress)
};
} // namespace Inferno } // namespace Inferno

198
src/inferno/event/mouseevent.h

@ -6,98 +6,110 @@
namespace Inferno { namespace Inferno {
class MouseButtonEvent : public Event { class MouseButtonEvent : public Event {
public: public:
inline int getButton() const { return m_button; } inline int getButton() const { return m_button; }
EVENT_CLASS_CATEGORY(InputEventCategory | MouseEventCategory | MouseButtonEventCategory) EVENT_CLASS_CATEGORY(InputEventCategory | MouseEventCategory | MouseButtonEventCategory)
protected: protected:
MouseButtonEvent(int button) : MouseButtonEvent(int button)
m_button(button) {} : m_button(button)
{
private: }
int m_button;
}; private:
int m_button;
class MouseButtonPressEvent : public MouseButtonEvent { };
public:
MouseButtonPressEvent(int button) : class MouseButtonPressEvent : public MouseButtonEvent {
MouseButtonEvent(button) {} public:
MouseButtonPressEvent(int button)
virtual std::string toString() const override : MouseButtonEvent(button)
{ {
std::stringstream ss; }
ss << "MouseButtonPressed: " << getButton();
return ss.str(); virtual std::string toString() const override
} {
std::stringstream ss;
EVENT_CLASS_TYPE(MouseButtonPress) ss << "MouseButtonPressed: " << getButton();
}; return ss.str();
}
class MouseButtonReleaseEvent : public MouseButtonEvent {
public: EVENT_CLASS_TYPE(MouseButtonPress)
MouseButtonReleaseEvent(int button) : };
MouseButtonEvent(button) {}
class MouseButtonReleaseEvent : public MouseButtonEvent {
virtual std::string toString() const override public:
{ MouseButtonReleaseEvent(int button)
std::stringstream ss; : MouseButtonEvent(button)
ss << "MouseButtonReleased: " << getButton(); {
return ss.str(); }
}
virtual std::string toString() const override
EVENT_CLASS_TYPE(MouseButtonRelease) {
}; std::stringstream ss;
ss << "MouseButtonReleased: " << getButton();
class MousePositionEvent : public Event { return ss.str();
public: }
MousePositionEvent(float xPos, float yPos) :
m_xPos(xPos), m_yPos(yPos) {} EVENT_CLASS_TYPE(MouseButtonRelease)
};
virtual std::string toString() const override
{ class MousePositionEvent : public Event {
std::stringstream ss; public:
ss << "MousePosition: " << m_xPos << "x" << m_yPos; MousePositionEvent(float xPos, float yPos)
return ss.str(); : m_xPos(xPos)
} , m_yPos(yPos)
{
// ----------------------------------------- }
inline float getXPos() const { return m_xPos; } virtual std::string toString() const override
inline float getYPos() const { return m_yPos; } {
std::stringstream ss;
EVENT_CLASS_TYPE(MousePosition) ss << "MousePosition: " << m_xPos << "x" << m_yPos;
EVENT_CLASS_CATEGORY(InputEventCategory | MouseEventCategory) return ss.str();
}
private:
float m_xPos; // -----------------------------------------
float m_yPos;
}; inline float getXPos() const { return m_xPos; }
inline float getYPos() const { return m_yPos; }
class MouseScrollEvent : public Event {
public: EVENT_CLASS_TYPE(MousePosition)
MouseScrollEvent(float xOffset, float yOffset) : EVENT_CLASS_CATEGORY(InputEventCategory | MouseEventCategory)
m_xOffset(xOffset), m_yOffset(yOffset) {}
private:
virtual std::string toString() const override float m_xPos;
{ float m_yPos;
std::stringstream ss; };
ss << "MouseScroll: " << m_xOffset << ":" << m_yOffset;
return ss.str(); class MouseScrollEvent : public Event {
} public:
MouseScrollEvent(float xOffset, float yOffset)
// ----------------------------------------- : m_xOffset(xOffset)
, m_yOffset(yOffset)
inline float getXOffset() const { return m_xOffset; } {
inline float getYOffset() const { return m_yOffset; } }
EVENT_CLASS_TYPE(MouseScroll) virtual std::string toString() const override
EVENT_CLASS_CATEGORY(InputEventCategory | MouseEventCategory) {
std::stringstream ss;
private: ss << "MouseScroll: " << m_xOffset << ":" << m_yOffset;
float m_xOffset; return ss.str();
float m_yOffset; }
};
// -----------------------------------------
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;
};
} // namespace Inferno } // namespace Inferno

74
src/inferno/io/file.cpp

@ -7,42 +7,42 @@
namespace Inferno { namespace Inferno {
std::shared_ptr<char[]> File::raw(const std::string& path) std::shared_ptr<char[]> File::raw(const std::string& path)
{ {
// Create input stream object and open file // Create input stream object and open file
std::ifstream file(path); std::ifstream file(path);
VERIFY(file.is_open(), "File could not open '{}'", path); VERIFY(file.is_open(), "File could not open '{}'", path);
// Get length of the file // Get length of the file
int32_t length = File::length(path, file); int32_t length = File::length(path, file);
// Allocate memory filled with zeros // Allocate memory filled with zeros
auto buffer = std::shared_ptr<char[]>(new char[length + 1]); auto buffer = std::shared_ptr<char[]>(new char[length + 1]);
// Fill buffer with file contents // Fill buffer with file contents
file.read(buffer.get(), length); file.read(buffer.get(), length);
file.close(); file.close();
// Null termination // Null termination
buffer[length] = '\0'; buffer[length] = '\0';
return buffer; return buffer;
} }
std::string File::read(const std::string &path) std::string File::read(const std::string& path)
{ {
// Create string from the buffer and return // Create string from the buffer and return
return std::string(raw(path).get()); return std::string(raw(path).get());
} }
int32_t File::length(const std::string& path, std::ifstream& file) int32_t File::length(const std::string& path, std::ifstream& file)
{ {
file.seekg(0, std::ios::end); file.seekg(0, std::ios::end);
int32_t length = file.tellg(); int32_t length = file.tellg();
file.seekg(0, std::ios::beg); file.seekg(0, std::ios::beg);
VERIFY(length != -1, "File could not determine length '{}'", path); VERIFY(length != -1, "File could not determine length '{}'", path);
return length; return length;
} }
} // namespace Inferno } // namespace Inferno

88
src/inferno/io/file.h

@ -11,52 +11,52 @@
namespace Inferno { namespace Inferno {
class File { class File {
public: public:
static std::shared_ptr<char[]> raw(const std::string& path); static std::shared_ptr<char[]> raw(const std::string& path);
static std::string read(const std::string& path); static std::string read(const std::string& path);
static int32_t length(const std::string& path, std::ifstream& file); static int32_t length(const std::string& path, std::ifstream& file);
template<typename T> template<typename T>
static bool ioRead(T* t, const std::string& path) static bool ioRead(T* t, const std::string& path)
{ {
std::ifstream file(path); std::ifstream file(path);
VERIFY(file.is_open(), "File could not open '{}'", path); VERIFY(file.is_open(), "File could not open '{}'", path);
if (!file.is_open()) { if (!file.is_open()) {
return false; return false;
}
try {
file >> *t;
}
catch (...) {
return false;
}
return true;
} }
template<typename T> try {
static bool ioWrite(T* t, const std::string& path) file >> *t;
{
std::ofstream file (path);
VERIFY(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;
} }
}; catch (...) {
return false;
}
return true;
}
template<typename T>
static bool ioWrite(T* t, const std::string& path)
{
std::ofstream file(path);
VERIFY(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;
}
};
} // namespace Inferno } // namespace Inferno

134
src/inferno/io/gltffile.cpp

@ -12,93 +12,93 @@
namespace Inferno { namespace Inferno {
std::pair<std::shared_ptr<char[]>, std::shared_ptr<char[]>> GltfFile::read(const std::string& path) 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(".")); std::string extension = path.substr(path.find_first_of("."));
if (extension.compare(".glb") == 0) { if (extension.compare(".glb") == 0) {
return glb(path); return glb(path);
} }
else if (extension.compare(".gltf") == 0) { else if (extension.compare(".gltf") == 0) {
return { File::raw(path), nullptr }; return { File::raw(path), nullptr };
}
VERIFY(false, "GltfFile unknown file extension!");
return {};
} }
std::pair<std::shared_ptr<char[]>, std::shared_ptr<char[]>> GltfFile::glb(const std::string& path) VERIFY(false, "GltfFile unknown file extension!");
{ return {};
// Create input stream object and open file }
std::ifstream glb(path, std::ios::in | std::ios::binary);
VERIFY(glb.is_open(), "GltfFile could not open '{}'", path);
constexpr uint32_t size = 4; std::pair<std::shared_ptr<char[]>, std::shared_ptr<char[]>> GltfFile::glb(const std::string& path)
constexpr uint32_t header = 12; {
constexpr uint32_t json = 27; // Minimum valid glTF has an asset property with version specifier // Create input stream object and open file
std::ifstream glb(path, std::ios::in | std::ios::binary);
VERIFY(glb.is_open(), "GltfFile could not open '{}'", path);
// Get the actual length of the file constexpr uint32_t size = 4;
uint32_t length = static_cast<uint32_t>(File::length(path, glb)); constexpr uint32_t header = 12;
VERIFY(length > header + json, "GltfFile too small to be valid '{}'", path); constexpr uint32_t json = 27; // Minimum valid glTF has an asset property with version specifier
// Read header // Get the actual length of the file
uint32_t length = static_cast<uint32_t>(File::length(path, glb));
VERIFY(length > header + json, "GltfFile too small to be valid '{}'", path);
char magic[size]; // Read header
char version[size];
char fileLength[size];
glb.read(magic, size); char magic[size];
glb.seekg(size * 1); char version[size];
glb.read(version, size); char fileLength[size];
glb.seekg(size * 2);
glb.read(fileLength, size);
// Validate header glb.read(magic, size);
glb.seekg(size * 1);
glb.read(version, size);
glb.seekg(size * 2);
glb.read(fileLength, size);
uint32_t magicInt = *reinterpret_cast<uint32_t*>(magic); // Validate header
VERIFY(magicInt == 0x46546c67, "Gltf invalid header magic '{}'", magic);
uint32_t versionInt = *reinterpret_cast<uint32_t*>(version); uint32_t magicInt = *reinterpret_cast<uint32_t*>(magic);
VERIFY(versionInt == 2, "Gltf unsupported version '{}'", versionInt); VERIFY(magicInt == 0x46546c67, "Gltf invalid header magic '{}'", magic);
uint32_t fileLengthInt = *reinterpret_cast<uint32_t*>(fileLength); uint32_t versionInt = *reinterpret_cast<uint32_t*>(version);
VERIFY(fileLengthInt == length, "Gltf file and reported byte size mismatch '{}' '{}'", length, fileLengthInt); VERIFY(versionInt == 2, "Gltf unsupported version '{}'", versionInt);
// Read JSON data uint32_t fileLengthInt = *reinterpret_cast<uint32_t*>(fileLength);
auto jsonChunk = readChunk(glb, header, 0x4e4f534a); VERIFY(fileLengthInt == length, "Gltf file and reported byte size mismatch '{}' '{}'", length, fileLengthInt);
VERIFY(jsonChunk.second >= json, "Gltf file invalid JSON content length '{}'", jsonChunk.second);
// Read binary data // Read JSON data
auto binaryChunk = readChunk(glb, header + size * 2 + jsonChunk.second, 0x004e4942); auto jsonChunk = readChunk(glb, header, 0x4e4f534a);
VERIFY(jsonChunk.second >= json, "Gltf file invalid JSON content length '{}'", jsonChunk.second);
glb.close(); // Read binary data
auto binaryChunk = readChunk(glb, header + size * 2 + jsonChunk.second, 0x004e4942);
return { jsonChunk.first, binaryChunk.first }; glb.close();
}
std::pair<std::shared_ptr<char[]>, uint32_t> GltfFile::readChunk(std::ifstream& ifstream, uint32_t offset, uint32_t type) return { jsonChunk.first, binaryChunk.first };
{ }
constexpr uint32_t size = 4;
char chunkLength[size]; std::pair<std::shared_ptr<char[]>, uint32_t> GltfFile::readChunk(std::ifstream& ifstream, uint32_t offset, uint32_t type)
char chunkType[size]; {
constexpr uint32_t size = 4;
ifstream.seekg(offset); char chunkLength[size];
ifstream.read(chunkLength, size); char chunkType[size];
ifstream.seekg(offset + size * 1);
ifstream.read(chunkType, size);
uint32_t chunkTypeInt = *reinterpret_cast<uint32_t*>(chunkType); ifstream.seekg(offset);
VERIFY(chunkTypeInt == type, "Gltf invalid chunk type '{}' != '{}'", chunkType, intToHex(type)); ifstream.read(chunkLength, size);
ifstream.seekg(offset + size * 1);
ifstream.read(chunkType, size);
uint32_t chunkLengthInt = *reinterpret_cast<uint32_t*>(chunkLength); uint32_t chunkTypeInt = *reinterpret_cast<uint32_t*>(chunkType);
// Allocate memory filled with zeros VERIFY(chunkTypeInt == type, "Gltf invalid chunk type '{}' != '{}'", chunkType, intToHex(type));
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 }; 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 } // namespace Inferno

14
src/inferno/io/gltffile.h

@ -7,13 +7,13 @@
namespace Inferno { namespace Inferno {
class GltfFile { class GltfFile {
public: public:
static std::pair<std::shared_ptr<char[]>, std::shared_ptr<char[]>> read(const std::string& path); static std::pair<std::shared_ptr<char[]>, std::shared_ptr<char[]>> read(const std::string& path);
private: private:
static std::pair<std::shared_ptr<char[]>, std::shared_ptr<char[]>> glb(const std::string& path); 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); static std::pair<std::shared_ptr<char[]>, uint32_t> readChunk(std::ifstream& ifstream, uint32_t offset, uint32_t type);
}; };
} // namespace Inferno } // namespace Inferno

136
src/inferno/io/input.cpp

@ -8,85 +8,85 @@
namespace Inferno { namespace Inferno {
bool Input::m_firstMousePos = true; bool Input::m_firstMousePos = true;
float Input::m_xPosLast = 0.0f; float Input::m_xPosLast = 0.0f;
float Input::m_yPosLast = 0.0f; float Input::m_yPosLast = 0.0f;
float Input::m_xOffset = 0.0f; float Input::m_xOffset = 0.0f;
float Input::m_yOffset = 0.0f; float Input::m_yOffset = 0.0f;
void Input::initialize() void Input::initialize()
{ {
// Set cursor in the middle of the screen // Set cursor in the middle of the screen
m_xPosLast = Application::the().getWindow().getWidth() / 2.0f; m_xPosLast = Application::the().getWindow().getWidth() / 2.0f;
m_yPosLast = Application::the().getWindow().getHeight() / 2.0f; m_yPosLast = Application::the().getWindow().getHeight() / 2.0f;
info() << "Input initialized"; info() << "Input initialized";
} }
void Input::update() void Input::update()
{ {
// Stop infinite mouse movement // Stop infinite mouse movement
m_xOffset = 0.0f; m_xOffset = 0.0f;
m_yOffset = 0.0f; m_yOffset = 0.0f;
} }
bool Input::onMousePosition(MousePositionEvent& e) bool Input::onMousePosition(MousePositionEvent& e)
{ {
// Prevent weird jump on first cursor window enter // Prevent weird jump on first cursor window enter
if(m_firstMousePos) { if (m_firstMousePos) {
m_firstMousePos = false; 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_xPosLast = e.getXPos();
m_yPosLast = e.getYPos(); m_yPosLast = e.getYPos();
return true;
} }
bool Input::isKeyPressed(int key) m_xOffset = e.getXPos() - m_xPosLast;
{ // Reversed since y-coordinates range from bottom to top
GLFWwindow* w = Application::the().getWindow().getWindow(); m_yOffset = m_yPosLast - e.getYPos();
return glfwGetKey(w, key) == GLFW_PRESS; m_xPosLast = e.getXPos();
} m_yPosLast = e.getYPos();
bool Input::isMouseButtonPressed(int button) return true;
{ }
GLFWwindow* w = Application::the().getWindow().getWindow();
return glfwGetMouseButton(w, button) == GLFW_PRESS;
}
std::pair<float, float> Input::getMousePosition() bool Input::isKeyPressed(int key)
{ {
GLFWwindow* w = Application::the().getWindow().getWindow(); GLFWwindow* w = Application::the().getWindow().getWindow();
double xPos; return glfwGetKey(w, key) == GLFW_PRESS;
double yPos; }
glfwGetCursorPos(w, &xPos, &yPos);
return { (float)xPos, (float)yPos };
}
float Input::getMouseX() bool Input::isMouseButtonPressed(int button)
{ {
return getMousePosition().first; GLFWwindow* w = Application::the().getWindow().getWindow();
} return glfwGetMouseButton(w, button) == GLFW_PRESS;
}
float Input::getMouseY() std::pair<float, float> Input::getMousePosition()
{ {
return getMousePosition().second; GLFWwindow* w = Application::the().getWindow().getWindow();
} double xPos;
double yPos;
glfwGetCursorPos(w, &xPos, &yPos);
return { (float)xPos, (float)yPos };
}
const char* Input::getKeyName(int key) float Input::getMouseX()
{ {
return glfwGetKeyName(key, getKeyScancode(key)); return getMousePosition().first;
} }
int Input::getKeyScancode(int key) float Input::getMouseY()
{ {
return glfwGetKeyScancode(key); return getMousePosition().second;
} }
const char* Input::getKeyName(int key)
{
return glfwGetKeyName(key, getKeyScancode(key));
} }
int Input::getKeyScancode(int key)
{
return glfwGetKeyScancode(key);
}
} // namespace Inferno

56
src/inferno/io/input.h

@ -4,33 +4,33 @@
namespace Inferno { namespace Inferno {
class MousePositionEvent; class MousePositionEvent;
class Input { class Input {
public: public:
static void initialize(); static void initialize();
static void update(); static void update();
static bool onMousePosition(MousePositionEvent& e); static bool onMousePosition(MousePositionEvent& e);
static bool isKeyPressed(int key); static bool isKeyPressed(int key);
static bool isMouseButtonPressed(int button); static bool isMouseButtonPressed(int button);
static std::pair<float, float> getMousePosition(); static std::pair<float, float> getMousePosition();
static float getMouseX(); static float getMouseX();
static float getMouseY(); static float getMouseY();
static const char* getKeyName(int key); static const char* getKeyName(int key);
static int getKeyScancode(int key); static int getKeyScancode(int key);
static inline float getXOffset() { return m_xOffset; } static inline float getXOffset() { return m_xOffset; }
static inline float getYOffset() { return m_yOffset; } static inline float getYOffset() { return m_yOffset; }
private: private:
static bool m_firstMousePos; static bool m_firstMousePos;
static float m_xPosLast; static float m_xPosLast;
static float m_yPosLast; static float m_yPosLast;
static float m_xOffset; static float m_xOffset;
static float m_yOffset; static float m_yOffset;
}; };
} // namespace Inferno } // namespace Inferno

526
src/inferno/io/log.cpp

@ -11,311 +11,311 @@
namespace Inferno { namespace Inferno {
BufferedLogStream::~BufferedLogStream() BufferedLogStream::~BufferedLogStream()
{ {
// Free buffer memory // Free buffer memory
if (m_capacity > sizeof(m_buffer.stack)) { if (m_capacity > sizeof(m_buffer.stack)) {
free(m_buffer.heap); free(m_buffer.heap);
}
} }
}
void BufferedLogStream::grow(size_t bytes) const void BufferedLogStream::grow(size_t bytes) const
{ {
// Bitwise & ~ example, we use 127 as binary starts at 0 // Bitwise & ~ example, we use 127 as binary starts at 0
// 0b001111111 127 ~ // 0b001111111 127 ~
// 0b100000100 260 & // 0b100000100 260 &
// ----------- // -----------
// 0b110000000 384 // 0b110000000 384
// 0b100000100 260 & // 0b100000100 260 &
// ----------- // -----------
// 0b100000000 256 // 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() // Buffer is increased in chunks of 128 bytes
{ size_t newCapacity = (m_count + bytes + BUFFER_SIZE - 1) & ~(BUFFER_SIZE - 1);
if (m_type != Log::None) {
const char* clear = "\033[0m";
write(clear, strlen(clear));
}
if (m_newline) { unsigned char* newBuffer = static_cast<unsigned char*>(malloc(newCapacity));
char newline = '\n';
write(&newline, 1);
}
fwrite(buffer(), 1, count(), stdout); // 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
void DebugLogStream::color() const else if (m_buffer.heap) {
{ memcpy(newBuffer, m_buffer.heap, m_count);
const char* color = ""; free(m_buffer.heap);
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));
} }
// ----------------------------------------- m_buffer.heap = newBuffer;
m_capacity = newCapacity;
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) DebugLogStream::~DebugLogStream()
{ {
if (value == nullptr) { if (m_type != Log::None) {
stream.write("(null)", 6); const char* clear = "\033[0m";
return stream; write(clear, strlen(clear));
}
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) if (m_newline) {
{ char newline = '\n';
char buffer[32]; write(&newline, 1);
snprintf(buffer, sizeof(buffer), "%lld", value);
return stream << buffer;
} }
const LogStream& operator<<(const LogStream& stream, unsigned int value) fwrite(buffer(), 1, count(), stdout);
{ }
char buffer[32];
snprintf(buffer, sizeof(buffer), "%u", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, long unsigned int value) void DebugLogStream::color() const
{ {
char buffer[32]; const char* color = "";
snprintf(buffer, sizeof(buffer), "%lu", value);
return stream << buffer;
}
const LogStream& operator<<(const LogStream& stream, long long unsigned int value) if (m_type == Log::Info) {
{ color = "\x1B[34m";
char buffer[32];
snprintf(buffer, sizeof(buffer), "%llu", value);
return stream << buffer;
} }
else if (m_type == Log::Warn) {
const LogStream& operator<<(const LogStream& stream, double value) color = "\x1B[33m";
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%.4f", value);
return stream << buffer;
} }
else if (m_type == Log::Danger) {
const LogStream& operator<<(const LogStream& stream, float value) color = "\x1B[31m";
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%.4f", value);
return stream << buffer;
} }
else if (m_type == Log::Success) {
const LogStream& operator<<(const LogStream& stream, const void* value) color = "\x1B[32m";
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%p", value);
return stream << buffer;
} }
else if (m_type == Log::Comment) {
const LogStream& operator<<(const LogStream& stream, bool value) color = "\x1B[37m";
{
return stream << (value ? "true": "false");
} }
const LogStream& operator<<(const LogStream& stream, Log value) write(color, strlen(color));
{ }
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:
VERIFY_NOT_REACHED();
return stream;
}
}
// ----------------------------------------- // -----------------------------------------
DebugLogStream dbg() StringLogStream::~StringLogStream()
{ {
return {}; char terminator = '\0';
} write(&terminator, 1);
*m_fill = std::string(reinterpret_cast<char*>(buffer()));
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() const LogStream& operator<<(const LogStream& stream, const char* value)
{ {
return DebugLogStream(Log::Comment); if (value == nullptr) {
stream.write("(null)", 6);
return stream;
} }
DebugLogStream info(bool newline) stream.write(value, strlen(value));
{ return stream;
return DebugLogStream(Log::Info, newline); }
}
DebugLogStream warn(bool newline) const LogStream& operator<<(const LogStream& stream, const unsigned char* value)
{ {
return DebugLogStream(Log::Warn, newline); if (value == nullptr) {
stream.write("(null)", 6);
return stream;
} }
DebugLogStream danger(bool newline) stream.write(value, strlen((const char*)value));
{ return stream;
return DebugLogStream(Log::Danger, newline); }
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:
VERIFY_NOT_REACHED();
return stream;
} }
}
DebugLogStream success(bool newline) // -----------------------------------------
{
return DebugLogStream(Log::Success, newline);
}
DebugLogStream comment(bool newline) DebugLogStream dbg()
{ {
return DebugLogStream(Log::Comment, newline); 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 dbgln(Log type, bool newline)
{ {
(void)type, DebugLogStream(newline); (void)type, DebugLogStream(newline);
} }
void dbgln(Log type, bool newline, const char* format) void dbgln(Log type, bool newline, const char* format)
{ {
DebugLogStream(type, newline) << format; DebugLogStream(type, newline) << format;
} }
// ----------------------------------------- // -----------------------------------------
StringLogStream str(std::string* fill) StringLogStream str(std::string* fill)
{ {
return StringLogStream(fill); return StringLogStream(fill);
} }
} // namespace Inferno } // namespace Inferno

264
src/inferno/io/log.h

@ -10,148 +10,164 @@
namespace Inferno { namespace Inferno {
enum class Log { enum class Log {
None, None,
Info, Info,
Warn, Warn,
Danger, Danger,
Success, Success,
Comment, Comment,
}; };
// ----------------------------------------- // -----------------------------------------
class LogStream { class LogStream {
public: public:
LogStream() {} LogStream() {}
virtual ~LogStream() {} virtual ~LogStream() {}
virtual void write(const char* characters, int length) const = 0; virtual void write(const char* characters, int length) const = 0;
virtual void write(const unsigned char* characters, int length) const = 0; virtual void write(const unsigned char* characters, int length) const = 0;
}; };
// ----------------------------------------- // -----------------------------------------
class BufferedLogStream : public LogStream { class BufferedLogStream : public LogStream {
public: public:
BufferedLogStream() {} BufferedLogStream() {}
virtual ~BufferedLogStream(); virtual ~BufferedLogStream();
inline virtual void write(const char* characters, int length) const override inline virtual void write(const char* characters, int length) const override
{ {
write(reinterpret_cast<const unsigned char*>(characters), length); 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 inline virtual void write(const unsigned char* characters, int length) const override
memcpy(buffer() + m_count, characters, length); {
size_t newSize = m_count + length;
m_count = newSize; if (newSize > m_capacity) {
grow(length);
} }
protected: // Append to buffer
inline unsigned char* buffer() const memcpy(buffer() + m_count, characters, length);
{
if (m_capacity <= sizeof(m_buffer.stack)) {
return m_buffer.stack;
}
return m_buffer.heap; m_count = newSize;
}
protected:
inline unsigned char* buffer() const
{
if (m_capacity <= sizeof(m_buffer.stack)) {
return m_buffer.stack;
} }
inline bool empty() const { return m_count == 0; } return m_buffer.heap;
inline size_t count() const { return m_count; } }
inline bool empty() const { return m_count == 0; }
inline size_t count() const { return m_count; }
private: private:
void grow(size_t bytes) const; void grow(size_t bytes) const;
mutable size_t m_count { 0 }; mutable size_t m_count { 0 };
mutable size_t m_capacity { BUFFER_SIZE }; mutable size_t m_capacity { BUFFER_SIZE };
union { union {
mutable unsigned char* heap { nullptr }; mutable unsigned char* heap { nullptr };
mutable unsigned char stack[BUFFER_SIZE]; mutable unsigned char stack[BUFFER_SIZE];
} m_buffer; } m_buffer;
}; };
// ----------------------------------------- // -----------------------------------------
class DebugLogStream final : public BufferedLogStream { class DebugLogStream final : public BufferedLogStream {
public: public:
DebugLogStream() DebugLogStream()
: m_newline(true), m_type(Log::None) {} : m_newline(true)
DebugLogStream(bool newline) , m_type(Log::None)
: m_newline(newline), m_type(Log::None) {} {
DebugLogStream(Log type) }
: m_newline(true), m_type(type) { color(); } DebugLogStream(bool newline)
DebugLogStream(Log type, bool newline) : m_newline(newline)
: m_newline(newline), m_type(type) { color(); } , m_type(Log::None)
virtual ~DebugLogStream() override; {
}
void color() const; DebugLogStream(Log type)
: m_newline(true)
private: , m_type(type)
bool m_newline; {
Log m_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 { class StringLogStream final : public BufferedLogStream {
public: public:
StringLogStream(std::string* fill) StringLogStream(std::string* fill)
: m_fill(fill) {} : m_fill(fill)
virtual ~StringLogStream() override; {
}
virtual ~StringLogStream() override;
private: private:
std::string* m_fill { nullptr }; std::string* m_fill { nullptr };
}; };
// ----------------------------------------- // -----------------------------------------
const LogStream& operator<<(const LogStream& stream, const char* value); 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 unsigned char* value);
const LogStream& operator<<(const LogStream& stream, const std::string& 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, const std::string_view& value);
const LogStream& operator<<(const LogStream& stream, char value); const LogStream& operator<<(const LogStream& stream, char value);
const LogStream& operator<<(const LogStream& stream, unsigned 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, int value);
const LogStream& operator<<(const LogStream& stream, long 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, long long int value);
const LogStream& operator<<(const LogStream& stream, unsigned 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 unsigned int value);
const LogStream& operator<<(const LogStream& stream, long 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, double value);
const LogStream& operator<<(const LogStream& stream, float value); const LogStream& operator<<(const LogStream& stream, float value);
const LogStream& operator<<(const LogStream& stream, const void* value); const LogStream& operator<<(const LogStream& stream, const void* value);
const LogStream& operator<<(const LogStream& stream, bool value); const LogStream& operator<<(const LogStream& stream, bool value);
const LogStream& operator<<(const LogStream& stream, Log value); const LogStream& operator<<(const LogStream& stream, Log value);
// ----------------------------------------- // -----------------------------------------
DebugLogStream dbg(); DebugLogStream dbg();
DebugLogStream info(); DebugLogStream info();
DebugLogStream warn(); DebugLogStream warn();
DebugLogStream danger(); DebugLogStream danger();
DebugLogStream success(); DebugLogStream success();
DebugLogStream comment(); DebugLogStream comment();
DebugLogStream dbg(bool newline); DebugLogStream dbg(bool newline);
DebugLogStream info(bool newline); DebugLogStream info(bool newline);
DebugLogStream warn(bool newline); DebugLogStream warn(bool newline);
DebugLogStream danger(bool newline); DebugLogStream danger(bool newline);
DebugLogStream success(bool newline); DebugLogStream success(bool newline);
DebugLogStream comment(bool newline); DebugLogStream comment(bool newline);
// ----------------------------------------- // -----------------------------------------
// clang-format off // clang-format off
template<typename... P> void dbgln(const char* format, P&&... parameters) { dbgln(Log::None, true, format, std::forward<P>(parameters)...); } 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 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 warnln(const char* format, P&&... parameters) { dbgln(Log::Warn, true, format, std::forward<P>(parameters)...); }
@ -193,32 +209,32 @@ namespace Inferno {
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 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 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)...); } template<typename... P> void commentln(bool newline, const std::string_view& format, P&&... parameters) { dbgln(Log::Comment, newline, format.data(), std::forward<P>(parameters)...); }
// clang-format on // clang-format on
// ----------------------------------------- // -----------------------------------------
void dbgln(Log type, bool newline); void dbgln(Log type, bool newline);
void dbgln(Log type, bool newline, const char* format); void dbgln(Log type, bool newline, const char* format);
// https://en.cppreference.com/w/cpp/language/parameter_pack#Example // https://en.cppreference.com/w/cpp/language/parameter_pack#Example
template<typename T, typename... P> template<typename T, typename... P>
void dbgln(Log type, bool newline, const char* format, T value, P&&... parameters) void dbgln(Log type, bool newline, const char* format, T value, P&&... parameters)
{ {
std::string_view view { format }; std::string_view view { format };
for(uint32_t i = 0; format[i] != '\0'; i++) { for (uint32_t i = 0; format[i] != '\0'; i++) {
if (format[i] == '{' && format[i + 1] == '}') { if (format[i] == '{' && format[i + 1] == '}') {
DebugLogStream(type, false) << view.substr(0, i) << value; DebugLogStream(type, false) << view.substr(0, i) << value;
dbgln(type, newline, format + i + 2, parameters...); dbgln(type, newline, format + i + 2, parameters...);
return; return;
}
} }
} }
// possible c++17 improvent https://riptutorial.com/cplusplus/example/3208/iterating-over-a-parameter-pack }
// possible c++17 improvent https://riptutorial.com/cplusplus/example/3208/iterating-over-a-parameter-pack
// ----------------------------------------- // -----------------------------------------
StringLogStream str(std::string* fill); StringLogStream str(std::string* fill);
} // namespace Inferno } // namespace Inferno

256
src/inferno/keycodes.cpp

@ -8,136 +8,136 @@
namespace Inferno { namespace Inferno {
static std::unordered_map<std::string, int> keys ({ static std::unordered_map<std::string, int> keys({
{ MAP_KEY(GLFW_KEY_UNKNOWN) }, { MAP_KEY(GLFW_KEY_UNKNOWN) },
{ MAP_KEY(GLFW_KEY_SPACE) }, { MAP_KEY(GLFW_KEY_SPACE) },
{ MAP_KEY(GLFW_KEY_APOSTROPHE) }, { MAP_KEY(GLFW_KEY_APOSTROPHE) },
{ MAP_KEY(GLFW_KEY_COMMA) }, { MAP_KEY(GLFW_KEY_COMMA) },
{ MAP_KEY(GLFW_KEY_MINUS) }, { MAP_KEY(GLFW_KEY_MINUS) },
{ MAP_KEY(GLFW_KEY_PERIOD) }, { MAP_KEY(GLFW_KEY_PERIOD) },
{ MAP_KEY(GLFW_KEY_SLASH) }, { MAP_KEY(GLFW_KEY_SLASH) },
{ MAP_KEY(GLFW_KEY_0) }, { MAP_KEY(GLFW_KEY_0) },
{ MAP_KEY(GLFW_KEY_1) }, { MAP_KEY(GLFW_KEY_1) },
{ MAP_KEY(GLFW_KEY_2) }, { MAP_KEY(GLFW_KEY_2) },
{ MAP_KEY(GLFW_KEY_3) }, { MAP_KEY(GLFW_KEY_3) },
{ MAP_KEY(GLFW_KEY_4) }, { MAP_KEY(GLFW_KEY_4) },
{ MAP_KEY(GLFW_KEY_5) }, { MAP_KEY(GLFW_KEY_5) },
{ MAP_KEY(GLFW_KEY_6) }, { MAP_KEY(GLFW_KEY_6) },
{ MAP_KEY(GLFW_KEY_7) }, { MAP_KEY(GLFW_KEY_7) },
{ MAP_KEY(GLFW_KEY_8) }, { MAP_KEY(GLFW_KEY_8) },
{ MAP_KEY(GLFW_KEY_9) }, { MAP_KEY(GLFW_KEY_9) },
{ MAP_KEY(GLFW_KEY_SEMICOLON) }, { MAP_KEY(GLFW_KEY_SEMICOLON) },
{ MAP_KEY(GLFW_KEY_EQUAL) }, { MAP_KEY(GLFW_KEY_EQUAL) },
{ MAP_KEY(GLFW_KEY_A) }, { MAP_KEY(GLFW_KEY_A) },
{ MAP_KEY(GLFW_KEY_B) }, { MAP_KEY(GLFW_KEY_B) },
{ MAP_KEY(GLFW_KEY_C) }, { MAP_KEY(GLFW_KEY_C) },
{ MAP_KEY(GLFW_KEY_D) }, { MAP_KEY(GLFW_KEY_D) },
{ MAP_KEY(GLFW_KEY_E) }, { MAP_KEY(GLFW_KEY_E) },
{ MAP_KEY(GLFW_KEY_F) }, { MAP_KEY(GLFW_KEY_F) },
{ MAP_KEY(GLFW_KEY_G) }, { MAP_KEY(GLFW_KEY_G) },
{ MAP_KEY(GLFW_KEY_H) }, { MAP_KEY(GLFW_KEY_H) },
{ MAP_KEY(GLFW_KEY_I) }, { MAP_KEY(GLFW_KEY_I) },
{ MAP_KEY(GLFW_KEY_J) }, { MAP_KEY(GLFW_KEY_J) },
{ MAP_KEY(GLFW_KEY_K) }, { MAP_KEY(GLFW_KEY_K) },
{ MAP_KEY(GLFW_KEY_L) }, { MAP_KEY(GLFW_KEY_L) },
{ MAP_KEY(GLFW_KEY_M) }, { MAP_KEY(GLFW_KEY_M) },
{ MAP_KEY(GLFW_KEY_N) }, { MAP_KEY(GLFW_KEY_N) },
{ MAP_KEY(GLFW_KEY_O) }, { MAP_KEY(GLFW_KEY_O) },
{ MAP_KEY(GLFW_KEY_P) }, { MAP_KEY(GLFW_KEY_P) },
{ MAP_KEY(GLFW_KEY_Q) }, { MAP_KEY(GLFW_KEY_Q) },
{ MAP_KEY(GLFW_KEY_R) }, { MAP_KEY(GLFW_KEY_R) },
{ MAP_KEY(GLFW_KEY_S) }, { MAP_KEY(GLFW_KEY_S) },
{ MAP_KEY(GLFW_KEY_T) }, { MAP_KEY(GLFW_KEY_T) },
{ MAP_KEY(GLFW_KEY_U) }, { MAP_KEY(GLFW_KEY_U) },
{ MAP_KEY(GLFW_KEY_V) }, { MAP_KEY(GLFW_KEY_V) },
{ MAP_KEY(GLFW_KEY_W) }, { MAP_KEY(GLFW_KEY_W) },
{ MAP_KEY(GLFW_KEY_X) }, { MAP_KEY(GLFW_KEY_X) },
{ MAP_KEY(GLFW_KEY_Y) }, { MAP_KEY(GLFW_KEY_Y) },
{ MAP_KEY(GLFW_KEY_Z) }, { MAP_KEY(GLFW_KEY_Z) },
{ MAP_KEY(GLFW_KEY_LEFT_BRACKET) }, { MAP_KEY(GLFW_KEY_LEFT_BRACKET) },
{ MAP_KEY(GLFW_KEY_BACKSLASH) }, { MAP_KEY(GLFW_KEY_BACKSLASH) },
{ MAP_KEY(GLFW_KEY_RIGHT_BRACKET) }, { MAP_KEY(GLFW_KEY_RIGHT_BRACKET) },
{ MAP_KEY(GLFW_KEY_GRAVE_ACCENT) }, { MAP_KEY(GLFW_KEY_GRAVE_ACCENT) },
{ MAP_KEY(GLFW_KEY_WORLD_1) }, { MAP_KEY(GLFW_KEY_WORLD_1) },
{ MAP_KEY(GLFW_KEY_WORLD_2) }, { MAP_KEY(GLFW_KEY_WORLD_2) },
{ MAP_KEY(GLFW_KEY_ESCAPE) }, { MAP_KEY(GLFW_KEY_ESCAPE) },
{ MAP_KEY(GLFW_KEY_ENTER) }, { MAP_KEY(GLFW_KEY_ENTER) },
{ MAP_KEY(GLFW_KEY_TAB) }, { MAP_KEY(GLFW_KEY_TAB) },
{ MAP_KEY(GLFW_KEY_BACKSPACE) }, { MAP_KEY(GLFW_KEY_BACKSPACE) },
{ MAP_KEY(GLFW_KEY_INSERT) }, { MAP_KEY(GLFW_KEY_INSERT) },
{ MAP_KEY(GLFW_KEY_DELETE) }, { MAP_KEY(GLFW_KEY_DELETE) },
{ MAP_KEY(GLFW_KEY_RIGHT) }, { MAP_KEY(GLFW_KEY_RIGHT) },
{ MAP_KEY(GLFW_KEY_LEFT) }, { MAP_KEY(GLFW_KEY_LEFT) },
{ MAP_KEY(GLFW_KEY_DOWN) }, { MAP_KEY(GLFW_KEY_DOWN) },
{ MAP_KEY(GLFW_KEY_UP) }, { MAP_KEY(GLFW_KEY_UP) },
{ MAP_KEY(GLFW_KEY_PAGE_UP) }, { MAP_KEY(GLFW_KEY_PAGE_UP) },
{ MAP_KEY(GLFW_KEY_PAGE_DOWN) }, { MAP_KEY(GLFW_KEY_PAGE_DOWN) },
{ MAP_KEY(GLFW_KEY_HOME) }, { MAP_KEY(GLFW_KEY_HOME) },
{ MAP_KEY(GLFW_KEY_END) }, { MAP_KEY(GLFW_KEY_END) },
{ MAP_KEY(GLFW_KEY_CAPS_LOCK) }, { MAP_KEY(GLFW_KEY_CAPS_LOCK) },
{ MAP_KEY(GLFW_KEY_SCROLL_LOCK) }, { MAP_KEY(GLFW_KEY_SCROLL_LOCK) },
{ MAP_KEY(GLFW_KEY_NUM_LOCK) }, { MAP_KEY(GLFW_KEY_NUM_LOCK) },
{ MAP_KEY(GLFW_KEY_PRINT_SCREEN) }, { MAP_KEY(GLFW_KEY_PRINT_SCREEN) },
{ MAP_KEY(GLFW_KEY_PAUSE) }, { MAP_KEY(GLFW_KEY_PAUSE) },
{ MAP_KEY(GLFW_KEY_F1) }, { MAP_KEY(GLFW_KEY_F1) },
{ MAP_KEY(GLFW_KEY_F2) }, { MAP_KEY(GLFW_KEY_F2) },
{ MAP_KEY(GLFW_KEY_F3) }, { MAP_KEY(GLFW_KEY_F3) },
{ MAP_KEY(GLFW_KEY_F4) }, { MAP_KEY(GLFW_KEY_F4) },
{ MAP_KEY(GLFW_KEY_F5) }, { MAP_KEY(GLFW_KEY_F5) },
{ MAP_KEY(GLFW_KEY_F6) }, { MAP_KEY(GLFW_KEY_F6) },
{ MAP_KEY(GLFW_KEY_F7) }, { MAP_KEY(GLFW_KEY_F7) },
{ MAP_KEY(GLFW_KEY_F8) }, { MAP_KEY(GLFW_KEY_F8) },
{ MAP_KEY(GLFW_KEY_F9) }, { MAP_KEY(GLFW_KEY_F9) },
{ MAP_KEY(GLFW_KEY_F10) }, { MAP_KEY(GLFW_KEY_F10) },
{ MAP_KEY(GLFW_KEY_F11) }, { MAP_KEY(GLFW_KEY_F11) },
{ MAP_KEY(GLFW_KEY_F12) }, { MAP_KEY(GLFW_KEY_F12) },
{ MAP_KEY(GLFW_KEY_F13) }, { MAP_KEY(GLFW_KEY_F13) },
{ MAP_KEY(GLFW_KEY_F14) }, { MAP_KEY(GLFW_KEY_F14) },
{ MAP_KEY(GLFW_KEY_F15) }, { MAP_KEY(GLFW_KEY_F15) },
{ MAP_KEY(GLFW_KEY_F16) }, { MAP_KEY(GLFW_KEY_F16) },
{ MAP_KEY(GLFW_KEY_F17) }, { MAP_KEY(GLFW_KEY_F17) },
{ MAP_KEY(GLFW_KEY_F18) }, { MAP_KEY(GLFW_KEY_F18) },
{ MAP_KEY(GLFW_KEY_F19) }, { MAP_KEY(GLFW_KEY_F19) },
{ MAP_KEY(GLFW_KEY_F20) }, { MAP_KEY(GLFW_KEY_F20) },
{ MAP_KEY(GLFW_KEY_F21) }, { MAP_KEY(GLFW_KEY_F21) },
{ MAP_KEY(GLFW_KEY_F22) }, { MAP_KEY(GLFW_KEY_F22) },
{ MAP_KEY(GLFW_KEY_F23) }, { MAP_KEY(GLFW_KEY_F23) },
{ MAP_KEY(GLFW_KEY_F24) }, { MAP_KEY(GLFW_KEY_F24) },
{ MAP_KEY(GLFW_KEY_F25) }, { MAP_KEY(GLFW_KEY_F25) },
{ MAP_KEY(GLFW_KEY_KP_0) }, { MAP_KEY(GLFW_KEY_KP_0) },
{ MAP_KEY(GLFW_KEY_KP_1) }, { MAP_KEY(GLFW_KEY_KP_1) },
{ MAP_KEY(GLFW_KEY_KP_2) }, { MAP_KEY(GLFW_KEY_KP_2) },
{ MAP_KEY(GLFW_KEY_KP_3) }, { MAP_KEY(GLFW_KEY_KP_3) },
{ MAP_KEY(GLFW_KEY_KP_4) }, { MAP_KEY(GLFW_KEY_KP_4) },
{ MAP_KEY(GLFW_KEY_KP_5) }, { MAP_KEY(GLFW_KEY_KP_5) },
{ MAP_KEY(GLFW_KEY_KP_6) }, { MAP_KEY(GLFW_KEY_KP_6) },
{ MAP_KEY(GLFW_KEY_KP_7) }, { MAP_KEY(GLFW_KEY_KP_7) },
{ MAP_KEY(GLFW_KEY_KP_8) }, { MAP_KEY(GLFW_KEY_KP_8) },
{ MAP_KEY(GLFW_KEY_KP_9) }, { MAP_KEY(GLFW_KEY_KP_9) },
{ MAP_KEY(GLFW_KEY_KP_DECIMAL) }, { MAP_KEY(GLFW_KEY_KP_DECIMAL) },
{ MAP_KEY(GLFW_KEY_KP_DIVIDE) }, { MAP_KEY(GLFW_KEY_KP_DIVIDE) },
{ MAP_KEY(GLFW_KEY_KP_MULTIPLY) }, { MAP_KEY(GLFW_KEY_KP_MULTIPLY) },
{ MAP_KEY(GLFW_KEY_KP_SUBTRACT) }, { MAP_KEY(GLFW_KEY_KP_SUBTRACT) },
{ MAP_KEY(GLFW_KEY_KP_ADD) }, { MAP_KEY(GLFW_KEY_KP_ADD) },
{ MAP_KEY(GLFW_KEY_KP_ENTER) }, { MAP_KEY(GLFW_KEY_KP_ENTER) },
{ MAP_KEY(GLFW_KEY_KP_EQUAL) }, { MAP_KEY(GLFW_KEY_KP_EQUAL) },
{ MAP_KEY(GLFW_KEY_LEFT_SHIFT) }, { MAP_KEY(GLFW_KEY_LEFT_SHIFT) },
{ MAP_KEY(GLFW_KEY_LEFT_CONTROL) }, { MAP_KEY(GLFW_KEY_LEFT_CONTROL) },
{ MAP_KEY(GLFW_KEY_LEFT_ALT) }, { MAP_KEY(GLFW_KEY_LEFT_ALT) },
{ MAP_KEY(GLFW_KEY_LEFT_SUPER) }, { MAP_KEY(GLFW_KEY_LEFT_SUPER) },
{ MAP_KEY(GLFW_KEY_RIGHT_SHIFT) }, { MAP_KEY(GLFW_KEY_RIGHT_SHIFT) },
{ MAP_KEY(GLFW_KEY_RIGHT_CONTROL) }, { MAP_KEY(GLFW_KEY_RIGHT_CONTROL) },
{ MAP_KEY(GLFW_KEY_RIGHT_ALT) }, { MAP_KEY(GLFW_KEY_RIGHT_ALT) },
{ MAP_KEY(GLFW_KEY_RIGHT_SUPER) }, { MAP_KEY(GLFW_KEY_RIGHT_SUPER) },
{ MAP_KEY(GLFW_KEY_MENU) }, { MAP_KEY(GLFW_KEY_MENU) },
}); });
// ----------------------------------------- // -----------------------------------------
int keyCode(const char* name) int keyCode(const char* name)
{ {
VERIFY(keys.find(name) != keys.end(), "keyCode could not find '{}'", name); VERIFY(keys.find(name) != keys.end(), "keyCode could not find '{}'", name);
return keys.at(name); return keys.at(name);
} }
} // namespace Inferno } // namespace Inferno

2
src/inferno/keycodes.h

@ -4,6 +4,6 @@
namespace Inferno { namespace Inferno {
int keyCode(const char* name); int keyCode(const char* name);
} }

581
src/inferno/render/buffer.cpp

@ -1,298 +1,379 @@
#include "glad/glad.h" #include "glad/glad.h"
#include "ruc/meta/assert.h"
#include "inferno/core.h" #include "inferno/core.h"
#include "inferno/io/log.h" #include "inferno/io/log.h"
#include "inferno/render/buffer.h" #include "inferno/render/buffer.h"
#include "ruc/meta/assert.h"
namespace Inferno { namespace Inferno {
// ----------------------------------------- // -----------------------------------------
BufferElement::BufferElement(BufferElementType type, std::string name, bool normalized) : BufferElement::BufferElement(BufferElementType type, std::string name, bool normalized)
m_type(type), : m_type(type)
m_name(name), , m_name(name)
m_size(BufferElement::getTypeSize(type)), , m_size(BufferElement::getTypeSize(type))
m_normalized(normalized) , m_normalized(normalized)
{ {
} }
uint32_t BufferElement::getTypeSize() const uint32_t BufferElement::getTypeSize() const
{ {
return BufferElement::getTypeSize(m_type); return BufferElement::getTypeSize(m_type);
} }
uint32_t BufferElement::getTypeCount() const uint32_t BufferElement::getTypeCount() const
{ {
return BufferElement::getTypeCount(m_type); return BufferElement::getTypeCount(m_type);
} }
uint32_t BufferElement::getTypeGL() const uint32_t BufferElement::getTypeGL() const
{ {
return BufferElement::getTypeGL(m_type); return BufferElement::getTypeGL(m_type);
} }
uint32_t BufferElement::getTypeSize(const BufferElementType type) uint32_t BufferElement::getTypeSize(const BufferElementType type)
{ {
switch (type) { switch (type) {
case BufferElementType::None: return 0; case BufferElementType::None:
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;
};
VERIFY(false, "BufferElement unknown BufferElementType size!");
return 0; return 0;
} case BufferElementType::Bool:
return sizeof(bool);
uint32_t BufferElement::getTypeCount(const BufferElementType type) case BufferElementType::Bool2:
{ return sizeof(bool) * 2;
switch (type) { case BufferElementType::Bool3:
case BufferElementType::None: return 0; return sizeof(bool) * 3;
case BufferElementType::Bool: return 1; case BufferElementType::Bool4:
case BufferElementType::Bool2: return 2; return sizeof(bool) * 4;
case BufferElementType::Bool3: return 3; case BufferElementType::Int:
case BufferElementType::Bool4: return 4; return sizeof(int32_t);
case BufferElementType::Int: return 1; case BufferElementType::Int2:
case BufferElementType::Int2: return 2; return sizeof(int32_t) * 2;
case BufferElementType::Int3: return 3; case BufferElementType::Int3:
case BufferElementType::Int4: return 4; return sizeof(int32_t) * 3;
case BufferElementType::Uint: return 1; case BufferElementType::Int4:
case BufferElementType::Uint2: return 2; return sizeof(int32_t) * 4;
case BufferElementType::Uint3: return 3; case BufferElementType::Uint:
case BufferElementType::Uint4: return 4; return sizeof(uint32_t);
case BufferElementType::Float: return 1; case BufferElementType::Uint2:
case BufferElementType::Vec2: return 2; return sizeof(uint32_t) * 2;
case BufferElementType::Vec3: return 3; case BufferElementType::Uint3:
case BufferElementType::Vec4: return 4; return sizeof(uint32_t) * 3;
case BufferElementType::Double: return 1; case BufferElementType::Uint4:
case BufferElementType::Double2: return 2; return sizeof(uint32_t) * 4;
case BufferElementType::Double3: return 3; case BufferElementType::Float:
case BufferElementType::Double4: return 4; return sizeof(float);
case BufferElementType::Mat2: return 2 * 2; case BufferElementType::Vec2:
case BufferElementType::Mat3: return 3 * 3; return sizeof(float) * 2;
case BufferElementType::Mat4: return 4 * 4; case BufferElementType::Vec3:
case BufferElementType::DoubleMat2: return 2 * 2; return sizeof(float) * 3;
case BufferElementType::DoubleMat3: return 3 * 3; case BufferElementType::Vec4:
case BufferElementType::DoubleMat4: return 4 * 4; return sizeof(float) * 4;
}; case BufferElementType::Double:
return sizeof(double);
VERIFY(false, "BufferElement unknown BufferElementType count!"); 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;
};
VERIFY(false, "BufferElement unknown BufferElementType size!");
return 0;
}
uint32_t BufferElement::getTypeCount(const BufferElementType type)
{
switch (type) {
case BufferElementType::None:
return 0; return 0;
} case BufferElementType::Bool:
return 1;
uint32_t BufferElement::getTypeGL(const BufferElementType type) case BufferElementType::Bool2:
{ return 2;
switch (type) { case BufferElementType::Bool3:
case BufferElementType::None: return GL_NONE; return 3;
case BufferElementType::Bool: return GL_BOOL; case BufferElementType::Bool4:
case BufferElementType::Bool2: return GL_BOOL; return 4;
case BufferElementType::Bool3: return GL_BOOL; case BufferElementType::Int:
case BufferElementType::Bool4: return GL_BOOL; return 1;
case BufferElementType::Int: return GL_INT; case BufferElementType::Int2:
case BufferElementType::Int2: return GL_INT; return 2;
case BufferElementType::Int3: return GL_INT; case BufferElementType::Int3:
case BufferElementType::Int4: return GL_INT; return 3;
case BufferElementType::Uint: return GL_UNSIGNED_INT; case BufferElementType::Int4:
case BufferElementType::Uint2: return GL_UNSIGNED_INT; return 4;
case BufferElementType::Uint3: return GL_UNSIGNED_INT; case BufferElementType::Uint:
case BufferElementType::Uint4: return GL_UNSIGNED_INT; return 1;
case BufferElementType::Float: return GL_FLOAT; case BufferElementType::Uint2:
case BufferElementType::Vec2: return GL_FLOAT; return 2;
case BufferElementType::Vec3: return GL_FLOAT; case BufferElementType::Uint3:
case BufferElementType::Vec4: return GL_FLOAT; return 3;
case BufferElementType::Double: return GL_DOUBLE; case BufferElementType::Uint4:
case BufferElementType::Double2: return GL_DOUBLE; return 4;
case BufferElementType::Double3: return GL_DOUBLE; case BufferElementType::Float:
case BufferElementType::Double4: return GL_DOUBLE; return 1;
case BufferElementType::Mat2: return GL_FLOAT; case BufferElementType::Vec2:
case BufferElementType::Mat3: return GL_FLOAT; return 2;
case BufferElementType::Mat4: return GL_FLOAT; case BufferElementType::Vec3:
case BufferElementType::DoubleMat2: return GL_DOUBLE; return 3;
case BufferElementType::DoubleMat3: return GL_DOUBLE; case BufferElementType::Vec4:
case BufferElementType::DoubleMat4: return GL_DOUBLE; return 4;
}; case BufferElementType::Double:
return 1;
VERIFY(false, "BufferElement unknown BufferElementType GL!"); case BufferElementType::Double2:
return 0; 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;
};
VERIFY(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;
};
VERIFY(false, "BufferElement unknown BufferElementType GL!");
return 0;
}
// ----------------------------------------- // -----------------------------------------
BufferLayout::BufferLayout(const std::initializer_list<BufferElement>& elements) BufferLayout::BufferLayout(const std::initializer_list<BufferElement>& elements)
: m_elements(elements) : m_elements(elements)
{ {
calculateOffsetsAndStride(); calculateOffsetsAndStride();
} }
void BufferLayout::calculateOffsetsAndStride() void BufferLayout::calculateOffsetsAndStride()
{ {
m_stride = 0; m_stride = 0;
for (auto& element : m_elements) { for (auto& element : m_elements) {
element.setOffset(m_stride); element.setOffset(m_stride);
m_stride += element.getSize(); m_stride += element.getSize();
}
} }
}
// ----------------------------------------- // -----------------------------------------
VertexBuffer::VertexBuffer(size_t size) VertexBuffer::VertexBuffer(size_t size)
{ {
glGenBuffers(1, &m_id); glGenBuffers(1, &m_id);
bind(); bind();
// Reserve data on the GPU // Reserve data on the GPU
glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_DYNAMIC_DRAW); glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_DYNAMIC_DRAW);
unbind(); unbind();
} }
VertexBuffer::VertexBuffer(float* vertices, size_t size) VertexBuffer::VertexBuffer(float* vertices, size_t size)
{ {
glGenBuffers(1, &m_id); glGenBuffers(1, &m_id);
bind(); bind();
// Upload data to the GPU // Upload data to the GPU
glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);
unbind(); unbind();
} }
VertexBuffer::~VertexBuffer() VertexBuffer::~VertexBuffer()
{ {
glDeleteBuffers(1, &m_id); glDeleteBuffers(1, &m_id);
} }
void VertexBuffer::bind() const void VertexBuffer::bind() const
{ {
glBindBuffer(GL_ARRAY_BUFFER, m_id); glBindBuffer(GL_ARRAY_BUFFER, m_id);
} }
void VertexBuffer::unbind() const void VertexBuffer::unbind() const
{ {
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
} }
void VertexBuffer::uploadData(const void* data, uint32_t size) void VertexBuffer::uploadData(const void* data, uint32_t size)
{ {
bind(); bind();
// Upload data to the GPU // Upload data to the GPU
glBufferSubData(GL_ARRAY_BUFFER, 0, size, data); glBufferSubData(GL_ARRAY_BUFFER, 0, size, data);
unbind(); unbind();
} }
// ----------------------------------------- // -----------------------------------------
IndexBuffer::IndexBuffer(uint32_t* indices, size_t size) : IndexBuffer::IndexBuffer(uint32_t* indices, size_t size)
m_count(size / sizeof(uint32_t)) : m_count(size / sizeof(uint32_t))
{ {
glCreateBuffers(1, &m_id); glCreateBuffers(1, &m_id);
bind(); bind();
// Upload data to the GPU // Upload data to the GPU
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, indices, GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, indices, GL_STATIC_DRAW);
unbind(); unbind();
} }
IndexBuffer::~IndexBuffer() IndexBuffer::~IndexBuffer()
{ {
glDeleteBuffers(1, &m_id); glDeleteBuffers(1, &m_id);
} }
void IndexBuffer::bind() const void IndexBuffer::bind() const
{ {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_id); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_id);
} }
void IndexBuffer::unbind() const void IndexBuffer::unbind() const
{ {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
} }
// ----------------------------------------- // -----------------------------------------
VertexArray::VertexArray() VertexArray::VertexArray()
{ {
glCreateVertexArrays(1, &m_id); 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();
VERIFY(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));
VertexArray::~VertexArray() unbind();
{ vertexBuffer->unbind();
glDeleteVertexArrays(1, &m_id); }
}
void VertexArray::bind() const void VertexArray::setIndexBuffer(std::shared_ptr<IndexBuffer> indexBuffer)
{ {
glBindVertexArray(m_id); bind();
} indexBuffer->bind();
void VertexArray::unbind() const m_indexBuffer = std::move(indexBuffer);
{
glBindVertexArray(0);
}
void VertexArray::addVertexBuffer(std::shared_ptr<VertexBuffer> vertexBuffer) unbind();
{ indexBuffer->unbind();
const auto& layout = vertexBuffer->getLayout(); }
VERIFY(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();
}
} // namespace Inferno } // namespace Inferno

208
src/inferno/render/buffer.h

@ -8,138 +8,140 @@
namespace Inferno { namespace Inferno {
// https://www.khronos.org/opengl/wiki/Data_Type_(GLSL) // clang-format off
enum class BufferElementType { // https://www.khronos.org/opengl/wiki/Data_Type_(GLSL)
None = 0, enum class BufferElementType {
Bool, Bool2, Bool3, Bool4, // bvec None = 0,
Int, Int2, Int3, Int4, // ivec Bool, Bool2, Bool3, Bool4, // bvec
Uint, Uint2, Uint3, Uint4, // uvec Int, Int2, Int3, Int4, // ivec
Float, Vec2, Vec3, Vec4, // vec Uint, Uint2, Uint3, Uint4, // uvec
Double, Double2, Double3, Double4, // dvec Float, Vec2, Vec3, Vec4, // vec
Mat2, Mat3, Mat4, // mat Double, Double2, Double3, Double4, // dvec
DoubleMat2, DoubleMat3, DoubleMat4, // dmat Mat2, Mat3, Mat4, // mat
}; DoubleMat2, DoubleMat3, DoubleMat4, // dmat
};
// clang-format on
// ----------------------------------------- // -----------------------------------------
// Describes one element of the BufferLayout // Describes one element of the BufferLayout
class BufferElement { class BufferElement {
public: public:
BufferElement(BufferElementType type, std::string name, bool normalized = false); BufferElement(BufferElementType type, std::string name, bool normalized = false);
uint32_t getTypeSize() const; uint32_t getTypeSize() const;
uint32_t getTypeCount() const; uint32_t getTypeCount() const;
uint32_t getTypeGL() const; uint32_t getTypeGL() const;
static uint32_t getTypeSize(const BufferElementType type); static uint32_t getTypeSize(const BufferElementType type);
static uint32_t getTypeCount(const BufferElementType type); static uint32_t getTypeCount(const BufferElementType type);
static uint32_t getTypeGL(const BufferElementType type); static uint32_t getTypeGL(const BufferElementType type);
inline BufferElementType getType() const{ return m_type; } inline BufferElementType getType() const { return m_type; }
inline std::string getName() const { return m_name; } inline std::string getName() const { return m_name; }
inline uint32_t getSize() const { return m_size; } inline uint32_t getSize() const { return m_size; }
inline uint32_t getOffset() const { return m_offset; } inline uint32_t getOffset() const { return m_offset; }
inline bool getNormalized() const { return m_normalized; } inline bool getNormalized() const { return m_normalized; }
inline void setType(const BufferElementType& type) { m_type = type; } inline void setType(const BufferElementType& type) { m_type = type; }
inline void setName(const std::string& name) { m_name = name; } inline void setName(const std::string& name) { m_name = name; }
inline void setSize(const uint32_t& size) { m_size = size; } inline void setSize(const uint32_t& size) { m_size = size; }
inline void setOffset(const uint32_t& offset) { m_offset = offset; } inline void setOffset(const uint32_t& offset) { m_offset = offset; }
inline void setNormalized(const bool& normalized) { m_normalized = normalized; } inline void setNormalized(const bool& normalized) { m_normalized = normalized; }
private: private:
BufferElementType m_type; BufferElementType m_type;
std::string m_name; std::string m_name;
uint32_t m_size { 0 }; uint32_t m_size { 0 };
uint32_t m_offset { 0 }; uint32_t m_offset { 0 };
bool m_normalized { false }; bool m_normalized { false };
}; };
// ----------------------------------------- // -----------------------------------------
// Layout that describes raw vertex data // Layout that describes raw vertex data
class BufferLayout { class BufferLayout {
public: public:
BufferLayout() {} BufferLayout() {}
BufferLayout(const std::initializer_list<BufferElement>& elements); BufferLayout(const std::initializer_list<BufferElement>& elements);
inline const std::vector<BufferElement>& getElements() const { return m_elements; } inline const std::vector<BufferElement>& getElements() const { return m_elements; }
inline uint32_t getStride() const { return m_stride; } inline uint32_t getStride() const { return m_stride; }
// Iterators // Iterators
inline std::vector<BufferElement>::iterator begin() { return m_elements.begin(); } inline std::vector<BufferElement>::iterator begin() { return m_elements.begin(); }
inline std::vector<BufferElement>::iterator end() { return m_elements.end(); } 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 begin() const { return m_elements.begin(); }
inline std::vector<BufferElement>::const_iterator end() const { return m_elements.end(); } inline std::vector<BufferElement>::const_iterator end() const { return m_elements.end(); }
protected: protected:
void calculateOffsetsAndStride(); void calculateOffsetsAndStride();
private: private:
std::vector<BufferElement> m_elements; std::vector<BufferElement> m_elements;
uint32_t m_stride { 0 }; uint32_t m_stride { 0 };
}; };
// ----------------------------------------- // -----------------------------------------
// GPU memory which holds raw vertex data // GPU memory which holds raw vertex data
class VertexBuffer { class VertexBuffer {
public: public:
VertexBuffer(size_t size); VertexBuffer(size_t size);
VertexBuffer(float* vertices, size_t size); VertexBuffer(float* vertices, size_t size);
~VertexBuffer(); ~VertexBuffer();
void bind() const; void bind() const;
void unbind() const; void unbind() const;
void uploadData(const void* data, uint32_t size); void uploadData(const void* data, uint32_t size);
inline const BufferLayout& getLayout() const { return m_layout; } inline const BufferLayout& getLayout() const { return m_layout; }
inline void setLayout(const BufferLayout& layout) { m_layout = layout; } inline void setLayout(const BufferLayout& layout) { m_layout = layout; }
private: private:
uint32_t m_id { 0 }; uint32_t m_id { 0 };
BufferLayout m_layout; BufferLayout m_layout;
}; };
// ----------------------------------------- // -----------------------------------------
// Vertices order of rendering // Vertices order of rendering
class IndexBuffer { class IndexBuffer {
public: public:
IndexBuffer(uint32_t* indices, size_t size); IndexBuffer(uint32_t* indices, size_t size);
~IndexBuffer(); ~IndexBuffer();
void bind() const; void bind() const;
void unbind() const; void unbind() const;
inline uint32_t getCount() const { return m_count; } inline uint32_t getCount() const { return m_count; }
private: private:
uint32_t m_id { 0 }; uint32_t m_id { 0 };
uint32_t m_count { 0 }; uint32_t m_count { 0 };
}; };
// ----------------------------------------- // -----------------------------------------
// Array that holds the vertex attributes configuration // Array that holds the vertex attributes configuration
class VertexArray { class VertexArray {
public: public:
VertexArray(); VertexArray();
~VertexArray(); ~VertexArray();
void bind() const; void bind() const;
void unbind() const; void unbind() const;
void addVertexBuffer(std::shared_ptr<VertexBuffer> vertexBuffer); void addVertexBuffer(std::shared_ptr<VertexBuffer> vertexBuffer);
void setIndexBuffer(std::shared_ptr<IndexBuffer> indexBuffer); void setIndexBuffer(std::shared_ptr<IndexBuffer> indexBuffer);
inline const std::vector<std::shared_ptr<VertexBuffer>>& getVertexBuffers() const { return m_vertexBuffers; } inline const std::vector<std::shared_ptr<VertexBuffer>>& getVertexBuffers() const { return m_vertexBuffers; }
inline std::shared_ptr<IndexBuffer> getIndexBuffer() const { return m_indexBuffer; } inline std::shared_ptr<IndexBuffer> getIndexBuffer() const { return m_indexBuffer; }
private: private:
uint32_t m_id { 0 }; uint32_t m_id { 0 };
std::vector<std::shared_ptr<VertexBuffer>> m_vertexBuffers; std::vector<std::shared_ptr<VertexBuffer>> m_vertexBuffers;
std::shared_ptr<IndexBuffer> m_indexBuffer; std::shared_ptr<IndexBuffer> m_indexBuffer;
}; };
} // namespace Inferno } // namespace Inferno

80
src/inferno/render/context.cpp

@ -1,5 +1,5 @@
#include "glad/glad.h"
#include "GLFW/glfw3.h" #include "GLFW/glfw3.h"
#include "glad/glad.h"
#include "ruc/meta/assert.h" #include "ruc/meta/assert.h"
#include "inferno/core.h" #include "inferno/core.h"
@ -9,44 +9,44 @@
namespace Inferno { namespace Inferno {
Context::Context(GLFWwindow* window) : Context::Context(GLFWwindow* window)
m_window(window) : m_window(window)
{ {
VERIFY(window, "Context window is nullptr!"); VERIFY(window, "Context window is nullptr!");
} }
void Context::initialize() void Context::initialize()
{ {
Context::setCurrent(); Context::setCurrent();
// Initialize glad // Initialize glad
int glad = gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); int glad = gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
VERIFY(glad, "Failed to initialize glad!"); VERIFY(glad, "Failed to initialize glad!");
// Log OpenGL properties // Log OpenGL properties
comment() << "OpenGL Info:"; comment() << "OpenGL Info:";
comment() << " Vendor: " << glGetString(GL_VENDOR); comment() << " Vendor: " << glGetString(GL_VENDOR);
comment() << " Renderer: " << glGetString(GL_RENDERER); comment() << " Renderer: " << glGetString(GL_RENDERER);
comment() << " Version: " << glGetString(GL_VERSION); comment() << " Version: " << glGetString(GL_VERSION);
// Check OpenGL version // Check OpenGL version
VERIFY(GLVersion.major > 4 || (GLVersion.major == 4 && GLVersion.minor >= 5), VERIFY(GLVersion.major > 4 || (GLVersion.major == 4 && GLVersion.minor >= 5),
"Inferno requires at least OpenGL version 4.5!"); "Inferno requires at least OpenGL version 4.5!");
} }
void Context::destroy() void Context::destroy()
{ {
} }
void Context::render() void Context::render()
{ {
glfwSwapBuffers(m_window); glfwSwapBuffers(m_window);
} }
void Context::setCurrent() void Context::setCurrent()
{ {
// Set current OpenGL context to this window // Set current OpenGL context to this window
glfwMakeContextCurrent(m_window); glfwMakeContextCurrent(m_window);
} }
} // namespace Inferno } // namespace Inferno

20
src/inferno/render/context.h

@ -4,18 +4,18 @@ struct GLFWwindow;
namespace Inferno { namespace Inferno {
class Context { class Context {
public: public:
Context(GLFWwindow* window); Context(GLFWwindow* window);
void initialize(); void initialize();
void destroy(); void destroy();
void render(); void render();
void setCurrent(); void setCurrent();
private: private:
GLFWwindow* m_window { nullptr }; GLFWwindow* m_window { nullptr };
}; };
} // namespace Inferno } // namespace Inferno

237
src/inferno/render/font.cpp

@ -11,154 +11,153 @@
namespace Inferno { namespace Inferno {
Font::Font(const std::string& name) Font::Font(const std::string& name)
: m_name(std::move(name)) : m_name(std::move(name))
{ {
std::string path = name + ".fnt"; std::string path = name + ".fnt";
std::string image = name + ".png"; std::string image = name + ".png";
std::string font = File::read(path); std::string font = File::read(path);
parseFont(font); parseFont(font);
m_texture = std::make_shared<Texture>(image); 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); void Font::parseFont(const std::string& font)
{
std::istringstream iss(font);
for (std::string line; std::getline(iss, line);) {
// Info if (findAction(line).compare("info") != 0 && findAction(line).compare("char") != 0) {
continue;
}
if (findAction(line).compare("info") == 0) { const std::vector<std::string> columns = findColumns(line);
m_size = std::stou(findValue("size", columns));
continue;
}
// Character // Info
unsigned char id = std::stoi(findValue("id", columns)); if (findAction(line).compare("info") == 0) {
Character character = { m_size = std::stou(findValue("size", columns));
{ std::stou(findValue("x", columns)), std::stou(findValue("y", columns)) }, continue;
{ 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) // Character
{
return line.substr(0, line.find(" "));
}
const std::vector<std::string> Font::findColumns(const std::string& line) unsigned char id = std::stoi(findValue("id", columns));
{ Character character = {
std::vector<std::string> elements; { std::stou(findValue("x", columns)), std::stou(findValue("y", columns)) },
{ std::stou(findValue("width", columns)), std::stou(findValue("height", columns)) },
size_t index = 0; { std::stoi(findValue("xoffset", columns)), std::stoi(findValue("yoffset", columns)) },
size_t find = 0; std::stou(findValue("xadvance", columns))
size_t findFirstNotOf = 0; };
// Loop over line characters m_characterList.emplace(id, std::make_shared<Character>(character));
while (find != std::string::npos) { }
find = line.find(" ", index); }
findFirstNotOf = line.find_first_not_of(" ", index);
const std::string Font::findAction(const std::string& line)
// Add element {
if (find > findFirstNotOf) { return line.substr(0, line.find(" "));
elements.push_back(line.substr(index, find - findFirstNotOf)); }
index += 1 + find - findFirstNotOf;
} const std::vector<std::string> Font::findColumns(const std::string& line)
// Skip double spaces {
else { std::vector<std::string> elements;
index = findFirstNotOf;
} 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;
} }
VERIFY(!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) VERIFY(!elements.empty(), "Font file did not find any columns");
{ return elements;
size_t find = 0; }
// Loop over columns
for (auto& column : columns) { const std::string Font::findValue(const std::string& key, const std::vector<std::string>& columns)
find = column.find(key + "="); {
if (find != std::string::npos) { size_t find = 0;
return column.substr(key.length() + 1); // Loop over columns
} for (auto& column : columns) {
find = column.find(key + "=");
if (find != std::string::npos) {
return column.substr(key.length() + 1);
} }
VERIFY(false, "Font file did not contain key '{}'", key);
return "";
} }
// ----------------------------------------- VERIFY(false, "Font file did not contain key '{}'", key);
return "";
}
FontManager::FontManager(s) // -----------------------------------------
{
info() << "FontManager initialized";
}
FontManager::~FontManager() FontManager::FontManager(s)
{ {
} info() << "FontManager initialized";
}
void FontManager::add(const std::string& name, std::shared_ptr<Font> font) FontManager::~FontManager()
{ {
// 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) void FontManager::add(const std::string& name, std::shared_ptr<Font> font)
{ {
if (exists(name)) { // Construct (key, value) pair and insert it into the unordered_map
return get(name); m_fontList.emplace(std::move(name), std::move(font));
} }
std::shared_ptr<Font> font = std::make_shared<Font>(name); std::shared_ptr<Font> FontManager::load(const std::string& name)
add(name, font); {
if (exists(name)) {
return get(name); return get(name);
} }
std::shared_ptr<Font> FontManager::get(const std::string& name) std::shared_ptr<Font> font = std::make_shared<Font>(name);
{ add(name, font);
return exists(name) ? m_fontList.at(name) : nullptr; 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);
} }
}
bool FontManager::exists(const std::string& name) void FontManager::remove(std::shared_ptr<Font> font)
{ {
return m_fontList.find(name) != m_fontList.end(); if (exists(font->name())) {
} m_fontList.erase(font->name());
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) const LogStream& operator<<(const LogStream& stream, const glm::ivec2& value)
{ {
return stream << "{ " << value.x << ", " << value.y << " }"; return stream << "{ " << value.x << ", " << value.y << " }";
} }
} // namespace Inferno } // namespace Inferno

86
src/inferno/render/font.h

@ -14,63 +14,63 @@
namespace Inferno { namespace Inferno {
class Texture; class Texture;
struct Character { struct Character {
glm::uvec2 position; // Position glm::uvec2 position; // Position
glm::uvec2 size; // Width/height glm::uvec2 size; // Width/height
glm::ivec2 offset; // Offset from baseline to left / top of glyph glm::ivec2 offset; // Offset from baseline to left / top of glyph
uint32_t advance; // Amount to advance to next glyph uint32_t advance; // Amount to advance to next glyph
}; };
// ------------------------------------- // -------------------------------------
class Font { class Font {
public: public:
Font(const std::string& name); Font(const std::string& name);
virtual ~Font() {} virtual ~Font() {}
inline std::string name() const { return m_name; } inline std::string name() const { return m_name; }
inline uint32_t size() const { return m_size; } inline uint32_t size() const { return m_size; }
inline std::shared_ptr<Texture> texture() const { return m_texture; } 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> 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); } inline std::shared_ptr<Character> operator[](unsigned char c) const { return m_characterList.at(c); }
private: private:
void parseFont(const std::string& font); void parseFont(const std::string& font);
const std::string findAction(const std::string& line); const std::string findAction(const std::string& line);
const std::vector<std::string> findColumns(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); const std::string findValue(const std::string& key, const std::vector<std::string>& columns);
std::string m_name; std::string m_name;
uint32_t m_size; uint32_t m_size;
std::shared_ptr<Texture> m_texture; std::shared_ptr<Texture> m_texture;
std::unordered_map<unsigned char, std::shared_ptr<Character>> m_characterList; std::unordered_map<unsigned char, std::shared_ptr<Character>> m_characterList;
}; };
// ------------------------------------- // -------------------------------------
class FontManager final : public ruc::Singleton<FontManager> { class FontManager final : public ruc::Singleton<FontManager> {
public: public:
FontManager(s); FontManager(s);
virtual ~FontManager(); virtual ~FontManager();
void add(const std::string& name, std::shared_ptr<Font> font); void add(const std::string& name, std::shared_ptr<Font> font);
std::shared_ptr<Font> load(const std::string& name); std::shared_ptr<Font> load(const std::string& name);
std::shared_ptr<Font> get(const std::string& name); std::shared_ptr<Font> get(const std::string& name);
bool exists(const std::string& name); bool exists(const std::string& name);
void remove(const std::string& name); void remove(const std::string& name);
void remove(std::shared_ptr<Font> font); void remove(std::shared_ptr<Font> font);
private: private:
std::unordered_map<std::string, std::shared_ptr<Font>> m_fontList; std::unordered_map<std::string, std::shared_ptr<Font>> m_fontList;
}; };
// ------------------------------------- // -------------------------------------
const LogStream& operator<<(const LogStream& stream, const glm::ivec2& value); const LogStream& operator<<(const LogStream& stream, const glm::ivec2& value);
} // namespace Inferno } // namespace Inferno

10
src/inferno/render/framebuffer.h

@ -2,10 +2,10 @@
namespace Inferno { namespace Inferno {
class Framebuffer { class Framebuffer {
public: public:
Framebuffer(); Framebuffer();
virtual ~Framebuffer(); virtual ~Framebuffer();
}; };
} // namespace Inferno } // namespace Inferno

18
src/inferno/render/gltf.cpp

@ -1,15 +1,15 @@
#if 0 #if 0
#include <algorithm> // std::copy #include <algorithm> // std::copy
#include <utility> // std::move #include <utility> // std::move
#include "nlohmann/json.hpp" #include "nlohmann/json.hpp"
#include "ruc/meta/assert.h" #include "ruc/meta/assert.h"
#include "inferno/io/file.h" #include "inferno/io/file.h"
#include "inferno/io/gltffile.h" #include "inferno/io/gltffile.h"
#include "inferno/io/log.h" #include "inferno/io/log.h"
#include "inferno/render/gltf.h" #include "inferno/render/gltf.h"
#include "inferno/util/integer.h" #include "inferno/util/integer.h"
namespace Inferno { namespace Inferno {

56
src/inferno/render/gltf.h

@ -1,34 +1,34 @@
#pragma once #pragma once
#if 0 #if 0
#include <cstdint> // uint32_t #include <cstdint> // uint32_t
#include <memory> // std::shared_ptr #include <memory> // std::shared_ptr
#include <string> // std::string #include <string> // std::string
#include <unordered_map> // std::unordered_map #include <unordered_map> // std::unordered_map
#include <vector> // std::vector #include <vector> // std::vector
#include "ruc/singleton.h" #include "ruc/singleton.h"
#include "inferno/util/json.h" #include "inferno/util/json.h"
#define GLTF_TYPE_SCALAR 1 #define GLTF_TYPE_SCALAR 1
#define GLTF_TYPE_VEC2 2 #define GLTF_TYPE_VEC2 2
#define GLTF_TYPE_VEC3 3 #define GLTF_TYPE_VEC3 3
#define GLTF_TYPE_VEC4 4 #define GLTF_TYPE_VEC4 4
#define GLTF_TYPE_MAT2 8 #define GLTF_TYPE_MAT2 8
#define GLTF_TYPE_MAT3 12 #define GLTF_TYPE_MAT3 12
#define GLTF_TYPE_MAT4 16 #define GLTF_TYPE_MAT4 16
#define GLTF_COMPONENT_TYPE_BYTE 5120 #define GLTF_COMPONENT_TYPE_BYTE 5120
#define GLTF_COMPONENT_TYPE_UNSIGNED_BYTE 5121 #define GLTF_COMPONENT_TYPE_UNSIGNED_BYTE 5121
#define GLTF_COMPONENT_TYPE_SHORT 5122 #define GLTF_COMPONENT_TYPE_SHORT 5122
#define GLTF_COMPONENT_TYPE_UNSIGNED_SHORT 5123 #define GLTF_COMPONENT_TYPE_UNSIGNED_SHORT 5123
#define GLTF_COMPONENT_TYPE_INT 5124 #define GLTF_COMPONENT_TYPE_INT 5124
#define GLTF_COMPONENT_TYPE_UNSIGNED_INT 5125 #define GLTF_COMPONENT_TYPE_UNSIGNED_INT 5125
#define GLTF_COMPONENT_TYPE_FLOAT 5126 #define GLTF_COMPONENT_TYPE_FLOAT 5126
#define GLTF_TARGET_ARRAY_BUFFER 34962 #define GLTF_TARGET_ARRAY_BUFFER 34962
#define GLTF_TARGET_ELEMENT_ARRAY_BUFFER 34963 #define GLTF_TARGET_ELEMENT_ARRAY_BUFFER 34963
namespace Inferno { namespace Inferno {

675
src/inferno/render/renderer.cpp

@ -10,433 +10,436 @@
namespace Inferno { namespace Inferno {
void RenderCommand::initialize() void RenderCommand::initialize()
{ {
setDepthTest(true); setDepthTest(true);
// Enable transparency // Enable transparency
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND); glEnable(GL_BLEND);
info() << "RenderCommand initialized"; info() << "RenderCommand initialized";
} }
void RenderCommand::destroy() void RenderCommand::destroy()
{ {
} }
void RenderCommand::clear() void RenderCommand::clear()
{ {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
} }
void RenderCommand::clearColor(const glm::vec4& color) void RenderCommand::clearColor(const glm::vec4& color)
{ {
glClearColor(color.r, color.g, color.b, color.a); glClearColor(color.r, color.g, color.b, color.a);
} }
void RenderCommand::drawIndexed(const VertexArray& vertexArray, uint32_t indexCount) void RenderCommand::drawIndexed(const VertexArray& vertexArray, uint32_t indexCount)
{ {
uint32_t count = indexCount ? indexCount : vertexArray.getIndexBuffer()->getCount(); uint32_t count = indexCount ? indexCount : vertexArray.getIndexBuffer()->getCount();
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, nullptr); glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, nullptr);
} }
void RenderCommand::setViewport(int32_t x, int32_t y, uint32_t width, uint32_t height) void RenderCommand::setViewport(int32_t x, int32_t y, uint32_t width, uint32_t height)
{ {
glViewport(x, y, width, height); glViewport(x, y, width, height);
} }
void RenderCommand::setDepthTest(bool enabled) void RenderCommand::setDepthTest(bool enabled)
{ {
// Set z-buffer / depth buffer // Set z-buffer / depth buffer
enabled ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST); enabled ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);
} }
bool RenderCommand::depthTest() bool RenderCommand::depthTest()
{ {
unsigned char depthTest = GL_FALSE; unsigned char depthTest = GL_FALSE;
glGetBooleanv(GL_DEPTH_TEST, &depthTest); glGetBooleanv(GL_DEPTH_TEST, &depthTest);
return depthTest == GL_TRUE; return depthTest == GL_TRUE;
} }
int32_t RenderCommand::textureUnitAmount() int32_t RenderCommand::textureUnitAmount()
{ {
int32_t amount = 0; int32_t amount = 0;
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &amount); glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &amount);
return amount; return amount;
} }
// ----------------------------------------- // -----------------------------------------
uint32_t Renderer::m_supportedTextureUnitPerBatch = 0; uint32_t Renderer::m_supportedTextureUnitPerBatch = 0;
void Renderer::initialize() void Renderer::initialize()
{ {
// Get amount of texture units supported by the GPU // Get amount of texture units supported by the GPU
uint32_t constTextureUnitCount = textureUnitPerBatch; uint32_t constTextureUnitCount = textureUnitPerBatch;
uint32_t gpuTextureUnitCount = RenderCommand::textureUnitAmount(); uint32_t gpuTextureUnitCount = RenderCommand::textureUnitAmount();
m_supportedTextureUnitPerBatch = std::min(constTextureUnitCount, gpuTextureUnitCount); m_supportedTextureUnitPerBatch = std::min(constTextureUnitCount, gpuTextureUnitCount);
// Texture unit 0 is reserved for no texture // Texture unit 0 is reserved for no texture
m_textureUnits[0] = nullptr; m_textureUnits[0] = nullptr;
// Create texture unit samplers // Create texture unit samplers
int32_t samplers[textureUnitPerBatch]; int32_t samplers[textureUnitPerBatch];
for (uint32_t i = 0; i < textureUnitPerBatch; i++) { for (uint32_t i = 0; i < textureUnitPerBatch; i++) {
samplers[i] = 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>();
}
// Create shader void Renderer::destroy()
loadShader(); {
m_shader->bind(); }
m_shader->setInt("u_textures", samplers, textureUnitPerBatch);
m_shader->unbind();
// Create vertex array uint32_t Renderer::addTextureUnit(std::shared_ptr<Texture> texture)
m_vertexArray = std::make_shared<VertexArray>(); {
if (texture == nullptr) {
return 0;
} }
void Renderer::destroy() // Create a new batch if the texture unit limit has been reached
{ if (m_textureUnitIndex >= m_supportedTextureUnitPerBatch) {
nextBatch();
} }
uint32_t Renderer::addTextureUnit(std::shared_ptr<Texture> texture) // If texure was already added
{ for (uint32_t i = 1; i < m_textureUnitIndex; i++) {
if (texture == nullptr) { if (m_textureUnits[i] == texture) {
return 0; return i;
} }
}
// Create a new batch if the texture unit limit has been reached // Add texture
if (m_textureUnitIndex >= m_supportedTextureUnitPerBatch) { uint32_t textureUnitIndex = m_textureUnitIndex;
nextBatch(); m_textureUnits[textureUnitIndex] = texture;
} m_textureUnitIndex++;
// If texure was already added return textureUnitIndex;
for (uint32_t i = 1; i < m_textureUnitIndex; i++) { }
if (m_textureUnits[i] == texture) {
return i;
}
}
// Add texture void Renderer::bind()
uint32_t textureUnitIndex = m_textureUnitIndex; {
m_textureUnits[textureUnitIndex] = texture; m_shader->bind();
m_textureUnitIndex++;
return textureUnitIndex; for (uint32_t i = 1; i < m_textureUnitIndex; i++) {
m_textureUnits[i]->bind(i);
} }
void Renderer::bind() m_vertexArray->bind();
{ }
m_shader->bind();
for (uint32_t i = 1; i < m_textureUnitIndex; i++) { void Renderer::unbind()
m_textureUnits[i]->bind(i); {
} m_vertexArray->unbind();
m_vertexArray->bind(); for (uint32_t i = 1; i < m_textureUnitIndex; i++) {
m_textureUnits[i]->unbind();
} }
void Renderer::unbind() m_shader->unbind();
{ }
m_vertexArray->unbind();
for (uint32_t i = 1; i < m_textureUnitIndex; i++) {
m_textureUnits[i]->unbind();
}
m_shader->unbind();
}
// ----------------------------------------- // -----------------------------------------
Renderer2D::Renderer2D(s) Renderer2D::Renderer2D(s)
{ {
Renderer::initialize(); Renderer::initialize();
// CPU
// ---------------------------------
// Create array for storing quads vertices // CPU
m_vertexBufferBase = std::make_unique<QuadVertex[]>(vertexCount); // ---------------------------------
m_vertexBufferPtr = m_vertexBufferBase.get();
// Set default quad vertex positions // Create array for storing quads vertices
m_vertexPositions[0] = { -0.5f, -0.5f, 0.0f, 1.0f }; m_vertexBufferBase = std::make_unique<QuadVertex[]>(vertexCount);
m_vertexPositions[1] = { 0.5f, -0.5f, 0.0f, 1.0f }; m_vertexBufferPtr = m_vertexBufferBase.get();
m_vertexPositions[2] = { 0.5f, 0.5f, 0.0f, 1.0f };
m_vertexPositions[3] = { -0.5f, 0.5f, 0.0f, 1.0f };
// Generate indices // 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 };
uint32_t* indices = new uint32_t[indexCount]; // Generate indices
uint32_t offset = 0; uint32_t* indices = new uint32_t[indexCount];
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; 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;
// GPU offset += vertexPerQuad;
// ---------------------------------
// 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() // GPU
{ // ---------------------------------
Renderer::destroy();
}
void Renderer2D::beginScene(glm::mat4 cameraProjectionView) // Create vertex buffer
{ auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(QuadVertex) * vertexCount);
m_shader->bind(); vertexBuffer->setLayout({
m_shader->setFloat("u_projectionView", cameraProjectionView); { BufferElementType::Vec3, "a_position" },
m_shader->unbind(); { BufferElementType::Vec4, "a_color" },
} { BufferElementType::Vec2, "a_textureCoordinates" },
{ BufferElementType::Float, "a_textureIndex" },
});
m_vertexArray->addVertexBuffer(vertexBuffer);
void Renderer2D::endScene() // Create index buffer
{ auto indexBuffer = std::make_shared<IndexBuffer>(indices, sizeof(uint32_t) * indexCount);
nextBatch(); m_vertexArray->setIndexBuffer(indexBuffer);
} delete[] indices;
void Renderer2D::drawQuad(const TransformComponent& transform, glm::vec4 color)
{
drawQuad(transform, color, nullptr);
}
void Renderer2D::drawQuad(const TransformComponent& transform, glm::mat4 color) info() << "Renderer2D initialized";
{ }
drawQuad(transform, color, nullptr);
}
void Renderer2D::drawQuad(const TransformComponent& transform, glm::vec4 color, std::shared_ptr<Texture> texture) Renderer2D::~Renderer2D()
{ {
drawQuad(transform, glm::mat4(color, color, color, color), texture); Renderer::destroy();
} }
void Renderer2D::drawQuad(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture) void Renderer2D::beginScene(glm::mat4 cameraProjectionView)
{ {
// Create a new batch if the quad limit has been reached m_shader->bind();
if (m_quadIndex >= quadCount) { m_shader->setFloat("u_projectionView", cameraProjectionView);
nextBatch(); m_shader->unbind();
} }
constexpr glm::vec2 textureCoordinates[] = { void Renderer2D::endScene()
{ 0.0f, 0.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f }, { 0.0f, 1.0f } {
}; nextBatch();
}
uint32_t textureUnitIndex = addTextureUnit(texture); void Renderer2D::drawQuad(const TransformComponent& transform, glm::vec4 color)
{
drawQuad(transform, color, nullptr);
}
// Add the quads 4 vertices void Renderer2D::drawQuad(const TransformComponent& transform, glm::mat4 color)
for (uint32_t i = 0; i < vertexPerQuad; i++) { {
m_vertexBufferPtr->position = transform.transform * m_vertexPositions[i]; drawQuad(transform, color, nullptr);
m_vertexBufferPtr->color = color[i]; }
m_vertexBufferPtr->textureCoordinates = textureCoordinates[i];
m_vertexBufferPtr->textureIndex = (float)textureUnitIndex;
m_vertexBufferPtr++;
}
m_quadIndex++; 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::loadShader() void Renderer2D::drawQuad(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture)
{ {
m_shader = ShaderManager::the().load("assets/glsl/batch-quad"); // Create a new batch if the quad limit has been reached
if (m_quadIndex >= quadCount) {
nextBatch();
} }
void Renderer2D::flush() constexpr glm::vec2 textureCoordinates[] = {
{ { 0.0f, 0.0f },
if (m_quadIndex == 0) { { 1.0f, 0.0f },
return; { 1.0f, 1.0f },
} { 0.0f, 1.0f }
};
// Upload vertex data to GPU uint32_t textureUnitIndex = addTextureUnit(texture);
m_vertexArray->getVertexBuffers().at(0)->uploadData(
m_vertexBufferBase.get(),
m_quadIndex * vertexPerQuad * sizeof(QuadVertex));
bind(); // Add the quads 4 vertices
for (uint32_t i = 0; i < vertexPerQuad; i++) {
// Render m_vertexBufferPtr->position = transform.transform * m_vertexPositions[i];
RenderCommand::drawIndexed(*m_vertexArray, m_quadIndex * indexPerQuad); m_vertexBufferPtr->color = color[i];
m_vertexBufferPtr->textureCoordinates = textureCoordinates[i];
unbind(); m_vertexBufferPtr->textureIndex = (float)textureUnitIndex;
m_vertexBufferPtr++;
} }
void Renderer2D::startBatch() m_quadIndex++;
{ }
m_quadIndex = 0;
m_vertexBufferPtr = m_vertexBufferBase.get();
m_textureUnitIndex = 1; void Renderer2D::loadShader()
} {
m_shader = ShaderManager::the().load("assets/glsl/batch-quad");
}
void Renderer2D::nextBatch() void Renderer2D::flush()
{ {
flush(); if (m_quadIndex == 0) {
startBatch(); return;
} }
// ----------------------------------------- // Upload vertex data to GPU
m_vertexArray->getVertexBuffers().at(0)->uploadData(
m_vertexBufferBase.get(),
m_quadIndex * vertexPerQuad * sizeof(QuadVertex));
RendererCharacter::RendererCharacter(s) bind();
{
Renderer::initialize();
// CPU // Render
// --------------------------------- RenderCommand::drawIndexed(*m_vertexArray, m_quadIndex * indexPerQuad);
// Create array for storing quads vertices unbind();
m_vertexBufferBase = std::make_unique<CharacterVertex[]>(vertexCount); }
m_vertexBufferPtr = m_vertexBufferBase.get();
// Generate indices void Renderer2D::startBatch()
{
m_quadIndex = 0;
m_vertexBufferPtr = m_vertexBufferBase.get();
uint32_t* indices = new uint32_t[indexCount]; m_textureUnitIndex = 1;
}
uint32_t offset = 0; void Renderer2D::nextBatch()
for (uint32_t i = 0; i < indexCount; i += indexPerQuad) { {
indices[i + 0] = offset + 0; flush();
indices[i + 1] = offset + 1; startBatch();
indices[i + 2] = offset + 2; }
indices[i + 3] = offset + 2;
indices[i + 4] = offset + 3;
indices[i + 5] = offset + 0;
offset += vertexPerQuad; // -----------------------------------------
}
// GPU RendererCharacter::RendererCharacter(s)
// --------------------------------- {
Renderer::initialize();
// Create vertex buffer
auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(CharacterVertex) * vertexCount); // CPU
vertexBuffer->setLayout({ // ---------------------------------
{ BufferElementType::Vec3, "a_position" },
{ BufferElementType::Vec4, "a_color" }, // Create array for storing quads vertices
{ BufferElementType::Vec2, "a_textureCoordinates" }, m_vertexBufferBase = std::make_unique<CharacterVertex[]>(vertexCount);
{ BufferElementType::Float, "a_textureIndex" }, m_vertexBufferPtr = m_vertexBufferBase.get();
{ BufferElementType::Float, "a_width" },
{ BufferElementType::Float, "a_edge" }, // Generate indices
{ BufferElementType::Float, "a_borderWidth" },
{ BufferElementType::Float, "a_borderEdge" }, uint32_t* indices = new uint32_t[indexCount];
{ BufferElementType::Vec4, "a_borderColor" },
{ BufferElementType::Float, "a_offset" }, uint32_t offset = 0;
}); for (uint32_t i = 0; i < indexCount; i += indexPerQuad) {
m_vertexArray->addVertexBuffer(vertexBuffer); indices[i + 0] = offset + 0;
indices[i + 1] = offset + 1;
// Create index buffer indices[i + 2] = offset + 2;
auto indexBuffer = std::make_shared<IndexBuffer>(indices, sizeof(uint32_t) * indexCount); indices[i + 3] = offset + 2;
m_vertexArray->setIndexBuffer(indexBuffer); indices[i + 4] = offset + 3;
delete[] indices; indices[i + 5] = offset + 0;
info() << "RendererCharacter initialized"; 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() RendererCharacter::~RendererCharacter()
{ {
Renderer::destroy(); Renderer::destroy();
} }
void RendererCharacter::beginScene() void RendererCharacter::beginScene()
{ {
} }
void RendererCharacter::endScene() 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(); nextBatch();
} }
void RendererCharacter::drawCharacter(std::array<CharacterVertex, vertexPerQuad>& characterQuad, std::shared_ptr<Texture> texture) uint32_t textureUnitIndex = addTextureUnit(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; // Add the quads 4 vertices
m_vertexBufferPtr->edge = characterQuad[i].edge; for (uint32_t i = 0; i < vertexPerQuad; i++) {
m_vertexBufferPtr->borderWidth = characterQuad[i].borderWidth; m_vertexBufferPtr->quad.position = characterQuad[i].quad.position;
m_vertexBufferPtr->borderEdge = characterQuad[i].borderEdge; m_vertexBufferPtr->quad.color = characterQuad[i].quad.color;
m_vertexBufferPtr->borderColor = characterQuad[i].borderColor; m_vertexBufferPtr->quad.textureCoordinates = characterQuad[i].quad.textureCoordinates;
m_vertexBufferPtr->offset = characterQuad[i].offset; m_vertexBufferPtr->quad.textureIndex = (float)textureUnitIndex;
m_vertexBufferPtr++; 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_quadIndex++; m_vertexBufferPtr++;
} }
void RendererCharacter::loadShader() m_quadIndex++;
{ }
m_shader = ShaderManager::the().load("assets/glsl/batch-font");
}
void RendererCharacter::flush() void RendererCharacter::loadShader()
{ {
if (m_quadIndex == 0) { m_shader = ShaderManager::the().load("assets/glsl/batch-font");
return; }
}
// Upload vertex data to GPU void RendererCharacter::flush()
m_vertexArray->getVertexBuffers().at(0)->uploadData( {
m_vertexBufferBase.get(), if (m_quadIndex == 0) {
m_quadIndex * vertexPerQuad * sizeof(CharacterVertex)); return;
}
bind(); // Upload vertex data to GPU
m_vertexArray->getVertexBuffers().at(0)->uploadData(
m_vertexBufferBase.get(),
m_quadIndex * vertexPerQuad * sizeof(CharacterVertex));
// Render bind();
bool depthTest = RenderCommand::depthTest();
RenderCommand::setDepthTest(false);
RenderCommand::drawIndexed(*m_vertexArray, m_quadIndex * indexPerQuad);
RenderCommand::setDepthTest(depthTest);
unbind(); // Render
} bool depthTest = RenderCommand::depthTest();
RenderCommand::setDepthTest(false);
RenderCommand::drawIndexed(*m_vertexArray, m_quadIndex * indexPerQuad);
RenderCommand::setDepthTest(depthTest);
void RendererCharacter::startBatch() unbind();
{ }
m_quadIndex = 0;
m_vertexBufferPtr = m_vertexBufferBase.get();
m_textureUnitIndex = 1; void RendererCharacter::startBatch()
} {
m_quadIndex = 0;
m_vertexBufferPtr = m_vertexBufferBase.get();
void RendererCharacter::nextBatch() m_textureUnitIndex = 1;
{ }
flush();
startBatch();
}
void RendererCharacter::nextBatch()
{
flush();
startBatch();
} }
} // namespace Inferno

276
src/inferno/render/renderer.h

@ -13,150 +13,150 @@
namespace Inferno { namespace Inferno {
class Shader; class Shader;
class Texture; class Texture;
class VertexArray; class VertexArray;
struct QuadVertex { struct QuadVertex {
glm::vec3 position { 0.0f, 0.0f, 0.0f }; glm::vec3 position { 0.0f, 0.0f, 0.0f };
glm::vec4 color { 1.0f, 1.0f, 1.0f, 1.0f }; glm::vec4 color { 1.0f, 1.0f, 1.0f, 1.0f };
glm::vec2 textureCoordinates { 0.0f, 0.0f }; glm::vec2 textureCoordinates { 0.0f, 0.0f };
float textureIndex = 0; // @Todo get int to pass to fragment correctly float textureIndex = 0; // @Todo get int to pass to fragment correctly
}; };
struct CharacterVertex { struct CharacterVertex {
QuadVertex quad; QuadVertex quad;
// Font // Font
float width = 0.44f; float width = 0.44f;
float edge = 0.15f; float edge = 0.15f;
// Outline // Outline
float borderWidth = 0.7f; float borderWidth = 0.7f;
float borderEdge = 0.1f; float borderEdge = 0.1f;
glm::vec4 borderColor { 1.0f, 1.0f, 1.0f, 1.0f }; glm::vec4 borderColor { 1.0f, 1.0f, 1.0f, 1.0f };
// Dropshadow // Dropshadow
float offset = 0.0f; float offset = 0.0f;
}; };
// ------------------------------------- // -------------------------------------
class RenderCommand { class RenderCommand {
public: public:
static void initialize(); static void initialize();
static void destroy(); static void destroy();
static void clear(); static void clear();
static void clearColor(const glm::vec4& color); static void clearColor(const glm::vec4& color);
static void drawIndexed(const VertexArray& vertexArray, uint32_t indexCount = 0); 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 setViewport(int32_t x, int32_t y, uint32_t width, uint32_t height);
static void setDepthTest(bool enabled); static void setDepthTest(bool enabled);
static bool depthTest(); static bool depthTest();
static int32_t textureUnitAmount(); static int32_t textureUnitAmount();
}; };
// ------------------------------------- // -------------------------------------
class Renderer { class Renderer {
public: public:
static const uint32_t vertexPerQuad = 4; static const uint32_t vertexPerQuad = 4;
static const uint32_t indexPerQuad = 6; static const uint32_t indexPerQuad = 6;
static const uint32_t textureUnitPerBatch = 32; static const uint32_t textureUnitPerBatch = 32;
protected: protected:
Renderer() {} Renderer() {}
void initialize(); void initialize();
void destroy(); void destroy();
uint32_t addTextureUnit(std::shared_ptr<Texture> texture); uint32_t addTextureUnit(std::shared_ptr<Texture> texture);
void bind(); void bind();
void unbind(); void unbind();
virtual void loadShader() = 0; virtual void loadShader() = 0;
virtual void flush() = 0; virtual void flush() = 0;
virtual void startBatch() = 0; virtual void startBatch() = 0;
virtual void nextBatch() = 0; virtual void nextBatch() = 0;
uint32_t m_quadIndex = 0; uint32_t m_quadIndex = 0;
// Texture units // Texture units
static uint32_t m_supportedTextureUnitPerBatch; static uint32_t m_supportedTextureUnitPerBatch;
uint32_t m_textureUnitIndex = 1; uint32_t m_textureUnitIndex = 1;
std::array<std::shared_ptr<Texture>, textureUnitPerBatch> m_textureUnits; std::array<std::shared_ptr<Texture>, textureUnitPerBatch> m_textureUnits;
// GPU objects // GPU objects
std::shared_ptr<Shader> m_shader; std::shared_ptr<Shader> m_shader;
std::shared_ptr<VertexArray> m_vertexArray; std::shared_ptr<VertexArray> m_vertexArray;
}; };
// ------------------------------------- // -------------------------------------
class Renderer2D final class Renderer2D final
: public Renderer : public Renderer
, public ruc::Singleton<Renderer2D> { , public ruc::Singleton<Renderer2D> {
public: public:
Renderer2D(s); Renderer2D(s);
virtual ~Renderer2D(); virtual ~Renderer2D();
using Singleton<Renderer2D>::destroy; using Singleton<Renderer2D>::destroy;
static const uint32_t quadCount = 1000; static const uint32_t quadCount = 1000;
static const uint32_t vertexCount = quadCount * vertexPerQuad; static const uint32_t vertexCount = quadCount * vertexPerQuad;
static const uint32_t indexCount = quadCount * indexPerQuad; static const uint32_t indexCount = quadCount * indexPerQuad;
void beginScene(glm::mat4 cameraProjectionView); void beginScene(glm::mat4 cameraProjectionView);
void endScene(); void endScene();
void drawQuad(const TransformComponent& transform, glm::vec4 color); void drawQuad(const TransformComponent& transform, glm::vec4 color);
void drawQuad(const TransformComponent& transform, glm::mat4 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::vec4 color, std::shared_ptr<Texture> texture);
void drawQuad(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture); void drawQuad(const TransformComponent& transform, glm::mat4 color, std::shared_ptr<Texture> texture);
private: private:
void loadShader() override; void loadShader() override;
void flush() override; void flush() override;
void startBatch() override; void startBatch() override;
void nextBatch() override; void nextBatch() override;
// CPU quad vertices // CPU quad vertices
std::unique_ptr<QuadVertex[]> m_vertexBufferBase; std::unique_ptr<QuadVertex[]> m_vertexBufferBase;
QuadVertex* m_vertexBufferPtr { nullptr }; QuadVertex* m_vertexBufferPtr { nullptr };
// Default quad vertex positions // Default quad vertex positions
glm::vec4 m_vertexPositions[vertexPerQuad]; glm::vec4 m_vertexPositions[vertexPerQuad];
}; };
// ------------------------------------- // -------------------------------------
class RendererCharacter final class RendererCharacter final
: public Renderer : public Renderer
, public ruc::Singleton<RendererCharacter> { , public ruc::Singleton<RendererCharacter> {
public: public:
RendererCharacter(s); RendererCharacter(s);
virtual ~RendererCharacter(); virtual ~RendererCharacter();
using Singleton<RendererCharacter>::destroy; using Singleton<RendererCharacter>::destroy;
static const uint32_t quadCount = 1000; static const uint32_t quadCount = 1000;
static const uint32_t vertexCount = quadCount * vertexPerQuad; static const uint32_t vertexCount = quadCount * vertexPerQuad;
static const uint32_t indexCount = quadCount * indexPerQuad; static const uint32_t indexCount = quadCount * indexPerQuad;
void beginScene(); void beginScene();
void endScene(); void endScene();
void drawCharacter(std::array<CharacterVertex, vertexPerQuad>& characterQuad, std::shared_ptr<Texture> texture); void drawCharacter(std::array<CharacterVertex, vertexPerQuad>& characterQuad, std::shared_ptr<Texture> texture);
private: private:
void loadShader() override; void loadShader() override;
void flush() override; void flush() override;
void startBatch() override; void startBatch() override;
void nextBatch() override; void nextBatch() override;
// CPU quad vertices // CPU quad vertices
std::unique_ptr<CharacterVertex[]> m_vertexBufferBase; std::unique_ptr<CharacterVertex[]> m_vertexBufferBase;
CharacterVertex* m_vertexBufferPtr { nullptr }; CharacterVertex* m_vertexBufferPtr { nullptr };
}; };
} // namespace Inferno } // namespace Inferno

446
src/inferno/render/shader.cpp

@ -12,259 +12,261 @@
namespace Inferno { namespace Inferno {
Shader::Shader(const std::string& name) Shader::Shader(const std::string& name)
: m_name(std::move(name)), : m_name(std::move(name))
m_id(0) , m_id(0)
{ {
// Get file contents // Get file contents
std::string vertexSrc = File::read(name + ".vert"); std::string vertexSrc = File::read(name + ".vert");
std::string fragmentSrc = File::read(name + ".frag"); std::string fragmentSrc = File::read(name + ".frag");
// Compile shaders // Compile shaders
uint32_t vertexID = compileShader(GL_VERTEX_SHADER, vertexSrc.c_str()); uint32_t vertexID = compileShader(GL_VERTEX_SHADER, vertexSrc.c_str());
uint32_t fragmentID = compileShader(GL_FRAGMENT_SHADER, fragmentSrc.c_str()); uint32_t fragmentID = compileShader(GL_FRAGMENT_SHADER, fragmentSrc.c_str());
// Link shaders // Link shaders
if (vertexID > 0 && fragmentID > 0) { if (vertexID > 0 && fragmentID > 0) {
m_id = linkShader(vertexID, fragmentID); m_id = linkShader(vertexID, fragmentID);
}
// Clear resources
else if (vertexID > 0) glDeleteShader(vertexID);
else if (fragmentID > 0) glDeleteShader(fragmentID);
} }
// Clear resources
Shader::~Shader() else if (vertexID > 0)
{ glDeleteShader(vertexID);
if (m_id > 0) { else if (fragmentID > 0)
glDeleteProgram(m_id); glDeleteShader(fragmentID);
m_id = 0; }
}
} Shader::~Shader()
{
int32_t Shader::findUniform(const std::string& name) const if (m_id > 0) {
{ glDeleteProgram(m_id);
int32_t location = glGetUniformLocation(m_id, name.c_str()); m_id = 0;
VERIFY(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
{ int32_t Shader::findUniform(const std::string& name) const
// Set uniform vec4 data {
glUniform4f(findUniform(name), value.x, value.y, value.z, value.w); int32_t location = glGetUniformLocation(m_id, name.c_str());
VERIFY(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;
} }
void Shader::setFloat(const std::string& name, glm::mat3 matrix) const // On fail
{ glDeleteShader(shader);
// Set uniform mat3 data return 0;
glUniformMatrix3fv(findUniform(name), 1, GL_FALSE, glm::value_ptr(matrix)); }
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;
} }
void Shader::setFloat(const std::string& name, glm::mat4 matrix) const // On fail
{ glDeleteProgram(shaderProgram);
// Set uniform mat4 data return 0;
glUniformMatrix4fv(findUniform(name), 1, GL_FALSE, glm::value_ptr(matrix)); }
}
void Shader::bind() const int32_t Shader::checkStatus(uint32_t check, bool isProgram) const
{ {
glUseProgram(m_id); int32_t success;
} int32_t maxLength = 0;
std::vector<char> infoLog;
void Shader::unbind() const // Get the compilation/linking status
{ !isProgram
glUseProgram(0); ? glGetShaderiv(check, GL_COMPILE_STATUS, &success)
} : glGetProgramiv(check, GL_LINK_STATUS, &success);
uint32_t Shader::compileShader(int32_t type, const char* source) const if (success != GL_TRUE) {
{ // Get max length of the log including \0 terminator
// 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 !isProgram
? glGetShaderiv(check, GL_COMPILE_STATUS, &success) ? glGetShaderiv(check, GL_INFO_LOG_LENGTH, &maxLength)
: glGetProgramiv(check, GL_LINK_STATUS, &success); : glGetProgramiv(check, GL_INFO_LOG_LENGTH, &maxLength);
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 // Reserve data for the log
infoLog.reserve(maxLength); infoLog.reserve(maxLength);
// Retrieve the error message // Retrieve the error message
!isProgram !isProgram
? glGetShaderInfoLog(check, maxLength, nullptr, &infoLog[0]) ? glGetShaderInfoLog(check, maxLength, nullptr, &infoLog[0])
: glGetProgramInfoLog(check, maxLength, nullptr, &infoLog[0]); : glGetProgramInfoLog(check, maxLength, nullptr, &infoLog[0]);
warn() << "Shader " << infoLog.data(); warn() << "Shader " << infoLog.data();
} }
VERIFY(success == GL_TRUE, "Shader program creation failed!"); VERIFY(success == GL_TRUE, "Shader program creation failed!");
return success; return success;
} }
// ----------------------------------------- // -----------------------------------------
ShaderManager::ShaderManager(s) ShaderManager::ShaderManager(s)
{ {
info() << "ShaderManager initialized"; info() << "ShaderManager initialized";
} }
ShaderManager::~ShaderManager() ShaderManager::~ShaderManager()
{ {
} }
void ShaderManager::add(const std::string& name, std::shared_ptr<Shader> shader) void ShaderManager::add(const std::string& name, std::shared_ptr<Shader> shader)
{ {
// Construct (key, value) pair and insert it into the unordered_map // Construct (key, value) pair and insert it into the unordered_map
m_shaderList.emplace(std::move(name), std::move(shader)); 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); std::shared_ptr<Shader> ShaderManager::load(const std::string& name)
add(name, shader); {
if (exists(name)) {
return get(name); return get(name);
} }
std::shared_ptr<Shader> ShaderManager::load(const std::string& vertexSource, std::shared_ptr<Shader> shader = std::make_shared<Shader>(name);
const std::string& fragmentSource) add(name, shader);
{ return get(name);
std::string name = computeName(vertexSource, fragmentSource); }
return load(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);
} }
}
std::shared_ptr<Shader> ShaderManager::get(const std::string& name) void ShaderManager::remove(std::shared_ptr<Shader> shader)
{ {
return exists(name) ? m_shaderList.at(name) : nullptr; if (exists(shader->name())) {
m_shaderList.erase(shader->name());
} }
}
bool ShaderManager::exists(const std::string& name) std::string ShaderManager::computeName(const std::string& vertexSource,
{ const std::string& fragmentSource)
return m_shaderList.find(name) != m_shaderList.end(); {
} auto vertexPos = vertexSource.find_last_of('.');
auto fragmentPos = fragmentSource.find_last_of('.');
void ShaderManager::remove(const std::string& name) VERIFY(vertexPos != std::string::npos, "Shader did not have file extension: '{}'", vertexSource);
{ VERIFY(fragmentPos != std::string::npos, "Shader did not have file extension: '{}'", fragmentSource);
if (exists(name)) {
m_shaderList.erase(name);
}
}
void ShaderManager::remove(std::shared_ptr<Shader> shader) auto vertexName = vertexSource.substr(0, vertexPos);
{ auto fragmentName = vertexSource.substr(0, fragmentPos);
if (exists(shader->name())) {
m_shaderList.erase(shader->name());
}
}
std::string ShaderManager::computeName(const std::string& vertexSource, VERIFY(vertexName == fragmentName, "Shader names did not match: {} {}", vertexSource, fragmentSource);
const std::string& fragmentSource)
{
auto vertexPos = vertexSource.find_last_of('.');
auto fragmentPos = fragmentSource.find_last_of('.');
VERIFY(vertexPos != std::string::npos, "Shader did not have file extension: '{}'", vertexSource); return vertexName;
VERIFY(fragmentPos != std::string::npos, "Shader did not have file extension: '{}'", fragmentSource); }
auto vertexName = vertexSource.substr(0, vertexPos);
auto fragmentName = vertexSource.substr(0, fragmentPos);
VERIFY(vertexName == fragmentName, "Shader names did not match: {} {}", vertexSource, fragmentSource);
return vertexName;
}
} // namespace Inferno } // namespace Inferno

114
src/inferno/render/shader.h

@ -10,62 +10,62 @@
namespace Inferno { namespace Inferno {
class Shader { class Shader {
public: public:
Shader(const std::string& name); Shader(const std::string& name);
virtual ~Shader(); virtual ~Shader();
int32_t findUniform(const std::string& name) const; int32_t findUniform(const std::string& name) const;
void setInt(const std::string& name, int value); void setInt(const std::string& name, int value);
void setInt(const std::string& name, int* values, uint32_t count); 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 value) const;
void setFloat(const std::string& name, float v1, float v2, float v3, float v4) 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::vec2 value) const;
void setFloat(const std::string& name, glm::vec3 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::vec4 value) const;
void setFloat(const std::string& name, glm::mat3 matrix) const; void setFloat(const std::string& name, glm::mat3 matrix) const;
void setFloat(const std::string& name, glm::mat4 matrix) const; void setFloat(const std::string& name, glm::mat4 matrix) const;
void bind() const; void bind() const;
void unbind() const; void unbind() const;
inline std::string name() const { return m_name; } inline std::string name() const { return m_name; }
inline uint32_t id() const { return m_id; } inline uint32_t id() const { return m_id; }
protected: protected:
uint32_t compileShader(int32_t type, const char* shaderSource) const; uint32_t compileShader(int32_t type, const char* shaderSource) const;
uint32_t linkShader(uint32_t vertex, uint32_t fragment) const; uint32_t linkShader(uint32_t vertex, uint32_t fragment) const;
int32_t checkStatus(uint32_t check, bool isProgram = false) const; int32_t checkStatus(uint32_t check, bool isProgram = false) const;
private: private:
std::string m_name; std::string m_name;
uint32_t m_id; uint32_t m_id;
}; };
// ------------------------------------- // -------------------------------------
class ShaderManager final : public ruc::Singleton<ShaderManager> { class ShaderManager final : public ruc::Singleton<ShaderManager> {
public: public:
ShaderManager(s); ShaderManager(s);
virtual ~ShaderManager(); virtual ~ShaderManager();
void add(const std::string& name, std::shared_ptr<Shader> shader); 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& name);
std::shared_ptr<Shader> load(const std::string& vertexSource, std::shared_ptr<Shader> load(const std::string& vertexSource,
const std::string& fragmentSource); const std::string& fragmentSource);
std::shared_ptr<Shader> get(const std::string& name); std::shared_ptr<Shader> get(const std::string& name);
bool exists(const std::string& name); bool exists(const std::string& name);
void remove(const std::string& name); void remove(const std::string& name);
void remove(std::shared_ptr<Shader> shader); void remove(std::shared_ptr<Shader> shader);
protected: protected:
std::string computeName(const std::string& vertexSource, std::string computeName(const std::string& vertexSource,
const std::string& fragmentSource); const std::string& fragmentSource);
private: private:
std::unordered_map<std::string, std::shared_ptr<Shader>> m_shaderList; std::unordered_map<std::string, std::shared_ptr<Shader>> m_shaderList;
}; };
} // namespace Inferno } // namespace Inferno

242
src/inferno/render/texture.cpp

@ -12,146 +12,146 @@
namespace Inferno { namespace Inferno {
Texture::Texture(const std::string& path) Texture::Texture(const std::string& path)
: m_path(std::move(path)) : m_path(std::move(path))
{ {
int width; int width;
int height; int height;
int channels; 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);
VERIFY(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() // Load image data
{ stbi_set_flip_vertically_on_load(1);
glDeleteTextures(1, &m_id); unsigned char* data = stbi_load(path.c_str(), &width, &height, &channels, STBI_default);
}
void Texture::bind(uint32_t unit) const VERIFY(data, "Failed to load image: '{}'", path);
{
// Set active unit
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, m_id); m_width = width;
m_height = height;
// Reset unit if (channels == 4) {
glActiveTexture(GL_TEXTURE0); m_internalFormat = GL_RGBA8;
m_dataFormat = GL_RGBA;
} }
else if (channels == 3) {
void Texture::unbind() const m_internalFormat = GL_RGB8;
{ m_dataFormat = GL_RGB;
glBindTexture(GL_TEXTURE_2D, 0);
} }
void Texture::create(unsigned char* data) create(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);
}
// ----------------------------------------- // Clean resources
stbi_image_free(data);
}
TextureManager::TextureManager(s) Texture::~Texture()
{ {
info() << "TextureManager initialized"; glDeleteTextures(1, &m_id);
} }
TextureManager::~TextureManager() void Texture::bind(uint32_t unit) const
{ {
} // Set active unit
glActiveTexture(GL_TEXTURE0 + unit);
void TextureManager::add(const std::string& path, std::shared_ptr<Texture> texture) glBindTexture(GL_TEXTURE_2D, m_id);
{
// 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) // Reset unit
{ glActiveTexture(GL_TEXTURE0);
if (exists(path)) { }
return get(path);
}
std::shared_ptr<Texture> texture = std::make_shared<Texture>(path); void Texture::unbind() const
add(path, texture); {
return get(path); glBindTexture(GL_TEXTURE_2D, 0);
} }
std::shared_ptr<Texture> TextureManager::get(const std::string& path) void Texture::create(unsigned char* data)
{ {
return exists(path) ? m_textureList.at(path) : nullptr; m_id = UINT_MAX;
}
// Create texture object
glGenTextures(1, &m_id);
bool TextureManager::exists(const std::string& path) // Bind texture object
{ glBindTexture(GL_TEXTURE_2D, m_id);
return m_textureList.find(path) != m_textureList.end();
// 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);
} }
void TextureManager::remove(const std::string& path) std::shared_ptr<Texture> texture = std::make_shared<Texture>(path);
{ add(path, texture);
if (exists(path)) { return get(path);
m_textureList.erase(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) void TextureManager::remove(std::shared_ptr<Texture> texture)
{ {
if (exists(texture->path())) { if (exists(texture->path())) {
m_textureList.erase(texture->path()); m_textureList.erase(texture->path());
}
} }
}
} // namespace Inferno } // namespace Inferno

90
src/inferno/render/texture.h

@ -9,50 +9,50 @@
namespace Inferno { namespace Inferno {
class Texture { class Texture {
public: public:
Texture(const std::string& path); Texture(const std::string& path);
virtual ~Texture(); virtual ~Texture();
void bind(uint32_t unit = 0) const; void bind(uint32_t unit = 0) const;
void unbind() const; void unbind() const;
inline std::string path() const { return m_path; } inline std::string path() const { return m_path; }
inline uint32_t width() const { return m_width; } inline uint32_t width() const { return m_width; }
inline uint32_t height() const { return m_height; } inline uint32_t height() const { return m_height; }
inline uint32_t id() const { return m_id; } inline uint32_t id() const { return m_id; }
inline uint32_t internalFormat() const { return m_internalFormat; } inline uint32_t internalFormat() const { return m_internalFormat; }
inline uint32_t dataFormat() const { return m_dataFormat; } inline uint32_t dataFormat() const { return m_dataFormat; }
protected: protected:
void create(unsigned char* data); void create(unsigned char* data);
private: private:
std::string m_path; std::string m_path;
uint32_t m_width; uint32_t m_width;
uint32_t m_height; uint32_t m_height;
uint32_t m_id; uint32_t m_id;
uint32_t m_internalFormat; uint32_t m_internalFormat;
uint32_t m_dataFormat; uint32_t m_dataFormat;
}; };
// ------------------------------------- // -------------------------------------
class TextureManager final : public ruc::Singleton<TextureManager> { class TextureManager final : public ruc::Singleton<TextureManager> {
public: public:
TextureManager(s); TextureManager(s);
virtual ~TextureManager(); virtual ~TextureManager();
void add(const std::string& path, std::shared_ptr<Texture> texture); void add(const std::string& path, std::shared_ptr<Texture> texture);
std::shared_ptr<Texture> load(const std::string& path); std::shared_ptr<Texture> load(const std::string& path);
std::shared_ptr<Texture> get(const std::string& path); std::shared_ptr<Texture> get(const std::string& path);
bool exists(const std::string& path); bool exists(const std::string& path);
void remove(const std::string& path); void remove(const std::string& path);
void remove(std::shared_ptr<Texture> texture); void remove(std::shared_ptr<Texture> texture);
private: private:
std::unordered_map<std::string, std::shared_ptr<Texture>> m_textureList; std::unordered_map<std::string, std::shared_ptr<Texture>> m_textureList;
}; };
} // namespace Inferno } // namespace Inferno

212
src/inferno/scene/scene.cpp

@ -17,111 +17,111 @@
namespace Inferno { namespace Inferno {
void Scene::initialize() void Scene::initialize()
{ {
// Initialize // Initialize
// --------------------------------- // ---------------------------------
m_registry = std::make_shared<entt::registry>(); m_registry = std::make_shared<entt::registry>();
TransformSystem::the().setRegistry(m_registry); TransformSystem::the().setRegistry(m_registry);
CameraSystem::the().setRegistry(m_registry); CameraSystem::the().setRegistry(m_registry);
RenderSystem::the().setRegistry(m_registry); RenderSystem::the().setRegistry(m_registry);
ScriptSystem::the().setScene(this); ScriptSystem::the().setScene(this);
TextAreaSystem::the().setScene(this); TextAreaSystem::the().setScene(this);
// Load assets // Load assets
// --------------------------------- // ---------------------------------
m_texture = TextureManager::the().load("assets/gfx/test.png"); m_texture = TextureManager::the().load("assets/gfx/test.png");
m_texture2 = TextureManager::the().load("assets/gfx/test-inverted.png"); m_texture2 = TextureManager::the().load("assets/gfx/test-inverted.png");
// Construct entities // Construct entities
// --------------------------------- // ---------------------------------
uint32_t camera = createEntity("Camera Entity"); uint32_t camera = createEntity("Camera Entity");
auto& cameraTransform = getComponent<TransformComponent>(camera); auto& cameraTransform = getComponent<TransformComponent>(camera);
// cameraTransform.rotate.z = 0.0f; // cameraTransform.rotate.z = 0.0f;
// cameraTransform.translate.z = -1.0f; // cameraTransform.translate.z = -1.0f;
// addComponent<CameraComponent>(camera, CameraType::Orthographic); // addComponent<CameraComponent>(camera, CameraType::Orthographic);
cameraTransform.rotate.z = -1.0f; cameraTransform.rotate.z = -1.0f;
cameraTransform.translate.z = 1.0f; cameraTransform.translate.z = 1.0f;
addComponent<CameraComponent>(camera, CameraType::Perspective); addComponent<CameraComponent>(camera, CameraType::Perspective);
// addComponent<NativeScriptComponent>(camera).bind<CameraController>(); // addComponent<NativeScriptComponent>(camera).bind<CameraController>();
addComponent<LuaScriptComponent>(camera, "assets/lua/cameracontroller.lua"); addComponent<LuaScriptComponent>(camera, "assets/lua/cameracontroller.lua");
uint32_t quad = createEntity("Quad"); uint32_t quad = createEntity("Quad");
addComponent<SpriteComponent>(quad, glm::vec4 { 1.0f, 1.0f, 1.0f, 1.0f }, m_texture); addComponent<SpriteComponent>(quad, glm::vec4 { 1.0f, 1.0f, 1.0f, 1.0f }, m_texture);
uint32_t quad2 = createEntity("Quad 2"); uint32_t quad2 = createEntity("Quad 2");
auto& quad2Transform = getComponent<TransformComponent>(quad2); auto& quad2Transform = getComponent<TransformComponent>(quad2);
quad2Transform.translate.x = 1.1f; quad2Transform.translate.x = 1.1f;
addComponent<SpriteComponent>(quad2, glm::vec4 { 0.5f, 0.6f, 0.8f, 1.0f }, m_texture); addComponent<SpriteComponent>(quad2, glm::vec4 { 0.5f, 0.6f, 0.8f, 1.0f }, m_texture);
uint32_t quad3 = createEntity("Quad 3"); uint32_t quad3 = createEntity("Quad 3");
auto& quad3Transform = getComponent<TransformComponent>(quad3); auto& quad3Transform = getComponent<TransformComponent>(quad3);
quad3Transform.translate.x = 2.2f; quad3Transform.translate.x = 2.2f;
addComponent<SpriteComponent>(quad3, glm::vec4 { 1.0f, 1.0f, 1.0f, 1.0f }, m_texture2); addComponent<SpriteComponent>(quad3, glm::vec4 { 1.0f, 1.0f, 1.0f, 1.0f }, m_texture2);
uint32_t text = createEntity("Text"); uint32_t text = createEntity("Text");
addComponent<TextAreaComponent>(text, "HelloWorld!", "assets/fnt/dejavu-sans", 0, 150, 3); addComponent<TextAreaComponent>(text, "HelloWorld!", "assets/fnt/dejavu-sans", 0, 150, 3);
// addComponent<TextAreaComponent>(text, "@#$%^&*()qygij!", "assets/fnt/dejavu-sans-test", 0, 150, 3); // addComponent<TextAreaComponent>(text, "@#$%^&*()qygij!", "assets/fnt/dejavu-sans-test", 0, 150, 3);
info() << "Scene initialized"; info() << "Scene initialized";
} }
void Scene::update(float deltaTime) void Scene::update(float deltaTime)
{ {
ScriptSystem::the().update(deltaTime); ScriptSystem::the().update(deltaTime);
TransformSystem::the().update(); TransformSystem::the().update();
CameraSystem::the().update(); CameraSystem::the().update();
} }
void Scene::render() void Scene::render()
{ {
RenderSystem::the().render(); RenderSystem::the().render();
TextAreaSystem::the().render(); TextAreaSystem::the().render();
} }
void Scene::destroy() void Scene::destroy()
{ {
ScriptSystem::destroy(); ScriptSystem::destroy();
RenderSystem::destroy(); RenderSystem::destroy();
CameraSystem::destroy(); CameraSystem::destroy();
TransformSystem::destroy(); TransformSystem::destroy();
} }
uint32_t Scene::createEntity(const std::string& name) uint32_t Scene::createEntity(const std::string& name)
{ {
uint32_t entity = static_cast<uint32_t>(m_registry->create()); uint32_t entity = static_cast<uint32_t>(m_registry->create());
addComponent<TagComponent>(entity, name.empty() ? "Unnamed Entity" : name); addComponent<TagComponent>(entity, name.empty() ? "Unnamed Entity" : name);
addComponent<TransformComponent>(entity); addComponent<TransformComponent>(entity);
return entity; return entity;
} }
void Scene::destroyEntity(uint32_t entity) void Scene::destroyEntity(uint32_t entity)
{ {
ScriptSystem::the().cleanup(entity); ScriptSystem::the().cleanup(entity);
m_registry->destroy(entt::entity { entity }); m_registry->destroy(entt::entity { entity });
} }
glm::mat4 Scene::cameraProjectionView() glm::mat4 Scene::cameraProjectionView()
{ {
return CameraSystem::the().projectionView(); return CameraSystem::the().projectionView();
} }
void Scene::validEntity(uint32_t entity) const void Scene::validEntity(uint32_t entity) const
{ {
VERIFY(m_registry->valid(entt::entity { entity }), "Entity is not valid"); VERIFY(m_registry->valid(entt::entity { entity }), "Entity is not valid");
} }
// ------------------------------------- // -------------------------------------
const LogStream& operator<<(const LogStream& stream, entt::entity entity) const LogStream& operator<<(const LogStream& stream, entt::entity entity)
{ {
return stream << static_cast<uint32_t>(entity); return stream << static_cast<uint32_t>(entity);
} }
} // namespace Inferno } // namespace Inferno

126
src/inferno/scene/scene.h

@ -10,73 +10,73 @@
namespace Inferno { namespace Inferno {
class Camera; class Camera;
class Texture; class Texture;
class Scene { class Scene {
public: public:
void initialize(); void initialize();
void update(float deltaTime); void update(float deltaTime);
void render(); void render();
void destroy(); void destroy();
uint32_t createEntity(const std::string& name = ""); uint32_t createEntity(const std::string& name = "");
void destroyEntity(uint32_t entity); void destroyEntity(uint32_t entity);
glm::mat4 cameraProjectionView(); glm::mat4 cameraProjectionView();
void validEntity(uint32_t entity) const; void validEntity(uint32_t entity) const;
template<typename... T> template<typename... T>
[[nodiscard]] bool hasComponent(uint32_t entity) const [[nodiscard]] bool hasComponent(uint32_t entity) const
{ {
validEntity(entity); validEntity(entity);
return m_registry->has<T...>(entt::entity { entity }); return m_registry->has<T...>(entt::entity { entity });
} }
template<typename... T> template<typename... T>
[[nodiscard]] bool anyComponent(uint32_t entity) const [[nodiscard]] bool anyComponent(uint32_t entity) const
{ {
validEntity(entity); validEntity(entity);
return m_registry->any<T...>(entt::entity { entity }); return m_registry->any<T...>(entt::entity { entity });
} }
// @Todo Should replace be allowed? could trigger memory leaks with nativescript // @Todo Should replace be allowed? could trigger memory leaks with nativescript
template<typename T, typename... P> template<typename T, typename... P>
T& addComponent(uint32_t entity, P&&... parameters) const T& addComponent(uint32_t entity, P&&... parameters) const
{ {
validEntity(entity); validEntity(entity);
return m_registry->emplace_or_replace<T>(entt::entity { entity }, std::forward<P>(parameters)...); 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;
}; };
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); const LogStream& operator<<(const LogStream& stream, entt::entity handle);
} // namespace Inferno } // namespace Inferno

224
src/inferno/script/cameracontroller.cpp

@ -1,4 +1,4 @@
#include "glm/ext/matrix_transform.hpp" // glm::radians #include "glm/ext/matrix_transform.hpp" // glm::radians
#include "inferno/component/cameracomponent.h" #include "inferno/component/cameracomponent.h"
#include "inferno/component/transformcomponent.h" #include "inferno/component/transformcomponent.h"
@ -8,115 +8,117 @@
namespace Inferno { namespace Inferno {
void CameraController::updateOrthographic(float deltaTime) void CameraController::updateOrthographic(float deltaTime)
{ {
// Update camera rotation // Update camera rotation
float cameraRotateSpeed = ROTATE_SPEED * deltaTime; float cameraRotateSpeed = ROTATE_SPEED * deltaTime;
if (Input::isKeyPressed(keyCode("GLFW_KEY_Q"))) { if (Input::isKeyPressed(keyCode("GLFW_KEY_Q"))) {
transform->rotate.z -= cameraRotateSpeed; transform->rotate.z -= cameraRotateSpeed;
} }
if (Input::isKeyPressed(keyCode("GLFW_KEY_E"))) { if (Input::isKeyPressed(keyCode("GLFW_KEY_E"))) {
transform->rotate.z += cameraRotateSpeed; transform->rotate.z += cameraRotateSpeed;
} }
if (transform->rotate.z > 180.0f) { if (transform->rotate.z > 180.0f) {
transform->rotate.z -= 360.0f; transform->rotate.z -= 360.0f;
} }
else if (transform->rotate.z <= -180.0f) { else if (transform->rotate.z <= -180.0f) {
transform->rotate.z += 360.0f; transform->rotate.z += 360.0f;
} }
// Update camera translation // Update camera translation
float cameraTranslateSpeed = TRANSLATE_SPEED * deltaTime; float cameraTranslateSpeed = TRANSLATE_SPEED * deltaTime;
// WASD movement // WASD movement
if (Input::isKeyPressed(keyCode("GLFW_KEY_W"))) { if (Input::isKeyPressed(keyCode("GLFW_KEY_W"))) {
transform->translate.x += -sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed; transform->translate.x += -sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
transform->translate.y += cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed; transform->translate.y += cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
} }
if (Input::isKeyPressed(keyCode("GLFW_KEY_S"))) { if (Input::isKeyPressed(keyCode("GLFW_KEY_S"))) {
transform->translate.x -= -sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed; transform->translate.x -= -sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
transform->translate.y -= cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed; transform->translate.y -= cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
} }
if (Input::isKeyPressed(keyCode("GLFW_KEY_A"))) { if (Input::isKeyPressed(keyCode("GLFW_KEY_A"))) {
transform->translate.x -= cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed; transform->translate.x -= cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
transform->translate.y -= sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed; transform->translate.y -= sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
} }
if (Input::isKeyPressed(keyCode("GLFW_KEY_D"))) { if (Input::isKeyPressed(keyCode("GLFW_KEY_D"))) {
transform->translate.x += cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed; transform->translate.x += cos(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
transform->translate.y += sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed; transform->translate.y += sin(glm::radians(transform->rotate.z)) * cameraTranslateSpeed;
} }
// Update camera zoom // Update camera zoom
float zoomSpeed = ZOOM_SENSITIVITY * deltaTime; float zoomSpeed = ZOOM_SENSITIVITY * deltaTime;
if (Input::isKeyPressed(keyCode("GLFW_KEY_EQUAL"))) { if (Input::isKeyPressed(keyCode("GLFW_KEY_EQUAL"))) {
m_camera->zoomLevel -= zoomSpeed; m_camera->zoomLevel -= zoomSpeed;
} }
if (Input::isKeyPressed(keyCode("GLFW_KEY_MINUS"))) { if (Input::isKeyPressed(keyCode("GLFW_KEY_MINUS"))) {
m_camera->zoomLevel += zoomSpeed; m_camera->zoomLevel += zoomSpeed;
} }
m_camera->zoomLevel = std::max(m_camera->zoomLevel, 0.25f); m_camera->zoomLevel = std::max(m_camera->zoomLevel, 0.25f);
m_camera->zoomLevel = std::min(m_camera->zoomLevel, 10.0f); m_camera->zoomLevel = std::min(m_camera->zoomLevel, 10.0f);
} }
void CameraController::updatePerspective(float deltaTime) void CameraController::updatePerspective(float deltaTime)
{ {
// Get mouse movement offset compared to last frame // Get mouse movement offset compared to last frame
float xOffset = Input::getXOffset() * MOUSE_SENSITIVITY; float xOffset = Input::getXOffset() * MOUSE_SENSITIVITY;
float yOffset = Input::getYOffset() * MOUSE_SENSITIVITY; float yOffset = Input::getYOffset() * MOUSE_SENSITIVITY;
m_camera->yaw += xOffset; m_camera->yaw += xOffset;
m_camera->pitch += yOffset; m_camera->pitch += yOffset;
// Prevent gimbal lock // Prevent gimbal lock
if (m_camera->pitch > 89.0f) m_camera->pitch = 89.0f; if (m_camera->pitch > 89.0f)
if (m_camera->pitch < -89.0f) m_camera->pitch = -89.0f; m_camera->pitch = 89.0f;
if (m_camera->pitch < -89.0f)
// Update camera rotation, by calculating direction vector via yaw and pitch m_camera->pitch = -89.0f;
transform->rotate = { // Update camera rotation, by calculating direction vector via yaw and pitch
cos(glm::radians(m_camera->pitch)) * cos(glm::radians(m_camera->yaw)),
sin(glm::radians(m_camera->pitch)), transform->rotate = {
cos(glm::radians(m_camera->pitch)) * sin(glm::radians(m_camera->yaw)) cos(glm::radians(m_camera->pitch)) * cos(glm::radians(m_camera->yaw)),
}; sin(glm::radians(m_camera->pitch)),
transform->rotate = glm::normalize(transform->rotate); cos(glm::radians(m_camera->pitch)) * sin(glm::radians(m_camera->yaw))
// The direction vector is based on };
// Camera direction (z): normalize(position - target) transform->rotate = glm::normalize(transform->rotate);
// Right axis (x): normalize(cross(up, direction)) // The direction vector is based on
// Up axis (y): cross(direction, right) // Camera direction (z): normalize(position - target)
// Right axis (x): normalize(cross(up, direction))
// Source: https://learnopengl.com/img/getting-started/camera_axes.png // Up axis (y): cross(direction, right)
// Cross = combination of two vectors in 3D space, // Source: https://learnopengl.com/img/getting-started/camera_axes.png
// where result is always perpendicular to both of the vectors
// Cross = combination of two vectors in 3D space,
// Update camera translation // where result is always perpendicular to both of the vectors
float cameraSpeed = TRANSLATE_SPEED * deltaTime; // Update camera translation
// WASD movement float cameraSpeed = TRANSLATE_SPEED * deltaTime;
if (Input::isKeyPressed(keyCode("GLFW_KEY_W"))) {
transform->translate += transform->rotate * cameraSpeed; // WASD movement
} if (Input::isKeyPressed(keyCode("GLFW_KEY_W"))) {
if (Input::isKeyPressed(keyCode("GLFW_KEY_S"))) { transform->translate += transform->rotate * cameraSpeed;
transform->translate -= transform->rotate * cameraSpeed; }
} if (Input::isKeyPressed(keyCode("GLFW_KEY_S"))) {
if (Input::isKeyPressed(keyCode("GLFW_KEY_A"))) { transform->translate -= transform->rotate * cameraSpeed;
transform->translate -= glm::normalize(glm::cross(transform->rotate, m_camera->up)) * cameraSpeed; }
} if (Input::isKeyPressed(keyCode("GLFW_KEY_A"))) {
if (Input::isKeyPressed(keyCode("GLFW_KEY_D"))) { transform->translate -= glm::normalize(glm::cross(transform->rotate, m_camera->up)) * cameraSpeed;
transform->translate += glm::normalize(glm::cross(transform->rotate, m_camera->up)) * cameraSpeed; }
} if (Input::isKeyPressed(keyCode("GLFW_KEY_D"))) {
// Up / down movement transform->translate += glm::normalize(glm::cross(transform->rotate, m_camera->up)) * cameraSpeed;
if (Input::isKeyPressed(keyCode("GLFW_KEY_SPACE"))) { }
transform->translate.y += cameraSpeed; // Up / down movement
} if (Input::isKeyPressed(keyCode("GLFW_KEY_SPACE"))) {
if (Input::isKeyPressed(keyCode("GLFW_KEY_LEFT_SHIFT"))) { transform->translate.y += cameraSpeed;
transform->translate.y -= cameraSpeed; }
} if (Input::isKeyPressed(keyCode("GLFW_KEY_LEFT_SHIFT"))) {
transform->translate.y -= cameraSpeed;
} }
} }
} // namespace Inferno

38
src/inferno/script/cameracontroller.h

@ -10,27 +10,27 @@
namespace Inferno { namespace Inferno {
struct CameraComponent; struct CameraComponent;
class CameraController final : public NativeScript { class CameraController final : public NativeScript {
public: public:
virtual void update(float deltaTime) override virtual void update(float deltaTime) override
{ {
m_camera = &getComponent<CameraComponent>(); m_camera = &getComponent<CameraComponent>();
if (m_camera->type == CameraType::Orthographic) { if (m_camera->type == CameraType::Orthographic) {
updateOrthographic(deltaTime); updateOrthographic(deltaTime);
} }
else if (m_camera->type == CameraType::Perspective) { else if (m_camera->type == CameraType::Perspective) {
updatePerspective(deltaTime); updatePerspective(deltaTime);
}
} }
}
void updateOrthographic(float deltaTime); void updateOrthographic(float deltaTime);
void updatePerspective(float deltaTime); void updatePerspective(float deltaTime);
private: private:
CameraComponent* m_camera { nullptr }; CameraComponent* m_camera { nullptr };
}; };
} // namespace Inferno } // namespace Inferno

128
src/inferno/script/luascript.cpp

@ -11,69 +11,69 @@
namespace Inferno { namespace Inferno {
void LuaScript::initialize() void LuaScript::initialize()
{ {
// Type registration // Type registration
// --------------------------------- // ---------------------------------
Registration::fill(m_state); Registration::fill(m_state);
// Load libraries // Load libraries
// --------------------------------- // ---------------------------------
m_state.open_libraries(sol::lib::base, sol::lib::math); m_state.open_libraries(sol::lib::base, sol::lib::math);
// Component get functions // Component get functions
// --------------------------------- // ---------------------------------
m_state.set_function("getTagComponent", [this]() -> TagComponent* { m_state.set_function("getTagComponent", [this]() -> TagComponent* {
return &m_scene->getComponent<TagComponent>(m_entity); return &m_scene->getComponent<TagComponent>(m_entity);
}); });
m_state.set_function("getTransformComponent", [this]() -> TransformComponent* { m_state.set_function("getTransformComponent", [this]() -> TransformComponent* {
return &m_scene->getComponent<TransformComponent>(m_entity); return &m_scene->getComponent<TransformComponent>(m_entity);
}); });
m_state.set_function("getCameraComponent", [this]() -> CameraComponent* { m_state.set_function("getCameraComponent", [this]() -> CameraComponent* {
return &m_scene->getComponent<CameraComponent>(m_entity); return &m_scene->getComponent<CameraComponent>(m_entity);
}); });
m_state.set_function("getSpriteComponent", [this]() -> SpriteComponent* { m_state.set_function("getSpriteComponent", [this]() -> SpriteComponent* {
return &m_scene->getComponent<SpriteComponent>(m_entity); return &m_scene->getComponent<SpriteComponent>(m_entity);
}); });
// Load and Initialize script // Load and Initialize script
// --------------------------------- // ---------------------------------
loadScript(); loadScript();
callFunction("LuaScript", "initialize"); callFunction("LuaScript", "initialize");
} }
void LuaScript::destroy() void LuaScript::destroy()
{ {
callFunction("LuaScript", "destroy"); callFunction("LuaScript", "destroy");
} }
void LuaScript::update(float deltaTime) void LuaScript::update(float deltaTime)
{ {
m_state["LuaScript"]["transform"] = &m_scene->getComponent<TransformComponent>(m_entity); m_state["LuaScript"]["transform"] = &m_scene->getComponent<TransformComponent>(m_entity);
callFunction("LuaScript", "update", deltaTime); callFunction("LuaScript", "update", deltaTime);
} }
void LuaScript::loadScript() void LuaScript::loadScript()
{ {
std::string script = File::read(m_path); std::string script = File::read(m_path);
auto result = m_state.script(script.c_str(), auto result = m_state.script(script.c_str(),
[](lua_State*, sol::protected_function_result pfr) { return pfr; }); [](lua_State*, sol::protected_function_result pfr) { return pfr; });
VERIFY(result.valid(), "LuaScript {}", ((sol::error)result).what()); VERIFY(result.valid(), "LuaScript {}", ((sol::error)result).what());
} }
sol::table LuaScript::getTable(const char* name) sol::table LuaScript::getTable(const char* name)
{ {
sol::table table = m_state[name]; sol::table table = m_state[name];
VERIFY(table.valid(), "LuaScript table does not exist"); VERIFY(table.valid(), "LuaScript table does not exist");
return table; return table;
} }
} // namespace Inferno } // namespace Inferno

54
src/inferno/script/luascript.h

@ -12,42 +12,42 @@
namespace Inferno { namespace Inferno {
struct TransformComponent; struct TransformComponent;
class Scene; class Scene;
class LuaScript { class LuaScript {
public: public:
void initialize(); void initialize();
void destroy(); void destroy();
void update(float deltaTime); void update(float deltaTime);
void loadScript(); void loadScript();
private: private:
sol::table getTable(const char* name); sol::table getTable(const char* name);
template<typename... P> template<typename... P>
void callFunction(const char* table, const char* function, P&&... parameters) void callFunction(const char* table, const char* function, P&&... parameters)
{ {
sol::table solTable = getTable(table); sol::table solTable = getTable(table);
sol::protected_function solFunction = solTable[function]; sol::protected_function solFunction = solTable[function];
// Only call function if it exists // Only call function if it exists
if (solFunction.valid()) { if (solFunction.valid()) {
sol::protected_function_result result = solFunction(solTable, parameters...); sol::protected_function_result result = solFunction(solTable, parameters...);
VERIFY(result.valid(), "Lua function {}", ((sol::error)result).what()); VERIFY(result.valid(), "Lua function {}", ((sol::error)result).what());
}
} }
}
sol::state m_state; sol::state m_state;
std::string m_path = ""; std::string m_path = "";
Scene* m_scene { nullptr }; Scene* m_scene { nullptr };
uint32_t m_entity { 0 }; uint32_t m_entity { 0 };
TransformComponent* transform { nullptr }; TransformComponent* transform { nullptr };
friend class ScriptSystem; friend class ScriptSystem;
}; };
} // namespace Inferno } // namespace Inferno

38
src/inferno/script/nativescript.h

@ -4,30 +4,30 @@
namespace Inferno { namespace Inferno {
struct TransformComponent; struct TransformComponent;
class NativeScript { class NativeScript {
public: public:
virtual ~NativeScript() {} virtual ~NativeScript() {}
protected: protected:
virtual void initialize() {} virtual void initialize() {}
virtual void destroy() {} virtual void destroy() {}
virtual void update(float deltaTime) { (void)deltaTime; } virtual void update(float deltaTime) { (void)deltaTime; }
template<typename T> template<typename T>
T& getComponent() const T& getComponent() const
{ {
return m_scene->getComponent<T>(m_entity); return m_scene->getComponent<T>(m_entity);
} }
TransformComponent* transform { nullptr }; TransformComponent* transform { nullptr };
private: private:
Scene* m_scene { nullptr }; Scene* m_scene { nullptr };
uint32_t m_entity { 0 }; uint32_t m_entity { 0 };
friend class ScriptSystem; friend class ScriptSystem;
}; };
} // namespace Inferno } // namespace Inferno

209
src/inferno/script/registration.cpp

@ -1,7 +1,7 @@
#include "glm/ext/matrix_transform.hpp" // glm::radians
#include "glm/ext/vector_float2.hpp" // glm::vec2 #include "glm/ext/vector_float2.hpp" // glm::vec2
#include "glm/ext/vector_float3.hpp" // glm::vec3 #include "glm/ext/vector_float3.hpp" // glm::vec3
#include "glm/ext/vector_float4.hpp" // glm::vec4 #include "glm/ext/vector_float4.hpp" // glm::vec4
#include "glm/ext/matrix_transform.hpp" // glm::radians
#include "inferno/component/cameracomponent.h" #include "inferno/component/cameracomponent.h"
#include "inferno/component/spritecomponent.h" #include "inferno/component/spritecomponent.h"
@ -13,110 +13,105 @@
namespace Inferno { namespace Inferno {
void Registration::fill(sol::state_view &state) void Registration::fill(sol::state_view& state)
{ {
glm(state); glm(state);
component(state); component(state);
input(state); input(state);
} }
void Registration::glm(sol::state_view& state) void Registration::glm(sol::state_view& state)
{ {
auto glm = state["glm"].get_or_create<sol::table>(); auto glm = state["glm"].get_or_create<sol::table>();
auto vec2 = glm.new_usertype<glm::vec2>( auto vec2 = glm.new_usertype<glm::vec2>(
"vec2", "vec2",
sol::call_constructor, sol::constructors<glm::vec2(), glm::vec2(glm::vec2), glm::vec2(float), glm::vec2(float, float)>(), 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, "x", &glm::vec2::x, "y", &glm::vec2::y,
"r", &glm::vec2::r, "g", &glm::vec2::g, "r", &glm::vec2::r, "g", &glm::vec2::g,
"s", &glm::vec2::s, "t", &glm::vec2::t, "s", &glm::vec2::s, "t", &glm::vec2::t,
"__add", addition<glm::vec2, float>(), "__add", addition<glm::vec2, float>(),
"__sub", subtraction<glm::vec2, float>(), "__sub", subtraction<glm::vec2, float>(),
"__mul", multiplication<glm::vec2, float>(), "__mul", multiplication<glm::vec2, float>(),
"__div", division<glm::vec2, float>(), "__div", division<glm::vec2, float>(),
"__tostring", string<glm::vec2> "__tostring", string<glm::vec2>);
);
auto vec3 = glm.new_usertype<glm::vec3>(
auto vec3 = glm.new_usertype<glm::vec3>( "vec3",
"vec3", sol::call_constructor, sol::constructors<glm::vec3(), glm::vec3(glm::vec3), glm::vec3(float), glm::vec3(float, float, float)>(),
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,
"x", &glm::vec3::x, "y", &glm::vec3::y, "z", &glm::vec3::z, "r", &glm::vec3::r, "g", &glm::vec3::g, "b", &glm::vec3::b,
"r", &glm::vec3::r, "g", &glm::vec3::g, "b", &glm::vec3::b, "s", &glm::vec3::s, "t", &glm::vec3::t, "p", &glm::vec3::p,
"s", &glm::vec3::s, "t", &glm::vec3::t, "p", &glm::vec3::p, "__add", addition<glm::vec3, float>(),
"__add", addition<glm::vec3, float>(), "__sub", subtraction<glm::vec3, float>(),
"__sub", subtraction<glm::vec3, float>(), "__mul", multiplication<glm::vec3, float>(),
"__mul", multiplication<glm::vec3, float>(), "__div", division<glm::vec3, float>(),
"__div", division<glm::vec3, float>(), "__tostring", string<glm::vec3>);
"__tostring", string<glm::vec3>
); auto vec4 = glm.new_usertype<glm::vec4>(
"vec4",
auto vec4 = glm.new_usertype<glm::vec4>( sol::call_constructor, sol::constructors<glm::vec4(), glm::vec4(glm::vec4), glm::vec4(float), glm::vec4(float, float, float, float)>(),
"vec4", "x", &glm::vec4::x, "y", &glm::vec4::y, "z", &glm::vec4::z, "w", &glm::vec4::w,
sol::call_constructor, sol::constructors<glm::vec4(), glm::vec4(glm::vec4), glm::vec4(float), glm::vec4(float, float, float, float)>(), "r", &glm::vec4::r, "g", &glm::vec4::g, "b", &glm::vec4::b, "a", &glm::vec4::a,
"x", &glm::vec4::x, "y", &glm::vec4::y, "z", &glm::vec4::z, "w", &glm::vec4::w, "s", &glm::vec4::s, "t", &glm::vec4::t, "p", &glm::vec4::p, "q", &glm::vec4::q,
"r", &glm::vec4::r, "g", &glm::vec4::g, "b", &glm::vec4::b, "a", &glm::vec4::a, "__add", addition<glm::vec4, float>(),
"s", &glm::vec4::s, "t", &glm::vec4::t, "p", &glm::vec4::p, "q", &glm::vec4::q, "__sub", subtraction<glm::vec4, float>(),
"__add", addition<glm::vec4, float>(), "__mul", multiplication<glm::vec4, float>(),
"__sub", subtraction<glm::vec4, float>(), "__div", division<glm::vec4, float>(),
"__mul", multiplication<glm::vec4, float>(), "__tostring", string<glm::vec4>);
"__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); },
glm.set_function("radians", sol::overload( [](const glm::vec3& v) { return glm::radians(v); },
[](float v) { return glm::radians(v); }, [](const glm::vec4& v) { return glm::radians(v); }));
[](const glm::vec2& v) { return glm::radians(v); },
[](const glm::vec3& v) { return glm::radians(v); }, glm.set_function("normalize", sol::overload(
[](const glm::vec4& v) { return glm::radians(v); } [](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("normalize", sol::overload(
[](const glm::vec2& v) { return glm::normalize(v); }, glm.set_function("cross", [](const glm::vec3& x, const glm::vec3& y) { return glm::cross(x, y); });
[](const glm::vec3& v) { return glm::normalize(v); }, }
[](const glm::vec4& v) { return glm::normalize(v); }
)); void Registration::component(sol::state_view& state)
{
glm.set_function("cross", [](const glm::vec3& x, const glm::vec3& y) { return glm::cross(x, y); }); auto tagComponent = state.new_usertype<TagComponent>("TagComponent", sol::no_constructor);
} tagComponent["tag"] = &TagComponent::tag;
void Registration::component(sol::state_view& state) auto transformComponent = state.new_usertype<TransformComponent>("TransformComponent", sol::no_constructor);
{ transformComponent["translate"] = &TransformComponent::translate;
auto tagComponent = state.new_usertype<TagComponent>("TagComponent", sol::no_constructor); transformComponent["rotate"] = &TransformComponent::rotate;
tagComponent["tag"] = &TagComponent::tag; transformComponent["scale"] = &TransformComponent::scale;
transformComponent["transform"] = &TransformComponent::transform;
auto transformComponent = state.new_usertype<TransformComponent>("TransformComponent", sol::no_constructor); transformComponent["__tostring"] = &string<TransformComponent>;
transformComponent["translate"] = &TransformComponent::translate;
transformComponent["rotate"] = &TransformComponent::rotate; auto cameraType = state.new_enum("CameraType",
transformComponent["scale"] = &TransformComponent::scale; "Orthographic", CameraType::Orthographic,
transformComponent["transform"] = &TransformComponent::transform; "Perspective", CameraType::Perspective);
transformComponent["__tostring"] = &string<TransformComponent>;
auto cameraComponent = state.new_usertype<CameraComponent>("CameraComponent", sol::no_constructor);
auto cameraType = state.new_enum("CameraType", cameraComponent["type"] = &CameraComponent::type;
"Orthographic", CameraType::Orthographic, cameraComponent["zoomLevel"] = &CameraComponent::zoomLevel;
"Perspective", CameraType::Perspective); cameraComponent["rotateAxis"] = &CameraComponent::rotateAxis;
cameraComponent["fov"] = &CameraComponent::fov;
auto cameraComponent = state.new_usertype<CameraComponent>("CameraComponent", sol::no_constructor); cameraComponent["pitch"] = &CameraComponent::pitch;
cameraComponent["type"] = &CameraComponent::type; cameraComponent["yaw"] = &CameraComponent::yaw;
cameraComponent["zoomLevel"] = &CameraComponent::zoomLevel; cameraComponent["up"] = &CameraComponent::up;
cameraComponent["rotateAxis"] = &CameraComponent::rotateAxis; cameraComponent["projection"] = &CameraComponent::projection;
cameraComponent["fov"] = &CameraComponent::fov;
cameraComponent["pitch"] = &CameraComponent::pitch; auto spriteComponent = state.new_usertype<SpriteComponent>("SpriteComponent", sol::no_constructor);
cameraComponent["yaw"] = &CameraComponent::yaw; spriteComponent["color"] = &SpriteComponent::color;
cameraComponent["up"] = &CameraComponent::up; spriteComponent["texture"] = &SpriteComponent::texture;
cameraComponent["projection"] = &CameraComponent::projection; }
auto spriteComponent = state.new_usertype<SpriteComponent>("SpriteComponent", sol::no_constructor); void Registration::input(sol::state_view& state)
spriteComponent["color"] = &SpriteComponent::color; {
spriteComponent["texture"] = &SpriteComponent::texture; state.set_function("keyCode", &keyCode);
}
auto input = state.new_usertype<Input>("Input", sol::no_constructor);
void Registration::input(sol::state_view& state) input["isKeyPressed"] = &Input::isKeyPressed;
{ input["getXOffset"] = &Input::getXOffset;
state.set_function("keyCode", &keyCode); input["getYOffset"] = &Input::getYOffset;
auto input = state.new_usertype<Input>("Input", sol::no_constructor);
input["isKeyPressed"] = &Input::isKeyPressed;
input["getXOffset"] = &Input::getXOffset;
input["getYOffset"] = &Input::getYOffset;
}
} }
} // namespace Inferno

98
src/inferno/script/registration.h

@ -7,62 +7,58 @@
namespace Inferno { namespace Inferno {
class Registration final { class Registration final {
public: public:
static void fill(sol::state_view& state); static void fill(sol::state_view& state);
private: private:
static void glm(sol::state_view& state); static void glm(sol::state_view& state);
static void component(sol::state_view& state); static void component(sol::state_view& state);
static void input(sol::state_view& state); static void input(sol::state_view& state);
template<typename T, typename V> template<typename T, typename V>
static auto addition() static auto addition()
{ {
return sol::overload( return sol::overload(
[](const T& lhs, const T& rhs) { return lhs + rhs; }, [](const T& lhs, const T& rhs) { return lhs + rhs; },
[](const T& lhs, const V& rhs) { return lhs + rhs; }, [](const T& lhs, const V& rhs) { return lhs + rhs; },
[](const V& lhs, const T& rhs) { return lhs + rhs; } [](const V& lhs, const T& rhs) { return lhs + rhs; });
); }
}
template<typename T, typename V> template<typename T, typename V>
static auto subtraction() static auto subtraction()
{ {
return sol::overload( return sol::overload(
[](const T& lhs, const T& rhs) { return lhs - rhs; }, [](const T& lhs, const T& rhs) { return lhs - rhs; },
[](const T& lhs, const V& rhs) { return lhs - rhs; }, [](const T& lhs, const V& rhs) { return lhs - rhs; },
[](const V& lhs, const T& rhs) { return lhs - rhs; } [](const V& lhs, const T& rhs) { return lhs - rhs; });
); }
}
template<typename T, typename V> template<typename T, typename V>
static auto multiplication() static auto multiplication()
{ {
return sol::overload( return sol::overload(
[](const T& lhs, const T& rhs) { return lhs * rhs; }, [](const T& lhs, const T& rhs) { return lhs * rhs; },
[](const T& lhs, const V& rhs) { return lhs * rhs; }, [](const T& lhs, const V& rhs) { return lhs * rhs; },
[](const V& lhs, const T& rhs) { return lhs * rhs; } [](const V& lhs, const T& rhs) { return lhs * rhs; });
); }
}
template<typename T, typename V> template<typename T, typename V>
static auto division() static auto division()
{ {
return sol::overload( return sol::overload(
[](const T& lhs, const T& rhs) { return lhs / rhs; }, [](const T& lhs, const T& rhs) { return lhs / rhs; },
[](const T& lhs, const V& rhs) { return lhs / rhs; }, [](const T& lhs, const V& rhs) { return lhs / rhs; },
[](const V& lhs, const T& rhs) { return lhs / rhs; } [](const V& lhs, const T& rhs) { return lhs / rhs; });
); }
}
template<typename T> template<typename T>
static std::string string(const T& t) static std::string string(const T& t)
{ {
std::string result; std::string result;
str(&result) << t; str(&result) << t;
return result; return result;
} }
}; };
} // namespace Inferno } // namespace Inferno

146
src/inferno/settings.cpp

@ -10,91 +10,91 @@
namespace Inferno { namespace Inferno {
const char* Settings::m_path { "assets/settings.json" }; const char* Settings::m_path { "assets/settings.json" };
SettingsProperties Settings::m_properties {}; SettingsProperties Settings::m_properties {};
void Settings::initialize() void Settings::initialize()
{ {
Settings::load(); Settings::load();
info() << "Settings initialized"; info() << "Settings initialized";
Settings::save(); Settings::save();
} }
void Settings::destroy()
{
}
bool Settings::load()
{
ruc::Json object;
if (!File::ioRead(&object, m_path)) {
warn() << "Settings invalid formatting, using default values";
return false;
}
m_properties = object.get<SettingsProperties>();
return true; void Settings::destroy()
} {
}
bool Settings::save()
{
ruc::Json object = m_properties;
if (!File::ioWrite(&object, m_path)) { bool Settings::load()
warn() << "Settings could not be saved"; {
return false; ruc::Json object;
}
info() << "Settings saved"; if (!File::ioRead(&object, m_path)) {
return true; warn() << "Settings invalid formatting, using default values";
return false;
} }
// ------------------------------------- m_properties = object.get<SettingsProperties>();
void toJson(ruc::Json& object, const SettingsProperties& settings)
{
object = ruc::Json {
{ "window", settings.window }
};
}
void fromJson(const ruc::Json& object, SettingsProperties& settings) return true;
{ }
VERIFY(object.type() == ruc::Json::Type::Object);
if (object.exists("window")) bool Settings::save()
object.at("window").getTo(settings.window); {
} ruc::Json object = m_properties;
void toJson(ruc::Json& object, const WindowProperties& window) if (!File::ioWrite(&object, m_path)) {
{ warn() << "Settings could not be saved";
object = ruc::Json { return false;
{ "title", window.title },
{ "width", window.width },
{ "height", window.height },
{ "fullscreen", window.fullscreen },
{ "vsync", window.vsync },
};
} }
void fromJson(const ruc::Json& object, WindowProperties& window) info() << "Settings saved";
{ return true;
VERIFY(object.type() == ruc::Json::Type::Object); }
if (object.exists("title")) // -------------------------------------
object.at("title").getTo(window.title);
if (object.exists("width")) void toJson(ruc::Json& object, const SettingsProperties& settings)
object.at("width").getTo(window.width); {
if (object.exists("height")) object = ruc::Json {
object.at("height").getTo(window.height); { "window", settings.window }
if (object.exists("fullscreen")) };
object.at("fullscreen").getTo(window.fullscreen); }
if (object.exists("vsync"))
object.at("vsync").getTo(window.vsync); void fromJson(const ruc::Json& object, SettingsProperties& settings)
} {
VERIFY(object.type() == ruc::Json::Type::Object);
if (object.exists("window"))
object.at("window").getTo(settings.window);
}
void toJson(ruc::Json& object, const WindowProperties& window)
{
object = ruc::Json {
{ "title", window.title },
{ "width", window.width },
{ "height", window.height },
{ "fullscreen", window.fullscreen },
{ "vsync", window.vsync },
};
}
void fromJson(const ruc::Json& object, WindowProperties& window)
{
VERIFY(object.type() == ruc::Json::Type::Object);
if (object.exists("title"))
object.at("title").getTo(window.title);
if (object.exists("width"))
object.at("width").getTo(window.width);
if (object.exists("height"))
object.at("height").getTo(window.height);
if (object.exists("fullscreen"))
object.at("fullscreen").getTo(window.fullscreen);
if (object.exists("vsync"))
object.at("vsync").getTo(window.vsync);
}
} // namespace Inferno } // namespace Inferno

38
src/inferno/settings.h

@ -6,33 +6,33 @@
namespace Inferno { namespace Inferno {
struct SettingsProperties { struct SettingsProperties {
WindowProperties window; WindowProperties window;
}; };
class Settings { class Settings {
public: public:
static void initialize(); static void initialize();
static void destroy(); static void destroy();
static bool load(); static bool load();
static bool save(); static bool save();
static inline SettingsProperties& get() { return m_properties; } static inline SettingsProperties& get() { return m_properties; }
private: private:
static const char* m_path; static const char* m_path;
static SettingsProperties m_properties; static SettingsProperties m_properties;
}; };
// ----------------------------------------- // -----------------------------------------
// Json arbitrary type conversion functions // Json arbitrary type conversion functions
void toJson(ruc::Json& object, const SettingsProperties& settings); void toJson(ruc::Json& object, const SettingsProperties& settings);
void fromJson(const ruc::Json& object, SettingsProperties& settings); void fromJson(const ruc::Json& object, SettingsProperties& settings);
void toJson(ruc::Json& object, const WindowProperties& window); void toJson(ruc::Json& object, const WindowProperties& window);
void fromJson(const ruc::Json& object, WindowProperties& window); void fromJson(const ruc::Json& object, WindowProperties& window);
} // namespace Inferno } // namespace Inferno

86
src/inferno/singleton.h

@ -4,48 +4,48 @@
namespace Inferno { namespace Inferno {
template<typename T> template<typename T>
class Singleton { class Singleton {
// Application is allowed to access its Singleton instance for early setting // Application is allowed to access its Singleton instance for early setting
friend class Application; friend class Application;
public: public:
static inline void initialize() static inline void initialize()
{ {
VERIFY(!s_instance, "singleton already exists"); VERIFY(!s_instance, "singleton already exists");
s_instance = new T { s {} }; s_instance = new T { s {} };
} }
static inline void destroy() static inline void destroy()
{ {
VERIFY(s_instance, "singleton does not exist"); VERIFY(s_instance, "singleton does not exist");
delete s_instance; delete s_instance;
s_instance = nullptr; s_instance = nullptr;
} }
static inline T& the() static inline T& the()
{ {
VERIFY(s_instance, "singleton does not exist"); VERIFY(s_instance, "singleton does not exist");
return *s_instance; return *s_instance;
} }
// Remove copy constructor and copy assignment operator // Remove copy constructor and copy assignment operator
Singleton(const Singleton&) = delete; Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete;
Singleton(Singleton&&) = delete; Singleton(Singleton&&) = delete;
Singleton& operator=(Singleton&&) = delete; Singleton& operator=(Singleton&&) = delete;
protected: protected:
Singleton() {} Singleton() {}
// Constructor token // Constructor token
struct s {}; struct s {};
private: private:
static T* s_instance; static T* s_instance;
}; };
template<typename T> template<typename T>
T* Singleton<T>::s_instance = nullptr; T* Singleton<T>::s_instance = nullptr;
} // namespace Inferno } // namespace Inferno

127
src/inferno/system/camerasystem.cpp

@ -12,86 +12,85 @@
namespace Inferno { namespace Inferno {
CameraSystem::CameraSystem(s) CameraSystem::CameraSystem(s)
{ {
info() << "CameraSystem initialized"; info() << "CameraSystem initialized";
} }
CameraSystem::~CameraSystem() CameraSystem::~CameraSystem()
{ {
} }
void CameraSystem::update() void CameraSystem::update()
{ {
auto view = m_registry->view<TransformComponent, CameraComponent>(); auto view = m_registry->view<TransformComponent, CameraComponent>();
for (auto [entity, transform, camera] : view.each()) { for (auto [entity, transform, camera] : view.each()) {
if (camera.type == CameraType::Orthographic) { if (camera.type == CameraType::Orthographic) {
updateOrthographic(transform, camera); updateOrthographic(transform, camera);
} }
else if (camera.type == CameraType::Perspective) { else if (camera.type == CameraType::Perspective) {
updatePerspective(transform, camera); updatePerspective(transform, camera);
}
} }
} }
}
glm::mat4 CameraSystem::projectionView() glm::mat4 CameraSystem::projectionView()
{ {
auto view = m_registry->view<TransformComponent, CameraComponent>(); auto view = m_registry->view<TransformComponent, CameraComponent>();
for (auto [entity, transform, camera] : view.each()) { for (auto [entity, transform, camera] : view.each()) {
return camera.projection * transform.transform; return camera.projection * transform.transform;
} }
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
return glm::mat4 { 1.0f }; return glm::mat4 { 1.0f };
} }
void CameraSystem::updateOrthographic(TransformComponent& transform, CameraComponent& camera) void CameraSystem::updateOrthographic(TransformComponent& transform, CameraComponent& camera)
{ {
// Update camera matrix // 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) // Local space -> World space: model matrix
{ // Is done in Object::update()
// Update camera matrix
// Local space -> World space: model matrix // World space -> View space: view matrix
// Is done in Object::update() 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) };
// World space -> View space: view matrix // View space -> Clip space: projection matrix
transform.transform = { glm::lookAt(transform.translate, transform.translate + transform.rotate, camera.up) }; float aspectRatio = Application::the().getWindow().getAspect();
camera.projection = {
glm::ortho(-aspectRatio * camera.zoomLevel, aspectRatio * camera.zoomLevel,
-camera.zoomLevel, camera.zoomLevel, -1.0f, 1.0f)
};
// View space -> Clip space: projection matrix // Clip space -> Screen space: viewport transform
float aspect = Application::the().getWindow().getAspect(); // Is done in the fragment shader using the settings of glViewport
camera.projection = { glm::perspective(glm::radians(camera.fov), aspect, NEAR_PLANE, FAR_PLANE) }; }
// Clip space -> Screen space: viewport transform void CameraSystem::updatePerspective(TransformComponent& transform, CameraComponent& camera)
// Is done in the fragment shader using the settings of glViewport {
// Update camera matrix
// Souce: https://learnopengl.com/img/getting-started/coordinate_systems.png // 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
}
} // namespace Inferno } // namespace Inferno

28
src/inferno/system/camerasystem.h

@ -11,25 +11,25 @@
namespace Inferno { namespace Inferno {
struct TransformComponent; struct TransformComponent;
struct CameraComponent; struct CameraComponent;
class CameraSystem final : public ruc::Singleton<CameraSystem> { class CameraSystem final : public ruc::Singleton<CameraSystem> {
public: public:
CameraSystem(s); CameraSystem(s);
virtual ~CameraSystem(); virtual ~CameraSystem();
void update(); void update();
glm::mat4 projectionView(); glm::mat4 projectionView();
void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; }; void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; };
private: private:
void updateOrthographic(TransformComponent& transform, CameraComponent& camera); void updateOrthographic(TransformComponent& transform, CameraComponent& camera);
void updatePerspective(TransformComponent& transform, CameraComponent& camera); void updatePerspective(TransformComponent& transform, CameraComponent& camera);
std::shared_ptr<entt::registry> m_registry; std::shared_ptr<entt::registry> m_registry;
}; };
} // namespace Inferno } // namespace Inferno

26
src/inferno/system/rendersystem.cpp

@ -8,22 +8,22 @@
namespace Inferno { namespace Inferno {
RenderSystem::RenderSystem(s) RenderSystem::RenderSystem(s)
{ {
info() << "RenderSystem initialized"; info() << "RenderSystem initialized";
} }
RenderSystem::~RenderSystem() RenderSystem::~RenderSystem()
{ {
} }
void RenderSystem::render() void RenderSystem::render()
{ {
auto group = m_registry->group<TransformComponent, SpriteComponent>(); auto group = m_registry->group<TransformComponent, SpriteComponent>();
for (auto [entity, transform, sprite] : group.each()) { for (auto [entity, transform, sprite] : group.each()) {
Renderer2D::the().drawQuad(transform, sprite.color, sprite.texture); Renderer2D::the().drawQuad(transform, sprite.color, sprite.texture);
}
} }
}
} // namespace Inferno } // namespace Inferno

18
src/inferno/system/rendersystem.h

@ -9,17 +9,17 @@
namespace Inferno { namespace Inferno {
class RenderSystem final : public ruc::Singleton<RenderSystem> { class RenderSystem final : public ruc::Singleton<RenderSystem> {
public: public:
RenderSystem(s); RenderSystem(s);
virtual ~RenderSystem(); virtual ~RenderSystem();
void render(); void render();
void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; }; void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; };
private: private:
std::shared_ptr<entt::registry> m_registry; std::shared_ptr<entt::registry> m_registry;
}; };
} // namespace Inferno } // namespace Inferno

126
src/inferno/system/scriptsystem.cpp

@ -11,91 +11,91 @@
namespace Inferno { namespace Inferno {
ScriptSystem::ScriptSystem(s) ScriptSystem::ScriptSystem(s)
{ {
info() << "ScriptSystem initialized"; info() << "ScriptSystem initialized";
} }
ScriptSystem::~ScriptSystem() ScriptSystem::~ScriptSystem()
{ {
auto nativeScriptView = m_scene->registry()->view<NativeScriptComponent>(); auto nativeScriptView = m_scene->registry()->view<NativeScriptComponent>();
for (auto entity : nativeScriptView) { for (auto entity : nativeScriptView) {
cleanup(nativeScriptView.get<NativeScriptComponent>(entity)); cleanup(nativeScriptView.get<NativeScriptComponent>(entity));
} }
auto luaScriptView = m_scene->registry()->view<LuaScriptComponent>(); auto luaScriptView = m_scene->registry()->view<LuaScriptComponent>();
for (auto entity : luaScriptView) { for (auto entity : luaScriptView) {
cleanup(luaScriptView.get<LuaScriptComponent>(entity)); cleanup(luaScriptView.get<LuaScriptComponent>(entity));
}
} }
}
void ScriptSystem::update(float deltaTime) void ScriptSystem::update(float deltaTime)
{ {
// @Todo figure out why group doesn't work here // @Todo figure out why group doesn't work here
auto nativeScriptView = m_scene->registry()->view<TransformComponent, NativeScriptComponent>(); auto nativeScriptView = m_scene->registry()->view<TransformComponent, NativeScriptComponent>();
for (auto [entity, transform, nativeScript] : nativeScriptView.each()) {
// Create native script if not initialized for (auto [entity, transform, nativeScript] : nativeScriptView.each()) {
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();
}
// Create native script if not initialized
if (!nativeScript.instance) {
nativeScript.instance = nativeScript.initialize();
nativeScript.instance->transform = &transform; nativeScript.instance->transform = &transform;
nativeScript.instance->update(deltaTime); nativeScript.instance->m_scene = m_scene;
nativeScript.instance->m_entity = static_cast<uint32_t>(entity);
nativeScript.instance->initialize();
} }
auto luaScriptView = m_scene->registry()->view<TransformComponent, LuaScriptComponent>(); nativeScript.instance->transform = &transform;
nativeScript.instance->update(deltaTime);
}
for (auto [entity, transform, luaScript] : luaScriptView.each()) { auto luaScriptView = m_scene->registry()->view<TransformComponent, LuaScriptComponent>();
// Create Lua script if not initialized for (auto [entity, transform, luaScript] : luaScriptView.each()) {
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); // 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) void ScriptSystem::cleanup(uint32_t entity)
{ {
if (m_scene->hasComponent<NativeScriptComponent>(entity)) { if (m_scene->hasComponent<NativeScriptComponent>(entity)) {
auto& nativeScript = m_scene->getComponent<NativeScriptComponent>(entity); auto& nativeScript = m_scene->getComponent<NativeScriptComponent>(entity);
cleanup(nativeScript); cleanup(nativeScript);
} }
if (m_scene->hasComponent<LuaScriptComponent>(entity)) { if (m_scene->hasComponent<LuaScriptComponent>(entity)) {
auto& luaScript = m_scene->getComponent<LuaScriptComponent>(entity); auto& luaScript = m_scene->getComponent<LuaScriptComponent>(entity);
cleanup(luaScript); cleanup(luaScript);
}
} }
}
void ScriptSystem::cleanup(NativeScriptComponent& nativeScript) void ScriptSystem::cleanup(NativeScriptComponent& nativeScript)
{ {
if (nativeScript.instance) { if (nativeScript.instance) {
nativeScript.instance->destroy(); nativeScript.instance->destroy();
nativeScript.destroy(); nativeScript.destroy();
}
} }
}
void ScriptSystem::cleanup(LuaScriptComponent& luaScript) void ScriptSystem::cleanup(LuaScriptComponent& luaScript)
{ {
if (luaScript.instance) { if (luaScript.instance) {
luaScript.instance->destroy(); luaScript.instance->destroy();
delete luaScript.instance; delete luaScript.instance;
}
} }
}
} // namespace Inferno } // namespace Inferno

30
src/inferno/system/scriptsystem.h

@ -6,26 +6,26 @@
namespace Inferno { namespace Inferno {
struct NativeScriptComponent; struct NativeScriptComponent;
struct LuaScriptComponent; struct LuaScriptComponent;
class Scene; class Scene;
class ScriptSystem final : public ruc::Singleton<ScriptSystem> { class ScriptSystem final : public ruc::Singleton<ScriptSystem> {
public: public:
ScriptSystem(s); ScriptSystem(s);
virtual ~ScriptSystem(); virtual ~ScriptSystem();
void update(float deltaTime); void update(float deltaTime);
void cleanup(uint32_t entity); void cleanup(uint32_t entity);
void cleanup(NativeScriptComponent& nativeScript); void cleanup(NativeScriptComponent& nativeScript);
void cleanup(LuaScriptComponent& luaScript); void cleanup(LuaScriptComponent& luaScript);
void setScene(Scene* scene) { m_scene = scene; } void setScene(Scene* scene) { m_scene = scene; }
private: private:
Scene* m_scene { nullptr }; Scene* m_scene { nullptr };
}; };
} // namespace Inferno } // namespace Inferno

168
src/inferno/system/textareasystem.cpp

@ -11,108 +11,108 @@
namespace Inferno { namespace Inferno {
TextAreaSystem::TextAreaSystem(s) TextAreaSystem::TextAreaSystem(s)
{ {
info() << "TextAreaSystem initialized"; info() << "TextAreaSystem initialized";
} }
TextAreaSystem::~TextAreaSystem() TextAreaSystem::~TextAreaSystem()
{ {
} }
void TextAreaSystem::render() void TextAreaSystem::render()
{ {
auto view = m_scene->registry()->view<TransformComponent, TextAreaComponent>(); auto view = m_scene->registry()->view<TransformComponent, TextAreaComponent>();
glm::ivec2 viewport = { glm::ivec2 viewport = {
Application::the().getWindow().getWidth(), Application::the().getWindow().getWidth(),
Application::the().getWindow().getHeight(), Application::the().getWindow().getHeight(),
}; };
for (auto [entity, transform, textarea] : view.each()) { for (auto [entity, transform, textarea] : view.each()) {
// Loop through textareas content // Loop through textareas content
// Linebreak if width reached // Linebreak if width reached
// Break if lines AND width reached // Break if lines AND width reached
// Calculate character quad // Calculate character quad
// Submit character quad for rendering // Submit character quad for rendering
std::shared_ptr<Font> font = FontManager::the().load(textarea.font); std::shared_ptr<Font> font = FontManager::the().load(textarea.font);
// glm::mat4 translate = transform.translate; // glm::mat4 translate = transform.translate;
float advance = 0.0f; float advance = 0.0f;
for (auto character : textarea.content) { for (auto character : textarea.content) {
std::optional<CharacterQuad> quad = calculateCharacterQuad(character, font, advance); std::optional<CharacterQuad> quad = calculateCharacterQuad(character, font, advance);
if (quad) { if (quad) {
RendererCharacter::the().drawCharacter(quad.value(), font->texture()); RendererCharacter::the().drawCharacter(quad.value(), font->texture());
}
} }
} }
} }
}
std::optional<CharacterQuad> TextAreaSystem::calculateCharacterQuad(unsigned char character, std::shared_ptr<Font> font, float& advance) std::optional<CharacterQuad> TextAreaSystem::calculateCharacterQuad(unsigned char character, std::shared_ptr<Font> font, float& advance)
{ {
CharacterQuad characterQuad; CharacterQuad characterQuad;
auto c = font->get(character); auto c = font->get(character);
// Texture // Texture
// --------------------------------- // ---------------------------------
float textureWidth = static_cast<float>(font->texture()->width()); float textureWidth = static_cast<float>(font->texture()->width());
float textureHeight = static_cast<float>(font->texture()->height()); float textureHeight = static_cast<float>(font->texture()->height());
VERIFY(textureWidth == textureHeight, "TextAreaSystem read invalid font texture"); VERIFY(textureWidth == textureHeight, "TextAreaSystem read invalid font texture");
// Skip empty characters // Skip empty characters
if (c->size.x == 0 || c->size.y == 0) { if (c->size.x == 0 || c->size.y == 0) {
// Jump to the next glyph // Jump to the next glyph
advance += c->advance / textureWidth; advance += c->advance / textureWidth;
return {}; return {};
} }
// Position // Position
// --------------------------------- // ---------------------------------
float quadWidth = c->size.x / textureWidth; float quadWidth = c->size.x / textureWidth;
float quadHeight = c->size.y / textureHeight; float quadHeight = c->size.y / textureHeight;
characterQuad.at(0).quad.position = { -quadWidth, -quadHeight, 0.0f }; // bottom left characterQuad.at(0).quad.position = { -quadWidth, -quadHeight, 0.0f }; // bottom left
characterQuad.at(1).quad.position = { quadWidth, -quadHeight, 0.0f }; // bottom right characterQuad.at(1).quad.position = { quadWidth, -quadHeight, 0.0f }; // bottom right
characterQuad.at(2).quad.position = { quadWidth, quadHeight, 0.0f }; // top right characterQuad.at(2).quad.position = { quadWidth, quadHeight, 0.0f }; // top right
characterQuad.at(3).quad.position = { -quadWidth, quadHeight, 0.0f }; // top left characterQuad.at(3).quad.position = { -quadWidth, quadHeight, 0.0f }; // top left
for (auto& quad : characterQuad) { for (auto& quad : characterQuad) {
quad.quad.position.x -= 0.5f; quad.quad.position.x -= 0.5f;
quad.quad.position.x += c->offset.x / (float)textureWidth; quad.quad.position.x += c->offset.x / (float)textureWidth;
quad.quad.position.y -= c->offset.y / (float)textureHeight; quad.quad.position.y -= c->offset.y / (float)textureHeight;
quad.quad.position.x += advance; quad.quad.position.x += advance;
} }
// dbgln("character: {} ({}) width: {} height: {} advance: {} x: {}", // dbgln("character: {} ({}) width: {} height: {} advance: {} x: {}",
// character, (int)character, quadWidth, quadHeight, advance, characterQuad.at(0).quad.position.x); // character, (int)character, quadWidth, quadHeight, advance, characterQuad.at(0).quad.position.x);
// Jump to the next glyph // Jump to the next glyph
advance += c->advance / textureWidth; advance += c->advance / textureWidth;
// Texture coordinates // Texture coordinates
// --------------------------------- // ---------------------------------
glm::vec2 x { glm::vec2 x {
1 - (textureWidth - c->position.x) / textureWidth, 1 - (textureWidth - c->position.x) / textureWidth,
1 - (textureWidth - c->position.x - c->size.x) / textureWidth 1 - (textureWidth - c->position.x - c->size.x) / textureWidth
}; };
glm::vec2 y { glm::vec2 y {
(textureHeight - c->position.y - c->size.y) / textureHeight, (textureHeight - c->position.y - c->size.y) / textureHeight,
(textureHeight - c->position.y) / textureHeight (textureHeight - c->position.y) / textureHeight
}; };
characterQuad.at(0).quad.textureCoordinates = { x.x, y.x }; characterQuad.at(0).quad.textureCoordinates = { x.x, y.x };
characterQuad.at(1).quad.textureCoordinates = { x.y, y.x }; characterQuad.at(1).quad.textureCoordinates = { x.y, y.x };
characterQuad.at(2).quad.textureCoordinates = { x.y, y.y }; characterQuad.at(2).quad.textureCoordinates = { x.y, y.y };
characterQuad.at(3).quad.textureCoordinates = { x.x, y.y }; characterQuad.at(3).quad.textureCoordinates = { x.x, y.y };
return characterQuad; return characterQuad;
} }
} // namespace Inferno } // namespace Inferno

26
src/inferno/system/textareasystem.h

@ -12,24 +12,24 @@
namespace Inferno { namespace Inferno {
using CharacterQuad = std::array<CharacterVertex, Renderer::vertexPerQuad>; using CharacterQuad = std::array<CharacterVertex, Renderer::vertexPerQuad>;
class Font; class Font;
class Scene; class Scene;
class TextAreaSystem final : public ruc::Singleton<TextAreaSystem> { class TextAreaSystem final : public ruc::Singleton<TextAreaSystem> {
public: public:
TextAreaSystem(s); TextAreaSystem(s);
virtual ~TextAreaSystem(); virtual ~TextAreaSystem();
void render(); void render();
void setScene(Scene* scene) { m_scene = scene; } void setScene(Scene* scene) { m_scene = scene; }
private: private:
std::optional<CharacterQuad> calculateCharacterQuad(unsigned char character, std::shared_ptr<Font> font, float& advance); std::optional<CharacterQuad> calculateCharacterQuad(unsigned char character, std::shared_ptr<Font> font, float& advance);
Scene* m_scene { nullptr }; Scene* m_scene { nullptr };
}; };
} // namespace Inferno } // namespace Inferno

46
src/inferno/system/transformsystem.cpp

@ -6,37 +6,37 @@
namespace Inferno { namespace Inferno {
TransformSystem::TransformSystem(s) TransformSystem::TransformSystem(s)
{ {
info() << "TransformSystem initialized"; info() << "TransformSystem initialized";
} }
TransformSystem::~TransformSystem() TransformSystem::~TransformSystem()
{ {
} }
void TransformSystem::update() void TransformSystem::update()
{ {
auto view = m_registry->view<TransformComponent>(); auto view = m_registry->view<TransformComponent>();
for (auto entity : view) { for (auto entity : view) {
auto& component = view.get<TransformComponent>(entity); auto& component = view.get<TransformComponent>(entity);
// Identity matrix // Identity matrix
component.transform = glm::mat4(1.0f); component.transform = glm::mat4(1.0f);
// Translate // Translate
component.transform = glm::translate(component.transform, component.translate); component.transform = glm::translate(component.transform, component.translate);
// Rotate // 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.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.y), { 0.0, 1.0, 0.0 });
component.transform = glm::rotate(component.transform, glm::radians(component.rotate.z), {0.0, 0.0, 1.0}); component.transform = glm::rotate(component.transform, glm::radians(component.rotate.z), { 0.0, 0.0, 1.0 });
// Scale // Scale
component.transform = glm::scale(component.transform, component.scale); component.transform = glm::scale(component.transform, component.scale);
}
} }
}
} // namespace Inferno } // namespace Inferno

18
src/inferno/system/transformsystem.h

@ -7,17 +7,17 @@
namespace Inferno { namespace Inferno {
class TransformSystem final : public ruc::Singleton<TransformSystem> { class TransformSystem final : public ruc::Singleton<TransformSystem> {
public: public:
TransformSystem(s); TransformSystem(s);
virtual ~TransformSystem(); virtual ~TransformSystem();
void update(); void update();
void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; }; void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; };
private: private:
std::shared_ptr<entt::registry> m_registry; std::shared_ptr<entt::registry> m_registry;
}; };
} // namespace Inferno } // namespace Inferno

10
src/inferno/time.cpp

@ -4,9 +4,9 @@
namespace Inferno { namespace Inferno {
float Time::time() float Time::time()
{ {
return static_cast<float>(glfwGetTime()); return static_cast<float>(glfwGetTime());
}
} }
} // namespace Inferno

8
src/inferno/time.h

@ -2,9 +2,9 @@
namespace Inferno { namespace Inferno {
class Time { class Time {
public: public:
static float time(); static float time();
}; };
} // namespace Inferno } // namespace Inferno

22
src/inferno/util/integer.h

@ -7,18 +7,18 @@
namespace std { namespace std {
// Can't believe this is not in the standard library // Can't believe this is not in the standard library
inline uint32_t stou(const std::string& string) inline uint32_t stou(const std::string& string)
{ {
unsigned long size = std::stoul(string); unsigned long size = std::stoul(string);
VERIFY(size <= std::numeric_limits<uint32_t>::max(), "String util not in uint32_t range '{}'", string); VERIFY(size <= std::numeric_limits<uint32_t>::max(), "String util not in uint32_t range '{}'", string);
return static_cast<uint32_t>(size); return static_cast<uint32_t>(size);
} }
inline uint32_t stou(const char* string) inline uint32_t stou(const char* string)
{ {
return stou(std::string(string)); return stou(std::string(string));
} }
} // namespace std } // namespace std

10
src/inferno/util/json.h

@ -1,12 +1,12 @@
#pragma once #pragma once
#if 0 #if 0
#include <cstdint> // int32_t, uint32_t #include <cstdint> // int32_t, uint32_t
#include <optional> // std::optional #include <optional> // std::optional
#include <vector> // std::vector #include <vector> // std::vector
#include "nlohmann/json.hpp" #include "nlohmann/json.hpp"
#include "ruc/meta/assert.h" #include "ruc/meta/assert.h"
namespace Inferno { namespace Inferno {

18
src/inferno/util/string.h

@ -5,15 +5,15 @@
namespace Inferno { namespace Inferno {
template<typename T> template<typename T>
std::string intToHex(T i) std::string intToHex(T i)
{ {
std::stringstream stream; std::stringstream stream;
stream << "0x" stream << "0x"
<< std::setfill('0') << std::setw(sizeof(T) * 2) << std::setfill('0') << std::setw(sizeof(T) * 2)
<< std::hex << i; << std::hex << i;
return stream.str(); return stream.str();
} }
} // namespace Inferno } // namespace Inferno

393
src/inferno/window.cpp

@ -18,244 +18,245 @@
namespace Inferno { namespace Inferno {
unsigned char Window::s_windowCount = 0; unsigned char Window::s_windowCount = 0;
Window::Window() Window::Window()
{ {
m_properties = { m_properties = {
Settings::get().window.title, Settings::get().window.title,
Settings::get().window.width, Settings::get().window.width,
Settings::get().window.height, Settings::get().window.height,
Settings::get().window.fullscreen, Settings::get().window.fullscreen,
Settings::get().window.vsync, Settings::get().window.vsync,
}; };
this->initialize(); this->initialize();
} }
Window::~Window() Window::~Window()
{ {
this->destroy(); this->destroy();
} }
// ----------------------------------------- // -----------------------------------------
void Window::initialize() void Window::initialize()
{ {
std::string title = m_properties.title; std::string title = m_properties.title;
uint32_t width = m_properties.width; uint32_t width = m_properties.width;
uint32_t height = m_properties.height; uint32_t height = m_properties.height;
bool vsync = m_properties.vsync; bool vsync = m_properties.vsync;
// Only init once // Only init once
if (s_windowCount == 0) { if (s_windowCount == 0) {
glfwInit(); glfwInit();
} }
// Set window properties // Set window properties
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
// Create GLFW window // Create GLFW window
m_window = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr); m_window = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);
s_windowCount++; s_windowCount++;
VERIFY(m_window, "Failed to create GLFW window!"); VERIFY(m_window, "Failed to create GLFW window!");
// Set windowed/fullscreen/borderless // Set windowed/fullscreen/borderless
this->setWindowMonitor(); this->setWindowMonitor();
// Associate the wrapper to the window // Associate the wrapper to the window
glfwSetWindowUserPointer(m_window, this); glfwSetWindowUserPointer(m_window, this);
// Create graphics context // Create graphics context
m_context = std::make_shared<Context>(m_window); m_context = std::make_shared<Context>(m_window);
m_context->initialize(); m_context->initialize();
// Set vsync, viewport // Set vsync, viewport
setVSync(vsync); setVSync(vsync);
RenderCommand::setViewport(0, 0, width, height); RenderCommand::setViewport(0, 0, width, height);
// Signal callbacks // Signal callbacks
signal(SIGINT, Window::signalCallback); signal(SIGINT, Window::signalCallback);
signal(SIGTERM, Window::signalCallback); signal(SIGTERM, Window::signalCallback);
// Error callback // Error callback
glfwSetErrorCallback([](int error, const char* description) { glfwSetErrorCallback([](int error, const char* description) {
dbgln("GLFW Error {}: {}", error, description); dbgln("GLFW Error {}: {}", error, description);
}); });
// Window close callback // Window close callback
glfwSetWindowCloseCallback(m_window, [](GLFWwindow* window) { glfwSetWindowCloseCallback(m_window, [](GLFWwindow* window) {
Window& w = *(Window*)glfwGetWindowUserPointer(window); Window& w = *(Window*)glfwGetWindowUserPointer(window);
WindowCloseEvent event; WindowCloseEvent event;
w.m_eventCallback(event); w.m_eventCallback(event);
}); });
// Window resize callback // Window resize callback
glfwSetWindowSizeCallback(m_window, [](GLFWwindow* window, int width, int height) { glfwSetWindowSizeCallback(m_window, [](GLFWwindow* window, int width, int height) {
Window& w = *(Window*)glfwGetWindowUserPointer(window); Window& w = *(Window*)glfwGetWindowUserPointer(window);
w.m_properties.width = width; w.m_properties.width = width;
w.m_properties.height = height; w.m_properties.height = height;
WindowResizeEvent event(width, 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); w.m_eventCallback(event);
}); break;
}
// Keyboard callback case GLFW_RELEASE: {
glfwSetKeyCallback(m_window, [](GLFWwindow* window, int key, int scanCode, int action, int mods) { KeyReleaseEvent event(key);
// Suppress unused warning w.m_eventCallback(event);
(void)scanCode; break;
(void)mods; }
case GLFW_REPEAT: {
Window& w = *(Window*)glfwGetWindowUserPointer(window); KeyRepeatEvent event(key);
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); w.m_eventCallback(event);
}); break;
}
}
});
// Mouse button callback
glfwSetMouseButtonCallback(m_window, [](GLFWwindow* window, int button, int action, int mods) {
// Suppress unused warning
(void)mods;
// Mouse scroll callback Window& w = *(Window*)glfwGetWindowUserPointer(window);
glfwSetScrollCallback(m_window, [](GLFWwindow* window, double xOffset, double yOffset) {
Window& w = *(Window*)glfwGetWindowUserPointer(window);
MouseScrollEvent event(xOffset, yOffset); switch (action) {
case GLFW_PRESS: {
MouseButtonPressEvent event(button);
w.m_eventCallback(event); w.m_eventCallback(event);
}); break;
} }
case GLFW_RELEASE: {
MouseButtonReleaseEvent event(button);
w.m_eventCallback(event);
break;
}
}
});
void Window::destroy() // Mouse position callback
{ glfwSetCursorPosCallback(m_window, [](GLFWwindow* window, double xPos, double yPos) {
m_context->destroy(); Window& w = *(Window*)glfwGetWindowUserPointer(window);
glfwDestroyWindow(m_window); MousePositionEvent event(xPos, yPos);
s_windowCount--; w.m_eventCallback(event);
});
if (s_windowCount == 0) { // Mouse scroll callback
glfwTerminate(); glfwSetScrollCallback(m_window, [](GLFWwindow* window, double xOffset, double yOffset) {
} Window& w = *(Window*)glfwGetWindowUserPointer(window);
}
void Window::update() MouseScrollEvent event(xOffset, yOffset);
{ w.m_eventCallback(event);
glfwPollEvents(); });
}
// Capture cursor in window and hide it void Window::destroy()
if (!Input::isKeyPressed(keyCode("GLFW_KEY_LEFT_SUPER"))) { {
glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); m_context->destroy();
}
else { glfwDestroyWindow(m_window);
glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); s_windowCount--;
}
if (s_windowCount == 0) {
glfwTerminate();
} }
}
void Window::update()
{
glfwPollEvents();
void Window::render() // Capture cursor in window and hide it
{ if (!Input::isKeyPressed(keyCode("GLFW_KEY_LEFT_SUPER"))) {
m_context->render(); 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) void Window::signalCallback(int signal)
{ {
Application::the().setStatus(signal); Application::the().setStatus(signal);
if (signal == SIGINT || signal == SIGTERM) { if (signal == SIGINT || signal == SIGTERM) {
WindowCloseEvent e; WindowCloseEvent e;
Application::the().getWindow().m_eventCallback(e); Application::the().getWindow().m_eventCallback(e);
}
} }
}
void Window::setWindowMonitor() const void Window::setWindowMonitor() const
{ {
GLFWmonitor* monitor = glfwGetPrimaryMonitor(); GLFWmonitor* monitor = glfwGetPrimaryMonitor();
int xPos = 0; int xPos = 0;
int yPos = 0; int yPos = 0;
unsigned int width = m_properties.width; unsigned int width = m_properties.width;
unsigned int height = m_properties.height; unsigned int height = m_properties.height;
int refresh = GLFW_DONT_CARE; int refresh = GLFW_DONT_CARE;
std::string fullscreen = m_properties.fullscreen;
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
if (fullscreen.compare("fullscreen") == 0) { std::string fullscreen = m_properties.fullscreen;
refresh = mode->refreshRate; const GLFWvidmode* mode = glfwGetVideoMode(monitor);
}
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); if (fullscreen.compare("fullscreen") == 0) {
refresh = mode->refreshRate;
} }
else if (fullscreen.compare("borderless") == 0) {
void Window::setVSync(bool enabled) width = mode->width;
{ height = mode->height;
enabled ? glfwSwapInterval(GL_TRUE) : glfwSwapInterval(GL_FALSE); refresh = mode->refreshRate;
m_properties.vsync = enabled;
} }
// Default window state is windowed
void Window::setShouldClose(bool close) const else {
{ monitor = nullptr;
glfwSetWindowShouldClose(m_window, close ? GL_TRUE : GL_FALSE); // Put window in the center of the monitor
xPos = (mode->width - width) / 2;
yPos = (mode->height - height) / 2;
} }
bool Window::shouldClose() const { glfwSetWindowMonitor(m_window, monitor, xPos, yPos, width, height, refresh);
return glfwWindowShouldClose(m_window); }
}
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);
}
} // namespace Inferno

74
src/inferno/window.h

@ -9,55 +9,55 @@ struct GLFWwindow;
namespace Inferno { namespace Inferno {
class Context; class Context;
class Event; class Event;
struct WindowProperties { struct WindowProperties {
std::string title { "Inferno" }; std::string title { "Inferno" };
uint32_t width = 1280; uint32_t width = 1280;
uint32_t height = 720; uint32_t height = 720;
std::string fullscreen { "windowed" }; // windowed/fullscreen/borderless std::string fullscreen { "windowed" }; // windowed/fullscreen/borderless
bool vsync = true; bool vsync = true;
}; };
class Window { class Window {
public: public:
Window(); Window();
virtual ~Window(); virtual ~Window();
// ----------------------------------------- // -----------------------------------------
void initialize(); void initialize();
void destroy(); void destroy();
void update(); void update();
void render(); void render();
// ----------------------------------------- // -----------------------------------------
static void signalCallback(int signal); static void signalCallback(int signal);
void setWindowMonitor() const; void setWindowMonitor() const;
void setVSync(bool enabled); void setVSync(bool enabled);
void setShouldClose(bool close) const; void setShouldClose(bool close) const;
bool shouldClose() const; bool shouldClose() const;
inline float getAspect() const { return static_cast<float>(m_properties.width) / static_cast<float>(m_properties.height); } 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 getWidth() const { return m_properties.width; }
inline uint32_t getHeight() const { return m_properties.height; } inline uint32_t getHeight() const { return m_properties.height; }
inline GLFWwindow* getWindow() const { return m_window; } inline GLFWwindow* getWindow() const { return m_window; }
inline std::shared_ptr<Context> getContext() const { return m_context; } inline std::shared_ptr<Context> getContext() const { return m_context; }
inline void setEventCallback(const std::function<void(Event&)>& callback) { m_eventCallback = callback; } inline void setEventCallback(const std::function<void(Event&)>& callback) { m_eventCallback = callback; }
private: private:
WindowProperties m_properties; WindowProperties m_properties;
GLFWwindow* m_window; GLFWwindow* m_window;
std::shared_ptr<Context> m_context; std::shared_ptr<Context> m_context;
std::function<void(Event&)> m_eventCallback; std::function<void(Event&)> m_eventCallback;
static unsigned char s_windowCount; static unsigned char s_windowCount;
}; };
} // namespace Inferno } // namespace Inferno

Loading…
Cancel
Save