diff --git a/data/dialogs/panel-animation.xml b/data/dialogs/panel-animation.xml
index 8d4bfe4..969dbab 100644
--- a/data/dialogs/panel-animation.xml
+++ b/data/dialogs/panel-animation.xml
@@ -20,7 +20,7 @@
-
+
@@ -28,28 +28,38 @@
-
+
-
-
+
+
+
+
-
+
+
+
+
+
+
+
+
+
@@ -63,10 +73,16 @@
+
+
+
+
-
-
+
+
+
+
diff --git a/src/app.cpp b/src/app.cpp
index 6bc384d..12c06bd 100644
--- a/src/app.cpp
+++ b/src/app.cpp
@@ -562,7 +562,7 @@ bool App::update_ui_observer(Node *n)
n->handle_on_screen(false, true);
n->m_on_screen = true;
}
- glm::ivec4 c = glm::vec4(box.x - 1, (height / zoom - box.y - box.w - 1), box.z + 2, box.w + 2) * zoom;
+ glm::ivec4 c = glm::vec4(box.x /*- 1*/, (height / zoom - box.y - box.w /*- 1*/), box.z /*+ 2*/, box.w /*+ 2*/) * zoom;
glScissor(floorf(c.x + off_x), floorf(c.y + off_y), ceilf(c.z), ceilf(c.w));
n->draw();
return true;
diff --git a/src/app_layout.cpp b/src/app_layout.cpp
index 51cf626..38a0509 100644
--- a/src/app_layout.cpp
+++ b/src/app_layout.cpp
@@ -1447,6 +1447,7 @@ void App::initLayout()
//layout_designer[main_id]->add_child(layout_designer.instantiate("tpl-panel-animation"));
auto p = layout_designer[main_id]->add_child();
p->SetPosition(300, 300);
+ p->SetSize(600, 400);
p->m_container->add_child();
};
//layout_designer.load("data/dialogs/panel-animation.xml");
diff --git a/src/canvas.cpp b/src/canvas.cpp
index eee3c89..3e5d673 100644
--- a/src/canvas.cpp
+++ b/src/canvas.cpp
@@ -1358,6 +1358,12 @@ void Canvas::anim_goto_next() noexcept
anim_goto_frame((m_anim_frame + 1) % anim_duration());
}
+void Canvas::anim_goto_prev() noexcept
+{
+ int k = anim_duration();
+ anim_goto_frame((m_anim_frame - 1 + k) % k);
+}
+
void Canvas::flood_fill(int layer, int plane, std::vector pos, FloodData& plane_data,
float threshold, glm::vec4 dest_color, std::unique_ptr& source_color)
{
diff --git a/src/canvas.h b/src/canvas.h
index d75d40d..091eefa 100644
--- a/src/canvas.h
+++ b/src/canvas.h
@@ -112,7 +112,7 @@ public:
std::unique_ptr m_dual_stroke;
bool m_show_tmp = false;
std::vector> m_layers;
- int m_anim_frame = 1;
+ int m_anim_frame = 0;
Layer m_layers_merge;
std::vector m_plane_shape[6]; // screen space projection of the plane
glm::mat4 m_plane_unproject[6] = SIXPLETTE(glm::mat4(1));
@@ -189,6 +189,7 @@ public:
int anim_duration() const noexcept;
void anim_goto_frame(int frame) noexcept;
void anim_goto_next() noexcept;
+ void anim_goto_prev() noexcept;
void flood_fill(int layer, int plane, std::vector pos, FloodData& plane_data,
float threshold, glm::vec4 dest_color, std::unique_ptr& source_color);
void stroke_start(glm::vec3 point, float pressure);
diff --git a/src/canvas_layer.cpp b/src/canvas_layer.cpp
index b728060..84946f6 100644
--- a/src/canvas_layer.cpp
+++ b/src/canvas_layer.cpp
@@ -238,6 +238,12 @@ bool Layer::add_frame()
return m_frames.back().create(w, h);
}
+void Layer::remove_frame(int frame)
+{
+ m_frames.erase(m_frames.begin() + frame);
+ m_frame_index = glm::clamp(m_frame_index, 0, (int)m_frames.size() - 1);
+}
+
int Layer::total_duration() const noexcept
{
int duration = 0;
diff --git a/src/canvas_layer.h b/src/canvas_layer.h
index 7ff3c92..d773620 100644
--- a/src/canvas_layer.h
+++ b/src/canvas_layer.h
@@ -61,6 +61,7 @@ public:
void resize(int width, int height);
bool create(int width, int height, std::string name);
bool add_frame();
+ void remove_frame(int frame);
int total_duration() const noexcept;
void goto_frame(int frame) noexcept;
void clear(const glm::vec4& c, int frame = -1);
diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp
index 553b311..0741cef 100644
--- a/src/node_canvas.cpp
+++ b/src/node_canvas.cpp
@@ -214,10 +214,10 @@ void NodeCanvas::draw()
auto layer_index = i;
for (int plane_index = 0; plane_index < 6; plane_index++)
{
- int onion_size = 1;
+ int onion_size = App::I->animation->get_onion_size();
int frame_current = m_canvas->m_layers[layer_index]->m_frame_index;
- int frame_start = glm::max(frame_current - 1, 0);
- int frame_end = glm::min(frame_current + 1, m_canvas->m_layers[layer_index]->m_frames.size() - 1);
+ int frame_start = glm::max(frame_current - onion_size, 0);
+ int frame_end = glm::min(frame_current + onion_size, m_canvas->m_layers[layer_index]->m_frames.size() - 1);
bool faces = false;
for (int frame = frame_start; frame <= frame_end; frame++)
faces |= m_canvas->m_layers[layer_index]->face(plane_index, frame);
diff --git a/src/node_combobox.cpp b/src/node_combobox.cpp
index 6a4b813..7fba2fb 100644
--- a/src/node_combobox.cpp
+++ b/src/node_combobox.cpp
@@ -119,3 +119,8 @@ float NodeComboBox::get_float() const noexcept
{
return std::stof(m_data[m_current_index]);
}
+
+int NodeComboBox::get_int() const noexcept
+{
+ return std::stoi(m_data[m_current_index]);
+}
diff --git a/src/node_combobox.h b/src/node_combobox.h
index 60ef833..6b0edcd 100644
--- a/src/node_combobox.h
+++ b/src/node_combobox.h
@@ -16,4 +16,5 @@ public:
void set_index(int index);
float get_float(int index) const noexcept;
float get_float() const noexcept;
+ int get_int() const noexcept;
};
diff --git a/src/node_panel_animation.cpp b/src/node_panel_animation.cpp
index 4ea0235..08becf0 100644
--- a/src/node_panel_animation.cpp
+++ b/src/node_panel_animation.cpp
@@ -38,11 +38,17 @@ void NodePanelAnimation::init_controls()
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_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->m_frames[m_selected_frame_index].m_duration =
@@ -56,12 +62,24 @@ void NodePanelAnimation::init_controls()
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);
@@ -90,7 +108,11 @@ void NodePanelAnimation::load_layers()
m_frames_container->remove_all_children();
auto& layers = Canvas::I->m_layers;
m_selected_frame = nullptr;
- float max_width = 0;
+
+ float max_width = find("hscroll")->GetWidth() - 2;
+ for (int i = 0; i < layers.size(); i++)
+ max_width = glm::max(max_width, layers[i]->total_duration() * 35.f);
+
for (int i = 0; i < layers.size(); i++)
{
auto l = m_layers_container->add_child();
@@ -98,8 +120,8 @@ void NodePanelAnimation::load_layers()
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();
- film->SetWidth(layers[i]->total_duration() * 35.f);
- max_width = glm::max(max_width, layers[i]->total_duration() * 35.f);
+ //film->m_color = glm::vec4(glm::vec3(i % 2 ? .8 : .7), 1);
+ film->SetWidth(max_width - 5);
for (int fi = 0; fi < layers[i]->m_frames.size(); fi++)
{
auto b = film->add_frame(layers[i]->m_frames[fi].m_duration);
@@ -118,11 +140,35 @@ void NodePanelAnimation::load_layers()
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->SetWidth(max_width);
+ m_timeline->SetWidth(max_width - 4);
+ 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::handle_resize(glm::vec2 old_size, glm::vec2 new_size, float zoom)
+{
+ parent::handle_resize(old_size, new_size, zoom);
+ auto& layers = Canvas::I->m_layers;
+ float max_width = find("hscroll")->GetWidth() - 2;
+ for (int i = 0; i < layers.size(); i++)
+ max_width = glm::max(max_width, layers[i]->total_duration() * 35.f);
+ for (auto& film : m_frames_container->m_children)
+ film->SetWidth(max_width - 5);
+ m_timeline->SetWidth(max_width - 4);
}
void NodePanelAnimation::on_tick(float dt)
@@ -136,6 +182,7 @@ void NodePanelAnimation::on_tick(float dt)
m_playback_timer = 0;
Canvas::I->anim_goto_next();
m_timeline->m_frame = Canvas::I->m_anim_frame;
+ update_frames();
}
}
}
@@ -181,17 +228,12 @@ void NodeAnimationLayer::draw()
parent::draw();
}
-//////////////////////////////////////////////////////////////////////////
-
-
-
//////////////////////////////////////////////////////////////////////////
void NodeAnimationTimeline::draw()
{
parent::draw();
ShaderManager::use(kShader::Color);
- ShaderManager::u_vec4(kShaderUniform::Col, m_cursor_color);
glDisable(GL_BLEND);
float step = 35.f;
@@ -199,21 +241,31 @@ void NodeAnimationTimeline::draw()
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 * 0.25f, m_size.y * 0.5f, 1))
+ * glm::scale(glm::vec3(step * m_onion_size * 2.f, m_size.y * 0.5f, 1))
);
m_plane.draw_fill();
- //bool scissor = glIsEnabled(GL_SCISSOR_TEST);
- //glDisable(GL_SCISSOR_TEST);
+ 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();
- //scissor ? glEnable(GL_SCISSOR_TEST) : glDisable(GL_SCISSOR_TEST);
+*/
}
kEventResult NodeAnimationTimeline::handle_event(Event* e)
diff --git a/src/node_panel_animation.h b/src/node_panel_animation.h
index af26936..a54e18d 100644
--- a/src/node_panel_animation.h
+++ b/src/node_panel_animation.h
@@ -33,6 +33,7 @@ public:
int m_frames_count = 1;
int m_frame = 0;
+ int m_onion_size = 1;
glm::vec4 m_cursor_color = { 1, 0, 0, 1 };
virtual Node* clone_instantiate() const override { return new this_class; }
@@ -57,6 +58,8 @@ class NodePanelAnimation : public Node
NodeAnimationFrame* m_selected_frame = nullptr;
NodeAnimationTimeline* m_timeline = nullptr;
NodeComboBox* m_fps = nullptr;
+ NodeComboBox* m_onion = nullptr;
+ NodeText* m_frame_label = nullptr;
int m_selected_frame_index = -1;
uint32_t m_selected_frame_layer_id = 0;
float m_playback_timer = 0;
@@ -69,9 +72,12 @@ public:
virtual void init() override;
virtual void added(Node* parent) override;
virtual void on_tick(float dt) override;
+ virtual void handle_resize(glm::vec2 old_size, glm::vec2 new_size, float zoom) override;
void init_controls();
void load_layers();
+ void update_frames();
+ int get_onion_size() const noexcept { return m_onion->get_int(); }
};
//////////////////////////////////////////////////////////////////////////