#include "pch.h" #include "node_panel_animation.h" #include "node_button.h" #include "node_button_custom.h" #include "canvas.h" #include "app.h" Node* NodePanelAnimation::clone_instantiate() const { return new this_class; } void NodePanelAnimation::clone_finalize(Node* dest) const { parent::clone_finalize(dest); auto n = static_cast(dest); n->init_controls(); } void NodePanelAnimation::init() { parent::init(); init_template_file("data/dialogs/panel-animation.xml", "tpl-panel-animation"); init_controls(); } void NodePanelAnimation::init_controls() { m_layers_container = find("layers"); m_frames_container = find("frames"); m_timeline = find("timeline"); btn_add = find("btn-add"); btn_remove = find("btn-remove"); btn_up = find("btn-up"); btn_down = find("btn-down"); btn_left = find("btn-left"); btn_right = find("btn-right"); btn_duplicate = find("btn-duplicate"); btn_next = find("btn-next"); btn_prev = find("btn-prev"); btn_play = find("btn-play"); m_fps = find("fps"); m_onion = find("onion"); m_frame_label = find("frame-index"); btn_add->on_click = [this](Node*) { Canvas::I->layer().add_frame(); load_layers(); }; btn_duplicate->on_click = [this](Node*) { Canvas::I->layer().duplicate_frame(m_selected_frame_index); load_layers(); }; btn_remove->on_click = [this](Node*) { Canvas::I->layer_with_id(m_selected_frame_layer_id)->remove_frame(m_selected_frame_index); load_layers(); }; btn_up->on_click = [this](Node*) { if (auto layer = Canvas::I->layer_with_id(m_selected_frame_layer_id)) layer->set_frame_duration(m_selected_frame_index, glm::max(layer->frame_duration(m_selected_frame_index) + 1, 1)); load_layers(); }; btn_down->on_click = [this](Node*) { if (auto layer = Canvas::I->layer_with_id(m_selected_frame_layer_id)) layer->set_frame_duration(m_selected_frame_index, glm::max(layer->frame_duration(m_selected_frame_index) - 1, 1)); load_layers(); }; btn_left->on_click = [this](Node*) { if (!m_selected_frame) return; if (auto layer = Canvas::I->layer_with_id(m_selected_frame_layer_id)) m_selected_frame_index = layer->move_frame_offset(m_selected_frame_index, -1); Canvas::I->anim_goto_frame(m_selected_frame_index); load_layers(); }; btn_right->on_click = [this](Node*) { if (!m_selected_frame) return; if (auto layer = Canvas::I->layer_with_id(m_selected_frame_layer_id)) m_selected_frame_index = layer->move_frame_offset(m_selected_frame_index, +1); Canvas::I->anim_goto_frame(m_selected_frame_index); load_layers(); }; m_onion->on_select = [this] (Node* target, int index) { m_timeline->m_onion_size = m_onion->get_int(); }; m_timeline->on_frame_changed = [this] (NodeAnimationTimeline* target, int frame) { LOG("goto frame %d", frame); Canvas::I->anim_goto_frame(frame); load_layers(); }; btn_next->on_click = [this] (Node* target) { Canvas::I->anim_goto_next(); load_layers(); }; btn_prev->on_click = [this](Node* target) { Canvas::I->anim_goto_prev(); load_layers(); }; btn_play->on_click = [this] (Node* target) { static auto mode = Canvas::I->m_current_mode; auto b = static_cast(target); if (b->is_active()) { Canvas::set_mode(mode); b->set_active(false); App::I->idle_ms = 100; } else { mode = Canvas::I->m_current_mode; Canvas::set_mode(kCanvasMode::Camera); m_playback_timer = 0; b->set_active(true); App::I->idle_ms = 10; } }; } void NodePanelAnimation::load_layers() { if (!added_to_root()) return; m_layers_container->remove_all_children(); m_frames_container->remove_all_children(); auto& layers = Canvas::I->m_layers; m_selected_frame = nullptr; for (int i = 0; i < layers.size(); i++) { auto l = m_layers_container->add_child(); l->set_text(layers[i]->m_name); l->set_selected(Canvas::I->m_current_layer_idx == i); l->set_chekcbox(layers[i]->m_visible); auto film = m_frames_container->add_child_ref(); for (int fi = 0; fi < layers[i]->frames_count(); fi++) { auto b = film->add_frame(layers[i]->frame_duration(fi)); if (m_selected_frame_layer_id == layers[i]->id && m_selected_frame_index == fi) { b->set_active(true); m_selected_frame = b.get(); } b->on_click = [this, fi, lid=layers[i]->id, i] (Node* target) { auto frame = static_cast(target); if (m_selected_frame) m_selected_frame->set_active(false); frame->set_active(true); m_selected_frame = frame; m_selected_frame_layer_id = lid; m_selected_frame_index = fi; m_timeline->m_frame = fi; Canvas::I->anim_goto_frame(fi); App::I->layers->handle_layer_selected(App::I->layers->get_layer_at(i)); }; } } m_timeline->m_frame = Canvas::I->m_anim_frame; m_timeline->m_onion_size = m_onion->get_int(); update_frames(); } void NodePanelAnimation::update_frames() { int total_frames = Canvas::I->anim_duration(); int digits = (int)floor(glm::log(total_frames)); m_frame_label->set_text_format("%0*d/%d", digits, m_timeline->m_frame + 1, total_frames); } void NodePanelAnimation::on_tick(float dt) { parent::on_tick(dt); if (btn_play->is_active()) { m_playback_timer += dt; if (m_playback_timer > (1.f / m_fps->get_float())) { m_playback_timer = 0; Canvas::I->anim_goto_next(); m_timeline->m_frame = Canvas::I->m_anim_frame; update_frames(); } } } void NodePanelAnimation::added(Node* parent) { parent::added(parent); load_layers(); } ////////////////////////////////////////////////////////////////////////// Node* NodeAnimationLayer::clone_instantiate() const { return new this_class; } void NodeAnimationLayer::clone_finalize(Node* dest) const { parent::clone_finalize(dest); auto n = static_cast(dest); n->init_controls(); } void NodeAnimationLayer::init() { parent::init(); init_template_file("data/dialogs/panel-animation.xml", "tpl-layer"); init_controls(); } void NodeAnimationLayer::init_controls() { m_label = find("label"); m_visibility = find("cb"); } void NodeAnimationLayer::draw() { auto c = m_selected ? m_color_selected : m_color_normal; m_thinkness = m_selected ? 1.f : 0.f; m_color = m_mouse_inside ? m_color_hover : c; parent::draw(); } ////////////////////////////////////////////////////////////////////////// void NodeAnimationTimeline::draw() { parent::draw(); ShaderManager::use(kShader::Color); glDisable(GL_BLEND); float step = 35.f; glm::vec2 cur_pos = { m_pos.x + step * m_frame + step * 0.5f, m_pos.y + m_size.y * 0.5f }; ShaderManager::u_vec4(kShaderUniform::Col, glm::vec4(glm::vec3(m_cursor_color) * 0.5f, 1.f)); ShaderManager::u_mat4(kShaderUniform::MVP, m_proj * glm::translate(glm::vec3(cur_pos, 0)) * glm::scale(glm::vec3(step * m_onion_size * 2.f, m_size.y * 0.5f, 1)) ); m_plane.draw_fill(); ShaderManager::u_vec4(kShaderUniform::Col, m_cursor_color); ShaderManager::u_mat4(kShaderUniform::MVP, m_proj * glm::translate(glm::vec3(cur_pos, 0)) * glm::scale(glm::vec3(step * 0.25f, m_size.y * 0.75f, 1)) ); m_plane.draw_fill(); /* ShaderManager::u_mat4(kShaderUniform::MVP, m_proj * glm::translate(glm::vec3(cur_pos, 0)) * glm::scale(glm::vec3(step * 0.15f, m_size.y * 0.5f, 1)) * glm::translate(glm::vec3(0, .5, 0)) ); m_plane.draw_fill(); */ } kEventResult NodeAnimationTimeline::handle_event(Event* e) { parent::handle_event(e); static int signaled_frame = -1; auto me = static_cast(e); auto ge = static_cast(e); auto update = [&](){ auto loc = me->m_pos - m_pos; m_frame = glm::clamp((int)glm::floor(loc.x / 35.f), 0, Canvas::I->anim_duration() - 1); if (on_frame_changed && signaled_frame != m_frame) on_frame_changed(this, m_frame); signaled_frame = m_frame; }; switch (e->m_type) { case kEventType::MouseDownL: mouse_capture(); m_dragging = true; m_drag_start_frame = m_frame; update(); break; case kEventType::MouseMove: if (m_dragging) update(); break; case kEventType::MouseUpL: m_dragging = false; mouse_release(); break; case kEventType::MouseCancel: m_dragging = false; m_frame = m_drag_start_frame; mouse_release(); break; default: return kEventResult::Available; break; } return kEventResult::Consumed; }