summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Opalach <andrew@akon.city> 2020-10-12 22:34:41 -0400
committerAndrew Opalach <andrew@akon.city> 2020-10-12 22:34:41 -0400
commit73f118641b2c05148eab673b2fbcf9b4e155411d (patch)
treedacf35cf395a7df820a380be3d88c1bbae5040bc
parent8df6b63ee07bbbbc515ccec904ccfa1e6ce35e71 (diff)
downloadmauri-73f118641b2c05148eab673b2fbcf9b4e155411d.tar.gz
mauri-73f118641b2c05148eab673b2fbcf9b4e155411d.tar.bz2
mauri-73f118641b2c05148eab673b2fbcf9b4e155411d.zip
misc render stuff, add visualizer
-rw-r--r--TODO2
-rw-r--r--meson.build7
-rw-r--r--nohup.out0
-rw-r--r--src/engine.cc22
-rw-r--r--src/engine.h9
-rw-r--r--src/framebuffer.cc29
-rw-r--r--src/framebuffer.h26
-rw-r--r--src/gl.cc36
-rw-r--r--src/gl.h9
-rw-r--r--src/json.h8
-rw-r--r--src/mauri.cc22
-rw-r--r--src/objects/effect.cc64
-rw-r--r--src/objects/effect.h2
-rw-r--r--src/objects/material.cc12
-rw-r--r--src/objects/object.c1
-rw-r--r--src/objects/object.cc79
-rw-r--r--src/objects/object.h12
-rw-r--r--src/objects/pass.cc160
-rw-r--r--src/objects/pass.h17
-rw-r--r--src/objects/scene.cc7
-rw-r--r--src/objects/scene.h5
-rw-r--r--src/shader.cc13
-rw-r--r--src/texture.cc53
-rw-r--r--src/texture.h52
-rw-r--r--src/util.h3
-rw-r--r--src/visualizer.cc303
-rw-r--r--src/visualizer.h80
27 files changed, 755 insertions, 278 deletions
diff --git a/TODO b/TODO
index b3fab49..47a522f 100644
--- a/TODO
+++ b/TODO
@@ -2,6 +2,8 @@
[x] pass parser as pointer everywhere
+[ ] cleanup visualizer code
+
[ ] RG88 & R8 textures
[ ] Re-think parse/load stage, parse stage could possibly be 1 stage where textures and framebuffers,
diff --git a/meson.build b/meson.build
index 482cd4a..65d37fc 100644
--- a/meson.build
+++ b/meson.build
@@ -34,7 +34,10 @@ Xrender = dependency('xrender', required: false)
Xext = dependency('xext', required: false)
GLX = dependency('glx', required: false)
-deps = [dl, json, glm, lz4, stbi, glad, glfw, fmt, s3tc, X11, Xrender, Xext, GLX]
+gstreamer = dependency('gstreamer-1.0', required: false)
+fftw3 = dependency('fftw3', required: false)
+
+deps = [dl, json, glm, lz4, stbi, glad, glfw, fmt, s3tc, X11, Xrender, Xext, GLX, gstreamer, fftw3]
src = [
'src/assets.cc',
@@ -44,9 +47,11 @@ src = [
'src/shader.cc',
'src/engine.cc',
'src/texture.cc',
+ 'src/framebuffer.cc',
'src/context.cc',
'src/context_glfw.cc',
'src/context_x11.cc',
+ 'src/visualizer.cc',
'src/objects/scene.cc',
'src/objects/object.cc',
'src/objects/model.cc',
diff --git a/nohup.out b/nohup.out
deleted file mode 100644
index e69de29..0000000
--- a/nohup.out
+++ /dev/null
diff --git a/src/engine.cc b/src/engine.cc
index c956ba9..ed4301a 100644
--- a/src/engine.cc
+++ b/src/engine.cc
@@ -4,6 +4,7 @@
#include "shader.h"
#include "src/gl.h"
#include "texture.h"
+#include "framebuffer.h"
#include "objects/object.h"
#include "objects/scene.h"
@@ -64,8 +65,6 @@ Engine::Engine(Scene *scene, Context *context, Parser *parser)
minimal_shader = new Shader(parser, "minimal");
minimal_shader->compile();
- texture_cache.reserve(100);
-
create_framebuffer(COMBINE_BUFFER, view.width, view.height, 1.f);
combine_buffer = get_framebuffer(COMBINE_BUFFER);
@@ -81,13 +80,13 @@ Texture *Engine::get_texture(Asset *asset)
{
for (auto &texture : texture_cache)
{
- if (texture.hash == asset->hash)
- return &texture;
+ if (texture->hash == asset->hash)
+ return texture;
}
- texture_cache.emplace_back(Texture(asset));
+ texture_cache.emplace_back(new Texture(asset));
- return &texture_cache.back();
+ return texture_cache.back();
}
Framebuffer *Engine::get_framebuffer(const std::string &name)
@@ -145,19 +144,19 @@ void Engine::draw()
scene->draw(this);
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ Render::bind_framebuffer(0);
default_object->bind();
minimal_shader->bind(this, &default_model_flipped);
combine_buffer->texture->bind(0);
- glBlendFunc(GL_ONE, GL_ZERO);
- glColorMask(1.f, 1.f, 1.f, 1.f);
+ Render::blend_func(GL_ONE, GL_ZERO);
+ Render::color_mask(1.f, 1.f, 1.f, 1.f);
view.center_scale_viewport();
- glDrawArrays(GL_TRIANGLES, 0, 6);
+ default_object->draw();
}
void Engine::run()
@@ -186,13 +185,12 @@ Engine::~Engine()
{
for (auto &buffer : framebuffers)
{
- buffer.second->unload();
delete buffer.second;
}
for (auto &texture : texture_cache)
{
- texture.unload();
+ delete texture;
}
delete default_object;
diff --git a/src/engine.h b/src/engine.h
index 30d8d3a..cb14cb8 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -7,6 +7,8 @@
#include "gl.h"
#include "shader.h"
#include "texture.h"
+#include "framebuffer.h"
+#include "visualizer.h"
using namespace glm;
@@ -48,6 +50,7 @@ class Engine
Parser *parser;
Context *context;
+ Visualizer *visualizer;
View view;
@@ -60,11 +63,7 @@ class Engine
Shader *minimal_shader;
- // Maximum textures that would be loaded by a wallpaper,
- // bassed on information from the parsing stage.
- u32 max_texture_count = 0;
-
- std::vector<Texture> texture_cache;
+ std::vector<Texture *> texture_cache;
Texture *get_texture(Asset *asset);
diff --git a/src/framebuffer.cc b/src/framebuffer.cc
new file mode 100644
index 0000000..15f0129
--- /dev/null
+++ b/src/framebuffer.cc
@@ -0,0 +1,29 @@
+#include "framebuffer.h"
+
+using namespace Mauri;
+
+Framebuffer::Framebuffer(std::string name, f32 width, f32 height, f32 scale)
+ : name(name)
+{
+ buffer = new RenderFramebuffer(width, height, scale);
+
+ texture = new Texture();
+
+ texture->wrapped = true;
+
+ texture->texture = buffer->texture;
+
+ texture->texture_res[0] = buffer->width;
+ texture->texture_res[1] = buffer->height;
+ texture->texture_res[2] = buffer->width;
+ texture->texture_res[3] = buffer->height;
+}
+
+Framebuffer::~Framebuffer()
+{
+ if (texture != nullptr)
+ delete texture;
+
+ if (buffer != nullptr)
+ delete buffer;
+} \ No newline at end of file
diff --git a/src/framebuffer.h b/src/framebuffer.h
new file mode 100644
index 0000000..69d224f
--- /dev/null
+++ b/src/framebuffer.h
@@ -0,0 +1,26 @@
+#ifndef _FRAMEBUFFER_H
+#define _FRAMEBUFFER_H
+
+#include "texture.h"
+#include "gl.h"
+
+namespace Mauri
+{
+
+class Framebuffer
+{
+ public:
+ Framebuffer(std::string name, f32 width, f32 height, f32 scale);
+
+ ~Framebuffer();
+
+ std::string name;
+
+ Texture *texture;
+
+ RenderFramebuffer *buffer;
+};
+
+}
+
+#endif // _FRAMEBUFFER_H \ No newline at end of file
diff --git a/src/gl.cc b/src/gl.cc
index f7291e6..627a763 100644
--- a/src/gl.cc
+++ b/src/gl.cc
@@ -42,6 +42,15 @@ void RenderObject::bind()
glBindBuffer(GL_ARRAY_BUFFER, vbo);
}
+void RenderObject::draw()
+{
+#ifdef _DEBUG_
+ if (!gl_initialized) return;
+#endif
+
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+}
+
RenderObject::RenderObject(RenderObjType type, f32 width, f32 height)
{
#ifdef _DEBUG_
@@ -141,7 +150,6 @@ RenderShader::RenderShader(const std::string &vs_source, const std::string &fs_s
if (!compile(vs_shader, vs_source.c_str(), error))
{
log_error("failed to compile vertex shader (%s)", error);
- std::cout << vs_source << "\n";
return;
}
@@ -261,6 +269,8 @@ RenderTexture::RenderTexture(bool interp, bool clamp_uv, s32 mm_count)
}
else
{
+ //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_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
}
@@ -373,3 +383,27 @@ RenderFramebuffer::~RenderFramebuffer()
glDeleteFramebuffers(1, &id);
}
+void Render::blend_func(s32 sfactor, s32 dfactor)
+{
+#ifdef _DEBUG_
+ if (!gl_initialized) return;
+#endif
+ glBlendFunc(sfactor, dfactor);
+}
+
+void Render::color_mask(f32 r, f32 g, f32 b, f32 a)
+{
+#ifdef _DEBUG_
+ if (!gl_initialized) return;
+#endif
+ glColorMask(r, g, b, a);
+}
+
+void Render::bind_framebuffer(s32 id)
+{
+#ifdef _DEBUG_
+ if (!gl_initialized) return;
+#endif
+ glBindFramebuffer(GL_FRAMEBUFFER, id);
+}
+
diff --git a/src/gl.h b/src/gl.h
index 9bbeef9..ead497f 100644
--- a/src/gl.h
+++ b/src/gl.h
@@ -38,6 +38,7 @@ class RenderObject
~RenderObject();
void bind();
+ void draw();
void set_data(float *vertices, s32 vertex_count);
private:
@@ -94,6 +95,14 @@ class RenderFramebuffer
void clear(vec4 color);
};
+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);
+};
+
} // namespace Mauri
#endif // _GL_H
diff --git a/src/json.h b/src/json.h
index 78556c7..2c3bb72 100644
--- a/src/json.h
+++ b/src/json.h
@@ -73,6 +73,14 @@ class Parser
}
type = INT;
}
+ else if (std::is_same<T, s32>::value)
+ {
+ if (jvalue.is_number())
+ {
+ *((s32 *)res) = jvalue.get<s32>();
+ }
+ type = INT;
+ }
else if (std::is_same<T, f32>::value)
{
if (jvalue.is_number())
diff --git a/src/mauri.cc b/src/mauri.cc
index f4c910d..f66e9b3 100644
--- a/src/mauri.cc
+++ b/src/mauri.cc
@@ -3,6 +3,7 @@
#include "gl.h"
#include "json.h"
#include "util.h"
+#include "visualizer.h"
#include "context.h"
#include "context_glfw.h"
@@ -21,10 +22,14 @@ s32 main(s32 argc, char *argv[])
{
srand(time(NULL));
+ gst_init(&argc, &argv);
+
+ Visualizer *v = new Visualizer();
+
//Context *context = new ContextX11(2560, 1440, "mauri", true);
//Context *context = new ContextGLFW(720, 1280, "mauri", false);
- //Context *context = new ContextGLFW(1920, 1080, "mauri", false);
- Context *context = new ContextX11(1920, 1080, "mauri", false);
+ Context *context = new ContextGLFW(1280, 720, "mauri", false);
+ //Context *context = new ContextX11(1920, 1080, "mauri", false);
//Context *context = new ContextNull(1920, 1080, "mauri", false);
if (argc == 2)
@@ -39,10 +44,12 @@ s32 main(s32 argc, char *argv[])
Scene *scene = new Scene(parser, scene_path);
- Engine engine(scene, context, &parser);
+ //context->resize_window(scene->width, scene->height);
- bool *visible;
+ Engine engine(scene, context, &parser);
+ engine.visualizer = v;
+ /*
for (auto &user : parser.values)
{
std::cout << user.first << ":\n";
@@ -64,7 +71,7 @@ s32 main(s32 argc, char *argv[])
std::cout << (*((vec3 *)value.v))[0];
break;
case VEC4:
- std::cout << (*((vec4 *)value.v))[0];
+ std::cout << (*((vec4 *)value.v))[0] << (*((vec4 *)value.v))[1];
break;
case BOOL:
std::cout << *((bool *)value.v);
@@ -77,10 +84,7 @@ s32 main(s32 argc, char *argv[])
std::cout << "\n";
}
}
-
- *visible = false;
-
- //context->resize_window(scene->width, scene->height);
+ */
engine.run();
diff --git a/src/objects/effect.cc b/src/objects/effect.cc
index fb1f4e3..33b72aa 100644
--- a/src/objects/effect.cc
+++ b/src/objects/effect.cc
@@ -18,15 +18,6 @@ using namespace Mauri;
Effect::Effect(Parser &p, json &root)
{
- p.get_value<u32>(root, "id", &id, 0);
-
- p.get_value<bool>(root, "visible", &visible, true);
-
- for (auto &pass0 : root["passes"])
- {
- passes0.emplace_back(new Pass(p, pass0, EFFECT0_PASS));
- }
-
auto asset = asset_manager()->get_file(root["file"], NONE);
if (asset->type == ASSET_VOID)
@@ -34,8 +25,15 @@ Effect::Effect(Parser &p, json &root)
auto file = json::parse(asset->as_string());
+ 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"])
+ {
+ passes0.emplace_back(new Pass(p, pass0, EFFECT0_PASS));
+ }
+
for (auto &pass1 : file["passes"])
{
passes1.emplace_back(new Pass(p, pass1, EFFECT1_PASS));
@@ -47,7 +45,7 @@ Effect::Effect(Parser &p, json &root)
}
}
-void Effect::load(Engine *engine, Object *object, bool last_effect)
+void Effect::load(Engine *engine, Object *object, bool last)
{
buffer_id = fmt::format("_{}_{}", object->id, id);
@@ -57,44 +55,26 @@ void Effect::load(Engine *engine, Object *object, bool last_effect)
object->size[1], fbo.scale);
}
- /*
- for (u32 i = 0; i < passes0.size(); i++)
- {
- Pass *pass = new Pass();
-
- pass->combine = (i == (passes0.size() - 1)) && last_effect;
-
- pass->object = object;
- pass->effect = this;
-
- passes0[i]->load(engine, EFFECT0_PASS, pass);
- passes1[i]->load(engine, EFFECT1_PASS, pass);
-
- this->passes.push_back(new RenderPass(engine, pass));
- }
- */
-
u32 index = 0;
for (u32 i = 0; i < passes1.size(); i++)
{
- Pass *pass = new Pass();
-
- pass->combine = (i == (passes1.size() - 1)) && last_effect;
+ Pass pass;
- pass->object = object;
- pass->effect = this;
+ pass.object = object;
+ pass.effect = this;
- if (passes1[i]->command == COPY)
- passes1[i]->load(engine, EFFECT1_PASS, pass);
- else
+ pass.combine = i == (passes1.size() - 1) && last;
+
+ if (passes1[i]->command != COPY)
{
- passes0[index]->load(engine, EFFECT0_PASS, pass);
- passes1[i]->load(engine, EFFECT1_PASS, pass);
+ passes0[index]->load(engine, EFFECT0_PASS, &pass);
index++;
}
- this->passes.push_back(new RenderPass(engine, pass));
+ passes1[i]->load(engine, EFFECT1_PASS, &pass);
+
+ this->passes.push_back(new RenderPass(engine, &pass));
}
}
@@ -102,9 +82,17 @@ void Effect::draw(Engine *engine)
{
if (!visible)
return;
+
+#ifdef _DEBUG_
+ //std::cout << name << ":\n";
+#endif
for (auto &pass : passes)
{
+#ifdef _DEBUG_
+ //if (pass->shader != nullptr)
+ // std::cout << "\t" << pass->shader->name << "\n";
+#endif
pass->draw(engine);
}
}
diff --git a/src/objects/effect.h b/src/objects/effect.h
index 713c36f..40110a8 100644
--- a/src/objects/effect.h
+++ b/src/objects/effect.h
@@ -29,7 +29,7 @@ class Effect
std::string buffer_id;
- void load(Engine *engine, Object *object, bool last_effect);
+ void load(Engine *engine, Object *object, bool last);
void draw(Engine *engine);
private:
diff --git a/src/objects/material.cc b/src/objects/material.cc
index ae25cee..465fab1 100644
--- a/src/objects/material.cc
+++ b/src/objects/material.cc
@@ -39,16 +39,16 @@ void Material::load(Engine *engine, Object *object, MaterialType type, Pass *pas
pass0->load(engine, MATERIAL_PASS, pass);
break;
case MATERIAL_MODEL:
- Pass *pass = new Pass();
+ Pass _pass;
- pass->combine = no_effects;
+ _pass.object = object;
+ _pass.effect = nullptr;
- pass->object = object;
- pass->effect = nullptr;
+ _pass.combine = no_effects && !object->passthrough && !object->fullscreen;
- pass0->load(engine, MATERIAL_ONLY_PASS, pass);
+ pass0->load(engine, MATERIAL_ONLY_PASS, &_pass);
- object->passes.push_back(new RenderPass(engine, pass));
+ object->passes.push_back(new RenderPass(engine, &_pass));
break;
}
diff --git a/src/objects/object.c b/src/objects/object.c
new file mode 100644
index 0000000..b498fd4
--- /dev/null
+++ b/src/objects/object.c
@@ -0,0 +1 @@
+/
diff --git a/src/objects/object.cc b/src/objects/object.cc
index efd3155..18bfdf0 100644
--- a/src/objects/object.cc
+++ b/src/objects/object.cc
@@ -34,8 +34,9 @@ Object::Object(Parser &p, json &root)
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<u32>(root, "colorblendmode", &color_blend_mode, 0);
+ p.get_value<s32>(root, "colorBlendMode", &color_blend_mode, 0);
p.get_value<bool>(root, "visible", &visible, true);
@@ -63,12 +64,12 @@ void Object::get_model(f32 width, f32 height, bool flip)
model = glm::translate(model, origin * 2.f);
- model = glm::scale(model, scale);
-
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});
+ model = glm::scale(model, scale);
+
mat4x4 _ortho = glm::ortho(-width, width, height, -height, 0.f, 1.f);
if (flip)
@@ -92,7 +93,6 @@ void Object::load(Engine *engine)
if (dep_object != nullptr)
dep_object->load(engine);
}
-
if (image != nullptr)
{
@@ -117,26 +117,28 @@ void Object::load(Engine *engine)
origin[1] = size[1] / 2.f;
}
- auto width = size[0];
- auto height = size[1];
-
buffer_a = fmt::format("_rt_imageLayerComposite_{}_a", id);
buffer_b = fmt::format("_rt_imageLayerComposite_{}_b", id);
- engine->create_framebuffer(buffer_a, width, height, 1.f);
- engine->create_framebuffer(buffer_b, width, height, 1.f);
+ engine->create_framebuffer(buffer_a, size[0], size[1], 1.f);
+ engine->create_framebuffer(buffer_b, size[0], size[1], 1.f);
get_model(engine->view.width, engine->view.height, effects.size() == 0);
- ortho = glm::ortho(-width, width, -height, height, 0.f, 1.f);
+ ortho = glm::ortho(-size[0], size[0], -size[1], size[1], 0.f, 1.f);
- gl_object = new RenderObject(OBJECT, width, height);
- gl_uv_object = new RenderObject(UV_SCALE, width, height);
+ gl_object = new RenderObject(OBJECT, size[0], size[1]);
+ gl_uv_object = new RenderObject(UV_SCALE, size[0], size[1]);
+
+ //blend_shader = new Shader(engine->parser, "passthroughblend");
+ //blend_shader->combos.push_back((Combo) { "TRANSFORM", 1 });
+ //blend_shader->combos.push_back((Combo) { "BLENDMODE", color_blend_mode });
+ //blend_shader->compile();
if (image != nullptr)
image->load(engine, this, effects.size() == 0);
- for (u32 i = 0; i < effects.size(); i++)
+ for (s32 i = 0; i < effects.size(); i++)
{
effects[i]->load(engine, this, i == (effects.size() - 1));
}
@@ -146,31 +148,55 @@ void Object::load(Engine *engine)
void Object::update(Engine *engine)
{
- //if (engine->time > this->shake_tick)
+ //if (engine->time > this->shake_tick)
//{
//}
}
void Object::draw(Engine *engine)
{
- //for (auto &dep : deps)
- //{
- // if (dep == id)
- // continue;
- // auto dep_object = engine->scene->get_object_by_id(dep);
- // if (dep_object != nullptr)
- // dep_object->draw(engine);
- //}
+ if (!visible)
+ return;
+
+#ifdef _DEBUG_
+ //std::cout << name << " (model):\n";
+#endif
for (auto &pass : passes)
{
+#ifdef _DEBUG_
+ //std::cout << "\t" << pass->shader->name << "\n";;
+#endif
pass->draw(engine);
}
-
+
for (auto &effect : effects)
{
effect->draw(engine);
}
+
+ //if (!visible)
+ // return;
+
+ //engine->combine_buffer_a->buffer->bind();
+
+ //blend_shader->bind(engine, &model);
+ //gl_object->bind();
+
+ //engine->get_framebuffer_texture(get_texture_buffer())->bind(0);
+
+ //engine->combine_buffer_b->texture->bind(1);
+
+ //Render::blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ //Render::color_mask(1.f, 1.f, 1.f, 1.f);
+
+ //engine->view.default_viewport(engine->scene->width, engine->scene->height);
+
+ //gl_object->draw();
+
+ //engine->combine_buffer_a->buffer->blit(engine->combine_buffer_b->buffer->id,
+ // engine->combine_buffer_a->buffer->width,
+ // engine->combine_buffer_a->buffer->height);
}
std::string Object::get_target_buffer() const
@@ -188,11 +214,10 @@ Object::~Object()
if (image != nullptr)
delete image;
- if (gl_object != nullptr)
- delete gl_object;
+ delete gl_object;
+ delete gl_uv_object;
- if (gl_uv_object != nullptr)
- delete gl_uv_object;
+ //delete blend_shader;
for (auto &pass : passes)
{
diff --git a/src/objects/object.h b/src/objects/object.h
index 37dd2df..2ce7347 100644
--- a/src/objects/object.h
+++ b/src/objects/object.h
@@ -51,13 +51,17 @@ class Object
RenderObject *gl_uv_object = nullptr;
RenderObject *gl_object = nullptr;
- u32 color_blend_mode;
+ s32 color_blend_mode;
std::string get_target_buffer() const;
std::string get_texture_buffer() const;
- void swap_buffer() {
- this->buffer_switch = !this->buffer_switch;
+ Framebuffer *previous_buffer;
+ Texture *previous_texture;
+
+ void swap_buffer()
+ {
+ buffer_switch = !buffer_switch;
}
std::vector<RenderPass *> passes;
@@ -70,6 +74,8 @@ class Object
private:
Model *image = nullptr;
+ Shader *blend_shader;
+
vec3 angles;
vec3 color;
diff --git a/src/objects/pass.cc b/src/objects/pass.cc
index 24fc868..38e68e3 100644
--- a/src/objects/pass.cc
+++ b/src/objects/pass.cc
@@ -31,7 +31,6 @@ Pass::Pass(Parser &p, json &root, PassStage stage)
for (auto &value : _uniforms.items())
{
- // Type and uname don't matter because they are stored on the shader.
uniforms.emplace_back(
new UniformOverride({ vec4(0.f), value.key() })
);
@@ -80,13 +79,13 @@ Pass::Pass(Parser &p, json &root, PassStage stage)
break;
}
- auto _textures = root["textures"];
-
- for (int i = 0; i < _textures.size(); i++)
+ for (int i = 0; i < MAX_TEXTURES; i++)
{
- auto _texture = _textures[i];
- if (_texture.is_string())
- textures[i] = _texture;
+ auto texture = root["textures"][i];
+ if (texture.is_string())
+ {
+ textures[i] = texture;
+ }
}
for (auto &combo : root["combos"].items())
@@ -97,14 +96,12 @@ Pass::Pass(Parser &p, json &root, PassStage stage)
void Pass::load(Engine *engine, PassStage stage, Pass *pass)
{
- for (int i = 0; i < 8; i++)
+ for (int i = 0; i < MAX_TEXTURES; i++)
{
if (textures[i].empty())
continue;
pass->textures[i] = textures[i];
-
- //engine->max_texture_count++;
}
for (auto &combo : combos)
@@ -128,17 +125,13 @@ void Pass::load(Engine *engine, PassStage stage, Pass *pass)
if (pass->target == "previous")
{
- if (pass->combine)
- pass->target = COMBINE_BUFFER;
- else
- pass->target = pass->object->get_target_buffer();
-
+ pass->target = pass->object->get_target_buffer();
pass->textures[0] = pass->object->get_texture_buffer();
}
else
pass->target.append(pass->effect->buffer_id);
- for (int i = 0; i < 8; i++)
+ for (int i = 0; i < MAX_TEXTURES; i++)
{
if (binds[i].empty())
continue;
@@ -157,13 +150,8 @@ void Pass::load(Engine *engine, PassStage stage, Pass *pass)
break;
case MATERIAL_ONLY_PASS:
- if (pass->combine)
- pass->target = COMBINE_BUFFER;
- else
- {
- pass->target = pass->object->get_target_buffer();
- pass->object->swap_buffer();
- }
+ pass->target = pass->object->get_target_buffer();
+ pass->object->swap_buffer();
[[fallthrough]];
case MATERIAL_PASS:
pass->shader = shader;
@@ -175,12 +163,19 @@ Pass::~Pass()
{
if (material != nullptr)
delete material;
+
+ //for (auto &uniform : uniforms)
+ //{
+ // delete uniform;
+ //}
}
RenderPass::RenderPass(Engine *engine, Pass *pass)
{
command = pass->command;
+ combine = pass->combine;
+
if (command == COPY)
{
target = engine->get_framebuffer(pass->target);
@@ -189,14 +184,11 @@ RenderPass::RenderPass(Engine *engine, Pass *pass)
return;
}
- object = pass->object;
-
- combine = pass->combine;
- combine_blend = (BlendMode)pass->object->color_blend_mode;
+ target = engine->get_framebuffer(pass->target);
shader = new Shader(engine->parser, pass->shader);
- for (int i = 0; i < 8; i++)
+ for (int i = 0; i < MAX_TEXTURES; i++)
{
if (pass->textures[i].empty() && !shader->textures[i].empty())
pass->textures[i] = shader->textures[i];
@@ -230,28 +222,6 @@ RenderPass::RenderPass(Engine *engine, Pass *pass)
shader_uniform->value = &shader_uniform->default_value;
}
- /*
- for (auto &shader_uniform : shader->uniforms)
- {
- auto add = true;
- for (auto &pass_uniform : pass->uniforms)
- {
- if (shader_uniform->name.empty())
- continue;
- if (pass_uniform->name == shader_uniform->name)
- {
- pass_uniform->uname = shader_uniform->uname;
- pass_uniform->type = shader_uniform->type;
- add = false;
- delete shader_uniform;
- break;
- }
- }
- if (add)
- pass->uniforms.push_back(shader_uniform);
- }
- */
-
for (auto &uniform : shader->uniforms)
{
// ex: g_Texture2Resolution (vec4)
@@ -261,16 +231,7 @@ RenderPass::RenderPass(Engine *engine, Pass *pass)
{
auto index = uniform->uname[9] - '0';
if (textures[index] != nullptr)
- uniform->value = &textures[index]->texture_resolution;
- }
- }
-
- for (auto &combo : shader->combos)
- {
- if (combo.name == "AUDIOPROCESSING")
- {
- combo.value = 0;
- break;
+ uniform->value = &textures[index]->texture_res;
}
}
@@ -290,9 +251,15 @@ RenderPass::RenderPass(Engine *engine, Pass *pass)
shader->combos.push_back(pass_combo);
}
- shader->compile();
+ /*
+ for (auto &combo : shader->combos)
+ {
+ if (combo.name == "AUDIOPROCESSING")
+ combo.value = 0;
+ }
+ */
- target = engine->get_framebuffer(pass->target);
+ shader->compile();
if (pass->effect == nullptr)
{
@@ -323,13 +290,47 @@ RenderPass::RenderPass(Engine *engine, Pass *pass)
model = &engine->default_model;
}
}
+
+ /*
+ // TODO fix this
+ if (pass->effect == nullptr)
+ {
+ if (pass->object->passthrough)
+ {
+ robject = pass->object->gl_object;
+ model = &pass->object->model;
+ }
+ else if (pass->object->fullscreen)
+ {
+ robject = engine->default_object;
+ model = &engine->default_model;
+ }
+ else
+ {
+ robject = pass->object->gl_uv_object;
+ model = &pass->object->ortho;
+ }
+ }
+ else
+ {
+ robject = engine->default_object;
+ model = &engine->default_model;
+ }
+ */
}
void RenderPass::draw(Engine *engine)
{
switch (command) {
case DRAW: {
- target->buffer->bind();
+ Framebuffer *_target;
+
+ if (combine)
+ _target = engine->combine_buffer;
+ else
+ _target = target;
+
+ _target->buffer->bind();
shader->bind(engine, model);
robject->bind();
@@ -340,35 +341,24 @@ void RenderPass::draw(Engine *engine)
textures[i]->bind(i);
}
- BlendMode blend;
-
if (combine)
- blend = combine_blend;
+ {
+ Render::blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ Render::color_mask(1.f, 1.f, 1.f, 0.f);
+ }
else
- blend = NORMAL;
-
- switch (blend)
{
- case NORMAL:
- glBlendFunc(GL_ONE, GL_ZERO);
- glColorMask(1.f, 1.f, 1.f, 1.f);
- break;
- case TRANSLUCENT:
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glColorMask(1.f, 1.f, 1.f, 0.f);
- break;
+ Render::blend_func(GL_ONE, GL_ZERO);
+ Render::color_mask(1.f, 1.f, 1.f, 1.f);
}
- engine->view.default_viewport(target->buffer->width, target->buffer->height);
+ engine->view.default_viewport(_target->buffer->width, _target->buffer->height);
- glDrawArrays(GL_TRIANGLES, 0, 6);
+ robject->draw();
-#if 0
- target->buffer->blit(0, engine->context->width, engine->context->height);
-
- engine->context->swap_buffers();
- std::this_thread::sleep_for(std::chrono::seconds(1));
-#endif
+ //_target->buffer->blit(0, engine->context->width, engine->context->height);
+ //engine->context->swap_buffers();
+ //std::this_thread::sleep_for(std::chrono::seconds(2));
break;
}
diff --git a/src/objects/pass.h b/src/objects/pass.h
index ff03a05..0211596 100644
--- a/src/objects/pass.h
+++ b/src/objects/pass.h
@@ -13,6 +13,8 @@
#include "objects/object.h"
+#define MAX_TEXTURES 8
+
namespace Mauri
{
@@ -56,8 +58,8 @@ class Pass
std::string shader;
- std::array<std::string, 8> textures;
- std::array<std::string, 8> binds;
+ std::array<std::string, MAX_TEXTURES> textures;
+ std::array<std::string, MAX_TEXTURES> binds;
bool combine;
@@ -76,14 +78,14 @@ class RenderPass
RenderPass(Engine *engine, Pass *pass);
~RenderPass();
+ Shader *shader = nullptr;
+
void draw(Engine *engine);
private:
PassCommand command;
- Object *object;
-
- Shader *shader = nullptr;
+ bool combine;
Framebuffer *target;
Framebuffer *source;
@@ -91,10 +93,7 @@ class RenderPass
mat4x4 *model;
RenderObject *robject;
- bool combine;
- BlendMode combine_blend;
-
- std::array<Texture *, 8> textures = {0};
+ std::array<Texture *, MAX_TEXTURES> textures = {0};
};
} // namespace Mauri
diff --git a/src/objects/scene.cc b/src/objects/scene.cc
index afb1e69..8bb2d70 100644
--- a/src/objects/scene.cc
+++ b/src/objects/scene.cc
@@ -41,6 +41,13 @@ Scene::Scene(Parser &p, const std::string &path)
for (auto &object : root["objects"])
{
+ if (object["image"].is_null())
+ continue;
+ if (object["name"] == "Compose")
+ {
+ //std::cout << "Skiped\n";
+ //continue;
+ }
objects.emplace_back(new Object(p, object));
}
}
diff --git a/src/objects/scene.h b/src/objects/scene.h
index bd8d1b1..5c2b3a0 100644
--- a/src/objects/scene.h
+++ b/src/objects/scene.h
@@ -42,14 +42,9 @@ class Scene
void load(Engine *engine);
void draw(Engine *engine);
- s32 estimated_buffer_count();
-
Object *get_object_by_id(u32 id);
std::vector<Object *> objects;
-
- private:
- std::vector<RenderPass *> passes;
};
} // namespace Mauri
diff --git a/src/shader.cc b/src/shader.cc
index bd66c16..80b928f 100644
--- a/src/shader.cc
+++ b/src/shader.cc
@@ -219,6 +219,19 @@ void Shader::bind(Engine *engine, mat4x4 *model)
rshader->set_uniform("g_ModelViewProjectionMatrix", TYPE_MAT4, glm::value_ptr(_model));
rshader->set_uniform("g_ModelViewProjectionMatrixInverse", TYPE_MAT4, glm::value_ptr(_inverse));
+
+ g_mutex_lock(&engine->visualizer->mutex);
+
+ 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(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(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]);
+
+ g_mutex_unlock(&engine->visualizer->mutex);
}
Shader::~Shader()
diff --git a/src/texture.cc b/src/texture.cc
index 5367933..fbd894b 100644
--- a/src/texture.cc
+++ b/src/texture.cc
@@ -30,25 +30,29 @@ Texture::Texture(Asset *asset)
asset->seek(18);
- format = (TextureFormat)asset->read<u32>();
+ auto format = (TextureFormat)asset->read<u32>();
- flags.integer = asset->read<u32>();
+ TextureFlags flags;
- texture_width = asset->read<u32>();
- texture_height = asset->read<u32>();
+ flags.u.i = asset->read<u32>();
+
+ auto texture_width = asset->read<u32>();
+ auto texture_height = asset->read<u32>();
width = asset->read<u32>();
height = asset->read<u32>();
- texture_resolution[0] = texture_width;
- texture_resolution[1] = texture_height;
- texture_resolution[2] = width;
- texture_resolution[3] = height;
+ texture_res[0] = texture_width;
+ texture_res[1] = texture_height;
+ texture_res[2] = width;
+ texture_res[3] = height;
asset->seek(4);
auto container = asset->reads(9);
+ TextureVersion version;
+
auto iformat = -1;
if (container.compare(0, 8, "TEXB0003") == 0)
@@ -69,12 +73,13 @@ Texture::Texture(Asset *asset)
}
else
{
+ version = UNKNOWN;
log_error("%s", "unknown texture version");
}
auto mm_count = asset->read<u32>();
- texture = new RenderTexture(flags.map.NO_INTERPOLATION, flags.map.CLAMP_UV, mm_count);
+ texture = new RenderTexture(flags.u.flags.NO_INTERPOLATION, flags.u.flags.CLAMP_UV, mm_count);
for (int i = 0; i < mm_count; i++)
{
@@ -162,7 +167,7 @@ Texture::Texture(Asset *asset)
asset->reset();
}
-void Texture::unload()
+Texture::~Texture()
{
if (!wrapped)
delete texture;
@@ -172,31 +177,3 @@ void Texture::bind(s32 index)
{
texture->bind(index);
}
-
-Framebuffer::Framebuffer(std::string name, f32 width, f32 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;
-}
-
-void Framebuffer::unload()
-{
- if (texture != nullptr)
- {
- texture->unload();
- delete texture;
- }
-
- if (buffer != nullptr)
- delete buffer;
-}
diff --git a/src/texture.h b/src/texture.h
index e12ad18..5093e87 100644
--- a/src/texture.h
+++ b/src/texture.h
@@ -25,15 +25,22 @@ enum TextureVersion
{
TEXB0001,
TEXB0002,
- TEXB0003
+ TEXB0003,
+ UNKNOWN
};
struct TextureFlags
{
- bool NO_INTERPOLATION : 1;
- bool CLAMP_UV : 1;
- bool IS_GIF : 1;
- u32 UNKNWON : 29;
+ union {
+ struct
+ {
+ bool NO_INTERPOLATION : 1;
+ bool CLAMP_UV : 1;
+ bool IS_GIF : 1;
+ u32 UNKNWON : 29;
+ } flags;
+ u32 i;
+ } u;
};
class Texture
@@ -42,7 +49,7 @@ class Texture
Texture(Asset *asset);
Texture() {}
- ~Texture() {};
+ ~Texture();
s32 width;
s32 height;
@@ -51,42 +58,11 @@ class Texture
bool wrapped = false;
- vec4 texture_resolution;
+ vec4 texture_res;
RenderTexture *texture;
- TextureFormat format;
-
- void load(Asset *asset);
void bind(s32 index);
-
- void unload();
-
- private:
- s32 texture_width;
- s32 texture_height;
-
- union {
- TextureFlags map;
- unsigned int integer;
- } flags;
-
- TextureVersion version;
-};
-
-class Framebuffer
-{
- public:
- Framebuffer(std::string name, f32 width, f32 height, f32 scale);
-
- ~Framebuffer() {};
-
- std::string name;
-
- Texture *texture;
- RenderFramebuffer *buffer;
-
- void unload();
};
} // namespace Mauri
diff --git a/src/util.h b/src/util.h
index a1bdb40..1cd3903 100644
--- a/src/util.h
+++ b/src/util.h
@@ -12,6 +12,9 @@ typedef int32_t s32;
typedef uint64_t u64;
typedef int64_t s64;
+typedef uint16_t u16;
+typedef int16_t s16;
+
typedef uint8_t u8;
typedef int8_t s8;
diff --git a/src/visualizer.cc b/src/visualizer.cc
new file mode 100644
index 0000000..adfe851
--- /dev/null
+++ b/src/visualizer.cc
@@ -0,0 +1,303 @@
+#include <cmath>
+#include <fftw3.h>
+#include <numeric>
+#include <stdio.h>
+#include <utility>
+
+#include "assets.h"
+#include "fmt/format.h"
+#include "gst/gstcaps.h"
+#include "gst/gstelement.h"
+#include "gst/gstsample.h"
+#include "gst/gststructure.h"
+#include "log.h"
+#include "objects/material.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 (s32 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));
+
+ 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 (int 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::vector<f32> smoothing_factors;
+ smoothing_factors.reserve(BAR_COUNT);
+
+ for (int i = 0; i < BAR_COUNT; ++i)
+ {
+ smoothing_factors[i] = std::pow(1.5, i);
+ }
+
+ for (int i = 1; i < BAR_COUNT; ++i)
+ {
+ for (int j = 0; j < BAR_COUNT; ++j)
+ {
+ if (i == j) continue;
+
+ const auto weighted_value = bars[i] / smoothing_factors[(int)(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 (s32 i = 0; i < BAR_COUNT; i++)
+ {
+ f64 magnitude = 0.0;
+
+ for (s32 s = 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.90,
+ bars_falloff[i] - 1.0);
+
+ bars_falloff[i] = std::max((f32)falloff_value, *bar);
+ }
+
+ monstercat_smoothing(right);
+
+ for (s32 i = 0; i < BAR_COUNT; i++)
+ {
+ bars_64[i] = bars_falloff[i] / 5500;
+ }
+
+ for (s32 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 (s32 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);
+
+ GstMemory *mem = gst_buffer_get_memory(buffer, 0);
+
+ Sample *samples = (Sample *)(mem + mem->offset);
+
+ g_mutex_lock(&mutex);
+
+ for (s32 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);
+
+ g_mutex_unlock(&mutex);
+}
+
+void Visualizer::update()
+{
+ g_mutex_lock(&mutex);
+
+ update_bars(true);
+ update_bars(false);
+
+ g_mutex_unlock(&mutex);
+}
+
+static void *update_thread(void *data)
+{
+ Visualizer *v = (Visualizer *)data;
+
+ while (true)
+ {
+ v->update();
+ g_usleep(20000);
+ }
+}
+
+static GstFlowReturn new_sample_callback(GstElement *appsink, gpointer *udata)
+{
+ Visualizer *v = (Visualizer *)udata;
+
+ v->update_sample();
+
+ 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 wont 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(bars_64_left_falloff, 0, sizeof(f32) * BAR_COUNT);
+ memset(bars_64_right_falloff, 0, sizeof(f32) * BAR_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);
+
+ g_thread_new(NULL, update_thread, this);
+ g_thread_new(NULL, main_thread, this);
+}
+
+
diff --git a/src/visualizer.h b/src/visualizer.h
new file mode 100644
index 0000000..5155391
--- /dev/null
+++ b/src/visualizer.h
@@ -0,0 +1,80 @@
+#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];
+ f32 bars_64_right_falloff[BAR_COUNT];
+
+ GstElement *pipeline;
+ GstBus *bus;
+
+ GMutex mutex;
+
+ void update();
+ void update_sample();
+
+private:
+ GstElement *appsink;
+
+ Sample *data;
+
+ 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];
+ f32 high_cutoff[BAR_COUNT];
+
+ f32 freqconst_per_bin[BAR_COUNT];
+
+ u32 high_freq_cap = 22050;
+ u32 low_freq_cap = 30;
+
+ u32 sample_count;
+ s32 sample_rate;
+
+ void calc_cutoff();
+ void update_bars(bool right);
+ void gaussian_blur(bool right);
+ void monstercat_smoothing(bool right);
+};
+
+} // namespace Mauri
+
+#endif // _VISUALIZER_H