summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Opalach <andrew@akon.city> 2023-11-10 19:24:56 -0500
committerAndrew Opalach <andrew@akon.city> 2023-11-12 20:04:01 -0500
commitacd44bb898996ff4e36b39b10e870e40bcaf2634 (patch)
treefa452ee2e583566a4fd28a4ac204cf62a9a1a0bc /src
parentf1a9751af6cc6aa0bac91e7f28fc43b1a4cb64fd (diff)
downloadmauri-acd44bb898996ff4e36b39b10e870e40bcaf2634.tar.gz
mauri-acd44bb898996ff4e36b39b10e870e40bcaf2634.tar.bz2
mauri-acd44bb898996ff4e36b39b10e870e40bcaf2634.zip
One last push
Signed-off-by: Andrew Opalach <andrew@akon.city>
Diffstat (limited to 'src')
-rw-r--r--src/assets.cc188
-rw-r--r--src/assets.h71
-rw-r--r--src/context.cc34
-rw-r--r--src/context.h57
-rw-r--r--src/context_glfw.cc144
-rw-r--r--src/context_glfw.h18
-rw-r--r--src/context_null.h40
-rw-r--r--src/context_x11.cc263
-rw-r--r--src/context_x11.h65
-rw-r--r--src/engine.cc211
-rw-r--r--src/engine.h64
-rw-r--r--src/framebuffer.cc23
-rw-r--r--src/framebuffer.h9
-rw-r--r--src/gl.cc559
-rw-r--r--src/gl.h70
-rw-r--r--src/json.h130
-rw-r--r--src/log.h22
-rw-r--r--src/mauri.cc87
-rw-r--r--src/objects/effect.cc89
-rw-r--r--src/objects/effect.h14
-rw-r--r--src/objects/material.cc57
-rw-r--r--src/objects/material.h12
-rw-r--r--src/objects/model.cc36
-rw-r--r--src/objects/model.h4
-rw-r--r--src/objects/object.cc314
-rw-r--r--src/objects/object.h71
-rw-r--r--src/objects/pass.cc412
-rw-r--r--src/objects/pass.h51
-rw-r--r--src/objects/scene.cc85
-rw-r--r--src/objects/scene.h20
-rw-r--r--src/shader.cc555
-rw-r--r--src/shader.h53
-rw-r--r--src/texture.cc270
-rw-r--r--src/texture.h58
-rw-r--r--src/util.cc16
-rw-r--r--src/util.h23
-rw-r--r--src/vis.cc286
-rw-r--r--src/vis.h87
-rw-r--r--src/visualizer.cc303
-rw-r--r--src/visualizer.h79
40 files changed, 2555 insertions, 2395 deletions
diff --git a/src/assets.cc b/src/assets.cc
index d48cffd..f892662 100644
--- a/src/assets.cc
+++ b/src/assets.cc
@@ -8,11 +8,11 @@
namespace Mauri
{
-static AssetManager _asset_manager;
+static AssetManager asset_manager_;
-AssetManager *asset_manager()
+auto asset_manager() -> AssetManager *
{
- return &_asset_manager;
+ return &asset_manager_;
}
} // namespace Mauri
@@ -21,25 +21,20 @@ using namespace Mauri;
Asset::Asset()
{
- type = ASSET_VOID;
- size = 0;
- pos = 0;
- data = nullptr;
- ltype = NONE;
- lasset = nullptr;
+ this->type = ASSET_VOID;
+ this->size = 0;
+ this->data = nullptr;
}
static Asset asset_void = Asset();
-Asset::Asset(const std::string &path, byte *begin, byte *end)
+Asset::Asset(const std::string &path, byte *start, byte *end)
: path(path)
{
- type = ASSET_SLICE;
- size = end - begin;
- pos = 0;
- data = begin;
- ltype = NONE;
- lasset = nullptr;
+ this->type = ASSET_SLICE;
+ this->size = end - start;
+ this->data = start;
+ this->hash = std::hash<std::string>{}(path);
}
Asset::Asset(const std::string &path)
@@ -49,44 +44,39 @@ Asset::Asset(const std::string &path)
if (file.bad() || file.fail())
{
- type = ASSET_VOID;
+ this->type = ASSET_VOID;
file.close();
return;
}
- size = file.tellg();
- data = new byte[size];
+ this->size = file.tellg();
+ this->data = new byte[size];
file.seekg(0, std::ios::beg);
- if (!file.read(reinterpret_cast<char *>(data), size))
+
+ if (!file.read(reinterpret_cast<char *>(this->data), this->size))
{
- type = ASSET_VOID;
+ this->type = ASSET_VOID;
file.close();
+ delete[] this->data;
return;
}
file.close();
- pos = 0;
- type = ASSET_FILE;
-
- ltype = NONE;
- lasset = nullptr;
+ this->type = ASSET_FILE;
}
Asset::~Asset()
{
- if (type == ASSET_FILE)
- {
- delete[] data;
- }
-
- if (lasset != nullptr)
+ if (this->type == ASSET_VOID) return;
+ if (this->type == ASSET_FILE) delete[] this->data;
+ if (this->lasset)
{
- switch (ltype)
+ switch (this->ltype)
{
case TEXTURE:
- delete (Texture *)lasset;
+ delete (Texture *)this->lasset;
break;
default:
break;
@@ -94,70 +84,67 @@ Asset::~Asset()
}
}
-bool AssetManager::load_package(const std::string &path)
+auto AssetManager::arm_package(const std::string &path, bool can_output) -> bool
{
- pkg = new Asset(path);
+ this->package = new Asset(path);
- if (pkg->type == ASSET_VOID)
+ if (this->package->type == ASSET_VOID)
{
- log_error("failed to load pkg file: (%s)", path.c_str());
+ error("failed to load package file: (%s)", path.c_str());
return false;
- };
+ }
- auto signature = pkg->reads(pkg->read<u32>());
+ std::string_view signature = this->package->reads(this->package->read<u32>());
if (signature.compare(0, 4, "PKGV") != 0)
{
- log_error("invalid pkg file (%s)", path.c_str());
+ error("invalid package file: (%s)", path.c_str());
return false;
}
- auto count = pkg->read<u32>();
+ u32 count = this->package->read<u32>();
+
+ this->assets.resize(count);
- std::vector<PkgFile> pkg_files;
- pkg_files.reserve(count);
+ std::vector<PackageFile> package_assets;
+ package_assets.resize(count);
- for (auto i = 0u; i < count; i++)
+ for (u32 i = 0; i < count; i++)
{
- pkg_files.emplace_back(PkgFile {
- pkg->reads(pkg->read<u32>()),
- pkg->read<u32>(),
- pkg->read<u32>()
- });
+ package_assets[i] = PackageFile{
+ this->package->reads(this->package->read<u32>()),
+ this->package->read<u32>(),
+ this->package->read<u32>()
+ };
}
- for (auto file : pkg_files)
+ for (u32 i = 0; i < count; i++)
{
- auto path = std::string(file.path);
-
- auto asset = new Asset(path,
- pkg->ptr() + file.offset,
- pkg->ptr() + file.offset + file.length
- );
-
- asset->hash = std::hash<std::string>{}(path);
-
- files.push_back(asset);
-
- log_debug("loaded file (%s)", std::string(file.path).c_str());
+ const PackageFile &asset = package_assets[i];
+ 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());
}
+ this->prepare_output = can_output;
+
return true;
}
-void AssetManager::unload_package()
+auto AssetManager::unload_package() -> void
{
- for (auto &asset : files)
+ for (Asset *asset : this->assets)
{
delete asset;
}
- files.clear();
+ this->assets.clear();
- delete pkg;
+ delete this->package;
}
-Asset *AssetManager::get_file(const std::string &part, FileTypeHint hint)
+auto AssetManager::get_file(const std::string &part, AssetTypeHint hint) -> Asset *
{
std::string path = part;
@@ -170,33 +157,33 @@ Asset *AssetManager::get_file(const std::string &part, FileTypeHint hint)
case SHADER:
path.insert(0, "shaders/");
break;
- case FRAGMENT_SHADER:
- path.insert(0, "shaders/");
- path.append(".frag");
- break;
case VERTEX_SHADER:
path.insert(0, "shaders/");
path.append(".vert");
break;
+ case FRAGMENT_SHADER:
+ path.insert(0, "shaders/");
+ path.append(".frag");
+ break;
case NONE:
default:
break;
}
Asset *asset = nullptr;
-
+
u64 hash = std::hash<std::string>{}(path);
- for (auto &file : files)
+ for (u32 i = 0; i < this->assets.size(); i++)
{
- if (file->hash == hash)
+ if (this->assets[i]->hash == hash)
{
- asset = file;
+ asset = this->assets[i];
break;
}
}
- if (asset == nullptr)
+ if (!asset)
{
path.insert(0, "assets/");
@@ -205,21 +192,25 @@ Asset *AssetManager::get_file(const std::string &part, FileTypeHint hint)
if (asset->type == ASSET_VOID)
{
+ error("failed to load asset: (%s)", path.c_str());
delete asset;
return &asset_void;
}
- files.push_back(asset);
+ debug("fetched asset: (%s)", path.c_str());
+
+ this->assets.push_back(asset);
}
asset->ltype = hint;
- if (asset->lasset == nullptr)
+ if (!asset->lasset)
{
switch (asset->ltype)
{
case TEXTURE:
asset->lasset = new Texture(asset);
+ debug("processed texture: (%s)", path.c_str());
break;
default:
break;
@@ -229,23 +220,23 @@ Asset *AssetManager::get_file(const std::string &part, FileTypeHint hint)
return asset;
}
-void AssetManager::write_files(const std::string &output_path)
+auto AssetManager::write_files(const std::string &output_path) -> void
{
- if (!std::filesystem::create_directories(output_path))
+ if (!std::filesystem::is_directory(output_path) && !std::filesystem::create_directories(output_path))
+ {
+ error("failed to create directory: (%s)", output_path.c_str());
return;
-
- for (auto &asset : files)
+ }
+
+ for (Asset *asset : this->assets)
{
std::stringstream path;
path << output_path;
- if (output_path.back() != '/')
- {
- path << '/';
- }
+ if (output_path.back() != '/') path << '/';
- auto index = asset->path.find_last_of('/');
+ size_t index = asset->path.find_last_of('/');
if (index != std::string::npos)
{
@@ -253,28 +244,31 @@ void AssetManager::write_files(const std::string &output_path)
}
path << asset->path;
-
+
switch (asset->ltype)
{
- case TEXTURE: {
- auto texture = ((Texture *)asset->lasset);
+ case TEXTURE:
+ {
+ Texture *texture = ((Texture *)asset->lasset);
texture->save_to_file(path.str() + ".png");
std::ofstream file(path.str() + ".flags");
- file << "NO_INTERPOLATION " << texture->flags.map.NO_INTERPOLATION << "\n";
- file << "CLAMP_UV " << texture->flags.map.CLAMP_UV << "\n";
- file << "IS_GIF " << texture->flags.map.IS_GIF << "\n";
+ file << "NO_INTERPOLATION " << texture->flags.m.NO_INTERPOLATION << "\n";
+ file << "CLAMP_UV " << texture->flags.m.CLAMP_UV << "\n";
+ file << "IS_GIF " << texture->flags.m.IS_GIF << "\n";
file.close();
break;
}
- case FRAGMENT_SHADER:
case VERTEX_SHADER:
- case SHADER: {
+ case FRAGMENT_SHADER:
+ case SHADER:
+ {
std::ofstream file(path.str());
file << asset->as_string();
file.close();
break;
}
- case NONE: {
+ case NONE:
+ {
std::ofstream file(path.str(), std::ios::binary);
file << asset->as_string();
file.close();
diff --git a/src/assets.h b/src/assets.h
index 72665d3..34e31df 100644
--- a/src/assets.h
+++ b/src/assets.h
@@ -9,21 +9,9 @@
namespace Mauri
{
-enum AssetType
-{
- ASSET_FILE,
- ASSET_SLICE,
- ASSET_VOID
-};
-enum FileTypeHint
-{
- TEXTURE,
- SHADER,
- FRAGMENT_SHADER,
- VERTEX_SHADER,
- NONE
-};
+enum AssetType { ASSET_VOID, ASSET_SLICE, ASSET_FILE };
+enum AssetTypeHint { NONE, TEXTURE, SHADER, FRAGMENT_SHADER, VERTEX_SHADER };
class Asset
{
@@ -31,66 +19,64 @@ class Asset
Asset();
Asset(const std::string &path, byte *begin, byte *end);
Asset(const std::string &path);
-
~Asset();
- // If this is ASSET_FILE, the data should be
- // free'd along with this asset.
AssetType type;
std::string path;
- // Info about loaded asset
- FileTypeHint ltype;
- void *lasset;
+ AssetTypeHint ltype = NONE;
+ void *lasset = nullptr;
u32 size;
u64 hash;
- byte *ptr() const
+ auto ptr() const -> byte *
{
return &this->data[this->pos];
}
- void seek(s32 n)
+ auto seek(s32 n) -> void
{
this->pos += n;
}
- void reset()
+ auto reset() -> void
{
this->pos = 0;
}
template <typename T>
- T read()
+ auto read() -> T
{
T val = *((T *)this->ptr());
this->seek(sizeof(T));
return val;
}
- std::string_view reads(u32 n)
+ auto reads(u32 n) -> std::string_view
{
std::string_view s((char *)this->ptr(), n);
this->seek(n);
return s;
}
-
- const std::string &as_string()
+
+ auto as_string() -> const std::string_view &
{
- if (_str.empty())
- _str = std::string((char *)this->ptr(), this->size);
- return _str;
+ if (str.empty())
+ {
+ str = std::string_view((char *)this->ptr(), this->size);
+ }
+ return str;
}
private:
- u32 pos;
+ u32 pos = 0;
byte *data;
- std::string _str;
+ std::string_view str;
};
-struct PkgFile
+struct PackageFile
{
std::string_view path;
u32 offset;
@@ -100,23 +86,24 @@ struct PkgFile
class AssetManager
{
public:
- AssetManager() {};
- ~AssetManager() {};
+ AssetManager() {}
+ ~AssetManager() {}
- std::vector<Asset *> files;
+ auto get_file(const std::string &part, AssetTypeHint hint = NONE) -> Asset *;
- Asset *get_file(const std::string &part, FileTypeHint hint);
+ auto arm_package(const std::string &path, bool can_output) -> bool;
+ auto unload_package() -> void;
- bool load_package(const std::string &path);
- void unload_package();
+ bool prepare_output;
- void write_files(const std::string &output_path);
+ auto write_files(const std::string &output_path) -> void;
private:
- Asset *pkg;
+ Asset *package;
+ std::vector<Asset *> assets;
};
-extern AssetManager *asset_manager();
+extern auto asset_manager() -> AssetManager *;
} // namespace Mauri
diff --git a/src/context.cc b/src/context.cc
index f40790f..a89f8b0 100644
--- a/src/context.cc
+++ b/src/context.cc
@@ -1,38 +1,36 @@
#include "context.h"
-namespace Mauri {
+namespace Mauri
+{
-static Context *_context = nullptr;
+static Context *context_ = nullptr;
-Context *context()
+auto context() -> Context *
{
- return _context;
+ return context_;
}
-void set_context(Context *c)
+auto set_context(Context *c) -> void
{
- if (_context != nullptr)
+ if (context_)
{
- _context->close_window();
- delete _context;
+ delete context_;
}
-
- _context = c;
+ context_ = c;
}
-}
+} // namespace Mauri
using namespace Mauri;
-void Context::print_gl_info()
+auto Context::print_gl_info() -> void
{
- log_info("%s", "OpenGL loaded");
- log_info("Vendor: %s", glGetString(GL_VENDOR));
- log_info("Renderer: %s", glGetString(GL_RENDERER));
- log_info("Version: %s", glGetString(GL_VERSION));
+ info("vendor: %s", glGetString(GL_VENDOR));
+ info("renderer: %s", glGetString(GL_RENDERER));
+ info("version: %s", glGetString(GL_VERSION));
}
-GLenum Context::check_error()
+auto Context::check_error() -> GLenum
{
GLenum error_code;
while ((error_code = glGetError()) != GL_NO_ERROR)
@@ -56,7 +54,7 @@ GLenum Context::check_error()
error = "INVALID_FRAMEBUFFER_OPERATION";
break;
}
- log_error("%s", error.c_str());
+ error("gl error: %s", error.c_str());
}
return error_code;
}
diff --git a/src/context.h b/src/context.h
index bc824b6..93e5290 100644
--- a/src/context.h
+++ b/src/context.h
@@ -1,13 +1,9 @@
#ifndef _CONTEXT_H
#define _CONTEXT_H
-#include <iostream>
-#include <glad/gl.h>
+#include <chrono>
-#include "util.h"
-
-#define GL_VERSION_MAJOR 3
-#define GL_VERSION_MINOR 3
+#include "gl.h"
namespace Mauri
{
@@ -15,45 +11,50 @@ namespace Mauri
class Context
{
public:
- Context(s32 width, s32 height, const std::string &name, bool wallpaper)
- : width(width), height(height) {}
-
+ Context() : start(std::chrono::system_clock::now()) {}
virtual ~Context() {}
- s32 width, height;
+ s32 width;
+ s32 height;
+
+ 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;
+
+ virtual auto process_input() -> void = 0;
+ virtual auto cursor_pos(f32 *x, f32 *y) -> void = 0;
- bool draw_enabled() const
+ auto is_draw_enabled() const -> bool
{
- return _draw_enabled;
+ return this->draw_enabled;
}
- void set_draw_enabled(bool enabled)
+ auto set_draw_enabled(bool enabled) -> void
{
- _draw_enabled = enabled;
+ this->draw_enabled = enabled;
}
- virtual void resize_window(s32 w, s32 h) = 0;
+ virtual auto swap_buffers() -> void = 0;
- virtual void close_window() = 0;
- virtual bool should_close() const = 0;
+ using us = std::chrono::microseconds;
- virtual void swap_buffers() = 0;
-
- virtual void process_input() = 0;
- virtual void cursor_pos(f32 *x, f32 *y) = 0;
-
- virtual f64 current_time() = 0;
+ auto current_time() const -> f64
+ {
+ return std::chrono::duration_cast<us>(std::chrono::system_clock::now() - this->start).count() / 1000000.f;
+ }
protected:
- GLenum check_error();
- void print_gl_info();
+ auto print_gl_info() -> void;
+ auto check_error() -> GLenum;
private:
- bool _draw_enabled = false;
+ bool draw_enabled = false;
+ std::chrono::time_point<std::chrono::system_clock> start;
};
-extern Context *context();
-extern void set_context(Context *c);
+extern auto context() -> Context *;
+extern auto set_context(Context *c) -> void;
} // namespace Mauri
diff --git a/src/context_glfw.cc b/src/context_glfw.cc
index c4f7d17..cbaea23 100644
--- a/src/context_glfw.cc
+++ b/src/context_glfw.cc
@@ -2,84 +2,45 @@
using namespace Mauri;
-void ContextGLFW::close_window()
-{
- glfwSetWindowShouldClose(window, GLFW_TRUE);
-}
-
-void ContextGLFW::resize_window(s32 w, s32 h)
-{
- width = w;
- height = h;
- glfwSetWindowSize(window, width, height);
-}
-
-bool ContextGLFW::should_close() const
-{
- return glfwWindowShouldClose(window);
-}
-
-void ContextGLFW::cursor_pos(f32 *x, f32 *y)
-{
- f64 _x, _y;
- glfwGetCursorPos(window, &_x, &_y);
- *x = (f32)_x;
- *y = (f32)_y;
-}
-
-void ContextGLFW::swap_buffers()
-{
- glfwSwapBuffers(window);
-}
-
-static void key_callback(GLFWwindow *window, s32 key, s32 scancode, s32 action, s32 mods)
+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()->draw_enabled());
+ context()->set_draw_enabled(!context()->is_draw_enabled());
}
}
-void ContextGLFW::process_input()
-{
- glfwPollEvents();
-}
-
-double ContextGLFW::current_time()
-{
- return glfwGetTime();
-}
-
-ContextGLFW::ContextGLFW(s32 width, s32 height, const std::string &name, bool wallpaper)
- : Context(width, height, name, wallpaper)
+auto ContextGLFW::create_window(s32 width, s32 height, const std::string &name, bool background) -> bool
{
if (!glfwInit())
{
- log_error("%s", "failed to init glfw");
- return;
+ 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 {
+ 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 },
+ {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_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
-
glfwWindowHint(GLFW_SRGB_CAPABLE, GLFW_TRUE);
- glfwWindowHint(GLFW_SAMPLES, 4);
+ //glfwWindowHint(GLFW_SAMPLES, 4);
for (u32 i = 0; i < ARRAY_SIZE(gl_vers); i++)
{
@@ -89,43 +50,82 @@ ContextGLFW::ContextGLFW(s32 width, s32 height, const std::string &name, bool wa
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
-
- window = glfwCreateWindow(width, height, name.c_str(), nullptr, nullptr);
-
- if (window)
+ if ((this->window = glfwCreateWindow(this->width, this->height, name.c_str(), nullptr, nullptr)))
{
break;
}
}
- if (!window)
+ if (!this->window)
{
- log_error("%s", "could not create opengl context");
- return;
+ error("could not create gl context");
+ return false;
}
- glfwMakeContextCurrent(window);
+ glfwMakeContextCurrent(this->window);
if (!gladLoadGL((GLADloadfunc)glfwGetProcAddress))
{
- log_error("%s", "could not load opengl");
- return;
+ error("could not load gl");
+ return false;
}
glEnable(GL_BLEND);
glEnable(GL_MULTISAMPLE);
- print_gl_info();
+ this->print_gl_info();
+
+ this->set_draw_enabled(true);
- set_draw_enabled(true);
+ glfwSetKeyCallback(this->window, key_callback);
- glfwSetKeyCallback(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()
{
- glfwDestroyWindow(this->window);
+ if (this->window) glfwDestroyWindow(this->window);
glfwTerminate();
}
diff --git a/src/context_glfw.h b/src/context_glfw.h
index 3d11775..1eb2991 100644
--- a/src/context_glfw.h
+++ b/src/context_glfw.h
@@ -12,20 +12,18 @@ namespace Mauri
class ContextGLFW : public Context
{
public:
- ContextGLFW(s32 width, s32 height, const std::string &name, bool wallpaper);
+ ContextGLFW() : Context() {}
~ContextGLFW();
- void close_window();
- void resize_window(s32 w, s32 h);
+ 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;
- bool should_close() const;
- void process_input();
+ auto process_input() -> void;
+ auto cursor_pos(f32 *x, f32 *y) -> void;
- void cursor_pos(f32 *x, f32 *y);
-
- void swap_buffers();
-
- f64 current_time();
+ auto swap_buffers() -> void;
private:
GLFWwindow *window;
diff --git a/src/context_null.h b/src/context_null.h
index f95375e..bcae058 100644
--- a/src/context_null.h
+++ b/src/context_null.h
@@ -9,47 +9,45 @@ namespace Mauri
class ContextNull : public Context
{
public:
- ContextNull(s32 width, s32 height, const std::string &name, bool wallpaper)
- : Context(width, height, name, wallpaper)
- {
- set_draw_enabled(false);
- }
-
+ ContextNull() : Context() { this->set_draw_enabled(false); }
~ContextNull() {}
- void resize_window(s32 w, s32 h)
+ auto create_window(s32 width, s32 height, const std::string &name, bool background) -> bool
{
- width = w;
- height = h;
+ return true;
}
- void close_window()
+ auto resize_window(s32 width, s32 height) -> void
{
- _should_close = true;
+ if (width != this->width || height != this->height)
+ {
+ this->width = width;
+ this->height = height;
+ }
}
- bool should_close() const
+ auto should_close_window() const -> bool
{
- return _should_close;
+ return this->should_close;
}
- void swap_buffers() {}
+ auto close_window() -> void
+ {
+ this->should_close = true;
+ }
- void process_input() {}
+ auto process_input() -> void {}
- void cursor_pos(f32 *x, f32 *y)
+ auto cursor_pos(f32 *x, f32 *y) -> void
{
*y = 0.f;
*x = 0.f;
}
- f64 current_time()
- {
- return 0.f;
- }
+ auto swap_buffers() -> void {}
private:
- bool _should_close = true;
+ bool should_close = true;
};
} // namespace Mauri
diff --git a/src/context_x11.cc b/src/context_x11.cc
index a35a9f2..7975a4a 100644
--- a/src/context_x11.cc
+++ b/src/context_x11.cc
@@ -4,149 +4,150 @@ using namespace Mauri;
static Atom ATOM_WM_DELETE_WINDOW, ATOM__NET_ACTIVE_WINDOW;
-void ContextX11::disable_input()
+auto ContextX11::disable_input() -> void
{
XWMHints wmHint;
wmHint.flags = InputHint | StateHint;
wmHint.input = false;
wmHint.initial_state = NormalState;
- XSetWMProperties(x11_d, window, NULL, NULL, NULL, 0, NULL, &wmHint, NULL);
+ XSetWMProperties(this->x11_d, this->window, NULL, NULL, NULL, 0, NULL, &wmHint, NULL);
}
-ContextX11::ContextX11(s32 width, s32 height, const std::string &name, bool wallpaper)
- : Context(width, height, name, wallpaper)
+auto ContextX11::create_window(s32 width, s32 height, const std::string &name, bool background) -> bool
{
- x11_d = XOpenDisplay(NULL);
-
- ATOM_WM_DELETE_WINDOW = XInternAtom(x11_d, "WM_DELETE_WINDOW", true);
+ this->x11_d = XOpenDisplay(NULL);
- if (!x11_d)
+ ATOM_WM_DELETE_WINDOW = XInternAtom(this->x11_d, "WM_DELETE_WINDOW", true);
+
+ if (!this->x11_d)
{
- log_error("%s", "could not open display");
- return;
+ error("could not open display");
+ return false;
}
-
- s32 screen = XDefaultScreen(x11_d);
- Window root = RootWindow(x11_d, screen);
+
+ 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_RENDER_TYPE, GLX_RGBA_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, 8,
+ GLX_ALPHA_SIZE, 0,
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_SAMPLES, 0,
None
};
GLint context_attrs[] = {
- GLX_CONTEXT_MAJOR_VERSION_ARB, GL_VERSION_MAJOR,
- GLX_CONTEXT_MINOR_VERSION_ARB, GL_VERSION_MINOR,
+ 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;
+ }
- GLXFBConfig *fbc = glXChooseFBConfig(x11_d, screen, gl_attrs, &fb_sz);
- if (!fbc)
- return;
-
- for (auto t = 0; t < fb_sz; ++t)
+ for (s32 t = 0; t < fb_sz; t++)
{
- XVisualInfo* xvi = glXGetVisualFromFBConfig(x11_d, fbc[t]);
- if (xvi)
+ 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))
{
- s32 samp_buf, samples;
- glXGetFBConfigAttrib(x11_d, fbc[t], GLX_SAMPLE_BUFFERS, &samp_buf);
- glXGetFBConfigAttrib(x11_d, fbc[t], GLX_SAMPLES, &samples);
- XRenderPictFormat* fmt = XRenderFindVisualFormat(x11_d, xvi->visual);
-
- if (!fmt) continue;
-
- if (best < 0 || (samp_buf && samples > samp))
- {
- best = t;
- samp = samples;
- }
- XFree(xvi);
+ best = t;
+ samp = samples;
}
+
+ XFree(xvi);
}
-
+
if (best == -1)
{
- log_error("%s", "XRender could not find suitable format");
- return;
+ error("could not find suitable XRender format");
+ return false;
}
GLXFBConfig config = fbc[best];
XFree(fbc);
- XVisualInfo *vi = glXGetVisualFromFBConfig(x11_d, config);
- Colormap cmap = XCreateColormap(x11_d, root, vi->visual, AllocNone);
+ 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 |
+ swa.event_mask = ExposureMask | KeyPressMask | StructureNotifyMask |
PropertyChangeMask | VisibilityChangeMask;
swa.background_pixmap = None;
swa.border_pixel = 0;
-
- window = XCreateWindow(x11_d, root, 0, 0, width, height, 0, vi->depth, InputOutput,
- vi->visual, CWColormap | CWEventMask | CWBackPixmap | CWBorderPixel, &swa);
+
+ this->window = XCreateWindow(this->x11_d, root, 0, 0, width, height, 0, vi->depth,
+ InputOutput, vi->visual, CWColormap | CWEventMask | CWBackPixmap | CWBorderPixel, &swa);
XFree(vi);
- //disable_input();
+ //this->disable_input();
- XStoreName(x11_d, window, name.c_str());
+ XStoreName(this->x11_d, this->window, name.c_str());
- XChangeProperty(x11_d, window,
- XInternAtom(x11_d, "_NET_WM_NAME", False),
- XInternAtom(x11_d, "UTF8_STRING", False),
+ 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<char *>(name.c_str());
class_hint.res_name = const_cast<char *>(name.c_str());
-
- XSetClassHint(x11_d, window, &class_hint);
+
+ XSetClassHint(this->x11_d, this->window, &class_hint);
glXCreateContextAttribsARBProc glXCreateContextAttribsARB = NULL;
glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
glXGetProcAddressARB((const GLubyte*) "glXCreateContextAttribsARB");
-
- if (!glXCreateContextAttribsARB)
- return;
-
- if (!(glc = glXCreateContextAttribsARB(x11_d, config, 0, True, context_attrs)))
- return;
-
- glXMakeCurrent(x11_d, window, glc);
+
+ 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))
{
- log_error("%s", "failed to load glad");
- return;
+ error("could not load gl");
+ return false;
}
- if (wallpaper)
+ if (background)
{
/*
- Atom desktop = XInternAtom(x11_d, "_NET_WM_DESKTOP", false);
-
+ Atom desktop = XInternAtom(this->x11_d, "_NET_WM_DESKTOP", false);
unsigned long all_desktops = XWIN_ALL_DESKTOPS;
- XChangeProperty(x11_d, window, desktop,
- XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&all_desktops, 1);
+ XChangeProperty(this->x11_d, this->window, desktop,
+ XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&all_desktops, 1);
*/
- Atom desktop_type = XInternAtom(x11_d, "_NET_WM_WINDOW_TYPE_DESKTOP", false);
-
- XChangeProperty(x11_d, window, XInternAtom(x11_d, "_NET_WM_WINDOW_TYPE", false),
+ 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);
/*
@@ -154,142 +155,148 @@ ContextX11::ContextX11(s32 width, s32 height, const std::string &name, bool wall
event.xclient.type = ClientMessage;
event.xclient.serial = 0;
event.xclient.send_event = True;
- event.xclient.display = x11_d;
- event.xclient.window = window;
- event.xclient.message_type = XInternAtom(x11_d, "_NET_WM_STATE", false);
+ 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(x11_d, "_NET_WM_STATE_BELOW", false);
+ 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(x11_d, root, false,
+ XSendEvent(this->x11_d, root, false,
SubstructureRedirectMask|SubstructureNotifyMask, &event);
- event.xclient.data.l[1] = XInternAtom(x11_d, "_NET_WM_STATE_STICKY", false);
+ 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(x11_d, "_NET_WM_STATE_FULLSCREEN", false);
+ event.xclient.data.l[1] = XInternAtom(this->x11_d, "_NET_WM_STATE_FULLSCREEN", false);
*/
}
- XSetWMProtocols(x11_d, window, &ATOM_WM_DELETE_WINDOW, 1);
-
- XMoveWindow(x11_d, window, 0, 0);
-
- XMapWindow(x11_d, window);
- XFlush(x11_d);
-
+ 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);
-
- print_gl_info();
-
- start = system_clock::now();
- set_draw_enabled(true);
-}
+ this->print_gl_info();
-void ContextX11::resize_window(s32 w, s32 h)
-{
- width = w;
- height = h;
+ this->set_draw_enabled(true);
+
+ return true;
}
-void ContextX11::swap_buffers()
+auto ContextX11::resize_window(s32 width, s32 height) -> void
{
- glXSwapBuffers(x11_d, window);
+ if (width != this->width || height != this->height)
+ {
+ this->width = width;
+ this->height = height;
+ }
}
-void ContextX11::raise()
+auto ContextX11::raise() -> void
{
XClientMessageEvent ev = {
.type = ClientMessage,
.serial = 0,
.send_event = true,
- .display = x11_d,
- .window = window,
+ .display = this->x11_d,
+ .window = this->window,
.message_type = ATOM__NET_ACTIVE_WINDOW,
.format = 32,
- .data = { .l = { 1, 0, (long)window } }
+ .data = {.l = {1, 0, (long)this->window}}
};
- XSendEvent(x11_d, DefaultRootWindow(x11_d), false, StructureNotifyMask, (XEvent *)&ev);
- XRaiseWindow(x11_d, window);
- XFlush(x11_d);
+ XSendEvent(this->x11_d, DefaultRootWindow(this->x11_d), false, StructureNotifyMask, (XEvent *)&ev);
+ XRaiseWindow(this->x11_d, this->window);
+ XFlush(this->x11_d);
}
-void ContextX11::set_clickthrough()
+auto ContextX11::set_clickthrough() -> void
{
- Window win = window, root = DefaultRootWindow(x11_d);
+ Window win = this->window, root = DefaultRootWindow(this->x11_d);
while (win != None)
{
Region region;
if ((region = XCreateRegion()))
{
- XShapeCombineRegion(x11_d, window, ShapeInput, 0, 0, region, ShapeSet);
+ XShapeCombineRegion(this->x11_d, this->window, ShapeInput, 0, 0, region, ShapeSet);
XDestroyRegion(region);
}
Window parent, *children = NULL;
u32 num_children;
- if (XQueryTree(x11_d, win, &root, &parent, &children, &num_children))
+ if (XQueryTree(this->x11_d, win, &root, &parent, &children, &num_children))
{
- if (children)
- XFree(children);
+ if (children) XFree(children);
}
win = (parent == root ? None : parent);
}
- XFlush(x11_d);
+ XFlush(this->x11_d);
}
-void ContextX11::close_window()
+auto ContextX11::close_window() -> void
{
- this->_should_close = true;
+ this->should_close = true;
}
-void ContextX11::cursor_pos(float *x, float *y)
+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(x11_d, window, &root_return, &child_return,
- &root_return_x, &root_return_y,
- &win_return_x, &win_return_y, &ret);
+ 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;
}
-void ContextX11::process_input()
+auto ContextX11::process_input() -> void
{
XEvent xev;
- while (XPending(x11_d) > 0)
+ while (XPending(this->x11_d) > 0)
{
- XNextEvent(x11_d, &xev);
+ XNextEvent(this->x11_d, &xev);
switch (xev.type)
{
case ClientMessage:
if ((u64)xev.xclient.data.l[0] == ATOM_WM_DELETE_WINDOW)
- _should_close = true;
+ {
+ this->should_close = true;
+ }
break;
- case MapNotify: // make window not clickable
+ case MapNotify:
//set_clickthrough();
- XFlush(x11_d);
+ XFlush(this->x11_d);
break;
}
}
}
+auto ContextX11::swap_buffers() -> void
+{
+ glXSwapBuffers(this->x11_d, this->window);
+}
+
ContextX11::~ContextX11()
{
- glXMakeCurrent(x11_d, None, NULL);
- glXDestroyContext(x11_d, glc);
- XDestroyWindow(x11_d, window);
- XCloseDisplay(x11_d);
+ 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
index 7e4a5a8..6bf898f 100644
--- a/src/context_x11.h
+++ b/src/context_x11.h
@@ -1,18 +1,15 @@
#ifndef _CONTEXT_X11_H
#define _CONTEXT_X11_H
-#include <chrono>
-
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xrender.h>
#include <X11/extensions/shape.h>
-#include <glad/gl.h>
-#include <GL/glx.h>
-
#include "context.h"
+#include <GL/glx.h>
+
#define XWIN_ALL_DESKTOPS 0xFFFFFFFF
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
@@ -24,51 +21,41 @@
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display *, GLXFBConfig, GLXContext, Bool, const s32 *);
-using std::chrono::time_point;
-using std::chrono::system_clock;
-
-namespace Mauri {
+namespace Mauri
+{
-class ContextX11 : public Context {
+class ContextX11 : public Context
+{
public:
- ContextX11(s32 width, s32 height, const std::string &name, bool wallpaper);
+ ContextX11() : Context() {}
~ContextX11();
- void close_window();
-
- void resize_window(s32 w, s32 h);
-
- bool should_close() const
+ 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;
+ return should_close;
}
+ auto close_window() -> void;
- void swap_buffers();
- void process_input();
+ auto process_input() -> void;
+ auto cursor_pos(f32 *x, f32 *y) -> void;
- void cursor_pos(f32 *x, f32 *y);
-
- f64 current_time()
- {
- return (system_clock::now() - start).count();
- }
+ auto swap_buffers() -> void;
private:
- bool _should_close = false;
-
- time_point<system_clock> start;
-
- void raise();
-
- // Make the window shape 0x0 so that its unclickable.
- void set_clickthrough();
-
- // Attempt to disable input by setting window hints.
- void disable_input();
-
+ 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;
- Display *x11_d;
-
GLXContext glc;
};
diff --git a/src/engine.cc b/src/engine.cc
index d6e597b..641ac15 100644
--- a/src/engine.cc
+++ b/src/engine.cc
@@ -8,192 +8,181 @@
using namespace Mauri;
-void View::center_scale_viewport()
+auto View::center_scale_viewport() -> void
{
- Render::set_viewport(camera_pos[0], camera_pos[1], width / scale, height / scale);
+ Render::set_viewport(this->camera_pos[0], this->camera_pos[1],
+ this->ortho_width / this->scale, this->ortho_height / this->scale);
}
-void View::center_viewport(f32 w1, f32 h1)
+auto View::center_viewport(f32 buffer_width, f32 buffer_height) -> void
{
- auto wpad = (width - w1) / 2.f;
- auto hpad = (height - h1) / 2.f;
-
- Render::set_viewport(wpad, hpad, w1, h1);
+ 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);
}
-void View::default_viewport(f32 w0, f32 h0)
+auto View::default_viewport(f32 buffer_width, f32 buffer_height) -> void
{
- Render::set_viewport(0, 0, w0, h0);
+ Render::set_viewport(0, 0, buffer_width, buffer_height);
}
-void View::center(f32 w1, f32 h1)
+auto View::center(f32 buffer_width, f32 buffer_height) -> void
{
- auto w_scale = width / w1;
- auto h_scale = height / h1;
+ f32 w_scale = this->width / buffer_width;
+ f32 h_scale = this->height / buffer_height;
- scale = (w_scale <= h_scale) ? w_scale : h_scale;
+ this->scale = (w_scale <= h_scale) ? w_scale : h_scale;
- auto scaled_width = width / scale;
- auto scaled_height = height / scale;
+ f32 scaled_width = this->width / this->scale;
+ f32 scaled_height = this->height / this->scale;
- camera_pos[0] = (scaled_width - w1) / -2.f;
- camera_pos[1] = (scaled_height - h1) / -2.f;
+ //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);
}
-Engine::Engine(Scene *scene, Parser *parser, bool audio)
- : scene(scene), parser(parser), audio_enabled(audio)
+Engine::Engine(Scene *scene, f32 rate, bool audio)
+ : scene(scene), rate(rate), audio_enabled(audio)
{
- view.width = scene->width;
- view.height = scene->height;
+ /*
+ 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";
- view.texel_size[0] = 1.f / view.width;
- view.texel_size[1] = 1.f / view.height;
+ this->view.width = scene->width;
+ this->view.height = scene->height;
+ this->view.ortho_width = scene->width;
+ this->view.ortho_height = scene->height;
- view.texel_half_size[0] = .5f / view.width;
- view.texel_half_size[1] = .5f / view.height;
+ this->view.texel_size[0] = 1.f / this->view.width;
+ this->view.texel_size[1] = 1.f / this->view.height;
- view.center(context()->width, context()->height);
+ 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);
#ifdef BUILD_AUDIO
- if (audio_enabled)
+ if (this->audio_enabled)
{
- visualizer = new Visualizer();
+ this->vis = new Visualizer();
+ if (!this->vis->run())
+ {
+ this->audio_enabled = false;
+ }
}
#else
- audio_enabled = false;
+ this->audio_enabled = false;
#endif
- //rate = 1.f;
- rate = 0.55f;
-
- minimal_shader = new Shader(parser, "minimal");
- minimal_shader->compile();
+ this->shader = get_shader("hdr_downsample");
+ this->render_shader = this->shader->compile({});
- create_framebuffer(COMBINE_BUFFER, view.width, view.height, 1.f);
- combine_buffer = get_framebuffer(COMBINE_BUFFER);
+ this->create_framebuffer(COMBINE_BUFFER, this->view.width, this->view.height, 1.f);
+ this->combine_buffer = this->get_framebuffer(COMBINE_BUFFER);
- default_object = new RenderObject(DEFAULT);
+ 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});
- default_model = mat4x4(1.f);
- default_model_flipped = glm::scale(default_model, vec3{1.f, -1.f, 1.f});
-
- scene->load(this);
+ this->default_object = new RenderObject(DEFAULT);
+ this->default_object_flipped = new RenderObject(DEFAULT_FLIPPED);
+ this->fullscreen_object = new RenderObject(FULLSCREEN);
}
-Framebuffer *Engine::get_framebuffer(const std::string &name)
+auto Engine::create_framebuffer(const std::string &name, f32 width, f32 height, f32 scale) -> void
{
- for (auto &buffer : framebuffers)
- {
- if (buffer->name == name)
- {
- return buffer;
- }
- }
-
- return nullptr;
+ this->framebuffers.emplace_back(new Framebuffer(name, width, height, scale));
}
-Texture *Engine::get_framebuffer_texture(const std::string &name)
+auto Engine::get_framebuffer(const std::string &name) -> Framebuffer *
{
- auto buffer = get_framebuffer(name);
-
- if (buffer != nullptr)
- return buffer->texture;
-
+ // Most likely wrong...
+ if (name == "_rt_MipMappedFrameBuffer")
+ {
+ return this->combine_buffer;
+ }
+ for (Framebuffer *buffer : this->framebuffers)
+ {
+ if (buffer->name == name) return buffer;
+ }
return nullptr;
}
-void Engine::create_framebuffer(const std::string &name, f32 width, f32 height, f32 scale)
+auto Engine::get_framebuffer_texture(const std::string &name) -> Texture *
{
- framebuffers.emplace_back(new Framebuffer(name, width, height, scale));
+ Framebuffer *buffer = this->get_framebuffer(name);
+ return ((buffer) ? buffer->texture : nullptr);
}
-void Engine::update()
+auto Engine::update() -> void
{
context()->process_input();
- context()->cursor_pos(&view.cursor_pos[0], &view.cursor_pos[1]);
-
- view.cursor_pos[0] *= view.scale;
- view.cursor_pos[1] *= view.scale;
+ context()->cursor_pos(&this->view.cursor_pos[0], &this->view.cursor_pos[1]);
- view.cursor_pos[0] -= view.camera_pos[0];
- view.cursor_pos[1] -= view.camera_pos[1];
+ this->view.cursor_pos[0] -= this->view.camera_pos[0];
+ this->view.cursor_pos[1] -= this->view.camera_pos[1];
- view.cursor_pos[0] /= view.width;
- view.cursor_pos[1] /= view.height;
+ this->view.cursor_pos[0] *= this->view.scale;
+ this->view.cursor_pos[1] *= this->view.scale;
- view.cursor_pos[0] = (view.cursor_pos[0] / 2.f) + 0.25f;
- view.cursor_pos[1] = ((1 - view.cursor_pos[1]) / 2.f) + 0.25f;
-
- for (auto &object: scene->objects)
- {
- object->update(this);
- }
+ this->view.cursor_pos[1] = this->view.height - this->view.cursor_pos[1];
}
-void Engine::draw()
+auto Engine::draw() -> void
{
- for (auto& buffer : framebuffers)
- {
- buffer->buffer->clear(vec4{0.f, 0.f, 0.f, 1.f});
- }
-
- if (scene->clear_enabled)
+ if (this->scene->clear_enabled)
{
- combine_buffer->buffer->clear(scene->clear_color);
+ this->combine_buffer->buffer->clear(this->scene->clear_color);
}
- scene->draw(this);
+ this->scene->draw(this);
Render::bind_framebuffer(0);
+ this->shader->bind(this->render_shader, this, nullptr, &this->default_mat, nullptr);
- default_object->bind();
-
- minimal_shader->bind(this, nullptr, &default_model_flipped, nullptr);
-
- combine_buffer->texture->bind(0);
-
- Render::blend_func(GL_ONE, GL_ZERO);
- Render::color_mask(1.f, 1.f, 1.f, 1.f);
+ this->combine_buffer->texture->bind(0);
- view.center_scale_viewport();
+ this->view.center_scale_viewport();
- default_object->draw();
+ this->default_object_flipped->bind();
+ this->default_object_flipped->draw();
}
-void Engine::run()
+auto Engine::run() -> void
{
- const f32 TARGET_FPS = 90.f;
-
- time = context()->current_time();
-
- while (!context()->should_close())
+ const f32 TARGET_FPS = 60.f;
+ while (!context()->should_close_window())
{
- update();
- draw();
+ this->time = context()->current_time();
+ this->update();
+ this->draw();
context()->swap_buffers();
-
- while (context()->current_time() < time + 1.f / TARGET_FPS)
+ while (context()->current_time() < this->time + 1.0f / TARGET_FPS)
{
- std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ std::this_thread::sleep_for(std::chrono::microseconds(500));
}
-
- time = context()->current_time();
}
}
Engine::~Engine()
{
- for (auto &buffer : framebuffers)
+ for (Framebuffer *buffer : this->framebuffers)
{
delete buffer;
}
- delete default_object;
- delete minimal_shader;
+ delete this->shader;
+ delete this->default_object;
+ delete this->fullscreen_object;
#ifdef BUILD_AUDIO
- delete visualizer;
+ delete this->vis;
#endif
}
diff --git a/src/engine.h b/src/engine.h
index 95b92ab..a1a063e 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -1,11 +1,11 @@
#ifndef _ENGINE_H
#define _ENGINE_H
-#include "framebuffer.h"
#include "shader.h"
+#include "framebuffer.h"
#ifdef BUILD_AUDIO
-#include "visualizer.h"
+#include "vis.h"
#endif
static const std::string COMBINE_BUFFER = "_rt_FullFrameBuffer";
@@ -13,13 +13,13 @@ static const std::string COMBINE_BUFFER = "_rt_FullFrameBuffer";
namespace Mauri
{
-class Scene;
-class Object;
-
struct View
{
- f32 width;
- f32 height;
+ f32 width = 0.f;
+ f32 height = 0.f;
+
+ s32 ortho_width;
+ s32 ortho_height;
vec2 texel_size;
vec2 texel_half_size;
@@ -29,49 +29,57 @@ struct View
vec2 camera_pos;
vec2 cursor_pos;
- void center(f32 w1, f32 h1);
+ f32 adjusted_width;
+ f32 adjusted_height;
- void center_scale_viewport();
- void center_viewport(f32 w0, f32 h0);
- void default_viewport(f32 w0, f32 h0);
+ auto center(f32 buffer_width, f32 buffer_height) -> void;
+
+ auto center_scale_viewport() -> void;
+ auto center_viewport(f32 buffer_width, f32 buffer_height) -> void;
+ auto default_viewport(f32 buffer_width, f32 buffer_height) -> void;
};
+class Scene;
+
class Engine
{
public:
- Engine(Scene *scene, Parser *parser, bool audio);
+ Engine(Scene *scene, f32 rate, bool audio);
~Engine();
- View view;
Scene *scene;
- Parser *parser;
+
+ f32 rate;
+ f32 time;
+
+ bool audio_enabled;
#ifdef BUILD_AUDIO
- Visualizer *visualizer;
+ Visualizer *vis;
#endif
- bool audio_enabled;
+ View view;
- f32 time;
- f32 rate;
+ mat4x4 default_mat;
+ mat4x4 default_mat_flipped;
RenderObject *default_object;
+ RenderObject *default_object_flipped;
+ RenderObject *fullscreen_object;
- mat4x4 default_model;
- mat4x4 default_model_flipped;
-
- Shader *minimal_shader;
+ Shader *shader;
+ RenderShader *render_shader;
Framebuffer *combine_buffer;
std::vector<Framebuffer *> framebuffers;
- void create_framebuffer(const std::string &name, f32 width, f32 height, f32 scale);
+ auto create_framebuffer(const std::string &name, f32 width, f32 height, f32 scale) -> void;
- Framebuffer *get_framebuffer(const std::string &name);
- Texture *get_framebuffer_texture(const std::string &name);
+ auto get_framebuffer(const std::string &name) -> Framebuffer *;
+ auto get_framebuffer_texture(const std::string &name) -> Texture *;
- void run();
- void draw();
- void update();
+ auto update() -> void;
+ auto draw() -> void;
+ auto run() -> void;
};
} // namespace Mauri
diff --git a/src/framebuffer.cc b/src/framebuffer.cc
index 6f65ab0..210a052 100644
--- a/src/framebuffer.cc
+++ b/src/framebuffer.cc
@@ -2,28 +2,15 @@
using namespace Mauri;
-Framebuffer::Framebuffer(std::string name, f32 width, f32 height, f32 scale)
+Framebuffer::Framebuffer(std::string name, s32 width, s32 height, f32 scale)
: name(name)
{
- buffer = new RenderFramebuffer(width, height, scale);
-
- texture = new Texture();
-
- texture->wrapped = true;
-
- texture->texture = buffer->texture;
-
- texture->texture_resolution[0] = buffer->width;
- texture->texture_resolution[1] = buffer->height;
- texture->texture_resolution[2] = buffer->width;
- texture->texture_resolution[3] = buffer->height;
+ this->buffer = new RenderFramebuffer(width, height, scale);
+ this->texture = new Texture(this->buffer);
}
Framebuffer::~Framebuffer()
{
- if (texture != nullptr)
- delete texture;
-
- if (buffer != nullptr)
- delete buffer;
+ if (this->buffer) delete this->buffer;
+ if (this->texture) delete this->texture;
}
diff --git a/src/framebuffer.h b/src/framebuffer.h
index 9b373fa..734715a 100644
--- a/src/framebuffer.h
+++ b/src/framebuffer.h
@@ -1,7 +1,6 @@
#ifndef _FRAMEBUFFER_H
#define _FRAMEBUFFER_H
-#include "gl.h"
#include "texture.h"
namespace Mauri
@@ -10,17 +9,15 @@ namespace Mauri
class Framebuffer
{
public:
- Framebuffer(std::string name, f32 width, f32 height, f32 scale);
-
+ Framebuffer(std::string name, s32 width, s32 height, f32 scale);
~Framebuffer();
std::string name;
- Texture *texture;
-
RenderFramebuffer *buffer;
+ Texture *texture;
};
-}
+} // namespace Mauri
#endif // _FRAMEBUFFER_H
diff --git a/src/gl.cc b/src/gl.cc
index c45d641..66690ba 100644
--- a/src/gl.cc
+++ b/src/gl.cc
@@ -1,267 +1,307 @@
#include "log.h"
-#include "texture.h"
#include "context.h"
+#include "texture.h"
#include "gl.h"
-using namespace Mauri;
+#include "objects/object.h"
-static u32 pack_rgba(byte r, byte g, byte b, byte a)
+namespace Mauri
{
- return (a << 24 | b << 16 | g << 8 | r);
-}
-static u32 pack_rg(byte r, byte g)
+auto uniform_type_to_string(UniformType type) -> std::string
{
- return (1 << 24 | 0 << 16 | g << 8 | r);
+ switch (type)
+ {
+ case TYPE_FLOAT:
+ return "float";
+ case TYPE_VEC4:
+ return "vec4";
+ case TYPE_VEC3:
+ return "vec3";
+ case TYPE_VEC2:
+ return "vec2";
+ case TYPE_MAT4:
+ return "mat4";
+ case TYPE_MAT3:
+ return "mat3";
+ case TYPE_SAMPLER2D:
+ return "sampler2D";
+ case TYPE_INVALID:
+ default:
+ return "INVALID";
+ }
}
-static u32 pack_red(byte r)
+auto uniform_type_from_string(const std::string_view &s) -> UniformType
{
- return (1 << 24 | 0 << 16 | 0 << 8 | r);
+ 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;
+ else if (s.compare(0, 4, "mat4") == 0) return TYPE_MAT4;
+ else if (s.compare(0, 4, "mat3") == 0) return TYPE_MAT3;
+ else if (s.compare(0, 9, "sampler2D") == 0) return TYPE_SAMPLER2D;
+ return TYPE_INVALID;
}
-void RenderObject::set_data(f32 *vertices, s32 vertex_count)
-{
- if (!context()->draw_enabled())
- return;
-
- glGenVertexArrays(1, &vao);
- glBindVertexArray(vao);
-
- glGenBuffers(1, &vbo);
- glBindBuffer(GL_ARRAY_BUFFER, vbo);
-
- glEnableVertexAttribArray(0);
- glEnableVertexAttribArray(1);
+} // namespace Mauri
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(f32), (void *)0);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(f32), (void *)12);
-
- glBufferData(GL_ARRAY_BUFFER, vertex_count, vertices, GL_STATIC_DRAW);
-}
+using namespace Mauri;
-void RenderObject::bind()
+RenderObject::RenderObject(ObjectType type, Object *object, Texture *texture)
{
- if (!context()->draw_enabled())
- return;
+ if (!context()->is_draw_enabled()) return;
- glBindVertexArray(vao);
- glBindBuffer(GL_ARRAY_BUFFER, vbo);
-}
+ f32 width = (object) ? object->size[0] : 0.f;
+ f32 height = (object) ? object->size[1] : 0.f;
-void RenderObject::draw()
-{
- if (!context()->draw_enabled())
- return;
+ f32 x_scale = 1.f;
+ f32 y_scale = 1.f;
- glDrawArrays(GL_TRIANGLES, 0, 6);
-}
-
-RenderObject::RenderObject(RenderObjType type, f32 width, f32 height)
-{
- if (!context()->draw_enabled())
- return;
+ if (texture && !texture->is_gif() && !(type == COMBINE && object->effects.size() != 0))
+ {
+ x_scale = (*texture->texture_resolution)[2] / (*texture->texture_resolution)[0];
+ y_scale = (*texture->texture_resolution)[3] / (*texture->texture_resolution)[1];
+ }
switch (type)
{
- case RenderObjType::DEFAULT: {
+ case DEFAULT:
+ {
f32 vertices[] = {
+ -1.f, -1.f, 0.f, 0.f, 0.f,
-1.f, 1.f, 0.f, 0.f, 1.f,
1.f, -1.f, 0.f, 1.f, 0.f,
- -1.f, -1.f, 0.f, 0.f, 0.f,
+ 1.f, -1.f, 0.f, 1.f, 0.f,
-1.f, 1.f, 0.f, 0.f, 1.f,
- 1.f, 1.f, 0.f, 1.f, 1.f,
- 1.f, -1.f, 0.f, 1.f, 0.f
+ 1.f, 1.f, 0.f, 1.f, 1.f
};
- set_data(vertices, sizeof(vertices));
+ this->set_data(vertices, sizeof(vertices));
+ this->vertex_count = 6;
break;
}
- case RenderObjType::UV_SCALE: {
- // Adjust UV coords here so that on the pass where this object is loadn
- // the UV cuts out the padding used to make the texture dimensions powers of two.
- f32 x_scale = width / (f32)next_power_of_two(width);
- f32 y_scale = height / (f32)next_power_of_two(height);
+ case DEFAULT_FLIPPED:
+ {
f32 vertices[] = {
- -width, height, 0.f, 0.f, y_scale,
- width, -height, 0.f, x_scale, 0.f,
- -width, -height, 0.f, 0.f, 0.f,
- -width, height, 0.f, 0.f, y_scale,
- width, height, 0.f, x_scale, y_scale,
- width, -height, 0.f, x_scale, 0.f
+ -1.f, 1.f, 0.f, 0.f, 0.f,
+ -1.f, -1.f, 0.f, 0.f, 1.f,
+ 1.f, 1.f, 0.f, 1.f, 0.f,
+ 1.f, 1.f, 0.f, 1.f, 0.f,
+ -1.f, -1.f, 0.f, 0.f, 1.f,
+ 1.f, -1.f, 0.f, 1.f, 1.f
};
- set_data(vertices, sizeof(vertices));
+ this->set_data(vertices, sizeof(vertices));
+ this->vertex_count = 6;
break;
}
- case RenderObjType::OBJECT: {
+ case FULLSCREEN:
+ {
f32 vertices[] = {
- -width, -height, 0.f, 0.f, 1.f,
- width, height, 0.f, 1.f, 0.f,
- -width, height, 0.f, 0.f, 0.f,
- -width, -height, 0.f, 0.f, 1.f,
- width, -height, 0.f, 1.f, 1.f,
- width, height, 0.f, 1.f, 0.f
+ -1.f, -1.f, 0.f, 0.f, 0.f,
+ -1.f, 3.f, 0.f, 0.f, 2.f,
+ 3.f, -1.f, 0.f, 2.f, 0.f
};
- set_data(vertices, sizeof(vertices));
+ this->set_data(vertices, sizeof(vertices));
+ this->vertex_count = 3;
break;
}
- case RenderObjType::OBJECT_FLIPPED: {
+ case MODEL:
+ {
f32 vertices[] = {
- -width, height, 0.f, 0.f, 1.f,
- width, -height, 0.f, 1.f, 0.f,
- -width, -height, 0.f, 0.f, 0.f,
- -width, height, 0.f, 0.f, 1.f,
- width, height, 0.f, 1.f, 1.f,
- width, -height, 0.f, 1.f, 0.f
+ 0.f, height, 0.f, 0.f, 0.f,
+ 0.f, 0.f, 0.f, 0.f, y_scale,
+ width, height, 0.f, x_scale, 0.f,
+ width, height, 0.f, x_scale, 0.f,
+ 0.f, 0.f, 0.f, 0.f, y_scale,
+ width, 0.f, 0.f, x_scale, y_scale
};
- set_data(vertices, sizeof(vertices));
+ this->set_data(vertices, sizeof(vertices));
+ this->vertex_count = 6;
+ break;
+ }
+ case COMBINE:
+ {
+ f32 half_width = width / 2.f;
+ f32 half_height = height / 2.f;
+ f32 vertices[] = {
+ -half_width, half_height, 0.f, 0.f, 0.f,
+ -half_width, -half_height, 0.f, 0.f, y_scale,
+ half_width, half_height, 0.f, x_scale, 0.f,
+ half_width, half_height, 0.f, x_scale, 0.f,
+ -half_width, -half_height, 0.f, 0.f, y_scale,
+ half_width, -half_height, 0.f, x_scale, y_scale
+ };
+ this->set_data(vertices, sizeof(vertices));
+ this->vertex_count = 6;
break;
}
}
}
-RenderObject::~RenderObject()
+auto RenderObject::set_data(f32 *vertices, s32 vertex_count) -> void
{
- if (!context()->draw_enabled())
- return;
+ if (!context()->is_draw_enabled()) return;
- glDeleteVertexArrays(1, &vao);
- glDeleteBuffers(1, &vbo);
-}
+ glGenVertexArrays(1, &this->vao);
+ glBindVertexArray(this->vao);
-bool RenderShader::compile(u32 program, const char *source, char *error)
-{
- if (!context()->draw_enabled())
- return true;
+ glGenBuffers(1, &this->vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, this->vbo);
- glShaderSource(program, 1, &source, 0);
- glCompileShader(program);
+ glEnableVertexAttribArray(0);
+ glEnableVertexAttribArray(1);
- s32 status;
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(f32), (void *)0);
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(f32), (void *)12);
- glGetShaderiv(program, GL_COMPILE_STATUS, &status);
+ glBufferData(GL_ARRAY_BUFFER, vertex_count, vertices, GL_STATIC_DRAW);
+}
- if (status == GL_FALSE)
- {
- glGetShaderInfoLog(program, 256, NULL, error);
- return false;
- }
+auto RenderObject::bind() -> void
+{
+ if (!context()->is_draw_enabled()) return;
+ glBindVertexArray(this->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, this->vbo);
+}
- return true;
+auto RenderObject::draw() -> void
+{
+ if (!context()->is_draw_enabled()) return;
+ glDrawArrays(GL_TRIANGLES, 0, this->vertex_count);
+}
+
+RenderObject::~RenderObject()
+{
+ if (!context()->is_draw_enabled()) return;
+ glDeleteVertexArrays(1, &this->vao);
+ glDeleteBuffers(1, &this->vbo);
}
RenderShader::RenderShader(const std::string &vs_source, const std::string &fs_source)
{
- if (!context()->draw_enabled())
- return;
+ if (!context()->is_draw_enabled()) return;
- uniform_locations.clear();
- program = glCreateProgram();
+ this->program = glCreateProgram();
char error[256];
u32 vs_shader = glCreateShader(GL_VERTEX_SHADER);
if (!compile(vs_shader, vs_source.c_str(), error))
{
- std::cout << vs_source << "\n";
- log_error("failed to compile vertex shader (%s)", error);
+ error("failed to compile vertex shader: (%s)", error);
+ debug("\n%s", vs_source.c_str());
return;
}
u32 fs_shader = glCreateShader(GL_FRAGMENT_SHADER);
if (!compile(fs_shader, fs_source.c_str(), error))
{
- log_error("failed to compile fragment shader (%s)", error);
+ error("failed to compile fragment shader: (%s)", error);
+ debug("\n%s", fs_source.c_str());
return;
}
- glAttachShader(program, vs_shader);
- glAttachShader(program, fs_shader);
+ glAttachShader(this->program, vs_shader);
+ glAttachShader(this->program, fs_shader);
- glLinkProgram(program);
+ glLinkProgram(this->program);
}
-void RenderShader::bind()
+auto RenderShader::compile(u32 shader, const char *source, char *error) -> bool
{
- if (!context()->draw_enabled())
- return;
+ if (!context()->is_draw_enabled()) return true;
- glUseProgram(program);
-}
+ glShaderSource(shader, 1, &source, 0);
+ glCompileShader(shader);
-RenderShader::~RenderShader()
-{
- if (!context()->draw_enabled())
- return;
+ s32 status;
+
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
- if (program != 0)
- glDeleteShader(program);
+ if (status == GL_FALSE)
+ {
+ glGetShaderInfoLog(shader, 256, NULL, error);
+ return false;
+ }
+
+ return true;
}
-s32 RenderShader::uniform_loc(const std::string &name)
+auto RenderShader::bind() -> void
{
- if (!context()->draw_enabled())
- return 0;
+ if (!context()->is_draw_enabled()) return;
+ glUseProgram(this->program);
+}
- auto loc = uniform_locations.find(name);
+auto RenderShader::get_uniform_location(const std::string &name) -> s32
+{
+ if (!context()->is_draw_enabled()) return 0;
- if (loc == uniform_locations.end())
+ auto loc = this->uniform_locations.find(name);
+ if (loc == this->uniform_locations.end())
{
- uniform_locations[name] = glGetUniformLocation(program, name.c_str());
- return uniform_locations[name];
+ this->uniform_locations[name] = glGetUniformLocation(this->program, name.c_str());
+ return this->uniform_locations[name];
}
else
+ {
return loc->second;
+ }
}
-void RenderShader::set_uniform(const std::string &name, UniformType type, f32 *value)
+auto RenderShader::set_uniform(const std::string &name, UniformType type, void *value) -> void
{
- if (!context()->draw_enabled())
- return;
+ if (!context()->is_draw_enabled()) return;
+
+ s32 loc = this->get_uniform_location(name);
+ if (loc == -1) return;
- auto loc = uniform_loc(name);
+#if UNIFORM_DEBUG
+ std::cout << name << "(" << type << ")" << " "
+ << ((f32 *)value)[0] << " " << ((f32 *)value)[1] << " "
+ << ((f32 *)value)[2] << " " << ((f32 *)value)[3] << "\n";
+#endif
switch (type)
{
case TYPE_FLOAT:
- glUniform1f(loc, *value);
+ glUniform1f(loc, *((f32 *)value));
break;
case TYPE_SAMPLER2D:
- glUniform1i(loc, (s32)*value);
+ glUniform1i(loc, (u32)(*((f32 *)value)));
break;
case TYPE_VEC2:
- glUniform2fv(loc, 1, value);
+ glUniform2fv(loc, 1, (f32 *)value);
break;
case TYPE_VEC3:
- glUniform3fv(loc, 1, value);
+ glUniform3fv(loc, 1, (f32 *)value);
break;
case TYPE_VEC4:
- glUniform4fv(loc, 1, value);
+ glUniform4fv(loc, 1, (f32 *)value);
break;
case TYPE_MAT4:
- glUniformMatrix4fv(loc, 1, GL_FALSE, value);
+ glUniformMatrix4fv(loc, 1, GL_FALSE, (f32 *)value);
+ break;
+ case TYPE_MAT3:
+ glUniformMatrix3fv(loc, 1, GL_FALSE, (f32 *)value);
break;
case TYPE_INVALID:
break;
}
}
-void RenderTexture::bind(s32 index)
+RenderShader::~RenderShader()
{
- if (!context()->draw_enabled())
- return;
-
- glActiveTexture(GL_TEXTURE0 + index);
- glBindTexture(GL_TEXTURE_2D, id);
+ if (!context()->is_draw_enabled()) return;
+ if (this->program != 0) glDeleteShader(this->program);
}
-RenderTexture::RenderTexture(bool no_interp, bool clamp_uv, bool filtering, s32 mm_count)
+RenderTexture::RenderTexture(bool no_interp, bool clamp, bool filtering, s32 mm_count)
{
- if (!context()->draw_enabled())
- return;
-
- glGenTextures(1, &id);
+ if (!context()->is_draw_enabled()) return;
- glBindTexture(GL_TEXTURE_2D, id);
+ glGenTextures(1, &this->id);
+ glBindTexture(GL_TEXTURE_2D, this->id);
if (filtering)
{
@@ -273,25 +313,25 @@ RenderTexture::RenderTexture(bool no_interp, bool clamp_uv, bool filtering, s32
if (no_interp)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- if (clamp_uv)
+ if (clamp)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
@@ -300,168 +340,171 @@ RenderTexture::RenderTexture(bool no_interp, bool clamp_uv, bool filtering, s32
glBindTexture(GL_TEXTURE_2D, 0);
}
-void RenderTexture::upload(byte *data, s32 width, s32 height, s32 level, bool dxt, bool scale)
+auto RenderTexture::upload(byte *data, s32 width, s32 height, s32 level, bool dxt) -> void
{
- // Save pixels in RGBA format as a simple utility.
- // NOTE: This is pretty wasteful on memory.
- if (data != nullptr && level == 0)
+ if (asset_manager()->prepare_output && data && level == 0)
{
- pixels.resize(width * height);
-
- switch (format)
- {
- case GL_RGBA: {
- byte *dp = data;
- for (auto i = 0; i < width * height; i++)
- {
- pixels[i] = pack_rgba(*dp, *(dp + 1), *(dp + 2), *(dp + 3));
- dp += 4;
- }
- break;
- }
- case GL_RG: {
- byte *dp = data;
- for (auto i = 0; i < width * height; i++)
- {
- pixels[i] = pack_rg(*dp, *(dp + 1));
- dp += 2;
- }
- break;
- }
- case GL_RED: {
- byte *dp = data;
- for (auto i = 0; i < width * height; i++)
- {
- pixels[i] = pack_red(*dp);
- dp += 1;
- }
- break;
- }
- }
+ this->save_pixels(data, width, height);
}
- if (!context()->draw_enabled())
- return;
+ if (!context()->is_draw_enabled()) return;
- bind(0);
+ this->bind(0);
- s32 iformat = GL_UNSIGNED_BYTE;
+ s32 iformat = (dxt) ? GL_UNSIGNED_INT_8_8_8_8 : GL_UNSIGNED_BYTE;
- if (dxt)
- {
- iformat = GL_UNSIGNED_INT_8_8_8_8;
- }
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, width, height, 0,
+ format, iformat, data);
+}
- if (scale)
- {
- s32 scaled_width = next_power_of_two(width);
- s32 scaled_height = next_power_of_two(height);
+auto RenderTexture::bind(s32 index) -> void
+{
+ if (!context()->is_draw_enabled()) return;
+ glActiveTexture(GL_TEXTURE0 + index);
+ glBindTexture(GL_TEXTURE_2D, this->id);
+}
- glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, scaled_width, scaled_height, 0,
- format, iformat, nullptr);
+static auto pack_rgba(byte r, byte g, byte b, byte a) -> u32
+{
+ return (a << 24 | b << 16 | g << 8 | r);
+}
+
+static auto pack_rgb(byte r, byte g, byte b) -> u32
+{
+ return (255 << 24 | b << 16 | g << 8 | r);
+}
+
+static auto pack_rg(byte r, byte g) -> u32
+{
+ return (255 << 24 | 0 << 16 | g << 8 | r);
+}
+
+static auto pack_red(byte r) -> u32
+{
+ return (255 << 24 | 0 << 16 | 0 << 8 | r);
+}
- glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, width, height,
- format, iformat, data);
+auto RenderTexture::save_pixels(byte *data, s32 width, s32 height) -> void
+{
+ this->pixels.resize(width * height);
+ byte *dp = data;
+ switch (format)
+ {
+ case GL_RGBA:
+ {
+ for (s32 i = 0; i < width * height; i++)
+ {
+ this->pixels[i] = pack_rgba(*dp, *(dp + 1), *(dp + 2), *(dp + 3));
+ dp += 4;
+ }
+ break;
}
- else
+ case GL_RGB:
{
- glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, width, height, 0,
- format, iformat, data);
+ for (s32 i = 0; i < width * height; i++)
+ {
+ this->pixels[i] = pack_rgb(*dp, *(dp + 1), *(dp + 2));
+ dp += 3;
+ }
+ break;
+ }
+ case GL_RG:
+ {
+ for (s32 i = 0; i < width * height; i++)
+ {
+ this->pixels[i] = pack_rg(*dp, *(dp + 1));
+ dp += 2;
+ }
+ break;
+ }
+ case GL_RED:
+ {
+ for (s32 i = 0; i < width * height; i++)
+ {
+ this->pixels[i] = pack_red(*dp);
+ dp += 1;
+ }
+ break;
+ }
+ default:
+ break;
}
}
RenderTexture::~RenderTexture()
{
- if (!context()->draw_enabled())
- return;
-
- glDeleteTextures(1, &id);
+ if (!context()->is_draw_enabled()) return;
+ glDeleteTextures(1, &this->id);
}
-RenderFramebuffer::RenderFramebuffer(f32 width0, f32 height0, f32 scale)
- : width(width0 / scale), height(height0 / scale)
+RenderFramebuffer::RenderFramebuffer(s32 width, s32 height, f32 scale)
+ : width(width / scale), height(height / scale)
{
- if (!context()->draw_enabled())
- return;
+ if (!context()->is_draw_enabled()) return;
- texture = new RenderTexture(false, true, false, 1);
+ this->texture = new RenderTexture(false, true, false, 1);
- texture->format = GL_RGBA;
- texture->upload(nullptr, width, height, 0, false, false);
+ this->texture->format = GL_RGBA;
+ this->texture->upload(nullptr, this->width, this->height, 0);
- glGenFramebuffers(1, &id);
- glBindFramebuffer(GL_FRAMEBUFFER, id);
+ glGenFramebuffers(1, &this->id);
+ glBindFramebuffer(GL_FRAMEBUFFER, this->id);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->id, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, this->texture->id, 0);
GLenum attatchment[] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, attatchment);
}
-void RenderFramebuffer::bind()
+auto RenderFramebuffer::bind() -> void
{
- if (!context()->draw_enabled())
- return;
-
- glBindFramebuffer(GL_FRAMEBUFFER, id);
+ if (!context()->is_draw_enabled()) return;
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, this->id);
}
-void RenderFramebuffer::blit(u32 dest, f32 w0, f32 h0)
+auto RenderFramebuffer::blit(u32 dest, s32 width, s32 height) -> void
{
- if (!context()->draw_enabled())
- return;
-
+ if (!context()->is_draw_enabled()) return;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dest);
- glBindFramebuffer(GL_READ_FRAMEBUFFER, id);
- glBlitFramebuffer(0, h0, w0, 0, 0, 0, w0, h0, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, this->id);
+ glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
-void RenderFramebuffer::clear(vec4 color)
+auto RenderFramebuffer::clear(vec4 color) -> void
{
- if (!context()->draw_enabled())
- return;
-
- glBindFramebuffer(GL_FRAMEBUFFER, id);
+ if (!context()->is_draw_enabled()) return;
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, this->id);
glClearBufferfv(GL_COLOR, 0, glm::value_ptr(color));
}
RenderFramebuffer::~RenderFramebuffer()
{
- if (!context()->draw_enabled())
- return;
-
+ if (!context()->is_draw_enabled()) return;
delete texture;
- glDeleteFramebuffers(1, &id);
+ glDeleteFramebuffers(1, &this->id);
}
-void Render::blend_func(s32 sfactor, s32 dfactor)
+auto Render::blend_func(s32 sfactor, s32 dfactor) -> void
{
- if (!context()->draw_enabled())
- return;
-
+ if (!context()->is_draw_enabled()) return;
glBlendFunc(sfactor, dfactor);
}
-void Render::color_mask(f32 r, f32 g, f32 b, f32 a)
+auto Render::color_mask(f32 r, f32 g, f32 b, f32 a) -> void
{
- if (!context()->draw_enabled())
- return;
-
+ if (!context()->is_draw_enabled()) return;
glColorMask(r, g, b, a);
}
-void Render::bind_framebuffer(s32 id)
+auto Render::bind_framebuffer(s32 id) -> void
{
- if (!context()->draw_enabled())
- return;
-
- glBindFramebuffer(GL_FRAMEBUFFER, id);
+ if (!context()->is_draw_enabled()) return;
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, id);
}
-void Render::set_viewport(u32 wpad, u32 hpad, u32 width, u32 height)
+auto Render::set_viewport(u32 wpad, u32 hpad, u32 width, u32 height) -> void
{
- if (!context()->draw_enabled())
- return;
-
+ if (!context()->is_draw_enabled()) return;
glViewport(wpad, hpad, width, height);
}
diff --git a/src/gl.h b/src/gl.h
index 3ee6ab6..9da72e7 100644
--- a/src/gl.h
+++ b/src/gl.h
@@ -8,38 +8,48 @@
namespace Mauri
{
-enum RenderObjType
+enum ObjectType
{
DEFAULT,
- UV_SCALE,
- OBJECT,
- OBJECT_FLIPPED
+ DEFAULT_FLIPPED,
+ FULLSCREEN,
+ MODEL,
+ COMBINE
};
enum UniformType
{
+ TYPE_INVALID,
TYPE_FLOAT,
TYPE_VEC4,
TYPE_VEC3,
TYPE_VEC2,
TYPE_MAT4,
- TYPE_SAMPLER2D,
- TYPE_INVALID
+ TYPE_MAT3,
+ TYPE_SAMPLER2D
};
+extern auto uniform_type_to_string(UniformType type) -> std::string;
+extern auto uniform_type_from_string(const std::string_view &s) -> UniformType;
+
+class Object;
+class Texture;
+
class RenderObject
{
public:
- RenderObject(RenderObjType type, f32 width = 0.f, f32 height = 0.f);
+ RenderObject(ObjectType type, Object *object = nullptr, Texture *texture = nullptr);
~RenderObject();
- void bind();
- void draw();
- void set_data(f32 *vertices, s32 vertex_count);
+ auto set_data(f32 *vertices, s32 vertex_count) -> void;
+
+ auto bind() -> void;
+ auto draw() -> void;
private:
u32 vao;
u32 vbo;
+ u32 vertex_count;
};
class RenderShader
@@ -48,43 +58,43 @@ class RenderShader
RenderShader(const std::string &vs_source, const std::string &fs_source);
~RenderShader();
- bool compile(u32 program, const char *source, char *error);
+ auto compile(u32 shader, const char *source, char *error) -> bool;
+ auto bind() -> void;
- void set_uniform(const std::string &name, UniformType type, f32 *value);
- s32 uniform_loc(const std::string &name);
-
- void bind();
+ auto get_uniform_location(const std::string &name) -> s32;
+ auto set_uniform(const std::string &name, UniformType type, void *value) -> void;
private:
u32 program = 0;
-
std::unordered_map<std::string, s32> uniform_locations;
};
class RenderTexture
{
public:
- RenderTexture(bool no_interp, bool clamp_uv, bool filtering, s32 mm_count);
+ RenderTexture(bool no_interp, bool clamp, bool filtering, s32 mm_count);
~RenderTexture();
u32 id = 0;
- f32 width;
- f32 height;
+ s32 width;
+ s32 height;
s32 format;
std::vector<u32> pixels;
- void bind(s32 index);
- void upload(byte *data, s32 width, s32 height, s32 level,
- bool dxt = false, bool scale = true);
+ auto upload(byte *data, s32 width, s32 height, s32 level, bool dxt = false) -> void;
+ auto bind(s32 index) -> void;
+
+ private:
+ auto save_pixels(byte *data, s32 width, s32 height) -> void;
};
class RenderFramebuffer
{
public:
- RenderFramebuffer(f32 width, f32 height, f32 scale);
+ RenderFramebuffer(s32 width, s32 height, f32 scale);
~RenderFramebuffer();
u32 id = 0;
@@ -94,18 +104,18 @@ class RenderFramebuffer
RenderTexture *texture = nullptr;
- void bind();
- void blit(u32 dest, f32 w0, f32 h0);
- void clear(vec4 color);
+ auto bind() -> void;
+ auto blit(u32 dest, s32 width, s32 height) -> void;
+ auto clear(vec4 color) -> void;
};
class Render
{
public:
- static void blend_func(s32 sfactor, s32 dfactor);
- static void color_mask(f32 r, f32 g, f32 b, f32 a);
- static void bind_framebuffer(s32 id);
- static void set_viewport(u32 wpad, u32 hpad, u32 width, u32 height);
+ 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;
};
} // namespace Mauri
diff --git a/src/json.h b/src/json.h
index fc55c02..34b5e72 100644
--- a/src/json.h
+++ b/src/json.h
@@ -9,130 +9,102 @@
namespace Mauri {
-enum JsonValueType
-{
- FLOAT,
- INT,
- VEC2,
- VEC3,
- VEC4,
- BOOL,
- STRING
-};
+enum JsonValueType { FLOAT, INT, VEC2, VEC3, VEC4, BOOL, STRING };
struct JsonValue
{
- JsonValueType type;
void *v;
+ JsonValueType type;
std::string name;
};
class Parser
{
public:
+ Parser() {}
+ ~Parser() {}
+
template<typename T>
- void get_value(json &root, const std::string &name, void *res, const T &_default)
+ static auto parse_value(const json &root, const std::string &name, void *out, const T &default_value) -> void
{
- json jvalue;
-
- if (name.empty())
- jvalue = root;
- else
- jvalue = root[name];
-
- std::string user;
-
- if (jvalue.is_object())
- {
- auto _user = jvalue["user"];
- if (_user.is_string())
- user = _user;
- jvalue = jvalue["value"];
- }
- else
- user = "root";
+ *((T *)out) = default_value;
- *((T *)res) = _default;
-
- JsonValueType type;
+ const json &value = (!name.empty() && root.contains(name)) ? root[name] : root;
if constexpr (std::is_same<T, u32>::value)
{
- if (jvalue.is_number())
- {
- *((u32 *)res) = jvalue.get<u32>();
- }
- type = INT;
+ if (value.is_number()) *((u32 *)out) = value.get<u32>();
}
else if constexpr (std::is_same<T, s32>::value)
{
- if (jvalue.is_number())
- {
- *((s32 *)res) = jvalue.get<s32>();
- }
- type = INT;
+ if (value.is_number()) *((s32 *)out) = value.get<s32>();
}
else if constexpr (std::is_same<T, f32>::value)
{
- if (jvalue.is_number())
- {
- *((f32 *)res) = jvalue.get<f32>();
- }
- type = FLOAT;
+ if (value.is_number()) *((f32 *)out) = value.get<f32>();
}
else if constexpr (std::is_same<T, std::string>::value)
{
- if (jvalue.is_string())
- {
- *((std::string *)res) = jvalue.get<std::string>();
- }
- type = STRING;
+ if (value.is_string()) *((std::string *)out) = value.get<std::string>();
}
else if constexpr (std::is_same<T, vec2>::value)
{
- if (jvalue.is_string())
- {
- str_vec2(jvalue.get<std::string>().c_str(), *((vec2 *)res));
- }
- type = VEC2;
+ if (value.is_string()) str_vec2(value.get<std::string>().c_str(), *((vec2 *)out));
}
else if constexpr (std::is_same<T, vec3>::value)
{
- if (jvalue.is_string())
- {
- str_vec3(jvalue.get<std::string>().c_str(), *((vec3 *)res));
- }
- type = VEC3;
+ if (value.is_string()) str_vec3(value.get<std::string>().c_str(), *((vec3 *)out));
}
else if constexpr (std::is_same<T, vec4>::value)
{
- // Special case for because VEC4 is used for all
- // uniform values and some are written as a single number, not a string.
- if (jvalue.is_number())
- {
- (*((vec4 *)res))[0] = jvalue.get<f32>();
- }
- else if (jvalue.is_string())
- {
- str_vec4(jvalue.get<std::string>().c_str(), *((vec4 *)res));
- }
- type = VEC4;
+ // Some uniforms are saved as a single number.
+ if (value.is_number()) (*((vec4 *)out))[0] = value.get<f32>();
+ else if (value.is_string()) str_vec4(value.get<std::string>().c_str(), *((vec4 *)out));
}
else if constexpr (std::is_same<T, bool>::value)
{
- if (jvalue.is_boolean())
+ if (value.is_boolean()) *((bool *)out) = value.get<bool>();
+ }
+ }
+
+ template<typename T>
+ auto map_value(const json &root, const std::string &name, void *out, const T &default_value) -> void
+ {
+ const json &value = (!name.empty() && root.contains(name)) ? root[name] : root;
+
+ std::string user = "root";
+
+ if (value.is_object())
+ {
+ if (value.contains("user"))
{
- *((bool *)res) = jvalue.get<bool>();
+ const json &user_value = value["user"];
+ if (user_value.is_string()) user = user_value;
}
- type = BOOL;
+ this->parse_value<T>(value, "value", out, default_value);
}
+ else
+ {
+ this->parse_value<T>(root, name, out, default_value);
+ }
+
+ JsonValueType type;
- values[user].push_back(JsonValue { type, res, name });
+ if constexpr (std::is_same<T, u32>::value) type = INT;
+ else if constexpr (std::is_same<T, s32>::value) type = INT;
+ else if constexpr (std::is_same<T, f32>::value) type = FLOAT;
+ else if constexpr (std::is_same<T, std::string>::value) type = STRING;
+ else if constexpr (std::is_same<T, vec2>::value) type = VEC2;
+ else if constexpr (std::is_same<T, vec3>::value) type = VEC3;
+ else if constexpr (std::is_same<T, vec4>::value) type = VEC4;
+ else if constexpr (std::is_same<T, bool>::value) type = BOOL;
+
+ this->values[user].emplace_back(JsonValue{out, type, name});
}
std::unordered_map<std::string, std::vector<JsonValue>> values;
};
-
+
} // namespace Mauri
#endif // _JSON_H
diff --git a/src/log.h b/src/log.h
index 8c97bc5..34f6cd1 100644
--- a/src/log.h
+++ b/src/log.h
@@ -4,25 +4,25 @@
#include <stdio.h>
#include <string.h>
-#define PRINT(x, ...) printf(x, ##__VA_ARGS__)
+#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__); \
+#define log_print(t, fmt, ...) \
+ do \
+ { \
+ _PRINT("%s:%d %s(): ", __FILENAME__, __LINE__, __FUNCTION__); \
+ _PRINT("%s -> " fmt "\n", t, ##__VA_ARGS__); \
} while (0)
-#define log_info(fmt, ...) log_print("info", fmt, ##__VA_ARGS__)
-#define log_warn(fmt, ...) log_print("warn", fmt, ##__VA_ARGS__)
-#define log_error(fmt, ...) log_print("error", fmt, ##__VA_ARGS__)
+#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 log_debug(fmt, ...) log_print("debug", fmt, ##__VA_ARGS__)
+#define debug(fmt, ...) log_print("debug", fmt, ##__VA_ARGS__)
#else
-#define log_debug(fmt, ...)
+#define debug(fmt, ...)
#endif
#endif // _LOG_H
diff --git a/src/mauri.cc b/src/mauri.cc
index 330daa9..fb0cc4b 100644
--- a/src/mauri.cc
+++ b/src/mauri.cc
@@ -1,3 +1,5 @@
+#include <args.h>
+
#include "assets.h"
#include "engine.h"
@@ -16,44 +18,99 @@
using namespace Mauri;
-static const std::string scene_path = "scene.json";
-
-s32 main(s32 argc, char *argv[])
+auto main(s32 argc, char *argv[]) -> s32
{
- if (argc != 2)
+ args::ArgParser args("Usage: ...", "0.12");
+
+ args.option("path p", "");
+ args.option("width w", "");
+ args.option("height h", "");
+ args.option("background b", "");
+ args.option("output o", "");
+ args.parse(argc, argv);
+
+ if (!args.found("path"))
{
- printf("Usage: %s <path_to_scene.pkg>\n", argv[0]);
+ std::cout << args.helptext << "\n";
return EXIT_FAILURE;
}
- if (!asset_manager()->load_package(std::string(argv[1])))
+ s32 width = -1;
+ s32 height = -1;
+
+ if (args.found("width")) width = args.value<s32>("width");
+ if (args.found("height")) height = args.value<s32>("height");
+
+ if (width == 0 || height == 0)
{
+ error("invalid width and/or height in arguments");
return EXIT_FAILURE;
}
+ bool background = false;
+
+ if (args.found("background"))
+ {
+ std::string opt = args.value<std::string>("background");
+ str_to_lower(opt);
+ background = opt == "true";
+ }
+
#ifdef BUILD_AUDIO
gst_init(&argc, &argv);
#endif
- set_context(new ContextGLFW(1920, 1080, "mauri", false));
- //set_context(new ContextX11(1920, 1080, "mauri", false));
- //set_context(new ContextNull(1920, 1080, "mauri", false));
+ //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))
+ {
+ return EXIT_FAILURE;
+ }
+
+ if (!asset_manager()->arm_package(args.value("path"), args.found("output")))
+ {
+ return EXIT_FAILURE;
+ }
+
+ set_context(new_context);
+
+ Scene *scene = new Scene("scene.json");
- Parser parser;
- Scene *scene = new Scene(parser, scene_path);
- //context()->resize_window(scene->width, scene->height);
- Engine *engine = new Engine(scene, &parser, true);
+ if (width <= 0) width = scene->width;
+ if (height <= 0) height = scene->height;
- //asset_manager()->write_files("./output");
+ context()->resize_window(width, height);
- engine->run();
+ Engine *engine = new Engine(scene, 1.f, true);
+
+ std::chrono::time_point<std::chrono::system_clock> begin = std::chrono::system_clock::now();
+
+ scene->load(engine);
+
+ using us = std::chrono::microseconds;
+ u64 duration = std::chrono::duration_cast<us>(std::chrono::system_clock::now() - begin).count();
+ info("scene loaded in %fs", duration / 1000000.f);
+
+ if (asset_manager()->prepare_output)
+ {
+ asset_manager()->write_files(args.value("output"));
+ }
+ else
+ {
+ engine->run();
+ }
delete scene;
delete engine;
asset_manager()->unload_package();
+ context()->close_window();
set_context(nullptr);
+#ifdef BUILD_AUDIO
+ //gst_deinit();
+#endif
+
return EXIT_SUCCESS;
}
diff --git a/src/objects/effect.cc b/src/objects/effect.cc
index 72d9e7e..5542ccc 100644
--- a/src/objects/effect.cc
+++ b/src/objects/effect.cc
@@ -3,86 +3,93 @@
using namespace Mauri;
-Effect::Effect(Parser &p, json &root)
+Effect::Effect(Parser &pr, const json &root)
{
- auto asset = asset_manager()->get_file(root["file"], NONE);
+ Asset *asset = asset_manager()->get_file(root["file"]);
+ if (asset->type == ASSET_VOID) return;
- if (asset->type == ASSET_VOID)
- return;
+ const json &file = json::parse(asset->as_string());
+ if (file.is_discarded()) return;
- auto file = json::parse(asset->as_string());
+ pr.map_value<u32>(root, "id", &this->id, 0);
+ pr.map_value<bool>(root, "visible", &this->visible, true);
+ pr.map_value<std::string>(file, "name", &this->name, "");
- p.get_value<u32>(root, "id", &id, 0);
- p.get_value<bool>(root, "visible", &visible, true);
- p.get_value<std::string>(file, "name", &name, "");
-
- for (auto &pass0 : root["passes"])
+ if (root.contains("passes"))
{
- passes0.emplace_back(new Pass(p, pass0, EFFECT0_PASS));
+ for (const json &pass0 : root["passes"])
+ {
+ this->passes0.emplace_back(new Pass(pr, pass0, EFFECT0_PASS));
+ }
}
- for (auto &pass1 : file["passes"])
+ if (file.contains("passes"))
{
- passes1.emplace_back(new Pass(p, pass1, EFFECT1_PASS));
+ for (const json &pass1 : file["passes"])
+ {
+ this->passes1.emplace_back(new Pass(pr, pass1, EFFECT1_PASS));
+ }
}
- for (auto &fbo : file["fbos"])
+ if (file.contains("fbos"))
{
- fbos.emplace_back(EffectBuffer { fbo["name"], fbo["scale"] });
+ for (const json &fbo : file["fbos"])
+ {
+ this->fbos.emplace_back(EffectBuffer{fbo["name"], fbo.contains("scale") ? (f32)fbo["scale"] : 1.f });
+ }
}
}
-void Effect::load(Engine *engine, Object *object, bool last)
+auto Effect::load(Engine *engine, Object *object, bool last) -> void
{
- std::stringstream _buffer_id;
- _buffer_id << "_" << object->id << "_" << id;
-
- buffer_id = _buffer_id.str();
+ this->buffer_id = str_format("_%i_%i", object->id, this->id);
- for (auto &fbo : fbos)
+ for (const EffectBuffer &fbo : this->fbos)
{
- engine->create_framebuffer(fbo.name + buffer_id, object->size[0], object->size[1], fbo.scale);
+ engine->create_framebuffer(fbo.name + this->buffer_id, object->size[0], object->size[1], fbo.scale);
}
u32 index = 0;
-
- for (auto i = 0u; i < passes1.size(); i++)
+
+ for (u32 i = 0; i < this->passes1.size(); i++)
{
Pass pass;
- pass.intermidiate = false;
+ pass.intermediate = false;
- pass.object = object;
pass.effect = this;
+ pass.object = object;
- pass.combine = object->visible && i == (passes1.size() - 1) && last;
+ pass.model = false;
+ pass.combine = object->visible && object->color_blend_mode == 0 &&
+ i == (this->passes1.size() - 1) && last;
+ //pass.combine = object->visible &&
+ // i == (this->passes1.size() - 1) && last;
- if (passes1[i]->command != COPY)
+ if (this->passes1[i]->command != COPY)
{
- passes0[index]->load(engine, EFFECT0_PASS, &pass);
+ this->passes0[index]->load(engine, EFFECT0_PASS, &pass);
index++;
}
- passes1[i]->load(engine, EFFECT1_PASS, &pass);
+ this->passes1[i]->load(engine, EFFECT1_PASS, &pass);
this->passes.push_back(new RenderPass(engine, &pass));
}
}
-void Effect::draw(Engine *engine)
+auto Effect::draw(Engine *engine) -> void
{
- if (!visible)
- return;
+ if (!this->visible) return;
#if FRAME_STEP
- std::cout << name << ":\n";
+ std::cout << this->name << ":\n";
#endif
-
- for (auto &pass : passes)
+
+ for (RenderPass *pass : this->passes)
{
#if FRAME_STEP
- if (pass->shader != nullptr)
- std::cout << "\t" << pass->shader->name << "\n";
+ if (pass->shader) std::cout << "\t" << pass->shader->origin()->name << "\n";
#endif
pass->draw(engine);
}
@@ -90,17 +97,17 @@ void Effect::draw(Engine *engine)
Effect::~Effect()
{
- for (auto &pass0 : passes0)
+ for (Pass *pass0 : this->passes0)
{
delete pass0;
}
- for (auto &pass1 : passes1)
+ for (Pass *pass1 : this->passes1)
{
delete pass1;
}
- for (auto &pass : passes)
+ for (RenderPass *pass : this->passes)
{
delete pass;
}
diff --git a/src/objects/effect.h b/src/objects/effect.h
index 558396b..cb53a04 100644
--- a/src/objects/effect.h
+++ b/src/objects/effect.h
@@ -1,7 +1,6 @@
#ifndef _EFFECT_H
#define _EFFECT_H
-#include "../util.h"
#include "../json.h"
#include "../engine.h"
#include "../texture.h"
@@ -9,19 +8,19 @@
namespace Mauri
{
-class Pass;
-class RenderPass;
-
struct EffectBuffer
{
std::string name;
f32 scale;
};
+class Pass;
+class RenderPass;
+
class Effect
{
public:
- Effect(Parser &p, json &root);
+ Effect(Parser &pr, const json &root);
~Effect();
u32 id;
@@ -33,13 +32,12 @@ class Effect
std::vector<RenderPass *> passes;
- void load(Engine *engine, Object *object, bool last);
- void draw(Engine *engine);
+ auto load(Engine *engine, Object *object, bool last) -> void;
+ auto draw(Engine *engine) -> void;
private:
std::vector<Pass *> passes0;
std::vector<Pass *> passes1;
-
std::vector<EffectBuffer> fbos;
};
diff --git a/src/objects/material.cc b/src/objects/material.cc
index 0957214..b17a102 100644
--- a/src/objects/material.cc
+++ b/src/objects/material.cc
@@ -3,59 +3,64 @@
using namespace Mauri;
-Material::Material(Parser &p, const std::string &path)
+Material::Material(Parser &pr, const std::string &path)
{
- auto asset = asset_manager()->get_file(path, NONE);
+ Asset *asset = asset_manager()->get_file(path);
+ if (asset->type == ASSET_VOID) return;
- if (asset->type == ASSET_VOID)
- {
- log_error("failed to load material.json (%s)", path.c_str());
- return;
- }
-
- auto root = json::parse(asset->as_string());
+ const json &root = json::parse(asset->as_string());
+ if (root.is_discarded()) return;
- for (auto &pass : root["passes"])
+ if (root.contains("passes"))
{
- passes0.push_back(new Pass(p, pass, MATERIAL_PASS));
+ for (const json &pass : root["passes"])
+ {
+ this->passes0.push_back(new Pass(pr, pass, MATERIAL_PASS));
+ }
}
}
-void Material::load(Engine *engine, Object *object, MaterialType type, Pass *pass)
+auto Material::load(Engine *engine, Object *object, MaterialType type, Pass *pass) -> void
{
- for (auto &pass0 : passes0)
+ for (Pass *pass0 : this->passes0)
{
switch (type)
{
case MATERIAL_EFFECT:
+ {
pass0->load(engine, MATERIAL_PASS, pass);
break;
+ }
case MATERIAL_MODEL:
- Pass _pass;
+ {
+ Pass model_pass;
+
+ model_pass.intermediate = false;
- _pass.intermidiate = false;
+ model_pass.object = object;
+ model_pass.effect = nullptr;
- _pass.object = object;
- _pass.effect = nullptr;
+ model_pass.model = true;
+ model_pass.combine = object->visible && object->effects.size() == 0 && !object->passthrough;
- if (object->effects.size() == 0
- && !object->passthrough && object->visible)
- _pass.combine = true;
- else
- _pass.combine = false;
-
- pass0->load(engine, MATERIAL_ONLY_PASS, &_pass);
+ if (model_pass.combine)
+ {
+ model_pass.combos.push_back(Combo("BLENDMODE", object->color_blend_mode));
+ }
- object->passes.push_back(new RenderPass(engine, &_pass));
+ pass0->load(engine, MATERIAL_ONLY_PASS, &model_pass);
+
+ object->passes.push_back(new RenderPass(engine, &model_pass));
break;
}
+ }
}
}
Material::~Material()
{
- for (auto &pass0 : passes0)
+ for (Pass *pass0 : this->passes0)
{
delete pass0;
}
diff --git a/src/objects/material.h b/src/objects/material.h
index 5bc7c3a..cfea216 100644
--- a/src/objects/material.h
+++ b/src/objects/material.h
@@ -7,23 +7,19 @@
namespace Mauri
{
-class Pass;
+enum MaterialType { MATERIAL_MODEL, MATERIAL_EFFECT };
-enum MaterialType
-{
- MATERIAL_MODEL,
- MATERIAL_EFFECT
-};
+class Pass;
class Material
{
public:
- Material(Parser &p, const std::string &path);
+ Material(Parser &pr, const std::string &path);
~Material();
std::vector<Pass *> passes0;
- void load(Engine *engine, Object *object, MaterialType type, Pass *pass);
+ auto load(Engine *engine, Object *object, MaterialType type, Pass *pass) -> void;
};
} // namespace Mauri
diff --git a/src/objects/model.cc b/src/objects/model.cc
index 1517b23..b916ec7 100644
--- a/src/objects/model.cc
+++ b/src/objects/model.cc
@@ -2,38 +2,30 @@
using namespace Mauri;
-Model::Model(Parser &p, const std::string &path)
+Model::Model(Parser &pr, const std::string &path)
{
- auto asset = asset_manager()->get_file(path, NONE);
+ Asset *asset = asset_manager()->get_file(path);
+ if (asset->type == ASSET_VOID) return;
- if (asset->type == ASSET_VOID)
- {
- log_error("failed to load model.json (%s)", path.c_str());
- return;
- }
+ const json &root = json::parse(asset->as_string());
+ if (root.is_discarded()) return;
- auto root = json::parse(asset->as_string());
+ pr.map_value<bool>(root, "autosize", &this->autosize, false);
+ pr.map_value<bool>(root, "fullscreen", &this->fullscreen, false);
+ pr.map_value<bool>(root, "passthrough", &this->passthrough, false);
- p.get_value<bool>(root, "autosize", &autosize, false);
- p.get_value<bool>(root, "fullscreen", &fullscreen, false);
- p.get_value<bool>(root, "passthrough", &passthrough, false);
+ pr.map_value<f32>(root, "width", &this->width, 0.f);
+ pr.map_value<f32>(root, "height", &this->height, 0.f);
- p.get_value<f32>(root, "width", &width, 0.f);
- p.get_value<f32>(root, "height", &height, 0.f);
-
- auto _material = root["material"];
-
- if (_material.is_string())
- material = new Material(p, _material);
+ if (root.contains("material")) this->material = new Material(pr, root["material"]);
}
-void Model::load(Engine *engine, Object *object)
+auto Model::load(Engine *engine, Object *object) -> void
{
- material->load(engine, object, MATERIAL_MODEL, NULL);
+ this->material->load(engine, object, MATERIAL_MODEL, NULL);
}
Model::~Model()
{
- if (material != nullptr)
- delete material;
+ if (this->material) delete this->material;
}
diff --git a/src/objects/model.h b/src/objects/model.h
index 0d5b313..f6b532a 100644
--- a/src/objects/model.h
+++ b/src/objects/model.h
@@ -9,7 +9,7 @@ namespace Mauri
class Model
{
public:
- Model(Parser &p, const std::string &path);
+ Model(Parser &pr, const std::string &path);
~Model();
bool autosize = true;
@@ -19,7 +19,7 @@ class Model
f32 width;
f32 height;
- void load(Engine *engine, Object *object);
+ auto load(Engine *engine, Object *object) -> void;
private:
Material *material = nullptr;
diff --git a/src/objects/object.cc b/src/objects/object.cc
index 73a16b3..ac64a25 100644
--- a/src/objects/object.cc
+++ b/src/objects/object.cc
@@ -1,32 +1,33 @@
+#include "../context.h"
+
#include "pass.h"
#include "scene.h"
#include "object.h"
using namespace Mauri;
-Object::Object(Parser &p, json &root)
+Object::Object(Parser &pr, const json &root)
{
- p.get_value<u32>(root, "id", &id, 0);
- p.get_value<std::string>(root, "name", &name, "");
+ pr.map_value<u32>(root, "id", &this->id, 0);
+ pr.map_value<std::string>(root, "name", &this->name, "");
- for (auto &id : root["dependencies"])
- deps.push_back(id);
+ if (root.contains("dependencies"))
+ {
+ for (const json &id : root["dependencies"])
+ {
+ this->deps.push_back(id);
+ }
+ }
// Filter deps that are either have the same id as this
// 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.
- std::vector<s32>::const_iterator it = deps.begin();
- while (it != deps.end())
+ auto it = this->deps.begin();
+ while (it != this->deps.end())
{
- bool remove = false;
-
- if ((u32)(*it) == id)
- {
- remove = true;
- }
-
- for (auto rt = deps.begin(); rt != deps.end(); ++rt)
+ bool remove = ((u32)(*it) == id);
+ for (auto rt = this->deps.begin(); rt != this->deps.end(); ++rt)
{
if (rt != it && *rt == *it)
{
@@ -34,217 +35,228 @@ Object::Object(Parser &p, json &root)
break;
}
}
-
- if (remove) deps.erase(it);
- else ++it;
+ if (remove) this->deps.erase(it);
+ else it++;
}
- p.get_value<vec3>(root, "angles", &angles, vec3(0.f));
- p.get_value<vec3>(root, "color", &color, vec3(0.f));
- p.get_value<vec2>(root, "size", &size, vec2(0.f));
- p.get_value<vec3>(root, "scale", &scale, vec3(0.f));
- p.get_value<vec3>(root, "origin", &origin, vec3(0.f));
- //origin[2] = 0.f;
-
- p.get_value<s32>(root, "colorBlendMode", &color_blend_mode, 0);
- p.get_value<f32>(root, "alpha", &alpha, 1.f);
- p.get_value<bool>(root, "visible", &visible, true);
-
- auto _image = root["image"];
+ pr.map_value<bool>(root, "visible", &this->visible, true);
+ pr.map_value<vec3>(root, "angles", &this->angles, vec3(0.f));
+ pr.map_value<vec2>(root, "size", &this->size, vec2(0.f));
+ pr.map_value<vec3>(root, "scale", &this->scale, vec3(0.f));
+ pr.map_value<vec3>(root, "origin", &this->origin, vec3(0.f));
+ if (this->origin[2] != 0.f)
+ {
+ warn("non 0 origin[2]");
+ this->origin[2] = 0.f;
+ }
+ pr.map_value<vec3>(root, "color", &this->color, vec3(0.f));
+ pr.map_value<f32>(root, "alpha", &this->alpha, 1.f);
+ pr.map_value<s32>(root, "colorBlendMode", &this->color_blend_mode, 0);
- if (_image.is_string())
- image = new Model(p, _image);
+ this->color4 = vec4{this->color[0], this->color[1], this->color[2], this->alpha};
- auto config = root["config"];
+ if (root.contains("image"))
+ {
+ const json &image = root["image"];
+ if (image.is_string()) this->model = new Model(pr, image);
+ }
- if (!config.is_null())
- p.get_value<bool>(config, "passthrough", &passthrough, false);
+ if (root.contains("config"))
+ {
+ pr.map_value<bool>(root["config"], "passthrough", &this->passthrough, false);
+ }
- for (auto &effect : root["effects"])
+ if (root.contains("effects"))
{
- effects.emplace_back(new Effect(p, effect));
+ for (const json &effect : root["effects"])
+ {
+ this->effects.emplace_back(new Effect(pr, effect));
+ }
}
}
-void Object::get_model(Engine *engine, f32 width, f32 height, bool flip)
+auto Object::load(Engine *engine) -> void
{
- model = mat4x4(1.f);
-
- model = glm::translate(model, vec3{-width, -height, -origin[2]});
- model = glm::translate(model, origin * 2.f);
-
- model = glm::rotate(model, angles[0], vec3{1.f, 0.f, 0.f});
- model = glm::rotate(model, angles[1], vec3{0.f, 1.f, 0.f});
- model = glm::rotate(model, angles[2], vec3{0.f, 0.f, 1.f});
+ if (this->loaded_as_dep || this->loaded) return;
- model = glm::scale(model, scale);
-
- mat4x4 _ortho = glm::ortho(-width, width, height, -height, 0.f, 1.f);
+ for (u32 dep : this->deps)
+ {
+ if (dep == this->id) continue;
+ Object *object = engine->scene->get_object_by_id(dep);
+ if (object)
+ {
+ object->load(engine);
+ object->loaded_as_dep = true;
+ }
+ }
- if (flip)
+ if (this->model)
{
- model = glm::scale(model, vec3{1.f, -1.f, 1.f});
+ if (this->model->fullscreen) this->fullscreen = true;
+ if (this->model->passthrough) this->passthrough = true;
}
- model = _ortho * model;
-}
+ if (this->size[0] == 0.f) this->size[0] = this->model->width;
+ if (this->size[1] == 0.f) this->size[1] = this->model->height;
-void Object::load(Engine *engine)
-{
- if (loaded_as_dep || loaded)
- return;
-
- for (auto &dep : deps)
+ if (this->fullscreen)
{
- auto object = engine->scene->get_object_by_id(dep);
- object->load(engine);
- object->loaded_as_dep = true;
+ this->size[0] = engine->scene->width;
+ this->size[1] = engine->scene->height;
}
-
- if (image != nullptr)
+ else if (this->passthrough)
{
- if (image->passthrough)
- {
- passthrough = true;
- }
+ if (this->size[0] == 0.f) this->size[0] = engine->scene->width;
+ if (this->size[1] == 0.f) this->size[1] = engine->scene->height;
+ }
- if (image->fullscreen)
- {
- fullscreen = true;
- }
+ this->buffer_a = str_format("_rt_imageLayerComposite_%i_a", this->id);
+ this->buffer_b = str_format("_rt_imageLayerComposite_%i_b", this->id);
+ 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);
- if (image->width != 0.f && image->height != 0.f)
+ if (this->effects.size() > 0)
+ {
+ for (auto it = this->effects.begin(); it != this->effects.end();)
{
- size[0] = image->width;
- size[1] = image->height;
+ if (!(*it)->visible) it = this->effects.erase(it);
+ else it++;
}
}
- if (size[0] == 0 && size[1] == 0)
+ if (this->model) this->model->load(engine, this);
+
+ for (u32 i = 0; i < this->effects.size(); i++)
{
- size[0] = engine->view.width;
- size[1] = engine->view.height;
- origin[0] = size[0] / 2.f;
- origin[1] = size[1] / 2.f;
+ this->effects[i]->load(engine, this, i == (this->effects.size() - 1));
}
- std::stringstream _buffer_a, _buffer_b;
+ if (this->effects.size() != 0 && this->color_blend_mode != 0)
+ {
+ Pass blend_pass;
- _buffer_a << "_rt_imageLayerComposite_" << id << "_a";
- _buffer_b << "_rt_imageLayerComposite_" << id << "_b";
+ blend_pass.intermediate = false;
- buffer_a = _buffer_a.str();
- buffer_b = _buffer_b.str();
+ blend_pass.object = this;
+ blend_pass.effect = nullptr;
- engine->create_framebuffer(buffer_a, size[0], size[1], 1.f);
- engine->create_framebuffer(buffer_b, size[0], size[1], 1.f);
+ blend_pass.model = false;
+ blend_pass.combine = true;
- get_model(engine, engine->view.width, engine->view.height, effects.size() == 0);
+ blend_pass.target = "previous";
+ blend_pass.textures[0] = "previous";
+ blend_pass.textures[1] = COMBINE_BUFFER;
+ blend_pass.shader = "passthroughblend";
- ortho = glm::ortho(-size[0], size[0], -size[1], size[1], 0.f, 1.f);
+ blend_pass.combos.push_back(Combo("BLENDMODE", this->color_blend_mode));
+ blend_pass.combos.push_back(Combo("TRANSFORM", 1));
- gl_uv_object = new RenderObject(UV_SCALE, size[0], size[1]);
+ RenderPass *pass = new RenderPass(engine, &blend_pass);
+ this->effects.back()->passes.emplace_back(pass);
- gl_object = new RenderObject(OBJECT, size[0], size[1]);
- gl_object_flipped = new RenderObject(OBJECT_FLIPPED, size[0], size[1]);
+ /*
+ blend_pass.combine = true;
- if (image != nullptr)
- {
- image->load(engine, this);
- }
+ blend_pass.target = "";
+ blend_pass.textures[1] = "";
+ blend_pass.shader = "minimal";
- if (effects.size() != 0)
- {
- // Get last effect that is visible
- // to know when to make a combine pass.
- Effect *last_effect = nullptr;
+ blend_pass.combos.clear();
- for (auto &effect : effects)
- {
- if (effect->visible)
- {
- last_effect = effect;
- }
- }
-
- if (last_effect != nullptr)
- {
- for (auto &effect : effects)
- {
- effect->load(engine, this, effect == last_effect);
- }
- }
- else if (visible)
- {
- // If there are effects but no visible effects, make sure
- // combine is set on the background pass.
- passes.back()->combine = true;
- }
+ pass = new RenderPass(engine, &blend_pass);
+ //pass->mat = &engine->default_mat;
+ //pass->render_object = engine->default_object;
+ this->effects.back()->passes.emplace_back(pass);
+ */
}
- loaded = true;
+ this->loaded = true;
}
-void Object::update(Engine *engine)
+auto Object::create_objects(Engine *engine, Texture *texture) -> void
{
-}
-
-void Object::draw(Engine *engine)
-{
- for (auto &dep : deps)
+ this->model_object = new RenderObject(MODEL, this, texture);
+ this->combine_object = new RenderObject(COMBINE, this, texture);
+ this->combine_model = glm::ortho(0.f, (f32)engine->scene->width, (f32)engine->scene->height, 0.f, -3.f, 1.f);
+ this->combine_model = glm::translate(this->combine_model, this->origin);
+ if (texture && texture->is_gif())
{
- engine->scene->get_object_by_id(dep)->draw(engine);
+ // Something about positioning is wrong, affects most gifs.
}
+ if (this->passthrough)
+ {
+ this->model_model = this->combine_model;
+ this->model_model = glm::rotate(this->model_model, this->angles[0], vec3{1.f, 0.f, 0.f});
+ this->model_model = glm::rotate(this->model_model, this->angles[1], vec3{0.f, 1.f, 0.f});
+ this->model_model = glm::rotate(this->model_model, this->angles[2], vec3{0.f, 0.f, 1.f});
+ this->model_model = glm::scale(this->model_model, this->scale);
+ this->model_model = glm::translate(this->model_model, vec3{this->size[0] / -2.f, this->size[1] / -2.f, 0.f});
+ }
+ else
+ {
+ this->model_model = glm::ortho(0.f, this->size[0], this->size[1], 0.f, -3.f, 1.f);
+ }
+ this->combine_model = glm::rotate(this->combine_model, this->angles[0], vec3{1.f, 0.f, 0.f});
+ this->combine_model = glm::rotate(this->combine_model, this->angles[1], vec3{0.f, 1.f, 0.f});
+ this->combine_model = glm::rotate(this->combine_model, this->angles[2], vec3{0.f, 0.f, 1.f});
+ this->combine_model = glm::scale(this->combine_model, this->scale);
+}
+auto Object::draw_internal(Engine *engine) -> void
+{
#if FRAME_STEP
- std::cout << name << " (model):\n";
+ std::cout << this->name << " (model):\n";
#endif
- // Reset this every frame so avoid passes that target one of
- // this objects buffers to get a different result every other
- // frame.
- buffer_switch = true;
+ this->buffer_switch = true;
- for (auto &pass : passes)
+ for (RenderPass *pass : this->passes)
{
#if FRAME_STEP
- std::cout << "\t" << pass->shader->name << "\n";;
+ std::cout << "\t" << pass->shader->origin()->name << "\n";;
#endif
pass->draw(engine);
}
-
- for (auto &effect : effects)
+
+ for (Effect *effect : this->effects)
{
effect->draw(engine);
}
}
-std::string Object::get_target_buffer() const
+auto Object::draw(Engine *engine) -> void
+{
+ for (s32 dep : this->deps)
+ {
+ Object *object = engine->scene->get_object_by_id(dep);
+ if (object) object->draw_internal(engine);
+ }
+ this->draw_internal(engine);
+}
+
+auto Object::get_target_buffer() const -> const std::string &
{
- return (buffer_switch) ? buffer_a : buffer_b;
+ return (this->buffer_switch) ? this->buffer_a : this->buffer_b;
}
-std::string Object::get_texture_buffer() const
+auto Object::get_texture_buffer() const -> const std::string &
{
- return (buffer_switch) ? buffer_b : buffer_a;
+ return (this->buffer_switch) ? this->buffer_b : this->buffer_a;
}
Object::~Object()
{
- if (image != nullptr)
- delete image;
-
- delete gl_uv_object;
+ if (this->model) delete this->model;
- delete gl_object;
- delete gl_object_flipped;
+ if (this->model_object) delete this->model_object;
+ if (this->combine_object) delete this->combine_object;
- for (auto &pass : passes)
+ for (RenderPass *pass : this->passes)
{
delete pass;
}
- for (auto &effect : effects)
+ for (Effect *effect : this->effects)
{
delete effect;
}
diff --git a/src/objects/object.h b/src/objects/object.h
index 1a79c6c..a171fae 100644
--- a/src/objects/object.h
+++ b/src/objects/object.h
@@ -7,21 +7,13 @@
namespace Mauri
{
-enum ObjectAlignment
-{
- CENTER,
-};
-
-enum BlendMode
-{
- TRANSLUCENT = 0,
- NORMAL = 1
-};
+enum ObjectAlignment { CENTER };
+enum BlendMode { TRANSLUCENT, NORMAL };
class Object
{
public:
- Object(Parser &p, json &root);
+ Object(Parser &pr, const json &root);
~Object();
u32 id;
@@ -29,58 +21,51 @@ class Object
bool visible;
- std::vector<s32> deps;
+ std::vector<u32> deps;
- bool passthrough = false;
bool fullscreen = false;
+ bool passthrough = false;
+ vec3 angles;
vec2 size;
-
- void get_model(Engine *engine, f32 width, f32 height, bool flip);
-
- mat4x4 ortho;
- mat4x4 model;
-
- RenderObject *gl_uv_object = nullptr;
- RenderObject *gl_object = nullptr;
- RenderObject *gl_object_flipped = nullptr;
-
+ vec3 scale;
+ vec3 origin;
+ vec3 color;
+ f32 alpha;
s32 color_blend_mode;
- f32 alpha;
- vec3 color;
+ vec4 color4;
- std::string get_target_buffer() const;
- std::string get_texture_buffer() const;
+ mat4x4 model_model;
+ mat4x4 combine_model;
- void swap_buffer()
- {
- buffer_switch = !buffer_switch;
- }
+ RenderObject *model_object = nullptr;
+ RenderObject *combine_object = nullptr;
- std::vector<RenderPass *> passes;
+ auto get_target_buffer() const -> const std::string &;
+ auto get_texture_buffer() const -> const std::string &;
- std::vector<Effect *> effects;
+ auto swap_buffers() -> void { buffer_switch = !buffer_switch; }
bool loaded = false;
bool loaded_as_dep = false;
- void load(Engine *engine);
- void update(Engine *engine);
- void draw(Engine *engine);
+ Model *model = nullptr;
+ std::vector<Effect *> effects;
- vec3 origin;
+ std::vector<RenderPass *> passes;
- private:
- vec3 angles;
- vec3 scale;
+ auto load(Engine *engine) -> void;
+ auto create_objects(Engine *engine, Texture *texture) -> void;
- std::string buffer_a;
- std::string buffer_b;
+ auto draw(Engine *engine) -> void;
+ private:
bool buffer_switch;
+ std::string buffer_a;
+ std::string buffer_b;
- Model *image = nullptr;
+ auto draw_internal(Engine *engine) -> void;
};
} // namespace Mauri
diff --git a/src/objects/pass.cc b/src/objects/pass.cc
index e6a9bfa..49533e1 100644
--- a/src/objects/pass.cc
+++ b/src/objects/pass.cc
@@ -1,146 +1,139 @@
#include <thread>
#include "../gl.h"
+#include "../context.h"
+#include "scene.h"
#include "pass.h"
using namespace Mauri;
-Pass::Pass(Parser &p, json &root, PassStage stage)
+Pass::Pass(Parser &pr, const json &root, PassStage stage)
{
switch (stage)
{
- case EFFECT0_PASS: {
- auto _uniforms = root["constantshadervalues"];
- for (auto &value : _uniforms.items())
- {
- uniforms.emplace_back(new UniformOverride({vec4(0.f), value.key()}));
- p.get_value<vec4>(_uniforms, value.key(), &uniforms.back()->value, vec4(0.f));
- }
+ case EFFECT0_PASS:
break;
- }
- case EFFECT1_PASS: {
- auto _material = root["material"];
- if (_material.is_string())
- {
- material = new Material(p, _material);
- }
-
- auto _command = root["command"];
- if (_command.is_string() && _command == "copy")
- {
- command = COPY;
- }
+ case EFFECT1_PASS:
+ {
+ if (root.contains("material")) this->material = new Material(pr, root["material"]);
- auto _target = root["target"];
- if (_target.is_string())
+ if (root.contains("command"))
{
- target = _target;
+ const json command = root["command"];
+ if (command == "copy") this->command = COPY;
}
- auto _source = root["source"];
- if (_source.is_string())
- {
- source = _source;
- }
+ if (root.contains("target")) this->target = root["target"];
+ if (root.contains("source")) this->source = root["source"];
- binds[0] = "previous";
- for (auto &bind : root["bind"])
+ this->binds[0] = "previous";
+ if (root.contains("bind"))
{
- u32 index = bind["index"];
- binds[index] = bind["name"];
+ for (const json &bind : root["bind"])
+ {
+ this->binds[bind["index"]] = bind["name"];
+ }
}
break;
}
case MATERIAL_ONLY_PASS:
case MATERIAL_PASS:
- shader = root["shader"];
+ this->shader = root["shader"];
break;
}
- auto _textures = root["textures"];
- for (auto i = 0u; i < _textures.size(); i++)
+ if (root.contains("constantshadervalues"))
+ {
+ const json uniforms = root["constantshadervalues"];
+ for (const auto &value : uniforms.items())
+ {
+ UniformOverride *uniform = new UniformOverride{vec4(0.f), value.key()};
+ pr.map_value<vec4>(uniforms, value.key(), &uniform->value, vec4(0.f));
+ this->uniforms.push_back(uniform);
+ }
+ }
+
+ if (root.contains("textures"))
{
- auto texture = _textures[i];
- if (texture.is_string())
+ const json textures = root["textures"];
+ for (u32 i = 0; i < textures.size(); i++)
{
- textures[i] = texture;
+ if (textures[i].is_string()) this->textures[i] = textures[i];
}
}
- for (auto &combo : root["combos"].items())
+ if (root.contains("combos"))
{
- combos.emplace_back(Combo { combo.key(), combo.value() });
+ for (const auto &combo : root["combos"].items())
+ {
+ this->combos.emplace_back(Combo(combo.key(), combo.value()));
+ }
}
}
-void Pass::load(Engine *engine, PassStage stage, Pass *pass)
+auto Pass::load(Engine *engine, PassStage stage, Pass *pass) -> void
{
- intermidiate = true;
-
- for (auto i = 0; i < MAX_TEXTURES; i++)
- {
- if (textures[i].empty())
- continue;
+ this->intermediate = true;
- pass->textures[i] = textures[i];
- }
+ pass->uniforms.insert(pass->uniforms.end(), this->uniforms.begin(), this->uniforms.end());
- for (auto &combo : combos)
+ for (u32 i = 0; i < MAX_TEXTURES; i++)
{
- pass->combos.push_back(combo);
+ if (!this->textures[i].empty())
+ {
+ pass->textures[i] = this->textures[i];
+ }
}
+ pass->combos.insert(pass->combos.end(), this->combos.begin(), this->combos.end());
+
switch (stage)
{
case EFFECT0_PASS:
- for (auto &uniform : uniforms)
- {
- pass->uniforms.push_back(uniform);
- }
break;
case EFFECT1_PASS:
- pass->command = command;
+ {
+ pass->command = this->command;
- pass->source = source + pass->effect->buffer_id;
- pass->target = target;
+ pass->target = this->target;
+ pass->source = this->source + pass->effect->buffer_id;
if (!pass->target.empty())
+ {
pass->target.append(pass->effect->buffer_id);
+ }
- for (auto i = 0; i < MAX_TEXTURES; i++)
+ for (u32 i = 0; i < MAX_TEXTURES; i++)
{
- if (binds[i].empty())
- continue;
+ if (this->binds[i].empty()) continue;
+
+ pass->textures[i] = this->binds[i];
- pass->textures[i] = binds[i];
-
if (pass->textures[i] != "previous")
- pass->textures[i] += pass->effect->buffer_id;
+ {
+ pass->textures[i].append(pass->effect->buffer_id);
+ }
}
- if (material != nullptr)
- {
- material->load(engine, pass->object, MATERIAL_EFFECT, pass);
- }
+ if (this->material) this->material->load(engine, pass->object, MATERIAL_EFFECT, pass);
break;
+ }
case MATERIAL_ONLY_PASS:
case MATERIAL_PASS:
- pass->shader = shader;
+ pass->shader = this->shader;
break;
}
}
Pass::~Pass()
{
- if (material != nullptr)
- delete material;
-
- if (intermidiate)
+ if (this->material) delete this->material;
+ if (this->intermediate)
{
- for (auto &uniform : uniforms)
+ for (UniformOverride *uniform : this->uniforms)
{
delete uniform;
}
@@ -149,235 +142,220 @@ Pass::~Pass()
RenderPass::RenderPass(Engine *engine, Pass *pass)
{
- command = pass->command;
- combine = pass->combine;
+ this->command = pass->command;
- // This object contains information needed for getting previous
- // framebuffer textures and targets.
- object = pass->object;
+ this->target = engine->get_framebuffer(pass->target);
- target = engine->get_framebuffer(pass->target);
-
- if (command == COPY)
+ if (this->command == COPY)
{
- // Target and source is the only needed information
- // for a COPY pass.
- source = engine->get_framebuffer(pass->source);
+ // Target and source is the only needed information for a COPY pass.
+ this->source = engine->get_framebuffer(pass->source);
return;
}
- shader = new Shader(engine->parser, pass->shader);
+ this->object = pass->object;
+
+ this->model = pass->model;
+ this->combine = pass->combine;
+
+ this->shader = get_shader(pass->shader);
- for (auto i = 0u; i < shader->texture_count; i++)
+ bool objects_created = false;
+
+ for (u32 i = 0; i < this->shader->origin()->texture_count; i++)
{
- if (!shader->textures[i].empty())
+ if (!this->shader->origin()->texture_combos[i].empty())
{
- // If there is no texture at "i" use default shader from the texture.
- //if (pass->textures[i].empty())
- // pass->textures[i] = shader->textures[i];
+ pass->combos.push_back(Combo(this->shader->origin()->texture_combos[i], !pass->textures[i].empty()));
+ }
- if (!shader->texture_combos[i].empty() && !pass->textures[i].empty())
- pass->combos.push_back(Combo { shader->texture_combos[i], 1 });
+ if (!this->shader->origin()->textures[i].empty() && pass->textures[i].empty())
+ {
+ pass->textures[i] = this->shader->origin()->textures[i];
}
- if (pass->textures[i].empty())
- continue;
+ if (pass->textures[i].empty()) continue;
if (pass->textures[i] == "previous")
{
- texture_types[i] = PREVIOUS;
+ this->texture_types[i] = PREVIOUS;
continue;
}
- // Check if texture is referencing a framebuffer.
- textures[i] = engine->get_framebuffer_texture(pass->textures[i]);
- if (textures[i] == nullptr)
+ this->textures[i] = engine->get_framebuffer_texture(pass->textures[i]);
+
+ if (!this->textures[i])
{
- // The texture wasn't a framebuffer so try to load it from an asset.
- auto asset = asset_manager()->get_file(pass->textures[i], TEXTURE);
+ Asset *asset = asset_manager()->get_file(pass->textures[i], TEXTURE);
if (asset->type != ASSET_VOID)
{
- textures[i] = (Texture *)asset->lasset;
+ this->textures[i] = (Texture *)asset->lasset;
}
}
+
+ if (i == 0 && this->textures[0] && this->model)
+ {
+ if (this->textures[0]->is_gif()) pass->combos.push_back(Combo("SPRITESHEET", 1));
+ this->object->create_objects(engine, this->textures[0]);
+ objects_created = true;
+ }
}
- for (auto &shader_uniform : shader->uniforms)
+ if (this->model && !objects_created)
{
- for (auto &uniform_override : pass->uniforms)
+ this->object->create_objects(engine, nullptr);
+ }
+
+ for (Uniform *uniform : this->shader->uniforms)
+ {
+ for (UniformOverride *uniform_override : pass->uniforms)
{
- if (shader_uniform->name.empty())
- continue;
- if (shader_uniform->name == uniform_override->name)
+ if (uniform->name.empty()) continue;
+ if (uniform->name == uniform_override->name)
{
// Take value as reference because "uniform_override->value" points
// to the value stored in the parser. This allows changing that value
// to have an instant effect.
- shader_uniform->value = &uniform_override->value;
+ uniform->value = &uniform_override->value;
break;
}
}
}
- for (auto &pass_combo : pass->combos)
+ this->render_shader = this->shader->compile(pass->combos);
+
+ if (this->model && this->object->fullscreen)
{
- auto add = true;
- for (auto &shader_combo : shader->combos)
- {
- if (pass_combo.name == shader_combo.name)
- {
- shader_combo.value = pass_combo.value;
- add = false;
- break;
- }
- }
- if (add)
- shader->combos.push_back(pass_combo);
+ this->mat = &engine->default_mat;
+ this->render_object = engine->fullscreen_object;
}
-
- // If visualizer is not enabled disable audio logic
- // on the shader.
- if (!engine->audio_enabled)
+ else if (this->object->passthrough)
{
- for (auto &combo : shader->combos)
+ if (this->combine)
{
- if (combo.name == "AUDIOPROCESSING")
- combo.value = 0;
+ this->mat = &this->object->model_model;
+ this->render_object = this->object->model_object;
+ }
+ else if (this->model)
+ {
+ this->mat = &this->object->combine_model;
+ this->render_object = this->object->combine_object;
+ }
+ else
+ {
+ this->mat = &engine->default_mat;
+ this->render_object = engine->default_object;
}
}
-
- // Compile shader only after all necessary combos are set.
- shader->compile();
-
- if (pass->effect == nullptr)
+ else
{
- // The fullscreen shader doesn't use ModelViewProjectionMatrix,
- if (pass->object->fullscreen)
+ if (this->combine)
{
- model = &engine->default_model;
- robject = engine->default_object;
+ this->mat = &this->object->combine_model;
+ this->render_object = this->object->combine_object;
}
-
- // The passthrough shader uses ModelViewProjectionMatrix
- // but, the texture is not scaled to a power of two.
- else if (pass->object->passthrough)
+ else if (this->model)
{
- model = &pass->object->model;
- robject = pass->object->gl_object;
- }
- // If there is no effect and combine is set,
- // we are forced to use a model which will
- // correctly position the object.
- else if (combine)
+ this->mat = &this->object->model_model;
+ this->render_object = this->object->model_object;
+ }
+ else
{
- model = &pass->object->model;
- if (textures[0]->is_gif)
- {
- robject = pass->object->gl_object_flipped;
- }
- else
- {
- robject = pass->object->gl_uv_object;
- }
+ this->mat = &engine->default_mat;
+ this->render_object = engine->default_object;
}
+ }
- // The object with UV's that scale the texture
- // also has the objects size on the verteices,
- // so we need to use ortho for the model.
- else
+#if _DEBUG_
+ debug("PASS (%s)", this->command == COPY ? "copy" : "draw");
+ debug(" object: %s (passthrough: %i, fullscreen %i)", 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);
+ for (u32 i = 0; i < this->shader->origin()->texture_count; i++)
+ {
+ switch (this->texture_types[i])
{
- model = &pass->object->ortho;
- if (textures[0]->is_gif)
+ case STATIC:
+ if (pass->textures[i].empty() && !this->shader->textures[i].empty())
{
- robject = pass->object->gl_object_flipped;
+ debug(" %s (DEFAULT)", this->shader->textures[i].c_str());
}
else
{
- robject = pass->object->gl_uv_object;
+ debug(" %s", pass->textures[i].c_str());
}
+ break;
+ case PREVIOUS:
+ debug(" previous");
+ break;
}
}
- else
+ debug(" uniforms (%li)", this->shader->uniforms.size());
+ for (Uniform *uniform : this->shader->uniforms)
{
- // When combine is set this is the final pass
- // that needs to position the object on the screen.
- // Except when fullscreen is set the object doesn't
- // want to be positioned.
- if (combine && !pass->object->fullscreen)
- {
- robject = pass->object->gl_object;
- model = &pass->object->model;
- }
- else // Default everything.
- {
- robject = engine->default_object;
- model = &engine->default_model;
- }
+ 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);
+#endif
}
-void RenderPass::draw(Engine *engine)
+auto RenderPass::draw(Engine *engine) -> void
{
- switch (command) {
- case DRAW: {
- Framebuffer *_target;
-
- if (combine)
- _target = engine->combine_buffer;
- else if (target != nullptr)
- _target = target;
- else
- _target = engine->get_framebuffer(object->get_target_buffer());
+ switch (this->command)
+ {
+ case DRAW:
+ {
+ Framebuffer *adjusted_target;
+ if (this->combine) adjusted_target = engine->combine_buffer;
+ else if (this->target) adjusted_target = this->target;
+ else adjusted_target = engine->get_framebuffer(this->object->get_target_buffer());
- _target->buffer->bind();
+ adjusted_target->buffer->bind();
- for (auto i = 0u; i < shader->texture_count; i++)
+ for (u32 i = 0; i < this->shader->origin()->texture_count; i++)
{
- if (texture_types[i] == PREVIOUS)
+ if (this->texture_types[i] == PREVIOUS)
{
- textures[i] = engine->get_framebuffer_texture(object->get_texture_buffer());
+ this->textures[i] = engine->get_framebuffer_texture(this->object->get_texture_buffer());
}
}
- shader->bind(engine, object, model, &textures);
- robject->bind();
+ this->render_object->bind();
+ this->shader->bind(this->render_shader, engine, this->object, this->mat, &this->textures);
- if (target == nullptr)
- object->swap_buffer();
+ if (!this->target) this->object->swap_buffers();
- if (combine)
- {
- Render::blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- Render::color_mask(1.f, 1.f, 1.f, 0.f);
- }
- else
- {
- Render::blend_func(GL_ONE, GL_ZERO);
- Render::color_mask(1.f, 1.f, 1.f, 1.f);
- }
+ if (this->combine) Render::blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ else Render::blend_func(GL_ONE, GL_ZERO);
+
+ Render::color_mask(1.f, 1.f, 1.f, this->combine ? 0.f : 1.f);
- engine->view.default_viewport(_target->buffer->width, _target->buffer->height);
+ engine->view.default_viewport(
+ adjusted_target->buffer->width, adjusted_target->buffer->height);
- robject->draw();
+ this->render_object->draw();
#if FRAME_STEP
- _target->buffer->blit(0, context()->width, context()->height);
+ adjusted_target->buffer->blit(0, context()->width, context()->height);
context()->swap_buffers();
std::this_thread::sleep_for(std::chrono::seconds(1));
#endif
-
break;
}
case COPY:
- source->buffer->blit(target->buffer->id, source->buffer->width, source->buffer->height);
+ this->source->buffer->blit(this->target->buffer->id, this->source->buffer->width, this->source->buffer->height);
break;
}
}
RenderPass::~RenderPass()
{
- if (shader != nullptr)
- delete shader;
+ if (this->shader) delete this->shader;
}
diff --git a/src/objects/pass.h b/src/objects/pass.h
index 97348a3..a2b3124 100644
--- a/src/objects/pass.h
+++ b/src/objects/pass.h
@@ -8,25 +8,10 @@
namespace Mauri
{
-enum PassStage
-{
- EFFECT0_PASS,
- EFFECT1_PASS,
- MATERIAL_PASS,
- MATERIAL_ONLY_PASS
-};
-
-enum PassCommand
-{
- DRAW,
- COPY
-};
+enum PassStage { EFFECT0_PASS, EFFECT1_PASS, MATERIAL_PASS, MATERIAL_ONLY_PASS };
+enum PassCommand { DRAW, COPY };
-enum TextureType
-{
- STATIC,
- PREVIOUS
-};
+enum TextureType { STATIC, PREVIOUS };
struct UniformOverride
{
@@ -34,18 +19,17 @@ struct UniformOverride
std::string name;
};
-class RenderPass;
-
class Pass
{
public:
Pass() {}
- Pass(Parser &p, json &root, PassStage stage);
-
+ Pass(Parser &pr, const json &root, PassStage stage);
~Pass();
+ bool intermediate;
+
PassCommand command = DRAW;
-
+
std::string target;
std::string source;
@@ -54,16 +38,16 @@ class Pass
std::string shader;
- std::array<std::string, MAX_TEXTURES> textures = {""};
- std::array<std::string, MAX_TEXTURES> binds = {""};
+ std::array<std::string, MAX_TEXTURES> binds = { };
+ std::array<std::string, MAX_TEXTURES> textures = { };
+ bool model;
bool combine;
- bool intermidiate;
std::vector<UniformOverride *> uniforms;
std::vector<Combo> combos;
- void load(Engine *engine, PassStage stage, Pass *pass);
+ auto load(Engine *engine, PassStage stage, Pass *pass) -> void;
private:
Material *material = nullptr;
@@ -75,14 +59,18 @@ class RenderPass
RenderPass(Engine *engine, Pass *pass);
~RenderPass();
+ bool model;
bool combine;
Shader *shader = nullptr;
- std::array<Texture *, MAX_TEXTURES> textures = {0};
- std::array<TextureType, MAX_TEXTURES> texture_types = {STATIC};
+ mat4x4 *mat;
+ RenderObject *render_object;
+
+ std::array<Texture *, MAX_TEXTURES> textures = { };
+ std::array<TextureType, MAX_TEXTURES> texture_types = { };
- void draw(Engine *engine);
+ auto draw(Engine *engine) -> void;
private:
PassCommand command;
@@ -92,8 +80,7 @@ class RenderPass
Framebuffer *target;
Framebuffer *source;
- mat4x4 *model;
- RenderObject *robject;
+ RenderShader *render_shader;
};
} // namespace Mauri
diff --git a/src/objects/scene.cc b/src/objects/scene.cc
index 8331b15..06412f5 100644
--- a/src/objects/scene.cc
+++ b/src/objects/scene.cc
@@ -2,77 +2,78 @@
using namespace Mauri;
-Scene::Scene(Parser &p, const std::string &path)
+Scene::Scene(const std::string &path)
{
- auto asset = asset_manager()->get_file(path, NONE);
- if (asset->type == ASSET_VOID)
- {
- log_error("%s", "failed to open scene.json");
- return;
- }
-
- auto root = json::parse(asset->as_string());
+ Asset *asset = asset_manager()->get_file(path);
+ if (asset->type == ASSET_VOID) return;
+
+ const json &root = json::parse(asset->as_string());
+ if (root.is_discarded()) return;
- auto camera = root["camera"];
- p.get_value<vec3>(camera, "center", &cam.center, vec3(0.f));
- p.get_value<vec3>(camera, "eye", &cam.eye, vec3(0.f));
- p.get_value<vec3>(camera, "up", &cam.up, vec3(0.f));
+ Parser &pr = this->parser;
- auto general = root["general"];
- p.get_value<bool>(general, "clearenabled", &clear_enabled, true);
- p.get_value<vec4>(general, "clearcolor", &clear_color, vec4(1.f));
- p.get_value<f32>(general, "nearz", &nearz, 0.f);
- p.get_value<f32>(general, "farz", &farz, 1.f);
+ const json &camera = root["camera"];
+ pr.map_value<vec3>(camera, "center", &this->cam.center, vec3(0.f));
+ pr.map_value<vec3>(camera, "eye", &this->cam.eye, vec3(0.f));
+ pr.map_value<vec3>(camera, "up", &this->cam.up, vec3(0.f));
- auto ortho = general["orthogonalprojection"];
- p.get_value<f32>(ortho, "width", &width, 0.f);
- p.get_value<f32>(ortho, "height", &height, 0.f);
+ const json &general = root["general"];
+ pr.map_value<bool>(general, "clearenabled", &this->clear_enabled, true);
+ pr.map_value<vec4>(general, "clearcolor", &this->clear_color, vec4(1.f));
+ pr.map_value<f32>(general, "nearz", &this->nearz, -1.f);
+ pr.map_value<f32>(general, "farz", &this->farz, 1.f);
- for (auto &object : root["objects"])
+ const json &ortho = general["orthogonalprojection"];
+ pr.map_value<s32>(ortho, "width", &this->width, 0);
+ pr.map_value<s32>(ortho, "height", &this->height, 0);
+
+ for (const json &object : root["objects"])
{
- if (object["image"].is_null())
- continue;
- objects.emplace_back(new Object(p, object));
+ if (!object.contains("image") || object["image"].is_null()) continue;
+ //if (object["name"] == "ICUE") continue;
+ this->objects.emplace_back(new Object(pr, object));
}
}
-Object *Scene::get_object_by_id(u32 id)
+auto Scene::get_object_by_id(u32 id) -> Object *
{
- for (auto &object : objects)
+ for (Object *object : this->objects)
{
- if (object->id == id)
- {
- return object;
- }
+ if (object->id == id) return object;
}
-
return nullptr;
}
-void Scene::load(Engine *engine)
+auto Scene::load(Engine *engine) -> void
{
- engine->view.width = width;
- engine->view.height = height;
+ /*
+ if (this->objects.size() > 0)
+ {
+ for (auto it = this->objects.begin(); it != this->objects.end();)
+ {
+ if (!(*it)->visible) it = this->objects.erase(it);
+ else it++;
+ }
+ }
+ */
- for (auto &object : objects)
+ for (Object *object : this->objects)
{
object->load(engine);
}
}
-void Scene::draw(Engine *engine)
+auto Scene::draw(Engine *engine) -> void
{
- for (auto &object : objects)
+ for (Object *object : this->objects)
{
- if (object->loaded_as_dep)
- continue;
- object->draw(engine);
+ if (!object->loaded_as_dep) object->draw(engine);
}
}
Scene::~Scene()
{
- for (auto &object : objects)
+ for (Object *object : this->objects)
{
delete object;
}
diff --git a/src/objects/scene.h b/src/objects/scene.h
index 672df96..7b3d07a 100644
--- a/src/objects/scene.h
+++ b/src/objects/scene.h
@@ -6,25 +6,25 @@
namespace Mauri
{
-struct Camera {
+struct Camera
+{
vec3 center;
vec3 eye;
vec3 up;
- f32 farz;
- f32 nearz;
- f32 fov;
};
class Scene
{
public:
- Scene(Parser &p, const std::string &path);
+ Scene(const std::string &path);
~Scene();
+ Parser parser;
+
Camera cam;
- f32 width;
- f32 height;
+ s32 width;
+ s32 height;
f32 nearz;
f32 farz;
@@ -32,10 +32,10 @@ class Scene
bool clear_enabled;
vec4 clear_color;
- void load(Engine *engine);
- void draw(Engine *engine);
+ auto get_object_by_id(u32 id) -> Object *;
- Object *get_object_by_id(u32 id);
+ auto load(Engine *engine) -> void;
+ auto draw(Engine *engine) -> void;
std::vector<Object *> objects;
};
diff --git a/src/shader.cc b/src/shader.cc
index 45c3e3e..0a2d568 100644
--- a/src/shader.cc
+++ b/src/shader.cc
@@ -1,335 +1,446 @@
#include <sstream>
-#include <regex>
+#include "json.h"
#include "shader.h"
-#include "objects/object.h"
+#include "objects/scene.h"
-static const char *gl_compat = \
- "#define highp\n"
- "#define mediump\n"
- "#define lowp\n"
- "#define mul(x, y) (y * x)\n"
+static const char *compat = \
+// "#define mul(x, y) ((y) * (x))\n"
"#define max(x, y) max(y, x)\n"
"#define frac fract\n"
- "#define CAST2(x) (vec2(x))\n"
- "#define CAST3(x) (vec3(x))\n"
- "#define CAST4(x) (vec4(x))\n"
- "#define CAST3X3(x) (mat3(x))\n"
- "#define saturate(x) (clamp(x, 0.0, 1.0))\n"
+ "#define log10 log\n"
+ "#define CAST2(x) vec2(x)\n"
+ "#define CAST3(x) vec3(x)\n"
+ "#define CAST4(x) vec4(x)\n"
+ "#define CAST3X3(x) mat3(x)\n"
+ "#define saturate(x) clamp(x, 0.0, 1.0)\n"
"#define lerp mix\n"
"#define texSample2D texture2D\n"
"#define texSample2DLod texture2DLod\n"
"#define texture2DLod texture2D\n"
"#define atan2 atan\n"
+ "#define fmod(x, y) ((x)-(y)*trunc((x)/(y)))\n"
"#define ddx dFdx\n"
"#define ddy(x) dFdy(-(x))\n"
"#define GLSL 1\n";
-static const char *version = "#version 130\n";
+static const char *mul = "#define mul(x, y) ((y) * (x))\n";
+//static const char *mul = "";
-//static const std::regex mod_regex("(\\(.*\\)\\s*)?(\\w*\\s*)%\\s*(\\w*)");
-//static const std::regex uint_regex("uint\\s*=(.*)");
+static const char *version = "#version 330\n";
+
+namespace Mauri
+{
+
+static std::unordered_map<std::string, Shader *> shader_map;
+static std::unordered_map<u64, RenderShader *> render_shader_map;
+
+auto get_shader(const std::string &name) -> Shader *
+{
+ if (shader_map.contains(name))
+ {
+ return new Shader(shader_map[name]);
+ }
+ Shader *shader = new Shader(name);
+ shader_map[name] = shader;
+ return shader;
+}
+
+} // namespace Mauri
using namespace Mauri;
-void Shader::build_shader_source(Parser *p, const std::string &isource, std::string &res, bool root)
+Shader::Shader(const std::string &name)
+ : name(name)
{
- auto stream = std::istringstream(isource);
+ Asset *vs_asset = asset_manager()->get_file(name, VERTEX_SHADER);
+ Asset *fs_asset = asset_manager()->get_file(name, FRAGMENT_SHADER);
+ this->build_shader_source(vs_asset->as_string(), this->vs_source);
+ this->build_shader_source(fs_asset->as_string(), this->fs_source);
+}
- if (root) res += gl_compat;
+Shader::Shader(Shader *origin)
+{
+ for (Uniform *uniform : origin->uniforms)
+ {
+ Uniform *copy = new Uniform();
+ copy->name = uniform->name;
+ copy->uname = uniform->uname;
+ copy->type = uniform->type;
+ copy->default_value = uniform->default_value;
+ this->uniforms.push_back(copy);
+ }
+ this->origin_ = origin;
+}
- for (std::string line; std::getline(stream, line);)
+static auto simple_audio_bars_hack(std::string_view &line) -> void
+{
+ if (line == " uint barFreq1 = frequency % RESOLUTION;")
+ {
+ line = " uint barFreq1 = uint(mod(frequency, RESOLUTION));";
+ }
+ else if (line == " uint barFreq2 = (barFreq1 + 1) % RESOLUTION;")
{
- auto cut_line = false;
- auto prepend_line = false;
+ line = " uint barFreq2 = uint(mod((barFreq1 + 1u), RESOLUTION));";
+ }
+ 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)))));")
+ {
+ line = " float 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, lerp(g_BarBounds.x, g_BarBounds.y, lerp(barVolume1, barVolume2, smoothstep(0, 1, fract(frequency)))));")
+ {
+ line = " float bar = step(1 - shapeCoord.y, lerp(g_BarBounds.x, g_BarBounds.y, lerp(barVolume1, barVolume2, smoothstep(0, 1, fract(frequency)))));";
+ }
+ else if (line == " int bar = step(1 - shapeCoord.y, barHeight);")
+ {
+ line = " float bar = step(1 - shapeCoord.y, barHeight);";
+ }
+ else if (line == " int barLeft = step(shapeCoord.y, barHeightLeft);")
+ {
+ line = " float barLeft = step(shapeCoord.y, barHeightLeft);";
+ }
+ else if (line == " int barRight = step(1 - shapeCoord.y, barHeightRight);")
+ {
+ line = " float barRight = step(1 - shapeCoord.y, barHeightRight);";
+ }
+}
- if (line.compare(0, 8, "#include") == 0)
- {
- auto open = line.find('"') + 1;
- auto include_name = line.substr(open, line.rfind('"') - open);
+auto Shader::build_shader_source(const std::string_view &isource, std::stringstream &out) -> void
+{
+ Combo current_preprocessor = Combo("", 0);
- auto asset = asset_manager()->get_file(include_name, SHADER);
+ std::stringstream prefix;
- std::string include_source;
- build_shader_source(p, asset->as_string(), include_source, false);
+ 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());
+
+ simple_audio_bars_hack(line);
- res += include_source;
+ bool cut_line = false;
+ bool prepend_line = false;
+
+ if (line.compare(0, 8, "#include") == 0)
+ {
+ size_t open = line.find('"') + 1;
+ std::string_view include_name = line.substr(open, line.rfind('"') - open);
+
+ Asset *asset = asset_manager()->get_file(std::string(include_name), SHADER);
+ if (asset->type != ASSET_VOID)
+ {
+ std::stringstream include_source;
+ this->build_shader_source(asset->as_string(), include_source);
+ out << include_source.rdbuf();
+ }
cut_line = true;
}
+ else if (line.compare(0, 3, "#if") == 0 && (line.compare(0, 4, "#ifd") != 0 && line.compare(0, 4, "#ifn") != 0))
+ {
+ std::string_view name_start = line.substr(line.find(' ') + 1);
+ size_t name_end = name_start.find(' ');
+ if (name_end != std::string::npos)
+ {
+ current_preprocessor.name = name_start.substr(0, name_end);
+ //std::string_view value_start = name_start.substr(name_end + 4);
+ //std::string_view value = value_start.substr(0);
+ }
+ else
+ {
+ current_preprocessor.name = name_start.substr(0);
+ }
+ }
+ else if (line.compare(0, 5, "#else") == 0)
+ {
+ // Change value.
+ }
+ else if (line.compare(0, 6, "#endif") == 0)
+ {
+ current_preprocessor.name = "";
+ }
else if (line.compare(0, 7, "uniform") == 0)
{
- auto type_string = line.substr(line.find(' ') + 1);
+ Uniform *uniform = new Uniform();
+
+ std::string_view type_string = line.substr(line.find(' ') + 1);
+ uniform->type = uniform_type_from_string(type_string);
- auto uniform = new Uniform();
+ size_t open;
- if (type_string.compare(0, 5, "float") == 0)
- uniform->type = TYPE_FLOAT;
- else if (type_string.compare(0, 4, "vec4") == 0)
- uniform->type = TYPE_VEC4;
- else if (type_string.compare(0, 4, "vec3") == 0)
- uniform->type = TYPE_VEC3;
- else if (type_string.compare(0, 4, "vec2") == 0)
- uniform->type = TYPE_VEC2;
- else if (type_string.compare(0, 4, "mat4") == 0)
- uniform->type = TYPE_MAT4;
- else if (type_string.compare(0, 9, "sampler2D") == 0)
+ if (uniform->type == TYPE_INVALID)
{
- uniform->type = TYPE_SAMPLER2D;
- uniform->default_value[0] = texture_count++;
- prepend_line = true;
+ open = type_string.find(' ');
+ uniform->precision = type_string.substr(0, open);
+ type_string = type_string.substr(open + 1);
+ uniform->type = uniform_type_from_string(type_string);
}
- auto open = type_string.find(' ') + 1;
-
+ open = type_string.find(' ') + 1;
uniform->uname = type_string.substr(open, type_string.find(';') - open);
- auto combo_start = line.find("// ");
+ if (uniform->type == TYPE_SAMPLER2D)
+ {
+ this->texture_count++;
+ s32 index = std::stoi(uniform->uname.substr(9));
+ uniform->default_value[0] = index;
+ prepend_line = true;
+ }
+ size_t combo_start = line.find("// ");
if (combo_start != std::string::npos)
{
- auto combo_string = line.substr(combo_start + 2);
-
- json root = json::parse(combo_string);
-
- // If material is present, it's always used to reference this
- // uniform for setting its values. If material is not present,
- // label is used.
- auto label = root["label"];
- auto material = root["material"];
-
- if (!material.is_null())
- uniform->name = material;
- else if (!label.is_null())
- uniform->name = label;
-
- switch (uniform->type)
+ std::string_view combo_string = line.substr(combo_start + 2);
+ const json &root = json::parse(combo_string, nullptr, false);
+ if (!root.is_discarded())
{
- case TYPE_SAMPLER2D: {
- auto _default = root["default"];
-
- if (!_default.is_null())
- textures[(s32)uniform->default_value[0]] = _default;
-
- auto combo = root["combo"];
+ if (root.contains("material"))
+ {
+ uniform->name = root["material"];
+ }
+ else if (root.contains("label"))
+ {
+ uniform->name = root["label"];
+ }
- if (!combo.is_null())
- texture_combos[(s32)uniform->default_value[0]] = combo;
-
- break;
+ switch (uniform->type)
+ {
+ case TYPE_SAMPLER2D:
+ {
+ if (root.contains("combo"))
+ {
+ this->texture_combos[(s32)uniform->default_value[0]] = root["combo"];
+ }
+ if (root.contains("default"))
+ {
+ this->textures[(s32)uniform->default_value[0]] = root["default"];
+ }
+ break;
+ }
+ case TYPE_FLOAT:
+ case TYPE_VEC4:
+ case TYPE_VEC3:
+ case TYPE_VEC2:
+ Parser::parse_value<vec4>(root, "default", &uniform->default_value, vec4(0.f));
+ break;
+ case TYPE_MAT4:
+ case TYPE_INVALID:
+ default:
+ break;
+ }
}
- case TYPE_FLOAT:
- case TYPE_VEC4:
- case TYPE_VEC3:
- case TYPE_VEC2:
- p->get_value<vec4>(root, "default", &uniform->default_value, vec4(0.f));
- break;
- case TYPE_MAT4:
- case TYPE_INVALID:
- uniform->default_value = vec4(0.f);
+ }
+
+ this->uniforms.push_back(uniform);
+ }
+ else if (line.compare(0, 7, "varying") == 0 && name == "effects/foliagesway") // HACK
+ {
+ std::string_view type_string = line.substr(line.find(' ') + 1);
+ size_t open = type_string.find(' ') + 1;
+ std::string_view variable_name = type_string.substr(open, type_string.find(';') - open);
+ bool duplicate = false;
+ for (const Variable &variable : this->variables)
+ {
+ if (variable.name == variable_name)
+ {
+ duplicate = true;
break;
}
}
-
- uniform->value = &uniform->default_value;
-
- uniforms.emplace_back(uniform);
+ if (!duplicate)
+ {
+ this->variables.emplace_back(Variable{std::string(variable_name), uniform_type_from_string(type_string)});
+ }
+ cut_line = true;
}
- else if (line.compare(0, 9, "// [COMBO") == 0)
+ else if (line.compare(0, 10, "// [COMBO]") == 0)
{
- auto open = line.find('{');
- auto combo = line.substr(open, line.length() - open);
-
- auto root = json::parse(combo);
-
- if (!root["default"].is_null())
+ size_t open = line.find('{');
+ std::string_view combo = line.substr(open, line.length() - open);
+ const json &root = json::parse(combo);
+ if (!root.is_discarded())
{
- combos.emplace_back(Combo { root["combo"], root["default"] });
+ if (root.contains("default"))
+ {
+ this->combos.emplace_back(Combo(root["combo"], root["default"]));
+ }
+ else
+ {
+ this->combos.emplace_back(Combo(root["combo"], 0));
+ }
}
+ cut_line = true;
}
if (!cut_line)
{
- //line = std::regex_replace(line, mod_regex, "mod($1$2, $3)");
- //line = std::regex_replace(line, mod_regex, "uint(uint($1$2) % $3)");
- //line = std::regex_replace(line, uint_regex, "int int($1)");
- if (prepend_line)
- {
- res.insert(0, line + "\n");
- }
- else
- {
- res += line + "\n";
- }
+ if (prepend_line) prefix << line << "\n";
+ else out << line << "\n";
}
}
+
+ prefix << out.rdbuf();
+ out = std::move(prefix);
}
-std::string Combo::to_string()
+auto Combo::to_string() const -> const std::string
{
- transform(name.begin(), name.end(), name.begin(), ::toupper);
-
- std::stringstream _combo;
- _combo << "#define " << name << " " << value << "\n";
-
- return _combo.str();
+ return str_format("#define %s %i\n", this->name.c_str(), this->value);
}
-void Shader::compile()
+auto Variable::to_string() const -> const std::string
{
- auto _vs_source = vs_source;
- auto _fs_source = fs_source;
-
- for (auto &combo : combos)
- {
- _vs_source.insert(0, combo.to_string());
- _fs_source.insert(0, combo.to_string());
- }
-
- _vs_source.insert(0, version);
- _fs_source.insert(0, version);
-
- rshader = new RenderShader(_vs_source, _fs_source);
+ return str_format("varying %s %s;\n", uniform_type_to_string(this->type).c_str(), this->name.c_str());
}
-Shader::Shader(Parser *p, const std::string &name)
- : name(name)
+auto Shader::compile(const std::vector<Combo> &combo_overrides) -> RenderShader *
{
- auto vs_asset = asset_manager()->get_file(name, VERTEX_SHADER);
- auto fs_asset = asset_manager()->get_file(name, FRAGMENT_SHADER);
+ std::vector<Combo> adjusted_combos = this->origin()->combos;
- if (vs_asset->type != ASSET_VOID)
- {
- build_shader_source(p, vs_asset->as_string(), vs_source, true);
- }
- else
+ for (const Combo &combo : combo_overrides)
{
- log_error("failed to load shader file (%s)", name.c_str());
- return;
+ bool add = true;
+ for (Combo &shader_combo : adjusted_combos)
+ {
+ if (combo.name == shader_combo.name)
+ {
+ shader_combo.value = combo.value;
+ add = false;
+ break;
+ }
+ }
+ if (add) adjusted_combos.push_back(combo);
}
- if (fs_asset->type != ASSET_VOID)
+ std::stringstream combos_str;
+
+ for (const Combo &combo : adjusted_combos)
{
- build_shader_source(p, fs_asset->as_string(), fs_source, true);
+ combos_str << combo.to_string();
}
- else
+
+ u64 hash = std::hash<std::string>{}(this->origin()->name + combos_str.str());
+
+ if (!render_shader_map.contains(hash))
{
- log_error("failed to load shader file (%s)", name.c_str());
- return;
+ std::stringstream preamble;
+
+ preamble << version;
+ preamble << compat;
+
+ preamble << combos_str.str();
+
+ for (const Variable &variable : this->origin()->variables)
+ {
+ preamble << variable.to_string();
+ }
+
+ std::string vs_source = preamble.str() + mul + this->origin()->vs_source.str();
+ std::string fs_source = preamble.str() + this->origin()->fs_source.str();
+
+ render_shader_map[hash] = new RenderShader(vs_source, fs_source);
}
+
+ return render_shader_map[hash];
}
-void Shader::bind(Engine *engine, Object *object, mat4x4 *model, std::array<Texture *, MAX_TEXTURES> *textures)
+auto Shader::bind(RenderShader *shader, Engine *engine, Object *object, mat4x4 *model,
+ const std::array<Texture *, MAX_TEXTURES> *textures) -> void
{
- rshader->bind();
+ shader->bind();
- for (auto &uniform : uniforms)
+ for (const Uniform *uniform : this->uniforms)
{
- if (uniform->uname.find('[') != std::string::npos)
- continue;
-#if UNIFORM_DEBUG
- std::cout << uniform->uname << "(" << uniform->type << ")" << " "
- << (*uniform->value)[0] << " " << (*uniform->value)[1] << " "
- << (*uniform->value)[2] << " " << (*uniform->value)[3] << "\n";
-#endif
- //if (uniform->value != nullptr && uniform->type != TYPE_MAT4)
- if (uniform->value != nullptr)
- rshader->set_uniform(uniform->uname, uniform->type, glm::value_ptr(*uniform->value));
+ if (uniform->type != TYPE_MAT4 && uniform->type != TYPE_MAT3 &&
+ uniform->uname.find('[') == std::string::npos)
+ {
+ shader->set_uniform(uniform->uname, uniform->type, glm::value_ptr(*uniform->value));
+ }
}
- if (textures != nullptr)
+ if (textures)
{
- for (auto i = 0u; i < texture_count; i++)
+ for (u32 i = 0; i < this->origin()->texture_count; i++)
{
- auto texture = (*textures)[i];
-
- if (texture == nullptr)
- continue;
+ Texture *texture = (*textures)[i];
+ if (!texture) continue;
texture->update(engine->time);
-
- auto index = std::to_string(i);
-
- auto texture_resolution = "g_Texture" + index + "Resolution";
- auto texture_translation = "g_Texture" + index + "Translation";
- auto texture_rotation = "g_Texture" + index + "Rotation";
-
- /*
- glm::vec4 resolution = {
- object->size[0],
- object->size[1],
- texture->texture_resolution[2],
- texture->texture_resolution[3]
- };
- rshader->set_uniform(texture_resolution, TYPE_VEC4, glm::value_ptr(resolution));
- */
- rshader->set_uniform(texture_resolution, TYPE_VEC4, glm::value_ptr(texture->texture_resolution));
- rshader->set_uniform(texture_translation, TYPE_VEC2, glm::value_ptr(texture->texture_translation));
- rshader->set_uniform(texture_rotation, TYPE_VEC4, glm::value_ptr(texture->texture_rotation));
-
texture->bind(i);
+
+ std::string index = std::to_string(i);
+ std::string texture_resolution = "g_Texture" + index + "Resolution";
+ std::string texture_translation = "g_Texture" + index + "Translation";
+ std::string texture_rotation = "g_Texture" + index + "Rotation";
+ shader->set_uniform(texture_resolution, TYPE_VEC4, glm::value_ptr(*texture->texture_resolution));
+ shader->set_uniform(texture_translation, TYPE_VEC2, glm::value_ptr(texture->texture_translation));
+ shader->set_uniform(texture_rotation, TYPE_VEC4, glm::value_ptr(texture->texture_rotation));
}
}
f32 adjusted_time = engine->time * engine->rate;
- rshader->set_uniform("g_Time", TYPE_FLOAT, &adjusted_time);
+ shader->set_uniform("g_Time", TYPE_FLOAT, &adjusted_time);
- rshader->set_uniform("g_TexelSize", TYPE_VEC2, glm::value_ptr(engine->view.texel_size));
- rshader->set_uniform("g_TexelSizeHalf", TYPE_VEC2, glm::value_ptr(engine->view.texel_half_size));
+ shader->set_uniform("g_TexelSize", TYPE_VEC2, glm::value_ptr(engine->view.texel_size));
+ shader->set_uniform("g_TexelSizeHalf", TYPE_VEC2, glm::value_ptr(engine->view.texel_half_size));
- if (object) {
- glm::vec2 cursor_pos = engine->view.cursor_pos;
- rshader->set_uniform("g_PointerPosition", TYPE_VEC2, glm::value_ptr(cursor_pos));
- } else {
- rshader->set_uniform("g_PointerPosition", TYPE_VEC2, glm::value_ptr(engine->view.cursor_pos));
+ if (model)
+ {
+ mat4x4 inverse = glm::inverse(*model);
+ shader->set_uniform("g_ModelViewProjectionMatrix", TYPE_MAT4, glm::value_ptr(*model));
+ shader->set_uniform("g_ModelViewProjectionMatrixInverse", TYPE_MAT4, glm::value_ptr(inverse));
+ shader->set_uniform("g_EffectModelViewProjectionMatrix", TYPE_MAT4, glm::value_ptr(engine->default_mat));
}
- mat4x4 _model, _inverse;
- if (!model)
- _model = mat4x4(1.f);
- else
- _model = *model;
-
- _inverse = glm::inverse(_model);
-
- rshader->set_uniform("g_ModelViewProjectionMatrix", TYPE_MAT4, glm::value_ptr(_model));
- rshader->set_uniform("g_ModelViewProjectionMatrixInverse", TYPE_MAT4, glm::value_ptr(_inverse));
-
- if (object != nullptr)
+ if (object)
{
- rshader->set_uniform("g_Alpha", TYPE_FLOAT, &object->alpha);
- rshader->set_uniform("g_Color", TYPE_VEC3, glm::value_ptr(object->color));
+ vec2 cursor_pos = engine->view.cursor_pos;
+ if (object->passthrough)
+ {
+ cursor_pos[0] -= object->size[0] / 2.f;
+ cursor_pos[1] -= object->size[1] / 2.f;
+ }
+ cursor_pos[0] /= engine->view.width;
+ cursor_pos[1] /= engine->view.height;
+ shader->set_uniform("g_PointerPosition", TYPE_VEC2, glm::value_ptr(cursor_pos));
+ shader->set_uniform("g_Alpha", TYPE_FLOAT, &object->alpha);
+ shader->set_uniform("g_Color", TYPE_VEC3, glm::value_ptr(object->color));
+ shader->set_uniform("g_Color4", TYPE_VEC4, glm::value_ptr(object->color4));
}
#ifdef BUILD_AUDIO
if (engine->audio_enabled)
{
- g_mutex_lock(&engine->visualizer->mutex);
+ engine->vis->update();
+
+ glUniform1fv(shader->get_uniform_location("g_AudioSpectrum64Right"), 64, engine->vis->bars_right.data());
+ glUniform1fv(shader->get_uniform_location("g_AudioSpectrum64Left"), 64, engine->vis->bars_left.data());
- glUniform1fv(rshader->uniform_loc("g_AudioSpectrum64Left"), 64, &engine->visualizer->bars_64_left[0]);
- glUniform1fv(rshader->uniform_loc("g_AudioSpectrum64Right"), 64, &engine->visualizer->bars_64_right[0]);
+ glUniform1fv(shader->get_uniform_location("g_AudioSpectrum32Right"), 32, engine->vis->bars_32_right.data());
+ glUniform1fv(shader->get_uniform_location("g_AudioSpectrum32Left"), 32, engine->vis->bars_32_left.data());
+
+ glUniform1fv(shader->get_uniform_location("g_AudioSpectrum16Right"), 16, engine->vis->bars_16_right.data());
+ glUniform1fv(shader->get_uniform_location("g_AudioSpectrum16Left"), 16, engine->vis->bars_16_left.data());
+ }
+ else
+ {
+#else
+ static std::array<f32, 64> empty_bars = { };
- glUniform1fv(rshader->uniform_loc("g_AudioSpectrum32Left"), 32, &engine->visualizer->bars_32_left[0]);
- glUniform1fv(rshader->uniform_loc("g_AudioSpectrum32Right"), 32, &engine->visualizer->bars_32_right[0]);
+ glUniform1fv(shader->get_uniform_location("g_AudioSpectrum64Left"), 64, empty_bars.data());
+ glUniform1fv(shader->get_uniform_location("g_AudioSpectrum64Right"), 64, empty_bars.data());
- glUniform1fv(rshader->uniform_loc("g_AudioSpectrum16Left"), 16, &engine->visualizer->bars_16_left[0]);
- glUniform1fv(rshader->uniform_loc("g_AudioSpectrum16Right"), 16, &engine->visualizer->bars_16_right[0]);
+ glUniform1fv(shader->get_uniform_location("g_AudioSpectrum32Left"), 32, empty_bars.data());
+ glUniform1fv(shader->get_uniform_location("g_AudioSpectrum32Right"), 32, empty_bars.data());
- g_mutex_unlock(&engine->visualizer->mutex);
+ 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
}
#endif
}
Shader::~Shader()
{
- if (rshader != nullptr)
- {
- delete rshader;
- }
-
- for (auto &uniform : uniforms)
- {
- delete uniform;
- }
}
diff --git a/src/shader.h b/src/shader.h
index 593ffa2..1ce4209 100644
--- a/src/shader.h
+++ b/src/shader.h
@@ -1,7 +1,6 @@
#ifndef _SHADER_H
#define _SHADER_H
-#include "json.h"
#include "texture.h"
#define MAX_TEXTURES 8
@@ -11,18 +10,35 @@ namespace Mauri
struct Uniform
{
+ Uniform() { this->value = &this->default_value; }
+
std::string name;
std::string uname;
+ std::string precision = "";
+
UniformType type;
- vec4 *value = nullptr;
+
vec4 default_value = vec4(0.f);
+ vec4 *value;
};
struct Combo
{
+ Combo(const std::string &name, s32 value)
+ : name(name), value(value)
+ {
+ str_to_upper(this->name);
+ }
std::string name;
s32 value;
- std::string to_string();
+ auto to_string() const -> const std::string;
+};
+
+struct Variable
+{
+ std::string name;
+ UniformType type;
+ auto to_string() const -> const std::string;
};
class Engine;
@@ -31,31 +47,40 @@ class Object;
class Shader
{
public:
- Shader(Parser *p, const std::string &name);
+ Shader(const std::string &name);
+ Shader(Shader *origin);
~Shader();
std::string name;
- std::vector<Uniform *> uniforms;
std::vector<Combo> combos;
+ std::vector<Uniform *> uniforms;
- std::array<std::string, MAX_TEXTURES> textures = {""};
- std::array<std::string, MAX_TEXTURES> texture_combos = {""};
+ std::array<std::string, MAX_TEXTURES> textures = { };
+ std::array<std::string, MAX_TEXTURES> texture_combos = { };
u32 texture_count = 0;
- void bind(Engine *engine, Object *object, mat4x4 *model, std::array<Texture *, MAX_TEXTURES> *textures);
- void compile();
+ std::stringstream vs_source;
+ std::stringstream fs_source;
+
+ std::vector<Variable> variables;
- private:
- std::string vs_source;
- std::string fs_source;
+ auto origin() -> Shader * { return this->origin_ ? this->origin_ : this; }
- RenderShader *rshader = nullptr;
+ auto compile(const std::vector<Combo> &combo_overrides) -> RenderShader *;
- void build_shader_source(Parser *p, const std::string &isource, std::string &res, bool root);
+ auto bind(RenderShader *shader, Engine *engine, Object *object, mat4x4 *model,
+ const std::array<Texture *, MAX_TEXTURES> *textures) -> void;
+
+private:
+ Shader *origin_ = nullptr;
+
+ auto build_shader_source(const std::string_view &isource, std::stringstream &out) -> void;
};
+extern auto get_shader(const std::string &name) -> Shader *;
+
} // namespace Mauri
#endif // _SHADER_H
diff --git a/src/texture.cc b/src/texture.cc
index 0cc2699..21dfd90 100644
--- a/src/texture.cc
+++ b/src/texture.cc
@@ -1,11 +1,14 @@
-#define STB_IMAGE_IMPLEMENTATION
-#include <stb_image.h>
-
#define STB_IMAGE_WRITE_IMPLEMENTATION
+#define STBI_NO_FAILURE_STRINGS
+#define STB_IMAGE_STATIC
#include <stb_image_write.h>
-#include <s3tc.h>
+#define STB_IMAGE_IMPLEMENTATION
+#define STBI_NO_STDIO
+#include <stb_image.h>
+
#include <lz4.h>
+#include <s3tc.h>
#include "texture.h"
@@ -13,81 +16,67 @@ using namespace Mauri;
Texture::Texture(Asset *asset)
{
- hash = asset->hash;
+ this->wrapped = false;
- //auto type = asset->reads(9);
- //auto itype = asset->reads(9);
+ //std::string_view type = asset->reads(9);
+ //std::string_view itype = asset->reads(9);
asset->seek(18);
- auto format = (TextureFormat)asset->read<u32>();
-
- flags.i = asset->read<u32>();
-
- is_gif = flags.map.IS_GIF == 1;
+ TextureFormat format = (TextureFormat)asset->read<u32>();
- auto texture_width = asset->read<u32>();
- auto texture_height = asset->read<u32>();
+ this->flags.i = asset->read<u32>();
- width = asset->read<u32>();
- height = asset->read<u32>();
+ //u32 texture_width = asset->read<u32>();
+ //u32 texture_height = asset->read<u32>();
+ asset->seek(8);
- texture_resolution[0] = texture_width;
- texture_resolution[1] = texture_height;
- texture_resolution[2] = width;
- texture_resolution[3] = height;
+ this->width = asset->read<u32>();
+ this->height = asset->read<u32>();
asset->seek(4);
- auto container = asset->reads(9);
+ std::string_view container = asset->reads(9);
TextureVersion version;
+ bool has_container = false;
- auto iformat = -1;
-
- auto image_count = asset->read<u32>();
+ u32 image_count = asset->read<u32>();
if (container.compare(0, 8, "TEXB0003") == 0)
{
+ has_container = asset->read<s32>() != -1;
version = TEXB0003;
- iformat = asset->read<u32>();
}
else if (container.compare(0, 8, "TEXB0002") == 0)
{
version = TEXB0002;
}
- else if (container.compare(0, 8, "TEXB0001") == 0)
- {
- version = TEXB0001;
- }
+ //else if (container.compare(0, 8, "TEXB0001") == 0)
else
{
- version = UNKNOWN;
- log_error("unknown texture version (%s)", asset->path.c_str());
+ version = TEXB0001;
}
- textures.resize(image_count);
+ this->textures.resize(image_count);
+ this->texture_resolutions.resize(image_count);
- for (auto s = 0u; s < image_count; s++)
+ for (u32 s = 0; s < image_count; s++)
{
- auto mm_count = asset->read<u32>();
-
- textures[s] = new RenderTexture(flags.map.NO_INTERPOLATION, flags.map.CLAMP_UV, true, mm_count);
+ u32 mm_count = asset->read<u32>();
- texture = textures[s];
+ bool clamp = this->flags.m.CLAMP_UV == 1;
+ bool no_interp = this->flags.m.NO_INTERPOLATION == 1;
+ RenderTexture *texture = new RenderTexture(no_interp, clamp, true, mm_count);
+ this->textures[s] = texture;
+ this->texture_resolutions[s] = vec4{0.f, 0.f, this->width, this->height};
- for (auto i = 0u; i < mm_count; i++)
+ for (u32 i = 0; i < mm_count; i++)
{
- auto mwidth = asset->read<u32>();
- auto mheight = asset->read<u32>();
-
- if (i == 0)
- {
- texture->width = mwidth;
- texture->height = mheight;
- }
+ u32 mm_width = asset->read<u32>();
+ u32 mm_height = asset->read<u32>();
- auto lz4_compressed = false;
- auto decompressed_byte_count = 0;
+ bool lz4_compressed = false;
+ u32 decompressed_byte_count = 0;
if (version == TEXB0002 || version == TEXB0003)
{
@@ -95,97 +84,131 @@ Texture::Texture(Asset *asset)
decompressed_byte_count = asset->read<u32>();
}
- auto byte_count = asset->read<u32>();
+ u32 byte_count = asset->read<u32>();
+ if (!lz4_compressed) decompressed_byte_count = byte_count;
- if (!lz4_compressed)
- decompressed_byte_count = byte_count;
-
- auto buffer = asset->ptr();
+ byte *buffer = asset->ptr();
if (lz4_compressed)
{
- auto decompressed = new char[decompressed_byte_count];
+ char *decompressed = new char[decompressed_byte_count];
LZ4_decompress_safe((char *)buffer, decompressed,
byte_count, decompressed_byte_count);
buffer = (byte *)decompressed;
}
- if (iformat == -1)
+ if (!has_container)
{
+ assert(buffer);
switch (format)
{
- case RGBA8888: {
+ case RGBA8888:
texture->format = GL_RGBA;
- texture->upload(buffer, mwidth, mheight, i);
+ texture->upload(buffer, mm_width, mm_height, i, false);
break;
- }
- case DXT5: {
- auto decompressed = new u32[decompressed_byte_count];
- BlockDecompressImageDXT5(mwidth, mheight, buffer, decompressed);
+ case DXT5:
+ {
+ u32 *decompressed = new u32[decompressed_byte_count];
+ BlockDecompressImageDXT5(mm_width, mm_height, buffer, decompressed);
texture->format = GL_RGBA;
- texture->upload((byte *)decompressed, mwidth, mheight, i, true);
+ assert(decompressed);
+ texture->upload((byte *)decompressed, mm_width, mm_height, i, true);
delete[] decompressed;
break;
}
- case DXT1: {
- auto decompressed = new u32[decompressed_byte_count * 2];
- BlockDecompressImageDXT1(mwidth, mheight, buffer, decompressed);
+ case DXT1:
+ {
+ u32 *decompressed = new u32[decompressed_byte_count * 2];
+ BlockDecompressImageDXT1(mm_width, mm_height, buffer, decompressed);
texture->format = GL_RGBA;
- texture->upload((byte *)decompressed, mwidth, mheight, i, true);
+ assert(decompressed);
+ texture->upload((byte *)decompressed, mm_width, mm_height, i, true);
delete[] decompressed;
break;
}
case DXT3:
- log_warn("%s", "DXT3 Texture");
+ warn("DXT3 texture");
break;
case RG88:
texture->format = GL_RG;
- texture->upload(buffer, mwidth, mheight, i);
+ texture->upload(buffer, mm_width, mm_height, i);
break;
case R8:
texture->format = GL_RED;
- texture->upload(buffer, mwidth, mheight, i);
+ texture->upload(buffer, mm_width, mm_height, i);
break;
default:
- log_warn("%s", "Uknown Texture");
+ warn("uknown texture format");
break;
}
+ if (i == 0)
+ {
+ this->textures[s]->width = mm_width;
+ this->textures[s]->height = mm_height;
+ }
}
else
{
s32 w, h, channels;
- byte *data = stbi_load_from_memory(buffer, byte_count, &w, &h, &channels, 4);
- texture->format = GL_RGBA;
- texture->upload(data, mwidth, mheight, i);
- free(data);
+ byte *data = stbi_load_from_memory(buffer, byte_count, &w, &h, &channels, 0);
+ assert(data);
+ switch (channels)
+ {
+ case 1:
+ texture->format = GL_RED;
+ break;
+ case 2:
+ texture->format = GL_RG;
+ break;
+ case 3:
+ texture->format = GL_RGB;
+ break;
+ case 4:
+ default:
+ texture->format = GL_RGBA;
+ break;
+ }
+ texture->upload(data, w, h, i);
+ stbi_image_free(data);
+ if (i == 0)
+ {
+ this->textures[s]->width = w;
+ this->textures[s]->height = h;
+ }
}
- if (lz4_compressed)
- delete[] buffer;
+ if (lz4_compressed) delete[] buffer;
asset->seek(byte_count);
}
+
+ this->texture_resolutions[s][0] = this->textures[s]->width;
+ this->texture_resolutions[s][1] = this->textures[s]->height;
}
- texture = textures.front();
+ this->texture = this->textures[0];
+ this->texture_resolution = &this->texture_resolutions[0];
- if (is_gif)
+ if (this->is_gif())
{
- auto gif_container = asset->reads(9);
-
- auto frame_count = asset->read<u32>();
+ std::string_view gif_container = asset->reads(9);
+ u32 gif_frame_count = asset->read<u32>();
- if (gif_container.compare(0, 8, "TEXS0002") == 0) {}
+ if (gif_container.compare(0, 8, "TEXS0002") == 0)
+ {
+ //this->flags.m.IS_GIF = 0;
+ }
else if (gif_container.compare(0, 8, "TEXS0003") == 0)
{
- gif_width = asset->read<u32>();
- gif_height = asset->read<u32>();
+ this->gif_width = asset->read<u32>();
+ this->gif_height = asset->read<u32>();
}
- for (auto i = 0u; i < frame_count; i++)
+ this->frames.resize(gif_frame_count);
+
+ for (u32 i = 0; i < gif_frame_count; i++)
{
- // See TextureFrame
- frames.push_back(TextureFrame {
+ this->frames[i] = TextureFrame{
asset->read<u32>(),
asset->read<f32>(),
asset->read<f32>(),
@@ -194,59 +217,70 @@ Texture::Texture(Asset *asset)
asset->read<f32>(),
asset->read<f32>(),
asset->read<f32>(),
- });
+ };
}
}
asset->reset();
}
-void Texture::save_to_file(const std::string &filename)
+Texture::Texture(RenderFramebuffer *buffer)
{
- stbi_write_png(filename.c_str(), texture->width, texture->height,
- 4, texture->pixels.data(), 4 * texture->width);
+ this->wrapped = true;
+ this->texture = buffer->texture;
+ this->width = buffer->width;
+ this->height = buffer->height;
+ this->texture->width = buffer->width;
+ this->texture->height = buffer->height;
+ this->texture_resolutions.resize(1);
+ this->texture_resolutions[0][0] = buffer->width;
+ this->texture_resolutions[0][1] = buffer->height;
+ this->texture_resolutions[0][2] = buffer->width;
+ this->texture_resolutions[0][3] = buffer->height;
+ this->texture_resolution = &this->texture_resolutions[0];
}
-void Texture::update(f32 time)
+auto Texture::update(f32 time) -> void
{
- if (wrapped || !is_gif)
- return;
-
- if (time >= gif_update)
- {
- auto frame = &frames[gif_frame_index];
+ if (!this->is_gif() || time < this->gif_update) return;
- texture = textures[frame->id];
+ TextureFrame *frame = &this->frames[this->gif_index];
- // Scale texture cordinates to size of one frame.
- texture_rotation[0] = frame->width / texture->width;
- texture_rotation[1] = 0.0;
- texture_rotation[2] = 0.0;
- texture_rotation[3] = frame->height / texture->height;
+ this->texture = this->textures[frame->id];
+ this->texture_resolution = &this->texture_resolutions[frame->id];
- // Offset texture cordinates to the current frame
- // in the spritesheet.
- texture_translation[0] = frame->x / texture->width;
- texture_translation[1] = frame->y / texture->height;
+ // Scale texture cordinates to size of one frame.
+ this->texture_rotation[0] = frame->width / (f32)this->texture->width;
+ //this->texture_rotation[1] = 0.f;
+ //this->texture_rotation[2] = 0.f;
+ this->texture_rotation[1] = frame->unknown0 / (f32)this->texture->width;
+ this->texture_rotation[2] = frame->unknown1 / (f32)this->texture->height;
+ this->texture_rotation[3] = frame->height / (f32)this->texture->height;
- gif_frame_index++;
+ // Offset texture cordinates to the current frame
+ // in the spritesheet.
+ this->texture_translation[0] = frame->x / (f32)this->texture->width;
+ this->texture_translation[1] = frame->y / (f32)this->texture->height;
- if (gif_frame_index >= frames.size())
- gif_frame_index = 0;
+ this->gif_index = (this->gif_index + 1) % this->frames.size();
+ this->gif_update = time + frame->frame_time;
+}
- gif_update = time + frame->frame_time;
- }
+auto Texture::bind(s32 index) -> void
+{
+ this->texture->bind(index);
}
-Texture::~Texture()
+auto Texture::save_to_file(const std::string &filename) -> void
{
- if (!wrapped)
+ for (u32 i = 0; i < this->textures.size(); i++)
{
- delete texture;
+ 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);
}
}
-void Texture::bind(s32 index)
+Texture::~Texture()
{
- texture->bind(index);
+ if (!this->wrapped) delete this->texture;
}
diff --git a/src/texture.h b/src/texture.h
index cf6491d..c552037 100644
--- a/src/texture.h
+++ b/src/texture.h
@@ -2,12 +2,13 @@
#define _TEXTURE_H
#include "gl.h"
-#include "util.h"
#include "assets.h"
namespace Mauri
{
+enum TextureVersion { TEXB0001, TEXB0002, TEXB0003 };
+
enum TextureFormat
{
RGBA8888 = 0,
@@ -18,14 +19,6 @@ enum TextureFormat
R8 = 9
};
-enum TextureVersion
-{
- UNKNOWN,
- TEXB0001,
- TEXB0002,
- TEXB0003
-};
-
struct TextureFlags
{
bool NO_INTERPOLATION : 1;
@@ -50,45 +43,40 @@ class Texture
{
public:
Texture(Asset *asset);
- Texture() {}
-
+ Texture(RenderFramebuffer *buffer);
~Texture();
- s32 width;
- s32 height;
+ bool wrapped;
- union {
- u32 i;
- TextureFlags map;
- } flags;
+ RenderTexture *texture;
- u64 hash;
+ u32 width;
+ u32 height;
- bool wrapped = false;
+ union { u32 i; TextureFlags m; } flags = { 0 };
- bool is_gif;
+ auto is_gif() const -> bool
+ {
+ return this->flags.m.IS_GIF == 1;
+ }
u32 gif_width;
u32 gif_height;
+ u32 gif_index = 0;
+ f32 gif_update = 0.f;
- u32 gif_frame_index = 0;
+ vec4 *texture_resolution;
+ vec2 texture_translation = vec2(0.f);
+ vec4 texture_rotation = vec4(0.f);
- f32 gif_update = 0;
-
- std::vector<TextureFrame> frames;
-
- vec4 texture_resolution;
- vec2 texture_translation;
- vec4 texture_rotation;
-
- RenderTexture *texture;
+ auto bind(s32 index) -> void;
+ auto update(f32 time) -> void;
+ auto save_to_file(const std::string &filename) -> void;
+ private:
std::vector<RenderTexture *> textures;
-
- void bind(s32 index);
- void update(f32 time);
- void save_pixels(byte *buffer, s32 mwidth, s32 mheight);
- void save_to_file(const std::string &filename);
+ std::vector<vec4> texture_resolutions;
+ std::vector<TextureFrame> frames;
};
} // namespace Mauri
diff --git a/src/util.cc b/src/util.cc
index a9d7664..8a02572 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -3,14 +3,14 @@
namespace Mauri
{
-s32 next_power_of_two(s32 n)
+auto str_to_lower(std::string &s) -> void
{
- n--;
- n |= n >> 1;
- n |= n >> 2;
- n |= n >> 4;
- n |= n >> 8;
- return ++n;
-};
+ 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 3b88745..c0c4084 100644
--- a/src/util.h
+++ b/src/util.h
@@ -2,14 +2,17 @@
#define _UTIL_H
#include <stdint.h>
-#include <nlohmann/json.hpp>
+
#include <glm/glm.hpp>
+#include <glm/gtx/matrix_major_storage.hpp>
#include <glm/gtc/type_ptr.hpp>
+#include <glm/gtx/string_cast.hpp>
+#include <nlohmann/json.hpp>
#include "log.h"
-using namespace nlohmann;
using namespace glm;
+using namespace nlohmann;
#define FRAME_STEP 0
#define UNIFORM_DEBUG 0
@@ -35,7 +38,21 @@ typedef unsigned char byte;
namespace Mauri
{
-extern s32 next_power_of_two(s32 n);
+
+template<typename ... Args>
+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_t>(size_s);
+ std::unique_ptr<char[]> buf(new char[size]);
+ std::snprintf(buf.get(), size, format.c_str(), args ...);
+ return std::string(buf.get(), buf.get() + size - 1);
}
+auto str_to_lower(std::string &s) -> void;
+auto str_to_upper(std::string &s) -> void;
+
+} // namespace Mauri
+
#endif // _UTIL_H
diff --git a/src/vis.cc b/src/vis.cc
new file mode 100644
index 0000000..7b52808
--- /dev/null
+++ b/src/vis.cc
@@ -0,0 +1,286 @@
+#include <cmath>
+
+#include "vis.h"
+
+using namespace Mauri;
+
+static const f32 gausian_array[] = {0.242f, 0.399f, 0.242f};
+
+auto Visualizer::calc_cutoff() -> void
+{
+ f64 freqconst = std::log10(freq_cap_low / (f64)freq_cap_high) / ((1.0 / (BAR_COUNT + 1.0)) - 1.0);
+
+ for (s32 i = 0; i <= BAR_COUNT; i++)
+ {
+ freqconst_per_bin[i] = freq_cap_high * std::pow(10.0,
+ (freqconst * -1) + (((i + 1.0) / (BAR_COUNT + 1.0)) * freqconst));
+
+ f64 freq = freqconst_per_bin[i] / (sample_rate / 2.0);
+
+ cutoff_low[i] = std::floor(freq * (sample_count / 4.0));
+
+ if (i == 0) continue;
+
+ if (cutoff_low[i] <= cutoff_low[i - 1])
+ {
+ cutoff_low[i] = cutoff_low[i - 1] + 1;
+ }
+
+ cutoff_high[i - 1] = cutoff_low[i - 1];
+ }
+}
+
+auto Visualizer::gaussian(f32 *bars) -> void
+{
+ for (s32 i = 1; i < BAR_COUNT - 1; i++)
+ {
+ bars[i] = bars[i - 1] * gausian_array[0] + bars[i] * gausian_array[1] + bars[i + 1] * gausian_array[2];
+ }
+}
+
+auto Visualizer::monstercat_smoothing(f32 *bars) -> void
+{
+ std::array<f32, BAR_COUNT> smoothing_factors;
+
+ for (s32 i = 0; i < BAR_COUNT; i++)
+ {
+ smoothing_factors[i] = std::pow(1.5, i);
+ }
+
+ for (s32 i = 1; i < BAR_COUNT; i++)
+ {
+ for (s32 j = 0; j < BAR_COUNT; j++)
+ {
+ if (i == j) continue;
+ f32 weighted = bars[i] / smoothing_factors[std::abs(i - j)];
+ if (bars[j] < weighted)
+ {
+ bars[j] = weighted;
+ }
+ }
+ }
+}
+
+auto Visualizer::update_bars(f32 *bars, f32 *bars_32, f32 *bars_16, f32 *bars_falloff, fftw_complex *out) -> void
+{
+ for (s32 i = 0; i < BAR_COUNT; i++)
+ {
+ f64 magnitude = 0.0;
+
+ s32 low = floor(cutoff_low[i]);
+ s32 high = floor(cutoff_high[i]);
+
+ for (s32 s = low; s <= high && s < (sample_count / 2); ++s)
+ {
+ magnitude += std::sqrt((out[s][0] * out[s][0]) + (out[s][1] * out[s][1]));
+ }
+
+ f32 *bar;
+
+ if (i < BAR_COUNT / 2) bar = &bars[((BAR_COUNT / 2) - 1) - i];
+ else bar = &bars[i];
+
+ *bar = magnitude / (cutoff_high[i] - cutoff_low[i] + 1.f);
+ *bar *= std::log2(2 + i) * (100.0 / BAR_COUNT);
+ *bar = std::pow(*bar, 0.5);
+
+ f32 falloff_value = std::min(bars_falloff[i] * 0.945f, bars_falloff[i] - 1.f);
+
+ bars_falloff[i] = std::max(falloff_value, *bar);
+ }
+
+ monstercat_smoothing(bars_falloff);
+
+ for (s32 i = 0; i < BAR_COUNT; i++)
+ {
+ bars[i] = bars_falloff[i] / 2500.f;
+ }
+
+ const s32 scale_32 = BAR_COUNT / 32;
+
+ for (s32 i = 0; i < 32; i++)
+ {
+ s32 s = i * scale_32;
+ bars_32[i] = 0.f;
+ for (s32 j = 0; j < scale_32; j++)
+ {
+ bars_32[i] += bars[s + j];
+ }
+ bars_32[i] /= (f32)scale_32;
+ }
+
+ const s32 scale_16 = BAR_COUNT / 16;
+
+ for (s32 i = 0; i < 16; i++)
+ {
+ s32 s = i * scale_16;
+ bars_16[i] = 0.f;
+ for (s32 j = 0; j < scale_16; j++)
+ {
+ bars_16[i] += bars[s + j];
+ }
+ bars_16[i] /= (f32)scale_16;
+ }
+}
+
+auto Visualizer::update() -> void
+{
+ if (this->sample_processed) return;
+
+ g_mutex_lock(&this->mutex);
+
+ if (!this->sample) return;
+
+ GstBuffer *buffer = gst_sample_get_buffer(sample);
+
+ GstMapInfo info;
+ gst_buffer_map(buffer, &info, GST_MAP_READ);
+
+ Sample *samples = (Sample *)(info.data);
+
+ for (s32 i = 0; i < sample_count; i++)
+ {
+ in_left[i] = (f64)samples[i].left;
+ in_right[i] = (f64)samples[i].right;
+ }
+
+ fftw_execute(this->plan_left);
+ fftw_execute(this->plan_right);
+
+ update_bars(this->bars_left.data(), this->bars_32_left.data(),
+ this->bars_16_left.data(), this->bars_left_falloff.data(), this->out_left);
+ update_bars(this->bars_right.data(), this->bars_32_right.data(),
+ this->bars_16_right.data(), this->bars_right_falloff.data(), this->out_right);
+
+ gst_buffer_unmap(buffer, &info);
+
+ this->sample_processed = true;
+
+ g_mutex_unlock(&this->mutex);
+}
+
+auto Visualizer::update_sample() -> void
+{
+ GstSample *sample;
+ g_signal_emit_by_name(this->appsink, "pull-sample", &sample);
+
+ if (this->sample)
+ {
+ gst_sample_unref(this->sample);
+ }
+ else
+ {
+ GstBuffer *buffer = gst_sample_get_buffer(sample);
+
+ GstCaps *caps = gst_sample_get_caps(sample);
+ GstStructure *structure = gst_caps_get_structure(caps, 0);
+ gst_structure_get_int(structure, "rate", &this->sample_rate);
+
+ gst_caps_unref(caps);
+
+ this->sample_count = gst_buffer_get_size(buffer) / sizeof(Sample);
+
+ this->in_left = (f64 *)fftw_malloc(sizeof(f64) * this->sample_count);
+ this->in_right = (f64 *)fftw_malloc(sizeof(f64) * this->sample_count);
+
+ this->out_left = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * this->sample_count);
+ this->out_right = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * this->sample_count);
+
+ memset(this->out_left, 0, sizeof(fftw_complex) * this->sample_count);
+ memset(this->out_right, 0, sizeof(fftw_complex) * this->sample_count);
+
+ this->calc_cutoff();
+
+ this->plan_left = fftw_plan_dft_r2c_1d(this->sample_count, this->in_left, this->out_left, FFTW_ESTIMATE);
+ this->plan_right = fftw_plan_dft_r2c_1d(this->sample_count, this->in_right, this->out_right, FFTW_ESTIMATE);
+ }
+
+ this->sample = sample;
+ this->sample_processed = false;
+}
+
+static auto new_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));
+
+ if (!msg) return 0;
+
+ switch (msg->type)
+ {
+ case GST_MESSAGE_ERROR:
+ error("gstreamer pipeline died, audio won't work");
+ break;
+ default:
+ break;
+ }
+
+ gst_message_unref(msg);
+
+ return 0;
+}
+
+auto Visualizer::run() -> bool
+{
+ g_mutex_init(&this->mutex);
+
+ this->pipeline = gst_pipeline_new(nullptr);
+
+ this->pulsesrc = gst_element_factory_make("pulsesrc", nullptr);
+ this->appsink = gst_element_factory_make("appsink", nullptr);
+
+ if (this->pulsesrc == nullptr || this->appsink == nullptr)
+ {
+ error("failed to create gstreamer pipeline");
+ return false;
+ }
+
+ g_object_set(this->appsink, "emit-signals", TRUE, nullptr);
+
+ gst_bin_add_many(GST_BIN(this->pipeline), this->pulsesrc, this->appsink, nullptr);
+ gst_element_link(this->pulsesrc, this->appsink);
+
+ 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->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);
+
+ //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);
+ */
+}
diff --git a/src/vis.h b/src/vis.h
new file mode 100644
index 0000000..65261c7
--- /dev/null
+++ b/src/vis.h
@@ -0,0 +1,87 @@
+#ifndef _VISUALIZER_H
+#define _VISUALIZER_H
+
+#include <atomic>
+#include <fftw3.h>
+#include <gst/gst.h>
+
+#include "util.h"
+
+#define BAR_COUNT 64
+
+namespace Mauri
+{
+
+struct Sample
+{
+ s16 left;
+ s16 right;
+};
+
+class Visualizer
+{
+ public:
+ Visualizer() {}
+ ~Visualizer();
+
+ std::array<f32, 16> bars_16_left;
+ std::array<f32, 16> bars_16_right;
+
+ std::array<f32, 32> bars_32_left;
+ std::array<f32, 32> bars_32_right;
+
+ std::array<f32, BAR_COUNT> bars_left = { };
+ std::array<f32, BAR_COUNT> bars_right = { };
+
+ std::array<f32, BAR_COUNT> bars_left_falloff = { };
+ std::array<f32, BAR_COUNT> bars_right_falloff = { };
+
+ GMutex mutex;
+
+ GstBus *bus;
+ GstElement *pipeline;
+
+ auto update() -> void;
+ auto update_sample() -> void;
+
+ auto run() -> bool;
+
+ private:
+ GstElement *pulsesrc;
+ GstElement *appsink;
+
+ GThread *thread;
+
+ gulong signal_handler;
+
+ GstSample *sample = nullptr;
+ std::atomic<bool> sample_processed = false;
+
+ f64 *in_left = nullptr;
+ f64 *in_right = nullptr;
+
+ fftw_plan plan_left;
+ fftw_plan plan_right;
+
+ fftw_complex *out_left = nullptr;
+ fftw_complex *out_right = nullptr;
+
+ std::array<f32, BAR_COUNT + 1> cutoff_low = { };
+ std::array<f32, BAR_COUNT + 1> cutoff_high = { };
+ std::array<f32, BAR_COUNT + 1> freqconst_per_bin = { };
+
+ u32 freq_cap_low = 20;
+ u32 freq_cap_high = 25000;
+
+ s32 sample_rate;
+ s32 sample_count;
+
+ auto calc_cutoff() -> void;
+ auto gaussian(f32 *bars) -> void;
+ auto monstercat_smoothing(f32 *bars) -> void;
+ auto update_bars(f32 *bars, f32 *bars_32, f32 *bars_16, f32 *bars_falloff, fftw_complex *out) -> void;
+};
+
+} // namespace Mauri
+
+#endif // _VISUALIZER_H
diff --git a/src/visualizer.cc b/src/visualizer.cc
deleted file mode 100644
index 8ef34d0..0000000
--- a/src/visualizer.cc
+++ /dev/null
@@ -1,303 +0,0 @@
-#include <cmath>
-
-#include "assets.h"
-#include "visualizer.h"
-
-using namespace Mauri;
-
-static const float gausian_array[] = {.242, .399, .242};
-
-void Visualizer::calc_cutoff()
-{
- f64 freqconst = std::log10(low_freq_cap / (f64)high_freq_cap) /
- ((1.0 / (BAR_COUNT + 1.0)) - 1.0);
-
- for (auto i = 0; i <= BAR_COUNT; ++i)
- {
- freqconst_per_bin[i] = high_freq_cap * std::pow(10.0, (freqconst * -1) +
- (((i + 1.0) / (BAR_COUNT + 1.0)) * freqconst));
-
- f64 freq = freqconst_per_bin[i] / (sample_rate / 2.0);
-
- low_cutoff[i] = std::floor(freq * (sample_count / 4.0));
-
- if (i <= 0) continue;
-
- if (low_cutoff[i] <= low_cutoff[i - 1])
- low_cutoff[i] = low_cutoff[i - 1] + 1;
-
- high_cutoff[i - 1] = low_cutoff[i - 1];
- }
-}
-
-void Visualizer::gaussian_blur(bool right)
-{
- f32 *bars = (right) ? (f32 *)bars_64_right : (f32 *)bars_64_left;
-
- for (auto i = 1; i < BAR_COUNT - 1; i++)
- {
- bars[i] = bars[i - 1] * gausian_array[0] +
- bars[i] * gausian_array[1] + bars[i + 1] * gausian_array[2];
- }
-}
-
-void Visualizer::monstercat_smoothing(bool right)
-{
- f32 *bars = (right) ? (f32 *)bars_64_right_falloff : (f32 *)bars_64_left_falloff;
-
- std::array<f32, BAR_COUNT> smoothing_factors;
-
- for (auto i = 0; i < BAR_COUNT; ++i)
- {
- smoothing_factors[i] = std::pow(1.5, i);
- }
-
- for (auto i = 1; i < BAR_COUNT; ++i)
- {
- for (auto j = 0; j < BAR_COUNT; ++j)
- {
- if (i == j) continue;
-
- const auto weighted_value = bars[i] / smoothing_factors[(s32)(std::abs(i - j))];
-
- if (bars[j] < weighted_value)
- {
- bars[j] = weighted_value;
- }
- }
- }
-}
-
-void Visualizer::update_bars(bool right)
-{
- f32 *bars_64, *bars_32, *bars_16, *bars_falloff;
- fftw_complex *out;
-
- if (right)
- {
- bars_64 = &bars_64_right[0];
- bars_32 = &bars_32_right[0];
- bars_16 = &bars_16_right[0];
- bars_falloff = &bars_64_right_falloff[0];
- out = &out_right[0];
- }
- else
- {
- bars_64 = &bars_64_left[0];
- bars_32 = &bars_32_left[0];
- bars_16 = &bars_16_left[0];
- bars_falloff = &bars_64_left_falloff[0];
- out = &out_left[0];
- }
-
- for (auto i = 0; i < BAR_COUNT; i++)
- {
- f64 magnitude = 0.0;
-
- for (auto s = (s32)low_cutoff[i]; s <= high_cutoff[i] && s < (sample_count / 2); ++s)
- {
- magnitude += std::sqrt((out[s][0] * out[s][0]) + (out[s][1] * out[s][1]));
- }
-
- f32 *bar;
-
- if (i < BAR_COUNT / 2)
- {
- bar = &bars_64[((BAR_COUNT / 2) - 1) - i];
- }
- else
- {
- bar = &bars_64[i];
- }
-
- *bar = magnitude / (high_cutoff[i] - low_cutoff[i] + 1);
-
- *bar *= std::log2(2 + i) * (100.0 / BAR_COUNT);
- *bar = std::pow(*bar, 0.5);
-
- auto falloff_value = std::min(
- bars_falloff[i] * 0.85,
- bars_falloff[i] - 1.0);
-
- bars_falloff[i] = std::max((f32)falloff_value, *bar);
- }
-
- //monstercat_smoothing(right);
-
- for (auto i = 0; i < BAR_COUNT; i++)
- {
- bars_64[i] = bars_falloff[i] / 5500;
- }
-
- for (auto i = 0; i < BAR_COUNT / 2; i++)
- {
- s32 index = i * 2;
-
- bars_32[i] = 0;
- bars_32[i] += bars_64[index];
- bars_32[i] += bars_64[index + 1];
-
- bars_32[i] /= 2.0;
- }
-
- for (auto i = 0; i < BAR_COUNT / 4; i++)
- {
- s32 index = i * 4;
-
- bars_16[i] = 0;
- bars_16[i] += bars_64[index];
- bars_16[i] += bars_64[index + 1];
- bars_16[i] += bars_64[index + 2];
- bars_16[i] += bars_64[index + 3];
-
- bars_16[i] /= 4.0;
- }
-}
-
-void Visualizer::update_sample()
-{
- GstSample *sample;
-
- g_signal_emit_by_name(appsink, "pull-sample", &sample);
-
- GstBuffer *buffer = gst_sample_get_buffer(sample);
-
- GstMapInfo info;
- gst_buffer_map(buffer, &info, GST_MAP_READ);
-
- Sample *samples = (Sample *)(info.data);
-
- g_mutex_lock(&mutex);
-
- for (auto i = 0; i < sample_count; i++)
- {
- in_left[i] = (f64)samples[i].left;
- in_right[i] = (f64)samples[i].right;
- }
-
- fftw_execute(p_left);
- fftw_execute(p_right);
-
- gst_sample_unref(sample);
-
- g_mutex_unlock(&mutex);
-}
-
-void Visualizer::update()
-{
- g_mutex_lock(&mutex);
-
- update_bars(true);
- update_bars(false);
-
- g_mutex_unlock(&mutex);
-}
-
-static GstFlowReturn new_sample_callback(GstElement *appsink, gpointer *udata)
-{
- Visualizer *v = (Visualizer *)udata;
-
- v->update_sample();
- v->update();
-
- return GST_FLOW_OK;
-}
-
-static void *main_thread(void *data)
-{
- Visualizer *v = (Visualizer *)data;
-
- GstMessage *msg = gst_bus_timed_pop_filtered(v->bus, GST_CLOCK_TIME_NONE,
- (GstMessageType)(GST_MESSAGE_ERROR | GST_MESSAGE_EOS));
-
- switch (msg->type)
- {
- case GST_MESSAGE_ERROR:
- log_error("%s", "gstreamer pipeline died, audio won't work");
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-Visualizer::Visualizer()
-{
- g_mutex_init(&mutex);
-
- GstElement *pulsesrc;
-
- pipeline = gst_pipeline_new(NULL);
-
- pulsesrc = gst_element_factory_make("pulsesrc", NULL);
- appsink = gst_element_factory_make("appsink", NULL);
-
- if (!pulsesrc || !appsink)
- {
- log_error("%s", "failed to create pipeline");
- return;
- }
-
- g_object_set(appsink, "emit-signals", TRUE, NULL);
-
- g_object_set(pulsesrc, "device", "0", NULL);
-
- gst_bin_add_many(GST_BIN(pipeline), pulsesrc, appsink, NULL);
- gst_element_link(pulsesrc, appsink);
-
- gst_element_set_state(pipeline, GST_STATE_PLAYING);
-
- bus = gst_element_get_bus(pipeline);
-
- GstSample *sample;
-
- g_signal_emit_by_name(appsink, "pull-sample", &sample);
-
- GstBuffer *buffer = gst_sample_get_buffer(sample);
-
- GstCaps *caps = gst_sample_get_caps(sample);
- GstStructure *structure = gst_caps_get_structure(caps, 0);
-
- gst_structure_get_int(structure, "rate", &sample_rate);
-
- gst_caps_unref(caps);
-
- sample_count = gst_buffer_get_size(buffer) / sizeof(Sample);
-
- in_left = (f64 *)fftw_malloc(sizeof(f64) * sample_count);
- in_right = (f64 *)fftw_malloc(sizeof(f64) * sample_count);
-
- out_left = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * sample_count);
- out_right = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * sample_count);
-
- memset(out_left, 0, sizeof(fftw_complex) * sample_count);
- memset(out_right, 0, sizeof(fftw_complex) * sample_count);
-
- calc_cutoff();
-
- p_left = fftw_plan_dft_r2c_1d(sample_count, in_left, out_left, FFTW_ESTIMATE);
- p_right = fftw_plan_dft_r2c_1d(sample_count, in_right, out_right, FFTW_ESTIMATE);
-
- g_signal_connect(appsink, "new-sample", G_CALLBACK(new_sample_callback), this);
-
- thread = g_thread_new(NULL, main_thread, this);
-}
-
-Visualizer::~Visualizer()
-{
- fftw_free(in_left);
- fftw_free(in_right);
-
- fftw_free(out_left);
- fftw_free(out_right);
-
- gst_bus_post(bus, gst_message_new_eos(GST_OBJECT(pipeline)));
-
- g_thread_join(thread);
-
- gst_element_set_state(pipeline, GST_STATE_NULL);
- gst_object_unref(pipeline);
-
- g_mutex_clear(&mutex);
-}
diff --git a/src/visualizer.h b/src/visualizer.h
deleted file mode 100644
index 2094d8a..0000000
--- a/src/visualizer.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef _VISUALIZER_H
-#define _VISUALIZER_H
-
-#include <gst/gst.h>
-#include <fftw3.h>
-
-#include "util.h"
-
-#define BAR_COUNT 64
-
-namespace Mauri
-{
-
-struct Sample
-{
- s16 left;
- s16 right;
-};
-
-class Visualizer
-{
-public:
- Visualizer();
-
- ~Visualizer();
-
- f32 bars_16_left[16];
- f32 bars_16_right[16];
-
- f32 bars_32_left[32];
- f32 bars_32_right[32];
-
- f32 bars_64_left[BAR_COUNT];
- f32 bars_64_right[BAR_COUNT];
-
- f32 bars_64_left_falloff[BAR_COUNT] = {0};
- f32 bars_64_right_falloff[BAR_COUNT] = {0};
-
- GstElement *pipeline;
- GstBus *bus;
-
- GMutex mutex;
- GThread *thread;
-
- void update();
- void update_sample();
-
-private:
- GstElement *appsink;
-
- f64 *in_left;
- f64 *in_right;
-
- fftw_complex *out_left;
- fftw_complex *out_right;
-
- fftw_plan p_left;
- fftw_plan p_right;
-
- f32 low_cutoff[BAR_COUNT + 1] = {0};
- f32 high_cutoff[BAR_COUNT + 1] = {0};
-
- f32 freqconst_per_bin[BAR_COUNT + 1] = {0};
-
- u32 high_freq_cap = 25000;
- u32 low_freq_cap = 20;
-
- u32 sample_count;
- s32 sample_rate;
-
- void calc_cutoff();
- void gaussian_blur(bool right);
- void update_bars(bool right);
- void monstercat_smoothing(bool right);
-};
-
-} // namespace Mauri
-
-#endif // _VISUALIZER_H