#include "../log.h" #include "object.h" #include "scene.h" #include "pass.h" using namespace Mauri; auto Object::parse(Parser &pr, const json &root) -> Object * { Object *object = new Object(); pr.map_value(root, "id", &object->id, 0); pr.map_value(root, "name", &object->name, ""); if (root.contains("dependencies")) { for (const json &id : root["dependencies"]) { object->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. auto it = object->deps.begin(); while (it != object->deps.end()) { bool remove = ((u32)(*it) == object->id); for (auto rt = object->deps.begin(); rt != object->deps.end(); ++rt) { if (rt != it && *rt == *it) { remove = true; break; } } if (remove) object->deps.erase(it); else it++; } pr.map_value(root, "visible", &object->visible, true); pr.map_value(root, "angles", &object->angles, vec3(0.f)); pr.map_value(root, "size", &object->size, vec2(0.f)); pr.map_value(root, "scale", &object->scale, vec3(1.f)); pr.map_value(root, "origin", &object->origin, vec3(0.f)); if (object->origin[2] != 0.f) { warn("non 0 origin[2]"); object->origin[2] = 0.f; } pr.map_value(root, "color", &object->color, vec3(1.f)); pr.map_value(root, "alpha", &object->alpha, 1.f); pr.map_value(root, "colorBlendMode", &object->color_blend_mode, 0); object->color4 = vec4{object->color[0], object->color[1], object->color[2], object->alpha}; if (root.contains("image")) { const json &image = root["image"]; if (image.is_string()) object->model = Model::parse(pr, image); if (!object->model) parse_fail(object); } if (root.contains("config")) { pr.map_value(root["config"], "passthrough", &object->passthrough, false); } if (root.contains("effects")) { for (const json &effect : root["effects"]) { Effect *eff = Effect::parse(pr, effect); if (eff) object->effects.emplace_back(eff); } } return object; } auto Object::load(Engine *engine) -> void { if (this->loaded_as_dep || this->loaded) return; 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 (this->model) { if (this->model->fullscreen) this->fullscreen = true; if (this->model->passthrough) this->passthrough = true; } if (this->size[0] == 0.f) this->size[0] = this->model->width; if (this->size[1] == 0.f) this->size[1] = this->model->height; if (this->fullscreen) { this->size[0] = engine->scene->width; this->size[1] = engine->scene->height; } else if (this->passthrough) { if (this->size[0] == 0.f) this->size[0] = engine->scene->width; if (this->size[1] == 0.f) this->size[1] = engine->scene->height; } const std::string buffer_name = "_rt_imageLayerComposite_" + std::to_string(this->id) + "_"; this->buffer_a = buffer_name + "a"; this->buffer_b = buffer_name + "b"; engine->create_framebuffer(this->buffer_a, this->size[0], this->size[1], 1.f); engine->create_framebuffer(this->buffer_b, this->size[0], this->size[1], 1.f); if (this->effects.size() > 0) { for (auto it = this->effects.begin(); it != this->effects.end();) { if (!(*it)->visible) it = this->effects.erase(it); else it++; } } if (this->model) this->model->load(engine, this); for (u32 i = 0; i < this->effects.size(); i++) { this->effects[i]->load(engine, this, i == (this->effects.size() - 1)); } if (this->effects.size() != 0 && this->color_blend_mode != 0) { Pass blend_pass; blend_pass.intermediate = false; blend_pass.object = this; blend_pass.effect = nullptr; blend_pass.model = false; blend_pass.combine = true; blend_pass.target = "previous"; blend_pass.textures[0] = "previous"; blend_pass.textures[1] = COMBINE_BUFFER; blend_pass.shader = "passthroughblend"; blend_pass.combos.push_back(Combo("BLENDMODE", this->color_blend_mode)); blend_pass.combos.push_back(Combo("TRANSFORM", 1)); this->effects.back()->passes.emplace_back(new RenderPass(engine, &blend_pass)); } this->loaded = true; } auto Object::create_objects(Engine *engine, Texture *texture) -> void { 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()) { // Something about positioning is wrong, affects most gifs. } if (this->passthrough && !this->fullscreen) { this->model_model = this->combine_model; this->model_model = glm::rotate(this->model_model, this->angles[0], vec3{1.f, 0.f, 0.f}); 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 { #ifdef FRAME_STEP al_printf("%s (model):\n", this->name.c_str()); #endif this->buffer_switch = true; for (RenderPass *pass : this->passes) { #ifdef FRAME_STEP al_printf("\t%s\n", pass->shader->origin()->name.c_str()); #endif pass->draw(engine); } for (Effect *effect : this->effects) { if (effect->visible) effect->draw(engine); } } 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 (this->buffer_switch) ? this->buffer_a : this->buffer_b; } auto Object::get_texture_buffer() const -> const std::string & { return (this->buffer_switch) ? this->buffer_b : this->buffer_a; } Object::~Object() { if (this->model) delete this->model; if (this->model_object) delete this->model_object; if (this->combine_object) delete this->combine_object; for (RenderPass *pass : this->passes) { delete pass; } for (Effect *effect : this->effects) { delete effect; } }