Files
panopainter/src/node_panel_animation.cpp
2019-11-10 15:16:02 +01:00

313 lines
9.6 KiB
C++

#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<this_class*>(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<NodeScroll>("layers");
m_frames_container = find<NodeScroll>("frames");
m_timeline = find<NodeAnimationTimeline>("timeline");
btn_add = find<NodeButtonCustom>("btn-add");
btn_remove = find<NodeButtonCustom>("btn-remove");
btn_up = find<NodeButtonCustom>("btn-up");
btn_down = find<NodeButtonCustom>("btn-down");
btn_left = find<NodeButtonCustom>("btn-left");
btn_right = find<NodeButtonCustom>("btn-right");
btn_duplicate = find<NodeButtonCustom>("btn-duplicate");
btn_next = find<NodeButtonCustom>("btn-next");
btn_prev = find<NodeButtonCustom>("btn-prev");
btn_play = find<NodeButtonCustom>("btn-play");
m_fps = find<NodeComboBox>("fps");
m_onion = find<NodeComboBox>("onion");
m_frame_label = find<NodeText>("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();
Canvas::I->anim_update();
};
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<NodeButtonCustom*>(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<NodeAnimationLayer>();
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<NodeAnimationFilm>();
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<NodeAnimationFrame*>(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<this_class*>(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<NodeText>("label");
m_visibility = find<NodeCheckBox>("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<MouseEvent*>(e);
auto ge = static_cast<GestureEvent*>(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;
}