From 0bf9b26b87075448d49482fe4411739af765d872 Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Thu, 3 Oct 2024 19:08:44 -0400 Subject: Update codebase Bring up-to-date with my other projects. Wallpaper engine behavior is mostly unchanged. Signed-off-by: Andrew Opalach --- src/assets.cc | 38 ++++-- src/assets.h | 29 +++-- src/context.cc | 43 +------ src/context.h | 110 ++++++++++++++---- src/context_glfw.cc | 131 --------------------- src/context_glfw.h | 34 ------ src/context_null.h | 55 --------- src/context_x11.cc | 302 ------------------------------------------------ src/context_x11.h | 64 ---------- src/engine.cc | 55 +++------ src/engine.h | 9 +- src/framebuffer.cc | 16 --- src/framebuffer.h | 23 ---- src/gl.cc | 46 +++++--- src/gl.h | 15 ++- src/json.h | 40 +++++-- src/log.h | 31 ++--- src/mauri.cc | 118 ++++++++++--------- src/objects/effect.cc | 42 ++++--- src/objects/effect.h | 5 +- src/objects/material.cc | 19 +-- src/objects/material.h | 10 +- src/objects/model.cc | 25 ++-- src/objects/model.h | 4 +- src/objects/object.cc | 91 +++++++-------- src/objects/object.h | 16 ++- src/objects/pass.cc | 77 ++++++------ src/objects/pass.h | 26 ++++- src/objects/scene.cc | 43 ++++--- src/objects/scene.h | 7 +- src/shader.cc | 138 ++++++++++++++-------- src/shader.h | 6 +- src/texture.cc | 34 ++++-- src/texture.h | 19 ++- src/util.cc | 16 --- src/util.h | 62 +++------- src/vis.cc | 44 ++++--- src/vis.h | 4 +- 38 files changed, 697 insertions(+), 1150 deletions(-) delete mode 100644 src/context_glfw.cc delete mode 100644 src/context_glfw.h delete mode 100644 src/context_null.h delete mode 100644 src/context_x11.cc delete mode 100644 src/context_x11.h delete mode 100644 src/framebuffer.cc delete mode 100644 src/framebuffer.h delete mode 100644 src/util.cc (limited to 'src') diff --git a/src/assets.cc b/src/assets.cc index f892662..baf3922 100644 --- a/src/assets.cc +++ b/src/assets.cc @@ -1,9 +1,8 @@ -#include #include -#include +#include -#include "texture.h" #include "assets.h" +#include "texture.h" namespace Mauri { @@ -124,7 +123,7 @@ auto AssetManager::arm_package(const std::string &path, bool can_output) -> bool byte *start = this->package->ptr() + asset.offset; byte *end = start + asset.length; this->assets[i] = new Asset(std::string(asset.path), start, end); - debug("package file: (%s)", std::string(asset.path).c_str()); + debug("package file: (%s)", this->assets[i]->path.c_str()); } this->prepare_output = can_output; @@ -144,6 +143,16 @@ auto AssetManager::unload_package() -> void delete this->package; } + +auto AssetManager::add_search_directory(const std::string &directory) -> bool +{ + if (!std::filesystem::is_directory(directory)) return false; + + this->directories.push_back(directory); + + return true; +} + auto AssetManager::get_file(const std::string &part, AssetTypeHint hint) -> Asset * { std::string path = part; @@ -185,15 +194,24 @@ auto AssetManager::get_file(const std::string &part, AssetTypeHint hint) -> Asse if (!asset) { - path.insert(0, "assets/"); - - asset = new Asset(path); - asset->hash = hash; + for (std::string &dir : this->directories) + { + std::string attempt = dir + "/" + path; + asset = new Asset(attempt); + if (asset->type == ASSET_VOID) + { + delete asset; + asset = nullptr; + continue; + } + asset->hash = hash; + debug("found asset in: (%s)", dir.c_str()); + break; + } - if (asset->type == ASSET_VOID) + if (!asset) { error("failed to load asset: (%s)", path.c_str()); - delete asset; return &asset_void; } diff --git a/src/assets.h b/src/assets.h index 34e31df..498308a 100644 --- a/src/assets.h +++ b/src/assets.h @@ -1,17 +1,26 @@ #ifndef _ASSET_H #define _ASSET_H -#include -#include -#include - #include "util.h" namespace Mauri { -enum AssetType { ASSET_VOID, ASSET_SLICE, ASSET_FILE }; -enum AssetTypeHint { NONE, TEXTURE, SHADER, FRAGMENT_SHADER, VERTEX_SHADER }; +enum AssetType +{ + ASSET_VOID = 0, + ASSET_SLICE, + ASSET_FILE +}; + +enum AssetTypeHint +{ + NONE = 0, + TEXTURE, + SHADER, + FRAGMENT_SHADER, + VERTEX_SHADER +}; class Asset { @@ -86,19 +95,23 @@ struct PackageFile class AssetManager { public: - AssetManager() {} - ~AssetManager() {} + AssetManager() = default; + ~AssetManager() = default; auto get_file(const std::string &part, AssetTypeHint hint = NONE) -> Asset *; auto arm_package(const std::string &path, bool can_output) -> bool; auto unload_package() -> void; + auto add_search_directory(const std::string &directory) -> bool; + bool prepare_output; auto write_files(const std::string &output_path) -> void; private: + std::vector directories; + Asset *package; std::vector assets; }; diff --git a/src/context.cc b/src/context.cc index a89f8b0..8dcbdbb 100644 --- a/src/context.cc +++ b/src/context.cc @@ -12,49 +12,8 @@ auto context() -> Context * auto set_context(Context *c) -> void { - if (context_) - { - delete context_; - } + if (context_) delete context_; context_ = c; } } // namespace Mauri - -using namespace Mauri; - -auto Context::print_gl_info() -> void -{ - info("vendor: %s", glGetString(GL_VENDOR)); - info("renderer: %s", glGetString(GL_RENDERER)); - info("version: %s", glGetString(GL_VERSION)); -} - -auto Context::check_error() -> GLenum -{ - GLenum error_code; - while ((error_code = glGetError()) != GL_NO_ERROR) - { - std::string error; - switch (error_code) - { - case GL_INVALID_ENUM: - error = "INVALID_ENUM"; - break; - case GL_INVALID_VALUE: - error = "INVALID_VALUE"; - break; - case GL_INVALID_OPERATION: - error = "INVALID_OPERATION"; - break; - case GL_OUT_OF_MEMORY: - error = "OUT_OF_MEMORY"; - break; - case GL_INVALID_FRAMEBUFFER_OPERATION: - error = "INVALID_FRAMEBUFFER_OPERATION"; - break; - } - error("gl error: %s", error.c_str()); - } - return error_code; -} diff --git a/src/context.h b/src/context.h index 93e5290..6919550 100644 --- a/src/context.h +++ b/src/context.h @@ -1,29 +1,76 @@ #ifndef _CONTEXT_H #define _CONTEXT_H -#include - #include "gl.h" +extern "C" { +#include +#include +} + namespace Mauri { +static bool pointer_pos_callback(void *userdata, f64 x, f64 y); +static void should_close_callback(void *userdata); + class Context { public: - Context() : start(std::chrono::system_clock::now()) {} - virtual ~Context() {} + Context() : start(aki_get_timestamp()) {} + ~Context() + { + if (this->window) this->window->free(&this->window); + } + + f64 pointer_x; + f64 pointer_y; + + bool should_close = false; + + auto create_window(s32 width, s32 height, const std::string &name, const std::string monitor) -> bool + { + this->window = stl_window_create(); + this->window->pointer_pos_callback = pointer_pos_callback; + this->window->should_close_callback = should_close_callback; + this->window->userdata = this; + s32 flags = STELA_WINDOW_VSYNC | (monitor.empty() ? 0 : STELA_WINDOW_WALLPAPER); + if (!this->window->create_window(this->window, width, height, monitor.c_str(), name.c_str(), flags)) { + return false; + } + this->window->gl_make_current(this->window); + if (!this->window->gl_loader_load(this->window)) { + return false; + } + glEnable(GL_BLEND); + glEnable(GL_MULTISAMPLE); + return true; + } - s32 width; - s32 height; + auto width() -> s32 + { + return this->window->width; + } - virtual auto create_window(s32 width, s32 height, const std::string &name, bool background) -> bool = 0; - virtual auto resize_window(s32 width, s32 height) -> void = 0; - virtual auto should_close_window() const -> bool = 0; - virtual auto close_window() -> void = 0; + auto height() -> s32 + { + return this->window->height; + } - virtual auto process_input() -> void = 0; - virtual auto cursor_pos(f32 *x, f32 *y) -> void = 0; + auto resize_window(s32 width, s32 height) -> void + { + this->window->resize(this->window, width, height); + } + + auto should_close_window() const -> bool + { + return this->should_close; + } + + auto close_window() -> void + { + this->should_close = true; + } auto is_draw_enabled() const -> bool { @@ -35,24 +82,47 @@ class Context this->draw_enabled = enabled; } - virtual auto swap_buffers() -> void = 0; + auto poll() -> void + { + this->window->poll(this->window, false); + this->window->process_events(this->window); + } - using us = std::chrono::microseconds; + auto swap_buffers() -> void + { + this->window->gl_swap_buffers(this->window); + }; auto current_time() const -> f64 { - return std::chrono::duration_cast(std::chrono::system_clock::now() - this->start).count() / 1000000.f; + return (aki_get_timestamp() - this->start) / 1000000.f; } - protected: - auto print_gl_info() -> void; - auto check_error() -> GLenum; + auto check_error() -> void + { + stl_gl_check_error(); + } private: - bool draw_enabled = false; - std::chrono::time_point start; + u64 start; + bool draw_enabled = true; + struct stl_window *window = nullptr; }; +bool pointer_pos_callback(void *userdata, f64 x, f64 y) +{ + Context *c = (Context *)userdata; + c->pointer_x = x; + c->pointer_y = y; + return true; +} + +void should_close_callback(void *userdata) +{ + Context *c = (Context *)userdata; + c->should_close = true; +} + extern auto context() -> Context *; extern auto set_context(Context *c) -> void; diff --git a/src/context_glfw.cc b/src/context_glfw.cc deleted file mode 100644 index cbaea23..0000000 --- a/src/context_glfw.cc +++ /dev/null @@ -1,131 +0,0 @@ -#include "context_glfw.h" - -using namespace Mauri; - -static auto key_callback(GLFWwindow *window, s32 key, s32 scancode, s32 action, s32 mods) -> void -{ - if (key == GLFW_KEY_B && action == GLFW_PRESS) - { - context()->set_draw_enabled(!context()->is_draw_enabled()); - } -} - -auto ContextGLFW::create_window(s32 width, s32 height, const std::string &name, bool background) -> bool -{ - if (!glfwInit()) - { - error("failed to init glfw"); - return false; - } - - this->width = width; - this->height = height; - - // https://github.com/haasn/libplacebo/blob/master/demos/window_glfw.c#L178 - struct - { - s32 api; - s32 major, minor; - s32 glsl_ver; - s32 profile; - } gl_vers[] = { - {GLFW_OPENGL_API, 4, 6, 460, GLFW_OPENGL_CORE_PROFILE}, - {GLFW_OPENGL_API, 4, 5, 450, GLFW_OPENGL_CORE_PROFILE}, - {GLFW_OPENGL_API, 4, 4, 440, GLFW_OPENGL_CORE_PROFILE}, - {GLFW_OPENGL_API, 4, 0, 400, GLFW_OPENGL_CORE_PROFILE}, - {GLFW_OPENGL_API, 3, 3, 330, GLFW_OPENGL_CORE_PROFILE}, - {GLFW_OPENGL_API, 3, 2, 150, GLFW_OPENGL_CORE_PROFILE}, - {GLFW_OPENGL_API, 3, 1, 140, 0}, - {GLFW_OPENGL_API, 3, 0, 130, 0}, - }; - - glfwWindowHint(GLFW_SRGB_CAPABLE, GLFW_TRUE); - //glfwWindowHint(GLFW_SAMPLES, 4); - - for (u32 i = 0; i < ARRAY_SIZE(gl_vers); i++) - { - glfwWindowHint(GLFW_CLIENT_API, gl_vers[i].api); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, gl_vers[i].major); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, gl_vers[i].minor); - glfwWindowHint(GLFW_OPENGL_PROFILE, gl_vers[i].profile); -#ifdef __APPLE__ - if (gl_vers[i].profile == GLFW_OPENGL_CORE_PROFILE) - { - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); - } -#endif - if ((this->window = glfwCreateWindow(this->width, this->height, name.c_str(), nullptr, nullptr))) - { - break; - } - } - - if (!this->window) - { - error("could not create gl context"); - return false; - } - - glfwMakeContextCurrent(this->window); - - if (!gladLoadGL((GLADloadfunc)glfwGetProcAddress)) - { - error("could not load gl"); - return false; - } - - glEnable(GL_BLEND); - glEnable(GL_MULTISAMPLE); - - this->print_gl_info(); - - this->set_draw_enabled(true); - - glfwSetKeyCallback(this->window, key_callback); - - return true; -} - -auto ContextGLFW::resize_window(s32 width, s32 height) -> void -{ - if (width != this->width || height != this->height) - { - this->width = width; - this->height = height; - glfwSetWindowSize(this->window, this->width, this->height); - } -} - -auto ContextGLFW::should_close_window() const -> bool -{ - return glfwWindowShouldClose(this->window); -} - -auto ContextGLFW::close_window() -> void -{ - glfwSetWindowShouldClose(this->window, GLFW_TRUE); -} - -auto ContextGLFW::process_input() -> void -{ - glfwPollEvents(); -} - -auto ContextGLFW::cursor_pos(f32 *x, f32 *y) -> void -{ - f64 x_, y_; - glfwGetCursorPos(this->window, &x_, &y_); - *x = (f32)x_; - *y = (f32)y_; -} - -auto ContextGLFW::swap_buffers() -> void -{ - glfwSwapBuffers(this->window); -} - -ContextGLFW::~ContextGLFW() -{ - if (this->window) glfwDestroyWindow(this->window); - glfwTerminate(); -} diff --git a/src/context_glfw.h b/src/context_glfw.h deleted file mode 100644 index 1eb2991..0000000 --- a/src/context_glfw.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef _CONTEXT_GLFW_HPP -#define _CONTEXT_GLFW_HPP - -#define GLFW_INCLUDE_NONE -#include - -#include "context.h" - -namespace Mauri -{ - -class ContextGLFW : public Context -{ - public: - ContextGLFW() : Context() {} - ~ContextGLFW(); - - auto create_window(s32 width, s32 height, const std::string &name, bool background) -> bool; - auto resize_window(s32 width, s32 height) -> void; - auto should_close_window() const -> bool; - auto close_window() -> void; - - auto process_input() -> void; - auto cursor_pos(f32 *x, f32 *y) -> void; - - auto swap_buffers() -> void; - - private: - GLFWwindow *window; -}; - -} // namespace Mauri - -#endif // _CONTEXT_GLFW_HPP diff --git a/src/context_null.h b/src/context_null.h deleted file mode 100644 index bcae058..0000000 --- a/src/context_null.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef _CONTEXT_NULL -#define _CONTEXT_NULL - -#include "context.h" - -namespace Mauri -{ - -class ContextNull : public Context -{ -public: - ContextNull() : Context() { this->set_draw_enabled(false); } - ~ContextNull() {} - - auto create_window(s32 width, s32 height, const std::string &name, bool background) -> bool - { - return true; - } - - auto resize_window(s32 width, s32 height) -> void - { - if (width != this->width || height != this->height) - { - this->width = width; - this->height = height; - } - } - - auto should_close_window() const -> bool - { - return this->should_close; - } - - auto close_window() -> void - { - this->should_close = true; - } - - auto process_input() -> void {} - - auto cursor_pos(f32 *x, f32 *y) -> void - { - *y = 0.f; - *x = 0.f; - } - - auto swap_buffers() -> void {} - - private: - bool should_close = true; -}; - -} // namespace Mauri - -#endif // _CONTEXT_NULL diff --git a/src/context_x11.cc b/src/context_x11.cc deleted file mode 100644 index 7975a4a..0000000 --- a/src/context_x11.cc +++ /dev/null @@ -1,302 +0,0 @@ -#include "context_x11.h" - -using namespace Mauri; - -static Atom ATOM_WM_DELETE_WINDOW, ATOM__NET_ACTIVE_WINDOW; - -auto ContextX11::disable_input() -> void -{ - XWMHints wmHint; - wmHint.flags = InputHint | StateHint; - wmHint.input = false; - wmHint.initial_state = NormalState; - XSetWMProperties(this->x11_d, this->window, NULL, NULL, NULL, 0, NULL, &wmHint, NULL); -} - -auto ContextX11::create_window(s32 width, s32 height, const std::string &name, bool background) -> bool -{ - this->x11_d = XOpenDisplay(NULL); - - ATOM_WM_DELETE_WINDOW = XInternAtom(this->x11_d, "WM_DELETE_WINDOW", true); - - if (!this->x11_d) - { - error("could not open display"); - return false; - } - - s32 screen = XDefaultScreen(this->x11_d); - Window root = RootWindow(this->x11_d, screen); - - static s32 gl_attrs[] = { - GLX_X_RENDERABLE, True, - GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, - GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, - GLX_DOUBLEBUFFER, True, - GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - GLX_ALPHA_SIZE, 0, - GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_SAMPLES, 0, - None - }; - - GLint context_attrs[] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, 3, - GLX_CONTEXT_MINOR_VERSION_ARB, 3, - None - }; - - // https://github.com/jarcode-foss/glava/blob/master/glava/glx_wcb.c#L383 - s32 fb_sz, best = -1, samp = -1; - GLXFBConfig *fbc = glXChooseFBConfig(this->x11_d, screen, gl_attrs, &fb_sz); - if (!fbc) - { - error("no glX FB configs"); - return false; - } - - for (s32 t = 0; t < fb_sz; t++) - { - XVisualInfo *xvi = glXGetVisualFromFBConfig(this->x11_d, fbc[t]); - if (!xvi) continue; - - s32 samp_buf, samples; - glXGetFBConfigAttrib(this->x11_d, fbc[t], GLX_SAMPLE_BUFFERS, &samp_buf); - glXGetFBConfigAttrib(this->x11_d, fbc[t], GLX_SAMPLES, &samples); - - XRenderPictFormat *fmt = XRenderFindVisualFormat(this->x11_d, xvi->visual); - if (!fmt) continue; - - if (best < 0 || (samp_buf && samples > samp)) - { - best = t; - samp = samples; - } - - XFree(xvi); - } - - if (best == -1) - { - error("could not find suitable XRender format"); - return false; - } - - GLXFBConfig config = fbc[best]; - XFree(fbc); - - XVisualInfo *vi = glXGetVisualFromFBConfig(this->x11_d, config); - Colormap cmap = XCreateColormap(this->x11_d, root, vi->visual, AllocNone); - XSetWindowAttributes swa; - swa.colormap = cmap; - swa.event_mask = ExposureMask | KeyPressMask | StructureNotifyMask | - PropertyChangeMask | VisibilityChangeMask; - - swa.background_pixmap = None; - swa.border_pixel = 0; - - this->window = XCreateWindow(this->x11_d, root, 0, 0, width, height, 0, vi->depth, - InputOutput, vi->visual, CWColormap | CWEventMask | CWBackPixmap | CWBorderPixel, &swa); - - XFree(vi); - - //this->disable_input(); - - XStoreName(this->x11_d, this->window, name.c_str()); - - XChangeProperty(this->x11_d, this->window, - XInternAtom(this->x11_d, "_NET_WM_NAME", False), - XInternAtom(this->x11_d, "UTF8_STRING", False), - 8, PropModeReplace, (unsigned char *)name.c_str(), name.length()); - - XClassHint class_hint; - - class_hint.res_class = const_cast(name.c_str()); - class_hint.res_name = const_cast(name.c_str()); - - XSetClassHint(this->x11_d, this->window, &class_hint); - - glXCreateContextAttribsARBProc glXCreateContextAttribsARB = NULL; - glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) - glXGetProcAddressARB((const GLubyte*) "glXCreateContextAttribsARB"); - - if (!glXCreateContextAttribsARB) return false; - if (!(this->glc = glXCreateContextAttribsARB(this->x11_d, config, 0, True, context_attrs))) - { - return false; - } - - glXMakeCurrent(this->x11_d, this->window, this->glc); - - if (!gladLoadGL((GLADloadfunc)glXGetProcAddressARB)) - { - error("could not load gl"); - return false; - } - - if (background) - { - /* - Atom desktop = XInternAtom(this->x11_d, "_NET_WM_DESKTOP", false); - unsigned long all_desktops = XWIN_ALL_DESKTOPS; - XChangeProperty(this->x11_d, this->window, desktop, - XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&all_desktops, 1); - */ - - Atom net_wm_type = XInternAtom(this->x11_d, "_NET_WM_WINDOW_TYPE", false); - Atom desktop_type = XInternAtom(this->x11_d, "_NET_WM_WINDOW_TYPE_DESKTOP", false); - XChangeProperty(this->x11_d, this->window, net_wm_type, - XA_ATOM, 32, PropModeReplace, (unsigned char*)&desktop_type, 1); - - /* - XEvent event; - event.xclient.type = ClientMessage; - event.xclient.serial = 0; - event.xclient.send_event = True; - event.xclient.display = this->x11_d; - event.xclient.window = this->window; - event.xclient.message_type = XInternAtom(this->x11_d, "_NET_WM_STATE", false); - event.xclient.format = 32; - - event.xclient.data.l[0] = _NET_WM_STATE_ADD; - event.xclient.data.l[1] = XInternAtom(this->x11_d, "_NET_WM_STATE_BELOW", false); - event.xclient.data.l[2] = 0; //unused. - event.xclient.data.l[3] = 0; - event.xclient.data.l[4] = 0; - - XSendEvent(this->x11_d, root, false, - SubstructureRedirectMask|SubstructureNotifyMask, &event); - - event.xclient.data.l[1] = XInternAtom(this->x11_d, "_NET_WM_STATE_STICKY", false); - - XSendEvent(x11_d, root, false, - SubstructureRedirectMask|SubstructureNotifyMask, &event); - - event.xclient.data.l[1] = XInternAtom(this->x11_d, "_NET_WM_STATE_FULLSCREEN", false); - */ - } - - XSetWMProtocols(this->x11_d, this->window, &ATOM_WM_DELETE_WINDOW, 1); - - XMoveWindow(this->x11_d, this->window, 0, 0); - - XMapWindow(this->x11_d, this->window); - XFlush(this->x11_d); - - glEnable(GL_BLEND); - glEnable(GL_MULTISAMPLE); - - this->print_gl_info(); - - this->set_draw_enabled(true); - - return true; -} - -auto ContextX11::resize_window(s32 width, s32 height) -> void -{ - if (width != this->width || height != this->height) - { - this->width = width; - this->height = height; - } -} - -auto ContextX11::raise() -> void -{ - XClientMessageEvent ev = { - .type = ClientMessage, - .serial = 0, - .send_event = true, - .display = this->x11_d, - .window = this->window, - .message_type = ATOM__NET_ACTIVE_WINDOW, - .format = 32, - .data = {.l = {1, 0, (long)this->window}} - }; - XSendEvent(this->x11_d, DefaultRootWindow(this->x11_d), false, StructureNotifyMask, (XEvent *)&ev); - XRaiseWindow(this->x11_d, this->window); - XFlush(this->x11_d); -} - -auto ContextX11::set_clickthrough() -> void -{ - Window win = this->window, root = DefaultRootWindow(this->x11_d); - while (win != None) - { - Region region; - if ((region = XCreateRegion())) - { - XShapeCombineRegion(this->x11_d, this->window, ShapeInput, 0, 0, region, ShapeSet); - XDestroyRegion(region); - } - - Window parent, *children = NULL; - u32 num_children; - if (XQueryTree(this->x11_d, win, &root, &parent, &children, &num_children)) - { - if (children) XFree(children); - } - - win = (parent == root ? None : parent); - } - - XFlush(this->x11_d); -} - -auto ContextX11::close_window() -> void -{ - this->should_close = true; -} - -auto ContextX11::cursor_pos(float *x, float *y) -> void -{ - u32 ret; - s32 root_return_x, root_return_y; - s32 win_return_x, win_return_y; - Window root_return, child_return; - XQueryPointer(this->x11_d, this->window, &root_return, &child_return, - &root_return_x, &root_return_y, &win_return_x, &win_return_y, &ret); - *x = (f32)win_return_x; - *y = (f32)win_return_y; -} - -auto ContextX11::process_input() -> void -{ - XEvent xev; - while (XPending(this->x11_d) > 0) - { - XNextEvent(this->x11_d, &xev); - switch (xev.type) - { - case ClientMessage: - if ((u64)xev.xclient.data.l[0] == ATOM_WM_DELETE_WINDOW) - { - this->should_close = true; - } - break; - case MapNotify: - //set_clickthrough(); - XFlush(this->x11_d); - break; - } - } -} - -auto ContextX11::swap_buffers() -> void -{ - glXSwapBuffers(this->x11_d, this->window); -} - -ContextX11::~ContextX11() -{ - if (this->x11_d) - { - glXMakeCurrent(this->x11_d, None, NULL); - glXDestroyContext(this->x11_d, this->glc); - XDestroyWindow(this->x11_d, this->window); - XCloseDisplay(this->x11_d); - } -} diff --git a/src/context_x11.h b/src/context_x11.h deleted file mode 100644 index 6bf898f..0000000 --- a/src/context_x11.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef _CONTEXT_X11_H -#define _CONTEXT_X11_H - -#include -#include -#include -#include - -#include "context.h" - -#include - -#define XWIN_ALL_DESKTOPS 0xFFFFFFFF - -#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 - -#define _NET_WM_STATE_REMOVE 0 -#define _NET_WM_STATE_ADD 1 -#define _NET_WM_STATE_TOGGLE 2 - -typedef GLXContext (*glXCreateContextAttribsARBProc)(Display *, GLXFBConfig, GLXContext, Bool, const s32 *); - -namespace Mauri -{ - -class ContextX11 : public Context -{ - public: - ContextX11() : Context() {} - ~ContextX11(); - - auto create_window(s32 width, s32 height, const std::string &name, bool background) -> bool; - auto resize_window(s32 width, s32 height) -> void; - auto should_close_window() const -> bool - { - return should_close; - } - auto close_window() -> void; - - auto process_input() -> void; - auto cursor_pos(f32 *x, f32 *y) -> void; - - auto swap_buffers() -> void; - - private: - bool should_close = false; - - auto raise() -> void; - - // Try to make the window shape 0x0 so that its unclickable. - auto set_clickthrough() -> void; - - // Try to disable input by setting window hints. - auto disable_input() -> void; - - Display *x11_d = nullptr; - Window window; - GLXContext glc; -}; - -} // namespace Mauri - -#endif // _CONTEXT_X11_H diff --git a/src/engine.cc b/src/engine.cc index 641ac15..ff90d65 100644 --- a/src/engine.cc +++ b/src/engine.cc @@ -1,9 +1,6 @@ -#include - -#include "context.h" #include "engine.h" +#include "context.h" -#include "objects/object.h" #include "objects/scene.h" using namespace Mauri; @@ -16,9 +13,8 @@ auto View::center_scale_viewport() -> void auto View::center_viewport(f32 buffer_width, f32 buffer_height) -> void { - f32 w_pad = (this->width - buffer_width) / -2.f; - f32 h_pad = (this->height - buffer_height) / -2.f; - Render::set_viewport(w_pad, h_pad, buffer_width, buffer_height); + Render::set_viewport((this->width - buffer_width) / -2, + (this->height - buffer_height) / -2, buffer_width, buffer_height); } auto View::default_viewport(f32 buffer_width, f32 buffer_height) -> void @@ -36,8 +32,6 @@ auto View::center(f32 buffer_width, f32 buffer_height) -> void f32 scaled_width = this->width / this->scale; f32 scaled_height = this->height / this->scale; - //this->camera_pos[0] = ((scaled_width - buffer_width) / -2.f) + ((scaled_width - buffer_width) / 2.f); - //this->camera_pos[1] = ((scaled_height - buffer_height) / -2.f) + ((scaled_height - buffer_height) / 2.f); this->camera_pos[0] = ((scaled_width - buffer_width) / -2.f); this->camera_pos[1] = ((scaled_height - buffer_height) / -2.f); } @@ -45,15 +39,6 @@ auto View::center(f32 buffer_width, f32 buffer_height) -> void Engine::Engine(Scene *scene, f32 rate, bool audio) : scene(scene), rate(rate), audio_enabled(audio) { - /* - for (Object *object : scene->objects) - { - if (object->size[0] > this->view.width) this->view.width = object->size[0]; - if (object->size[1] > this->view.height) this->view.height = object->size[1]; - } - */ - //std::cout << this->view.width << " " << this->view.height << "\n"; - this->view.width = scene->width; this->view.height = scene->height; this->view.ortho_width = scene->width; @@ -65,9 +50,11 @@ Engine::Engine(Scene *scene, f32 rate, bool audio) this->view.texel_half_size[0] = .5f / this->view.width; this->view.texel_half_size[1] = .5f / this->view.height; - this->view.center(context()->width, context()->height); + this->view.center(context()->width(), context()->height()); + this->view.camera_pos[0] += scene->cam.offset[0]; + this->view.camera_pos[1] += scene->cam.offset[1]; -#ifdef BUILD_AUDIO +#ifdef HAVE_AUDIO if (this->audio_enabled) { this->vis = new Visualizer(); @@ -85,13 +72,13 @@ Engine::Engine(Scene *scene, f32 rate, bool audio) this->create_framebuffer(COMBINE_BUFFER, this->view.width, this->view.height, 1.f); this->combine_buffer = this->get_framebuffer(COMBINE_BUFFER); + this->create_framebuffer(MIPMAPPED_BUFFER, this->view.width, this->view.height, 1.f); this->default_mat = glm::ortho(-1.f, 1.f, -1.f, 1.f, -3.f, 1.f); this->default_mat = glm::scale(this->default_mat, vec3{1.f, 1.f, 0.001f}); - this->default_mat_flipped = glm::scale(this->default_mat, vec3{1.f, -1.f, 1.f}); this->default_object = new RenderObject(DEFAULT); - this->default_object_flipped = new RenderObject(DEFAULT_FLIPPED); + this->flipped_object = new RenderObject(DEFAULT_FLIPPED); this->fullscreen_object = new RenderObject(FULLSCREEN); } @@ -102,11 +89,6 @@ auto Engine::create_framebuffer(const std::string &name, f32 width, f32 height, auto Engine::get_framebuffer(const std::string &name) -> Framebuffer * { - // Most likely wrong... - if (name == "_rt_MipMappedFrameBuffer") - { - return this->combine_buffer; - } for (Framebuffer *buffer : this->framebuffers) { if (buffer->name == name) return buffer; @@ -122,9 +104,8 @@ auto Engine::get_framebuffer_texture(const std::string &name) -> Texture * auto Engine::update() -> void { - context()->process_input(); - - context()->cursor_pos(&this->view.cursor_pos[0], &this->view.cursor_pos[1]); + this->view.cursor_pos[0] = (f32)context()->pointer_x; + this->view.cursor_pos[1] = (f32)context()->pointer_y; this->view.cursor_pos[0] -= this->view.camera_pos[0]; this->view.cursor_pos[1] -= this->view.camera_pos[1]; @@ -151,23 +132,19 @@ auto Engine::draw() -> void this->view.center_scale_viewport(); - this->default_object_flipped->bind(); - this->default_object_flipped->draw(); + this->flipped_object->bind(); + this->flipped_object->draw(); } auto Engine::run() -> void { - const f32 TARGET_FPS = 60.f; while (!context()->should_close_window()) { this->time = context()->current_time(); + context()->poll(); this->update(); this->draw(); context()->swap_buffers(); - while (context()->current_time() < this->time + 1.0f / TARGET_FPS) - { - std::this_thread::sleep_for(std::chrono::microseconds(500)); - } } } @@ -179,10 +156,12 @@ Engine::~Engine() } delete this->shader; + delete this->default_object; + delete this->flipped_object; delete this->fullscreen_object; -#ifdef BUILD_AUDIO +#ifdef HAVE_AUDIO delete this->vis; #endif } diff --git a/src/engine.h b/src/engine.h index a1a063e..dc8c052 100644 --- a/src/engine.h +++ b/src/engine.h @@ -2,13 +2,13 @@ #define _ENGINE_H #include "shader.h" -#include "framebuffer.h" -#ifdef BUILD_AUDIO +#ifdef HAVE_AUDIO #include "vis.h" #endif static const std::string COMBINE_BUFFER = "_rt_FullFrameBuffer"; +static const std::string MIPMAPPED_BUFFER = "_rt_MipMappedFrameBuffer"; namespace Mauri { @@ -53,17 +53,16 @@ class Engine f32 time; bool audio_enabled; -#ifdef BUILD_AUDIO +#ifdef HAVE_AUDIO Visualizer *vis; #endif View view; mat4x4 default_mat; - mat4x4 default_mat_flipped; RenderObject *default_object; - RenderObject *default_object_flipped; + RenderObject *flipped_object; RenderObject *fullscreen_object; Shader *shader; diff --git a/src/framebuffer.cc b/src/framebuffer.cc deleted file mode 100644 index 210a052..0000000 --- a/src/framebuffer.cc +++ /dev/null @@ -1,16 +0,0 @@ -#include "framebuffer.h" - -using namespace Mauri; - -Framebuffer::Framebuffer(std::string name, s32 width, s32 height, f32 scale) - : name(name) -{ - this->buffer = new RenderFramebuffer(width, height, scale); - this->texture = new Texture(this->buffer); -} - -Framebuffer::~Framebuffer() -{ - if (this->buffer) delete this->buffer; - if (this->texture) delete this->texture; -} diff --git a/src/framebuffer.h b/src/framebuffer.h deleted file mode 100644 index 734715a..0000000 --- a/src/framebuffer.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _FRAMEBUFFER_H -#define _FRAMEBUFFER_H - -#include "texture.h" - -namespace Mauri -{ - -class Framebuffer -{ - public: - Framebuffer(std::string name, s32 width, s32 height, f32 scale); - ~Framebuffer(); - - std::string name; - - RenderFramebuffer *buffer; - Texture *texture; -}; - -} // namespace Mauri - -#endif // _FRAMEBUFFER_H diff --git a/src/gl.cc b/src/gl.cc index 66690ba..6629ed6 100644 --- a/src/gl.cc +++ b/src/gl.cc @@ -1,7 +1,7 @@ +#include "gl.h" #include "log.h" #include "context.h" #include "texture.h" -#include "gl.h" #include "objects/object.h" @@ -12,6 +12,8 @@ auto uniform_type_to_string(UniformType type) -> std::string { switch (type) { + case TYPE_UINT: + return "uint"; case TYPE_FLOAT: return "float"; case TYPE_VEC4: @@ -34,7 +36,8 @@ auto uniform_type_to_string(UniformType type) -> std::string auto uniform_type_from_string(const std::string_view &s) -> UniformType { - if (s.compare(0, 5, "float") == 0) return TYPE_FLOAT; + if (s.compare(0, 4, "uint") == 0) return TYPE_UINT; + else if (s.compare(0, 5, "float") == 0) return TYPE_FLOAT; else if (s.compare(0, 4, "vec4") == 0) return TYPE_VEC4; else if (s.compare(0, 4, "vec3") == 0) return TYPE_VEC3; else if (s.compare(0, 4, "vec2") == 0) return TYPE_VEC2; @@ -184,20 +187,23 @@ RenderShader::RenderShader(const std::string &vs_source, const std::string &fs_s this->program = glCreateProgram(); char error[256]; + const char *c_str; u32 vs_shader = glCreateShader(GL_VERTEX_SHADER); - if (!compile(vs_shader, vs_source.c_str(), error)) + c_str = vs_source.c_str(); + if (!compile(vs_shader, c_str, error)) { error("failed to compile vertex shader: (%s)", error); - debug("\n%s", vs_source.c_str()); + debug("\n%s\n", c_str); return; } u32 fs_shader = glCreateShader(GL_FRAGMENT_SHADER); - if (!compile(fs_shader, fs_source.c_str(), error)) + c_str = fs_source.c_str(); + if (!compile(fs_shader, c_str, error)) { error("failed to compile fragment shader: (%s)", error); - debug("\n%s", fs_source.c_str()); + debug("\n%s\n", c_str); return; } @@ -256,20 +262,21 @@ auto RenderShader::set_uniform(const std::string &name, UniformType type, void * s32 loc = this->get_uniform_location(name); if (loc == -1) return; -#if UNIFORM_DEBUG - std::cout << name << "(" << type << ")" << " " - << ((f32 *)value)[0] << " " << ((f32 *)value)[1] << " " - << ((f32 *)value)[2] << " " << ((f32 *)value)[3] << "\n"; +#ifdef UNIFORM_DEBUG + al_printf("%s(%i) %f %f %f %f\n", name.c_str(), type, + ((f32 *)value)[0], ((f32 *)value)[1], + ((f32 *)value)[2], ((f32 *)value)[3]); #endif switch (type) { - case TYPE_FLOAT: - glUniform1f(loc, *((f32 *)value)); - break; + case TYPE_UINT: case TYPE_SAMPLER2D: glUniform1i(loc, (u32)(*((f32 *)value))); break; + case TYPE_FLOAT: + glUniform1f(loc, *((f32 *)value)); + break; case TYPE_VEC2: glUniform2fv(loc, 1, (f32 *)value); break; @@ -303,12 +310,15 @@ RenderTexture::RenderTexture(bool no_interp, bool clamp, bool filtering, s32 mm_ glGenTextures(1, &this->id); glBindTexture(GL_TEXTURE_2D, this->id); + /* if (filtering) { f32 aniso; glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &aniso); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso); } + */ + (void)filtering; if (no_interp) { @@ -441,11 +451,11 @@ RenderTexture::~RenderTexture() RenderFramebuffer::RenderFramebuffer(s32 width, s32 height, f32 scale) : width(width / scale), height(height / scale) { - if (!context()->is_draw_enabled()) return; - this->texture = new RenderTexture(false, true, false, 1); - this->texture->format = GL_RGBA; + + if (!context()->is_draw_enabled()) return; + this->texture->upload(nullptr, this->width, this->height, 0); glGenFramebuffers(1, &this->id); @@ -503,8 +513,8 @@ auto Render::bind_framebuffer(s32 id) -> void glBindFramebuffer(GL_DRAW_FRAMEBUFFER, id); } -auto Render::set_viewport(u32 wpad, u32 hpad, u32 width, u32 height) -> void +auto Render::set_viewport(s32 x, s32 y, s32 width, s32 height) -> void { if (!context()->is_draw_enabled()) return; - glViewport(wpad, hpad, width, height); + glViewport(x, y, width, height); } diff --git a/src/gl.h b/src/gl.h index 9da72e7..600c58b 100644 --- a/src/gl.h +++ b/src/gl.h @@ -1,10 +1,20 @@ #ifndef _GL_H #define _GL_H -#include +extern "C" { +#include +} + +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include +#include #include "util.h" +using namespace glm; + namespace Mauri { @@ -20,6 +30,7 @@ enum ObjectType enum UniformType { TYPE_INVALID, + TYPE_UINT, TYPE_FLOAT, TYPE_VEC4, TYPE_VEC3, @@ -115,7 +126,7 @@ class Render static auto blend_func(s32 sfactor, s32 dfactor) -> void; static auto color_mask(f32 r, f32 g, f32 b, f32 a) -> void; static auto bind_framebuffer(s32 id) -> void; - static auto set_viewport(u32 wpad, u32 hpad, u32 width, u32 height) -> void; + static auto set_viewport(s32 x, s32 y, s32 width, s32 height) -> void; }; } // namespace Mauri diff --git a/src/json.h b/src/json.h index 34b5e72..300f1b3 100644 --- a/src/json.h +++ b/src/json.h @@ -1,15 +1,35 @@ #ifndef _JSON_H #define _JSON_H -#include "util.h" +#define JSON_NO_IO +#undef array +#include -#define str_vec4(s, v) sscanf(s, "%f %f %f %f", &(v)[0], &(v)[1], &(v)[2], &(v)[3]) -#define str_vec3(s, v) sscanf(s, "%f %f %f", &(v)[0], &(v)[1], &(v)[2]) -#define str_vec2(s, v) sscanf(s, "%f %f", &(v)[0], &(v)[1]) +#include "gl.h" + +using json = nlohmann::json; + +#define json_str_vec4(s, v) sscanf(s, "%f %f %f %f", &(v)[0], &(v)[1], &(v)[2], &(v)[3]) +#define json_str_vec3(s, v) sscanf(s, "%f %f %f", &(v)[0], &(v)[1], &(v)[2]) +#define json_str_vec2(s, v) sscanf(s, "%f %f", &(v)[0], &(v)[1]) + +#define parse_fail(obj) do { \ + delete obj; \ + return nullptr; \ +} while (0) namespace Mauri { -enum JsonValueType { FLOAT, INT, VEC2, VEC3, VEC4, BOOL, STRING }; +enum JsonValueType +{ + INT = 0, + FLOAT, + VEC2, + VEC3, + VEC4, + BOOL, + STRING +}; struct JsonValue { @@ -21,8 +41,8 @@ struct JsonValue class Parser { public: - Parser() {} - ~Parser() {} + Parser() = default; + ~Parser() = default; template static auto parse_value(const json &root, const std::string &name, void *out, const T &default_value) -> void @@ -49,17 +69,17 @@ class Parser } else if constexpr (std::is_same::value) { - if (value.is_string()) str_vec2(value.get().c_str(), *((vec2 *)out)); + if (value.is_string()) json_str_vec2(value.get().c_str(), *((vec2 *)out)); } else if constexpr (std::is_same::value) { - if (value.is_string()) str_vec3(value.get().c_str(), *((vec3 *)out)); + if (value.is_string()) json_str_vec3(value.get().c_str(), *((vec3 *)out)); } else if constexpr (std::is_same::value) { // Some uniforms are saved as a single number. if (value.is_number()) (*((vec4 *)out))[0] = value.get(); - else if (value.is_string()) str_vec4(value.get().c_str(), *((vec4 *)out)); + else if (value.is_string()) json_str_vec4(value.get().c_str(), *((vec4 *)out)); } else if constexpr (std::is_same::value) { diff --git a/src/log.h b/src/log.h index 34f6cd1..b7655ff 100644 --- a/src/log.h +++ b/src/log.h @@ -1,28 +1,13 @@ #ifndef _LOG_H #define _LOG_H -#include -#include - -#define _PRINT(x, ...) printf(x, ##__VA_ARGS__) - -#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) - -#define log_print(t, fmt, ...) \ - do \ - { \ - _PRINT("%s:%d %s(): ", __FILENAME__, __LINE__, __FUNCTION__); \ - _PRINT("%s -> " fmt "\n", t, ##__VA_ARGS__); \ - } while (0) - -#define info(fmt, ...) log_print("info", fmt, ##__VA_ARGS__) -#define warn(fmt, ...) log_print("warn", fmt, ##__VA_ARGS__) -#define error(fmt, ...) log_print("error", fmt, ##__VA_ARGS__) - -#ifdef _DEBUG_ -#define debug(fmt, ...) log_print("debug", fmt, ##__VA_ARGS__) -#else -#define debug(fmt, ...) -#endif +extern "C" { +#include +} + +#define info(fmt, ...) al_log_info(NULL, fmt, ##__VA_ARGS__) +#define warn(fmt, ...) al_log_warn(NULL, fmt, ##__VA_ARGS__) +#define error(fmt, ...) al_log_error(NULL, fmt, ##__VA_ARGS__) +#define debug(fmt, ...) al_log_debug(NULL, fmt, ##__VA_ARGS__) #endif // _LOG_H diff --git a/src/mauri.cc b/src/mauri.cc index fb0cc4b..03e314f 100644 --- a/src/mauri.cc +++ b/src/mauri.cc @@ -1,45 +1,58 @@ -#include +#include +extern "C" { +#include +#include +} +#include "context.h" #include "assets.h" #include "engine.h" -#include "context.h" -#include "context_null.h" - -#ifdef BUILD_GLFW -#include "context_glfw.h" -#endif - -#ifdef BUILD_X11 -#include "context_x11.h" -#endif - #include "objects/scene.h" using namespace Mauri; +#ifndef _WIN32 auto main(s32 argc, char *argv[]) -> s32 +#else +auto wmain(s32 argc, wchar_t **argv) -> s32 +#endif { - args::ArgParser args("Usage: ...", "0.12"); + if (!aki_common_init() || !stl_global_init()) { + return EXIT_FAILURE; + } - args.option("path p", ""); - args.option("width w", ""); - args.option("height h", ""); - args.option("background b", ""); - args.option("output o", ""); + janus::ArgParser args("Usage: ...", "0.12"); + + args.newString("package p", ""); + args.newString("directory d", ""); + args.newInt("width w", 0); + args.newInt("height h", 0); + args.newInt("xoffset x", 0); + args.newInt("yoffset y", 0); + args.newString("monitor m", ""); + args.newString("output o", ""); +#ifndef _WIN32 args.parse(argc, argv); +#else + args.wparse(argc, argv); +#endif - if (!args.found("path")) + if (!(args.found("package") ^ args.found("directory"))) { - std::cout << args.helptext << "\n"; + al_printf("%s\n", args.helptext.c_str()); return EXIT_FAILURE; } - s32 width = -1; - s32 height = -1; + s32 width = 640; + s32 height = 480; + s32 xoffset = 0; + s32 yoffset = 0; - if (args.found("width")) width = args.value("width"); - if (args.found("height")) height = args.value("height"); + if (args.found("width")) width = args.getInt("width"); + if (args.found("height")) height = args.getInt("height"); + if (args.found("xoffset")) xoffset = args.getInt("xoffset"); + if (args.found("yoffset")) yoffset = args.getInt("yoffset"); if (width == 0 || height == 0) { @@ -47,68 +60,67 @@ auto main(s32 argc, char *argv[]) -> s32 return EXIT_FAILURE; } - bool background = false; + const std::string monitor = args.found("monitor") ? args.getString("monitor") : ""; - if (args.found("background")) - { - std::string opt = args.value("background"); - str_to_lower(opt); - background = opt == "true"; - } - -#ifdef BUILD_AUDIO +#ifdef HAVE_AUDIO gst_init(&argc, &argv); #endif - //Context *new_context = new ContextGLFW(); - Context *new_context = new ContextX11(); - if (!new_context->create_window(width > 0 ? width : 640, height > 0 ? height : 480, "mauri", background)) + Context *new_context = new Context(); + if (!new_context->create_window(width, height, "mauri", monitor)) { return EXIT_FAILURE; } - if (!asset_manager()->arm_package(args.value("path"), args.found("output"))) + if (args.found("package")) { - return EXIT_FAILURE; + if (!asset_manager()->arm_package(args.getString("package"), args.found("output"))) + { + return EXIT_FAILURE; + } + } + + asset_manager()->add_search_directory("./assets"); + + if (args.found("directory")) + { + asset_manager()->add_search_directory(args.getString("directory")); } set_context(new_context); - Scene *scene = new Scene("scene.json"); + Scene *scene = Scene::parse("scene.json"); + if (!scene) return EXIT_FAILURE; if (width <= 0) width = scene->width; if (height <= 0) height = scene->height; + scene->offset_camera(xoffset, yoffset); context()->resize_window(width, height); Engine *engine = new Engine(scene, 1.f, true); - std::chrono::time_point begin = std::chrono::system_clock::now(); + u64 begin = aki_get_timestamp(); scene->load(engine); - using us = std::chrono::microseconds; - u64 duration = std::chrono::duration_cast(std::chrono::system_clock::now() - begin).count(); - info("scene loaded in %fs", duration / 1000000.f); + u64 duration = aki_get_timestamp() - begin; + info("scene loaded in %.2fs", duration / 1000000.f); - if (asset_manager()->prepare_output) - { - asset_manager()->write_files(args.value("output")); - } - else - { - engine->run(); - } + if (asset_manager()->prepare_output) asset_manager()->write_files(args.getString("output")); + else engine->run(); delete scene; delete engine; - asset_manager()->unload_package(); + unload_shaders(); + + if (args.found("package")) asset_manager()->unload_package(); context()->close_window(); set_context(nullptr); -#ifdef BUILD_AUDIO +#ifdef HAVE_AUDIO //gst_deinit(); #endif diff --git a/src/objects/effect.cc b/src/objects/effect.cc index 5542ccc..92f7dda 100644 --- a/src/objects/effect.cc +++ b/src/objects/effect.cc @@ -1,48 +1,58 @@ -#include "pass.h" #include "effect.h" +#include "pass.h" using namespace Mauri; -Effect::Effect(Parser &pr, const json &root) +auto Effect::parse(Parser &pr, const json &root) -> Effect * { + Effect *effect = new Effect(); + Asset *asset = asset_manager()->get_file(root["file"]); - if (asset->type == ASSET_VOID) return; + if (asset->type == ASSET_VOID) parse_fail(effect); - const json &file = json::parse(asset->as_string()); - if (file.is_discarded()) return; + const json &file = json::parse(asset->as_string(), nullptr, false); + if (file.is_discarded()) parse_fail(effect); - pr.map_value(root, "id", &this->id, 0); - pr.map_value(root, "visible", &this->visible, true); - pr.map_value(file, "name", &this->name, ""); + pr.map_value(root, "id", &effect->id, 0); + pr.map_value(root, "visible", &effect->visible, true); + pr.map_value(file, "name", &effect->name, ""); if (root.contains("passes")) { for (const json &pass0 : root["passes"]) { - this->passes0.emplace_back(new Pass(pr, pass0, EFFECT0_PASS)); + Pass *pass = Pass::parse(pr, pass0, EFFECT0_PASS); + if (pass) effect->passes0.emplace_back(pass); } } + if (effect->passes0.size() == 0) parse_fail(effect); + if (file.contains("passes")) { for (const json &pass1 : file["passes"]) { - this->passes1.emplace_back(new Pass(pr, pass1, EFFECT1_PASS)); + Pass *pass = Pass::parse(pr, pass1, EFFECT1_PASS); + if (pass) effect->passes1.emplace_back(pass); } } + if (effect->passes1.size() == 0) parse_fail(effect); + if (file.contains("fbos")) { for (const json &fbo : file["fbos"]) { - this->fbos.emplace_back(EffectBuffer{fbo["name"], fbo.contains("scale") ? (f32)fbo["scale"] : 1.f }); + effect->fbos.emplace_back(EffectBuffer{fbo["name"], fbo.contains("scale") ? (f32)fbo["scale"] : 1.f }); } } + + return effect; } auto Effect::load(Engine *engine, Object *object, bool last) -> void { - this->buffer_id = str_format("_%i_%i", object->id, this->id); + this->buffer_id = "_" + std::to_string(object->id) + "_" + std::to_string(this->id); for (const EffectBuffer &fbo : this->fbos) { @@ -82,14 +92,14 @@ auto Effect::draw(Engine *engine) -> void { if (!this->visible) return; -#if FRAME_STEP - std::cout << this->name << ":\n"; +#ifdef FRAME_STEP + al_printf("%s\n", this->name.c_str()); #endif for (RenderPass *pass : this->passes) { -#if FRAME_STEP - if (pass->shader) std::cout << "\t" << pass->shader->origin()->name << "\n"; +#ifdef FRAME_STEP + if (pass->shader) al_printf("\t%s\n", pass->shader->origin()->name.c_str()); #endif pass->draw(engine); } diff --git a/src/objects/effect.h b/src/objects/effect.h index cb53a04..710fc51 100644 --- a/src/objects/effect.h +++ b/src/objects/effect.h @@ -3,7 +3,6 @@ #include "../json.h" #include "../engine.h" -#include "../texture.h" namespace Mauri { @@ -20,7 +19,7 @@ class RenderPass; class Effect { public: - Effect(Parser &pr, const json &root); + Effect() = default; ~Effect(); u32 id; @@ -32,6 +31,8 @@ class Effect std::vector passes; + static auto parse(Parser &pr, const json &root) -> Effect *; + auto load(Engine *engine, Object *object, bool last) -> void; auto draw(Engine *engine) -> void; diff --git a/src/objects/material.cc b/src/objects/material.cc index b17a102..e3e3e02 100644 --- a/src/objects/material.cc +++ b/src/objects/material.cc @@ -1,23 +1,28 @@ -#include "pass.h" #include "material.h" +#include "pass.h" using namespace Mauri; -Material::Material(Parser &pr, const std::string &path) +auto Material::parse(Parser &pr, const std::string &path) -> Material * { + Material *material = new Material(); + Asset *asset = asset_manager()->get_file(path); - if (asset->type == ASSET_VOID) return; + if (asset->type == ASSET_VOID) parse_fail(material); - const json &root = json::parse(asset->as_string()); - if (root.is_discarded()) return; + const json &root = json::parse(asset->as_string(), nullptr, false); + if (root.is_discarded()) parse_fail(material); if (root.contains("passes")) { - for (const json &pass : root["passes"]) + for (const json &pass0 : root["passes"]) { - this->passes0.push_back(new Pass(pr, pass, MATERIAL_PASS)); + Pass *pass = Pass::parse(pr, pass0, MATERIAL_PASS); + if (pass) material->passes0.push_back(pass); } } + + return material; } auto Material::load(Engine *engine, Object *object, MaterialType type, Pass *pass) -> void diff --git a/src/objects/material.h b/src/objects/material.h index cfea216..a0edca7 100644 --- a/src/objects/material.h +++ b/src/objects/material.h @@ -7,16 +7,22 @@ namespace Mauri { -enum MaterialType { MATERIAL_MODEL, MATERIAL_EFFECT }; +enum MaterialType +{ + MATERIAL_MODEL = 0, + MATERIAL_EFFECT +}; class Pass; class Material { public: - Material(Parser &pr, const std::string &path); + Material() = default; ~Material(); + static auto parse(Parser &pr, const std::string &path) -> Material *; + std::vector passes0; auto load(Engine *engine, Object *object, MaterialType type, Pass *pass) -> void; diff --git a/src/objects/model.cc b/src/objects/model.cc index b916ec7..830bdaf 100644 --- a/src/objects/model.cc +++ b/src/objects/model.cc @@ -2,22 +2,27 @@ using namespace Mauri; -Model::Model(Parser &pr, const std::string &path) +auto Model::parse(Parser &pr, const std::string &path) -> Model * { + Model *model = new Model(); + Asset *asset = asset_manager()->get_file(path); - if (asset->type == ASSET_VOID) return; + if (asset->type == ASSET_VOID) parse_fail(model); + + const json &root = json::parse(asset->as_string(), nullptr, false); + if (root.is_discarded()) parse_fail(model); - const json &root = json::parse(asset->as_string()); - if (root.is_discarded()) return; + pr.map_value(root, "autosize", &model->autosize, false); + pr.map_value(root, "fullscreen", &model->fullscreen, false); + pr.map_value(root, "passthrough", &model->passthrough, false); - pr.map_value(root, "autosize", &this->autosize, false); - pr.map_value(root, "fullscreen", &this->fullscreen, false); - pr.map_value(root, "passthrough", &this->passthrough, false); + pr.map_value(root, "width", &model->width, 0.f); + pr.map_value(root, "height", &model->height, 0.f); - pr.map_value(root, "width", &this->width, 0.f); - pr.map_value(root, "height", &this->height, 0.f); + if (root.contains("material")) model->material = Material::parse(pr, root["material"]); + if (!model->material) parse_fail(model); - if (root.contains("material")) this->material = new Material(pr, root["material"]); + return model; } auto Model::load(Engine *engine, Object *object) -> void diff --git a/src/objects/model.h b/src/objects/model.h index f6b532a..d000bd7 100644 --- a/src/objects/model.h +++ b/src/objects/model.h @@ -9,7 +9,7 @@ namespace Mauri class Model { public: - Model(Parser &pr, const std::string &path); + Model() = default; ~Model(); bool autosize = true; @@ -19,6 +19,8 @@ class Model f32 width; f32 height; + static auto parse(Parser &pr, const std::string &path) -> Model *; + auto load(Engine *engine, Object *object) -> void; private: diff --git a/src/objects/object.cc b/src/objects/object.cc index ac64a25..d648b63 100644 --- a/src/objects/object.cc +++ b/src/objects/object.cc @@ -1,21 +1,21 @@ -#include "../context.h" - -#include "pass.h" -#include "scene.h" #include "object.h" +#include "scene.h" +#include "pass.h" using namespace Mauri; -Object::Object(Parser &pr, const json &root) +auto Object::parse(Parser &pr, const json &root) -> Object * { - pr.map_value(root, "id", &this->id, 0); - pr.map_value(root, "name", &this->name, ""); + Object *object = new Object(); + + pr.map_value(root, "id", &object->id, 0); + pr.map_value(root, "name", &object->name, ""); if (root.contains("dependencies")) { for (const json &id : root["dependencies"]) { - this->deps.push_back(id); + object->deps.push_back(id); } } @@ -23,11 +23,11 @@ Object::Object(Parser &pr, const json &root) // object or are repeated. This could be handled be sorting objects // on the scene in order of deps but I'm not sure if that would // break other things. - auto it = this->deps.begin(); - while (it != this->deps.end()) + auto it = object->deps.begin(); + while (it != object->deps.end()) { - bool remove = ((u32)(*it) == id); - for (auto rt = this->deps.begin(); rt != this->deps.end(); ++rt) + bool remove = ((u32)(*it) == object->id); + for (auto rt = object->deps.begin(); rt != object->deps.end(); ++rt) { if (rt != it && *rt == *it) { @@ -35,44 +35,48 @@ Object::Object(Parser &pr, const json &root) break; } } - if (remove) this->deps.erase(it); + if (remove) object->deps.erase(it); else it++; } - pr.map_value(root, "visible", &this->visible, true); - pr.map_value(root, "angles", &this->angles, vec3(0.f)); - pr.map_value(root, "size", &this->size, vec2(0.f)); - pr.map_value(root, "scale", &this->scale, vec3(0.f)); - pr.map_value(root, "origin", &this->origin, vec3(0.f)); - if (this->origin[2] != 0.f) + pr.map_value(root, "visible", &object->visible, true); + pr.map_value(root, "angles", &object->angles, vec3(0.f)); + pr.map_value(root, "size", &object->size, vec2(0.f)); + pr.map_value(root, "scale", &object->scale, vec3(1.f)); + pr.map_value(root, "origin", &object->origin, vec3(0.f)); + if (object->origin[2] != 0.f) { warn("non 0 origin[2]"); - this->origin[2] = 0.f; + object->origin[2] = 0.f; } - pr.map_value(root, "color", &this->color, vec3(0.f)); - pr.map_value(root, "alpha", &this->alpha, 1.f); - pr.map_value(root, "colorBlendMode", &this->color_blend_mode, 0); + pr.map_value(root, "color", &object->color, vec3(0.f)); + pr.map_value(root, "alpha", &object->alpha, 1.f); + pr.map_value(root, "colorBlendMode", &object->color_blend_mode, 0); - this->color4 = vec4{this->color[0], this->color[1], this->color[2], this->alpha}; + object->color4 = vec4{object->color[0], object->color[1], object->color[2], object->alpha}; if (root.contains("image")) { const json &image = root["image"]; - if (image.is_string()) this->model = new Model(pr, image); + if (image.is_string()) object->model = Model::parse(pr, image); + if (!object->model) parse_fail(object); } if (root.contains("config")) { - pr.map_value(root["config"], "passthrough", &this->passthrough, false); + pr.map_value(root["config"], "passthrough", &object->passthrough, false); } if (root.contains("effects")) { for (const json &effect : root["effects"]) { - this->effects.emplace_back(new Effect(pr, effect)); + Effect *eff = Effect::parse(pr, effect); + if (eff) object->effects.emplace_back(eff); } } + + return object; } auto Object::load(Engine *engine) -> void @@ -110,8 +114,9 @@ auto Object::load(Engine *engine) -> void if (this->size[1] == 0.f) this->size[1] = engine->scene->height; } - this->buffer_a = str_format("_rt_imageLayerComposite_%i_a", this->id); - this->buffer_b = str_format("_rt_imageLayerComposite_%i_b", this->id); + const std::string buffer_name = "_rt_imageLayerComposite_" + std::to_string(this->id) + "_"; + this->buffer_a = buffer_name + "a"; + this->buffer_b = buffer_name + "b"; engine->create_framebuffer(this->buffer_a, this->size[0], this->size[1], 1.f); engine->create_framebuffer(this->buffer_b, this->size[0], this->size[1], 1.f); @@ -151,23 +156,7 @@ auto Object::load(Engine *engine) -> void blend_pass.combos.push_back(Combo("BLENDMODE", this->color_blend_mode)); blend_pass.combos.push_back(Combo("TRANSFORM", 1)); - RenderPass *pass = new RenderPass(engine, &blend_pass); - this->effects.back()->passes.emplace_back(pass); - - /* - blend_pass.combine = true; - - blend_pass.target = ""; - blend_pass.textures[1] = ""; - blend_pass.shader = "minimal"; - - blend_pass.combos.clear(); - - pass = new RenderPass(engine, &blend_pass); - //pass->mat = &engine->default_mat; - //pass->render_object = engine->default_object; - this->effects.back()->passes.emplace_back(pass); - */ + this->effects.back()->passes.emplace_back(new RenderPass(engine, &blend_pass)); } this->loaded = true; @@ -183,7 +172,7 @@ auto Object::create_objects(Engine *engine, Texture *texture) -> void { // Something about positioning is wrong, affects most gifs. } - if (this->passthrough) + if (this->passthrough && !this->fullscreen) { this->model_model = this->combine_model; this->model_model = glm::rotate(this->model_model, this->angles[0], vec3{1.f, 0.f, 0.f}); @@ -204,16 +193,16 @@ auto Object::create_objects(Engine *engine, Texture *texture) -> void auto Object::draw_internal(Engine *engine) -> void { -#if FRAME_STEP - std::cout << this->name << " (model):\n"; +#ifdef FRAME_STEP + al_printf("%s (model):\n", this->name.c_str()); #endif this->buffer_switch = true; for (RenderPass *pass : this->passes) { -#if FRAME_STEP - std::cout << "\t" << pass->shader->origin()->name << "\n";; +#ifdef FRAME_STEP + al_printf("\t%s\n", pass->shader->origin()->name.c_str()); #endif pass->draw(engine); } diff --git a/src/objects/object.h b/src/objects/object.h index a171fae..9c9f60c 100644 --- a/src/objects/object.h +++ b/src/objects/object.h @@ -7,13 +7,21 @@ namespace Mauri { -enum ObjectAlignment { CENTER }; -enum BlendMode { TRANSLUCENT, NORMAL }; +enum ObjectAlignment +{ + CENTER = 0 +}; + +enum BlendMode +{ + TRANSLUCENT = 0, + NORMAL +}; class Object { public: - Object(Parser &pr, const json &root); + Object() = default; ~Object(); u32 id; @@ -42,6 +50,8 @@ class Object RenderObject *model_object = nullptr; RenderObject *combine_object = nullptr; + static auto parse(Parser &pr, const json &root) -> Object *; + auto get_target_buffer() const -> const std::string &; auto get_texture_buffer() const -> const std::string &; diff --git a/src/objects/pass.cc b/src/objects/pass.cc index 49533e1..04e23d5 100644 --- a/src/objects/pass.cc +++ b/src/objects/pass.cc @@ -1,38 +1,37 @@ -#include - #include "../gl.h" -#include "../context.h" -#include "scene.h" #include "pass.h" using namespace Mauri; -Pass::Pass(Parser &pr, const json &root, PassStage stage) +auto Pass::parse(Parser &pr, const json &root, PassStage stage) -> Pass * { + Pass *pass = new Pass(); + switch (stage) { case EFFECT0_PASS: break; case EFFECT1_PASS: { - if (root.contains("material")) this->material = new Material(pr, root["material"]); + if (root.contains("material")) pass->material = Material::parse(pr, root["material"]); + if (!pass->material) parse_fail(pass); if (root.contains("command")) { const json command = root["command"]; - if (command == "copy") this->command = COPY; + if (command == "copy") pass->command = COPY; } - if (root.contains("target")) this->target = root["target"]; - if (root.contains("source")) this->source = root["source"]; + if (root.contains("target")) pass->target = root["target"]; + if (root.contains("source")) pass->source = root["source"]; - this->binds[0] = "previous"; + pass->binds[0] = "previous"; if (root.contains("bind")) { for (const json &bind : root["bind"]) { - this->binds[bind["index"]] = bind["name"]; + pass->binds[bind["index"]] = bind["name"]; } } @@ -40,7 +39,10 @@ Pass::Pass(Parser &pr, const json &root, PassStage stage) } case MATERIAL_ONLY_PASS: case MATERIAL_PASS: - this->shader = root["shader"]; + pass->shader = root["shader"]; + if (pass->shader == "genericimage4") { + pass->shader = "genericimage2"; + } break; } @@ -51,7 +53,7 @@ Pass::Pass(Parser &pr, const json &root, PassStage stage) { UniformOverride *uniform = new UniformOverride{vec4(0.f), value.key()}; pr.map_value(uniforms, value.key(), &uniform->value, vec4(0.f)); - this->uniforms.push_back(uniform); + pass->uniforms.push_back(uniform); } } @@ -60,7 +62,7 @@ Pass::Pass(Parser &pr, const json &root, PassStage stage) const json textures = root["textures"]; for (u32 i = 0; i < textures.size(); i++) { - if (textures[i].is_string()) this->textures[i] = textures[i]; + if (textures[i].is_string()) pass->textures[i] = textures[i]; } } @@ -68,9 +70,11 @@ Pass::Pass(Parser &pr, const json &root, PassStage stage) { for (const auto &combo : root["combos"].items()) { - this->combos.emplace_back(Combo(combo.key(), combo.value())); + pass->combos.emplace_back(Combo(combo.key(), combo.value())); } } + + return pass; } auto Pass::load(Engine *engine, PassStage stage, Pass *pass) -> void @@ -169,7 +173,7 @@ RenderPass::RenderPass(Engine *engine, Pass *pass) pass->combos.push_back(Combo(this->shader->origin()->texture_combos[i], !pass->textures[i].empty())); } - if (!this->shader->origin()->textures[i].empty() && pass->textures[i].empty()) + if (pass->textures[i].empty() && !this->shader->origin()->textures[i].empty()) { pass->textures[i] = this->shader->origin()->textures[i]; } @@ -193,9 +197,12 @@ RenderPass::RenderPass(Engine *engine, Pass *pass) } } - if (i == 0 && this->textures[0] && this->model) + if (this->model && i == 0 && this->textures[0]) { - if (this->textures[0]->is_gif()) pass->combos.push_back(Combo("SPRITESHEET", 1)); + if (this->textures[0]->is_gif()) + { + pass->combos.push_back(Combo("SPRITESHEET", 1)); + } this->object->create_objects(engine, this->textures[0]); objects_created = true; } @@ -267,41 +274,41 @@ RenderPass::RenderPass(Engine *engine, Pass *pass) } } -#if _DEBUG_ +#ifdef _DEBUG_ debug("PASS (%s)", this->command == COPY ? "copy" : "draw"); - debug(" object: %s (passthrough: %i, fullscreen %i)", this->object->name.c_str(), + debug(" object: %s (passthrough: %d, fullscreen %d)", this->object->name.c_str(), this->object->passthrough, this->object->fullscreen); - //debug(" visible: %i", ); - debug(" shader: %s", this->shader->origin()->name.c_str()); - debug(" target: %s", pass->target.c_str()); - debug(" textures (%i):", this->shader->origin()->texture_count); + debug(" visible: %d", this->object->visible); + debug(" shader: %s", this->shader->origin()->name.c_str()); + debug(" target: %s", pass->target.c_str()); + debug(" textures (%u):", this->shader->origin()->texture_count); for (u32 i = 0; i < this->shader->origin()->texture_count; i++) { switch (this->texture_types[i]) { case STATIC: - if (pass->textures[i].empty() && !this->shader->textures[i].empty()) + if (pass->textures[i].empty() && !this->shader->origin()->textures[i].empty()) { - debug(" %s (DEFAULT)", this->shader->textures[i].c_str()); + debug(" [%u] %s (DEFAULT)", i, this->shader->origin()->textures[i].c_str()); } else { - debug(" %s", pass->textures[i].c_str()); + debug(" [%u] %s", i, pass->textures[i].c_str()); } break; case PREVIOUS: - debug(" previous"); + debug(" [%u] previous", i); break; } } - debug(" uniforms (%li)", this->shader->uniforms.size()); + debug(" uniforms (%u)", this->shader->uniforms.size()); for (Uniform *uniform : this->shader->uniforms) { - debug(" %s %s %s", uniform_type_to_string(uniform->type).c_str(), + debug(" %s %s %s", uniform_type_to_string(uniform->type).c_str(), uniform->uname.c_str(), glm::to_string(*uniform->value).c_str()); } - debug(" model: %i", this->model); - debug(" combine: %i", this->combine); + debug(" model: %d", this->model); + debug(" combine: %d", this->combine); #endif } @@ -341,10 +348,10 @@ auto RenderPass::draw(Engine *engine) -> void this->render_object->draw(); -#if FRAME_STEP - adjusted_target->buffer->blit(0, context()->width, context()->height); +#ifdef FRAME_STEP + adjusted_target->buffer->blit(0, context()->width(), context()->height()); context()->swap_buffers(); - std::this_thread::sleep_for(std::chrono::seconds(1)); + aki_thread_sleep(AKI_TS_FROM_USEC(1000000)); #endif break; } diff --git a/src/objects/pass.h b/src/objects/pass.h index a2b3124..5012ed5 100644 --- a/src/objects/pass.h +++ b/src/objects/pass.h @@ -8,10 +8,25 @@ namespace Mauri { -enum PassStage { EFFECT0_PASS, EFFECT1_PASS, MATERIAL_PASS, MATERIAL_ONLY_PASS }; -enum PassCommand { DRAW, COPY }; +enum PassStage +{ + EFFECT0_PASS = 0, + EFFECT1_PASS, + MATERIAL_PASS, + MATERIAL_ONLY_PASS +}; + +enum PassCommand +{ + DRAW = 0, + COPY +}; -enum TextureType { STATIC, PREVIOUS }; +enum TextureType +{ + STATIC = 0, + PREVIOUS +}; struct UniformOverride { @@ -22,8 +37,7 @@ struct UniformOverride class Pass { public: - Pass() {} - Pass(Parser &pr, const json &root, PassStage stage); + Pass() = default; ~Pass(); bool intermediate; @@ -47,6 +61,8 @@ class Pass std::vector uniforms; std::vector combos; + static auto parse(Parser &pr, const json &root, PassStage stage) -> Pass *; + auto load(Engine *engine, PassStage stage, Pass *pass) -> void; private: diff --git a/src/objects/scene.cc b/src/objects/scene.cc index 06412f5..b7d1192 100644 --- a/src/objects/scene.cc +++ b/src/objects/scene.cc @@ -2,37 +2,48 @@ using namespace Mauri; -Scene::Scene(const std::string &path) +auto Scene::parse(const std::string &path) -> Scene * { + Scene *scene = new Scene(); + Asset *asset = asset_manager()->get_file(path); - if (asset->type == ASSET_VOID) return; + if (asset->type == ASSET_VOID) parse_fail(scene); - const json &root = json::parse(asset->as_string()); - if (root.is_discarded()) return; + const json &root = json::parse(asset->as_string(), nullptr, false); + if (root.is_discarded()) parse_fail(scene); - Parser &pr = this->parser; + Parser &pr = scene->parser; const json &camera = root["camera"]; - pr.map_value(camera, "center", &this->cam.center, vec3(0.f)); - pr.map_value(camera, "eye", &this->cam.eye, vec3(0.f)); - pr.map_value(camera, "up", &this->cam.up, vec3(0.f)); + pr.map_value(camera, "center", &scene->cam.center, vec3(0.f)); + pr.map_value(camera, "eye", &scene->cam.eye, vec3(0.f)); + pr.map_value(camera, "up", &scene->cam.up, vec3(0.f)); const json &general = root["general"]; - pr.map_value(general, "clearenabled", &this->clear_enabled, true); - pr.map_value(general, "clearcolor", &this->clear_color, vec4(1.f)); - pr.map_value(general, "nearz", &this->nearz, -1.f); - pr.map_value(general, "farz", &this->farz, 1.f); + pr.map_value(general, "clearenabled", &scene->clear_enabled, true); + pr.map_value(general, "clearcolor", &scene->clear_color, vec4(1.f)); + pr.map_value(general, "nearz", &scene->nearz, -1.f); + pr.map_value(general, "farz", &scene->farz, 1.f); const json &ortho = general["orthogonalprojection"]; - pr.map_value(ortho, "width", &this->width, 0); - pr.map_value(ortho, "height", &this->height, 0); + pr.map_value(ortho, "width", &scene->width, 0); + pr.map_value(ortho, "height", &scene->height, 0); for (const json &object : root["objects"]) { if (!object.contains("image") || object["image"].is_null()) continue; - //if (object["name"] == "ICUE") continue; - this->objects.emplace_back(new Object(pr, object)); + if (object["name"] == "ICUE") continue; + Object *obj = Object::parse(scene->parser, object); + if (obj) scene->objects.emplace_back(obj); } + + return scene; +} + +auto Scene::offset_camera(s32 x, s32 y) -> void +{ + this->cam.offset[0] = x; + this->cam.offset[1] = y; } auto Scene::get_object_by_id(u32 id) -> Object * diff --git a/src/objects/scene.h b/src/objects/scene.h index 7b3d07a..2472fda 100644 --- a/src/objects/scene.h +++ b/src/objects/scene.h @@ -11,12 +11,13 @@ struct Camera vec3 center; vec3 eye; vec3 up; + vec2 offset = vec2(0.f); }; class Scene { public: - Scene(const std::string &path); + Scene() = default; ~Scene(); Parser parser; @@ -32,6 +33,10 @@ class Scene bool clear_enabled; vec4 clear_color; + static auto parse(const std::string &path) -> Scene *; + + auto offset_camera(s32 x, s32 y) -> void; + auto get_object_by_id(u32 id) -> Object *; auto load(Engine *engine) -> void; diff --git a/src/shader.cc b/src/shader.cc index 0a2d568..2820b57 100644 --- a/src/shader.cc +++ b/src/shader.cc @@ -1,9 +1,8 @@ -#include - -#include "json.h" #include "shader.h" +#include "gl.h" +#include "json.h" -#include "objects/scene.h" +#include "objects/object.h" static const char *compat = \ // "#define mul(x, y) ((y) * (x))\n" @@ -38,15 +37,21 @@ static std::unordered_map render_shader_map; auto get_shader(const std::string &name) -> Shader * { - if (shader_map.contains(name)) - { - return new Shader(shader_map[name]); - } + auto rshader = shader_map.find(name); + if (rshader != shader_map.end()) return new Shader(rshader->second); Shader *shader = new Shader(name); shader_map[name] = shader; return shader; } +extern auto unload_shaders() -> void +{ + for (auto &entry : render_shader_map) + { + delete entry.second; + } +} + } // namespace Mauri using namespace Mauri; @@ -74,36 +79,61 @@ Shader::Shader(Shader *origin) this->origin_ = origin; } -static auto simple_audio_bars_hack(std::string_view &line) -> void +static auto simple_audio_bars_hack(std::string_view &line) -> const std::string_view { - if (line == " uint barFreq1 = frequency % RESOLUTION;") + if (line == " uint barFreq1 = frequency % RESOLUTION;\r\n") + { + return " uint barFreq1 = uint(mod(frequency, RESOLUTION));\r\n"; + } + else if (line == " uint barFreq2 = (barFreq1 + 1) % RESOLUTION;\r\n") + { + return " uint barFreq2 = uint(mod((barFreq1 + 1u), RESOLUTION));\r\n"; + } + else if (line == " int bar = step(shapeCoord.y, 0.5 * lerp(g_BarBounds.x, g_BarBounds.y, lerp(barVolume1L, barVolume2L, smoothstep(0, 1, fract(frequency)))));\r\n") { - line = " uint barFreq1 = uint(mod(frequency, RESOLUTION));"; + return " float bar = step(shapeCoord.y, 0.5 * lerp(g_BarBounds.x, g_BarBounds.y, lerp(barVolume1L, barVolume2L, smoothstep(0, 1, fract(frequency)))));\r\n"; } - else if (line == " uint barFreq2 = (barFreq1 + 1) % RESOLUTION;") + else if (line == " int bar = step(1 - shapeCoord.y, lerp(g_BarBounds.x, g_BarBounds.y, lerp(barVolume1, barVolume2, smoothstep(0, 1, fract(frequency)))));\r\n") { - line = " uint barFreq2 = uint(mod((barFreq1 + 1u), RESOLUTION));"; + return " float bar = step(1 - shapeCoord.y, lerp(g_BarBounds.x, g_BarBounds.y, lerp(barVolume1, barVolume2, smoothstep(0, 1, fract(frequency)))));\r\n"; } - else if (line == " int bar = step(shapeCoord.y, 0.5 * lerp(g_BarBounds.x, g_BarBounds.y, lerp(barVolume1L, barVolume2L, smoothstep(0, 1, fract(frequency)))));") + else if (line == " int bar = step(1 - shapeCoord.y, barHeight);\r\n") { - line = " float bar = step(shapeCoord.y, 0.5 * lerp(g_BarBounds.x, g_BarBounds.y, lerp(barVolume1L, barVolume2L, smoothstep(0, 1, fract(frequency)))));"; + return " float bar = step(1 - shapeCoord.y, barHeight);\r\n"; } - else if (line == " int bar = step(1 - shapeCoord.y, lerp(g_BarBounds.x, g_BarBounds.y, lerp(barVolume1, barVolume2, smoothstep(0, 1, fract(frequency)))));") + else if (line == " int barLeft = step(shapeCoord.y, barHeightLeft);\r\n") { - line = " float bar = step(1 - shapeCoord.y, lerp(g_BarBounds.x, g_BarBounds.y, lerp(barVolume1, barVolume2, smoothstep(0, 1, fract(frequency)))));"; + return " float barLeft = step(shapeCoord.y, barHeightLeft);\r\n"; } - else if (line == " int bar = step(1 - shapeCoord.y, barHeight);") + else if (line == " int barRight = step(1 - shapeCoord.y, barHeightRight);\r\n") { - line = " float bar = step(1 - shapeCoord.y, barHeight);"; + return " float barRight = step(1 - shapeCoord.y, barHeightRight);\r\n"; } - else if (line == " int barLeft = step(shapeCoord.y, barHeightLeft);") + else if (line == " shapeCoord.x += endAngle - startAngle < 0.0;\r\n") { - line = " float barLeft = step(shapeCoord.y, barHeightLeft);"; + return " shapeCoord.x += endAngle - int(startAngle < 0.0);\r\n"; } - else if (line == " int barRight = step(1 - shapeCoord.y, barHeightRight);") + else if (line == " bar *= shapeCoord.x > 0.0 && shapeCoord.x * sign(endAngle - startAngle) < 1.0;\r\n") { - line = " float barRight = step(1 - shapeCoord.y, barHeightRight);"; + return " bar *= int(shapeCoord.x > 0.0 && shapeCoord.x * sign(endAngle - startAngle) < 1.0);\r\n"; } + return line; +} + +static auto bokeh_blur_hack(std::string_view &line) -> const std::string_view +{ + if (line == " depth *= (depth < blurPreciseLimit) * 6.0;\r\n") + { + return " depth *= int(depth < blurPreciseLimit) * 6.0;\r\n"; + } + return line; +} + +static auto apply_hacks(std::string_view line) -> const std::string_view +{ + line = simple_audio_bars_hack(line); + line = bokeh_blur_hack(line); + return line; } auto Shader::build_shader_source(const std::string_view &isource, std::stringstream &out) -> void @@ -112,11 +142,18 @@ auto Shader::build_shader_source(const std::string_view &isource, std::stringstr std::stringstream prefix; - for (const auto &range : std::ranges::split_view(isource, std::string_view("\r\n"))) - { - std::string_view line = std::string_view(range.data(), range.size()); + auto cursor = isource.begin(); + auto end = isource.end(); - simple_audio_bars_hack(line); + while (cursor != end) + { + auto end_of_line = std::find(cursor, end, '\n'); + if (end_of_line != end) { + end_of_line++; + } + std::string_view raw_line = std::string_view(cursor, end_of_line - cursor); + cursor += raw_line.length(); + const std::string_view line = apply_hacks(raw_line); bool cut_line = false; bool prepend_line = false; @@ -257,7 +294,7 @@ auto Shader::build_shader_source(const std::string_view &isource, std::stringstr { size_t open = line.find('{'); std::string_view combo = line.substr(open, line.length() - open); - const json &root = json::parse(combo); + const json &root = json::parse(combo, nullptr, false); if (!root.is_discarded()) { if (root.contains("default")) @@ -274,8 +311,8 @@ auto Shader::build_shader_source(const std::string_view &isource, std::stringstr if (!cut_line) { - if (prepend_line) prefix << line << "\n"; - else out << line << "\n"; + if (prepend_line) prefix << line; + else out << line; } } @@ -285,12 +322,12 @@ auto Shader::build_shader_source(const std::string_view &isource, std::stringstr auto Combo::to_string() const -> const std::string { - return str_format("#define %s %i\n", this->name.c_str(), this->value); + return "#define " + this->name + " " + std::to_string(this->value) + "\n"; } auto Variable::to_string() const -> const std::string { - return str_format("varying %s %s;\n", uniform_type_to_string(this->type).c_str(), this->name.c_str()); + return "varying " + uniform_type_to_string(this->type) + " " + this->name + ";\n"; } auto Shader::compile(const std::vector &combo_overrides) -> RenderShader * @@ -306,7 +343,6 @@ auto Shader::compile(const std::vector &combo_overrides) -> RenderShader { shader_combo.value = combo.value; add = false; - break; } } if (add) adjusted_combos.push_back(combo); @@ -321,27 +357,25 @@ auto Shader::compile(const std::vector &combo_overrides) -> RenderShader u64 hash = std::hash{}(this->origin()->name + combos_str.str()); - if (!render_shader_map.contains(hash)) - { - std::stringstream preamble; - - preamble << version; - preamble << compat; + auto rshader = render_shader_map.find(hash); + if (rshader != render_shader_map.end()) return rshader->second; - preamble << combos_str.str(); + std::stringstream preamble; - for (const Variable &variable : this->origin()->variables) - { - preamble << variable.to_string(); - } + preamble << version; + preamble << compat; - std::string vs_source = preamble.str() + mul + this->origin()->vs_source.str(); - std::string fs_source = preamble.str() + this->origin()->fs_source.str(); + preamble << combos_str.str(); - render_shader_map[hash] = new RenderShader(vs_source, fs_source); + for (const Variable &variable : this->origin()->variables) + { + preamble << variable.to_string(); } - return render_shader_map[hash]; + std::string vs_source = preamble.str() + mul + this->origin()->vs_source.str(); + std::string fs_source = preamble.str() + this->origin()->fs_source.str(); + + return render_shader_map[hash] = new RenderShader(vs_source, fs_source); } auto Shader::bind(RenderShader *shader, Engine *engine, Object *object, mat4x4 *model, @@ -408,7 +442,7 @@ auto Shader::bind(RenderShader *shader, Engine *engine, Object *object, mat4x4 * shader->set_uniform("g_Color4", TYPE_VEC4, glm::value_ptr(object->color4)); } -#ifdef BUILD_AUDIO +#ifdef HAVE_AUDIO if (engine->audio_enabled) { engine->vis->update(); @@ -436,11 +470,15 @@ auto Shader::bind(RenderShader *shader, Engine *engine, Object *object, mat4x4 * glUniform1fv(shader->get_uniform_location("g_AudioSpectrum16Left"), 16, empty_bars.data()); glUniform1fv(shader->get_uniform_location("g_AudioSpectrum16Right"), 16, empty_bars.data()); #endif -#ifdef BUILD_AUDIO +#ifdef HAVE_AUDIO } #endif } Shader::~Shader() { + for (Uniform *uniform : this->uniforms) + { + delete uniform; + } } diff --git a/src/shader.h b/src/shader.h index 1ce4209..c3b2738 100644 --- a/src/shader.h +++ b/src/shader.h @@ -24,10 +24,9 @@ struct Uniform struct Combo { - Combo(const std::string &name, s32 value) - : name(name), value(value) + Combo(const std::string &name, s32 value) : name(name), value(value) { - str_to_upper(this->name); + std::transform(this->name.begin(), this->name.end(), this->name.begin(), ::toupper); } std::string name; s32 value; @@ -80,6 +79,7 @@ private: }; extern auto get_shader(const std::string &name) -> Shader *; +extern auto unload_shaders() -> void; } // namespace Mauri diff --git a/src/texture.cc b/src/texture.cc index 21dfd90..8b7aa23 100644 --- a/src/texture.cc +++ b/src/texture.cc @@ -1,12 +1,16 @@ +_Pragma("GCC diagnostic push") +_Pragma("GCC diagnostic ignored \"-Wunused-function\"") +_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") #define STB_IMAGE_WRITE_IMPLEMENTATION -#define STBI_NO_FAILURE_STRINGS -#define STB_IMAGE_STATIC +#define STB_IMAGE_WRITE_STATIC #include #define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_STATIC #define STBI_NO_STDIO +#define STBI_NO_FAILURE_STRINGS #include - +_Pragma("GCC diagnostic pop") #include #include @@ -194,10 +198,7 @@ Texture::Texture(Asset *asset) std::string_view gif_container = asset->reads(9); u32 gif_frame_count = asset->read(); - if (gif_container.compare(0, 8, "TEXS0002") == 0) - { - //this->flags.m.IS_GIF = 0; - } + if (gif_container.compare(0, 8, "TEXS0002") == 0) {} else if (gif_container.compare(0, 8, "TEXS0003") == 0) { this->gif_width = asset->read(); @@ -275,8 +276,10 @@ auto Texture::save_to_file(const std::string &filename) -> void { for (u32 i = 0; i < this->textures.size(); i++) { - stbi_write_png((filename + std::to_string(i)).c_str(), this->textures[i]->width, this->textures[i]->height, - 4, this->textures[i]->pixels.data(), 4 * this->textures[i]->width); + u32 width = this->textures[i]->width; + u32 height = this->textures[i]->height; + u32 *data = this->textures[i]->pixels.data(); + stbi_write_png((filename + std::to_string(i)).c_str(), width, height, 4, data, 4 * width); } } @@ -284,3 +287,16 @@ Texture::~Texture() { if (!this->wrapped) delete this->texture; } + +Framebuffer::Framebuffer(std::string name, s32 width, s32 height, f32 scale) + : name(name) +{ + this->buffer = new RenderFramebuffer(width, height, scale); + this->texture = new Texture(this->buffer); +} + +Framebuffer::~Framebuffer() +{ + if (this->buffer) delete this->buffer; + if (this->texture) delete this->texture; +} diff --git a/src/texture.h b/src/texture.h index c552037..e68ce1f 100644 --- a/src/texture.h +++ b/src/texture.h @@ -7,7 +7,12 @@ namespace Mauri { -enum TextureVersion { TEXB0001, TEXB0002, TEXB0003 }; +enum TextureVersion +{ + TEXB0001 = 0, + TEXB0002, + TEXB0003 +}; enum TextureFormat { @@ -79,6 +84,18 @@ class Texture std::vector frames; }; +class Framebuffer +{ + public: + Framebuffer(std::string name, s32 width, s32 height, f32 scale); + ~Framebuffer(); + + std::string name; + + RenderFramebuffer *buffer; + Texture *texture; +}; + } // namespace Mauri #endif // _TEXTURE_H diff --git a/src/util.cc b/src/util.cc deleted file mode 100644 index 8a02572..0000000 --- a/src/util.cc +++ /dev/null @@ -1,16 +0,0 @@ -#include "util.h" - -namespace Mauri -{ - -auto str_to_lower(std::string &s) -> void -{ - transform(s.begin(), s.end(), s.begin(), ::tolower); -} - -auto str_to_upper(std::string &s) -> void -{ - transform(s.begin(), s.end(), s.begin(), ::toupper); -} - -} // namespace Mauri diff --git a/src/util.h b/src/util.h index c0c4084..6548a9b 100644 --- a/src/util.h +++ b/src/util.h @@ -1,58 +1,26 @@ #ifndef _UTIL_H #define _UTIL_H -#include +extern "C" { +#include +} -#include -#include -#include -#include -#include +#undef array +#include +#include +#include +#include +#include +#include #include "log.h" -using namespace glm; -using namespace nlohmann; - -#define FRAME_STEP 0 -#define UNIFORM_DEBUG 0 - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) - -typedef uint32_t u32; -typedef int32_t s32; - -typedef uint64_t u64; -typedef int64_t s64; - -typedef uint16_t u16; -typedef int16_t s16; - -typedef uint8_t u8; -typedef int8_t s8; - -typedef float f32; -typedef double f64; - -typedef unsigned char byte; - -namespace Mauri -{ - -template -static auto str_format(const std::string &format, Args ... args) -> std::string -{ - s32 size_s = std::snprintf(nullptr, 0, format.c_str(), args ...) + 1; - if (size_s <= 0) { return ""; } - auto size = static_cast(size_s); - std::unique_ptr buf(new char[size]); - std::snprintf(buf.get(), size, format.c_str(), args ...); - return std::string(buf.get(), buf.get() + size - 1); -} +// Pause after every pass. +//#define FRAME_STEP -auto str_to_lower(std::string &s) -> void; -auto str_to_upper(std::string &s) -> void; +// Print uniforms each frame. +//#define UNIFORM_DEBUG -} // namespace Mauri +typedef uint8_t byte; #endif // _UTIL_H diff --git a/src/vis.cc b/src/vis.cc index 7b52808..062bb62 100644 --- a/src/vis.cc +++ b/src/vis.cc @@ -1,5 +1,3 @@ -#include - #include "vis.h" using namespace Mauri; @@ -129,7 +127,11 @@ auto Visualizer::update() -> void g_mutex_lock(&this->mutex); - if (!this->sample) return; + if (!this->sample) + { + g_mutex_unlock(&this->mutex); + return; + } GstBuffer *buffer = gst_sample_get_buffer(sample); @@ -199,21 +201,24 @@ auto Visualizer::update_sample() -> void this->sample_processed = false; } -static auto new_sample_callback(GstElement *appsink, gpointer *data) -> GstFlowReturn +static auto sample_callback(GstElement *appsink, gpointer *data) -> GstFlowReturn { Visualizer *vis = (Visualizer *)data; + g_mutex_lock(&vis->mutex); vis->update_sample(); g_mutex_unlock(&vis->mutex); + return GST_FLOW_OK; } +/* static auto main_thread(void *data) -> void * { Visualizer *vis = (Visualizer *)data; - GstMessage *msg = gst_bus_timed_pop_filtered(vis->bus, - GST_CLOCK_TIME_NONE, (GstMessageType)(GST_MESSAGE_ERROR | GST_MESSAGE_EOS)); + GstMessageType filter = (GstMessageType)(GST_MESSAGE_ERROR | GST_MESSAGE_EOS); + GstMessage *msg = gst_bus_timed_pop_filtered(vis->bus, GST_CLOCK_TIME_NONE, filter); if (!msg) return 0; @@ -230,6 +235,7 @@ static auto main_thread(void *data) -> void * return 0; } +*/ auto Visualizer::run() -> bool { @@ -253,34 +259,34 @@ auto Visualizer::run() -> bool gst_element_set_state(this->pipeline, GST_STATE_PLAYING); - this->bus = gst_pipeline_get_bus(GST_PIPELINE(this->pipeline)); - - this->signal_handler = g_signal_connect(this->appsink, "new-sample", - G_CALLBACK(new_sample_callback), this); + this->signal_handler = g_signal_connect(this->appsink, "new-sample", G_CALLBACK(sample_callback), this); - this->thread = g_thread_new(nullptr, main_thread, this); + //this->bus = gst_pipeline_get_bus(GST_PIPELINE(this->pipeline)); + //this->thread = g_thread_new(nullptr, main_thread, this); return true; } Visualizer::~Visualizer() { - if (this->in_left) fftw_free(this->in_left); - if (this->in_right) fftw_free(this->in_right); - if (this->out_left) fftw_free(this->out_left); - if (this->out_right) fftw_free(this->out_right); - - g_mutex_clear(&this->mutex); - /* gst_bus_post(this->bus, gst_message_new_eos(GST_OBJECT(this->pipeline))); g_thread_join(this->thread); gst_object_unref(this->bus); + */ + + g_signal_handler_disconnect(this->appsink, this->signal_handler); //gst_element_set_state(this->pipeline, GST_STATE_NULL); //gst_element_get_state(this->pipeline, nullptr, nullptr, GST_CLOCK_TIME_NONE); //gst_object_unref(this->pipeline); if (this->sample) gst_sample_unref(this->sample); - */ + + if (this->in_left) fftw_free(this->in_left); + if (this->in_right) fftw_free(this->in_right); + if (this->out_left) fftw_free(this->out_left); + if (this->out_right) fftw_free(this->out_right); + + g_mutex_clear(&this->mutex); } diff --git a/src/vis.h b/src/vis.h index 65261c7..5d8f38c 100644 --- a/src/vis.h +++ b/src/vis.h @@ -1,9 +1,9 @@ #ifndef _VISUALIZER_H #define _VISUALIZER_H -#include -#include #include +#include +#include #include "util.h" -- cgit v1.2.3-101-g0448