added timeline slider and export animation frames

This commit is contained in:
2017-05-15 00:43:37 +01:00
parent 95509956f3
commit 7b99f0510a
10 changed files with 132 additions and 12 deletions

View File

@@ -393,6 +393,12 @@
<!--<panel-color id="panel-color"/>-->
</scroll>
</node>
<!-- timeline -->
<node height="100%" width="1" grow="1" dir="col" justify="flex-end">
<border color=".3 .3 .3 .4" height="50" width="100%" pad="10">
<slider-h id="frames-slider"></slider-h>
</border>
</node>
</node>
<!-- status bar -->
<!--<border height="30" width="100%" color=".15" border-color=".3" dir="row" pad="0 0 0 10" align="center">

View File

@@ -47,7 +47,6 @@ bool App::mouse_scroll(float x, float y, float delta)
e.m_scroll_delta = delta * 0.1f;
auto ret = layout[main_id]->on_event(&e);
layout[main_id]->update();
LOG("wheel x %.2f y %.2f", x, y);
return ret == kEventResult::Consumed;
}
bool App::mouse_cancel(int button)

View File

@@ -232,7 +232,7 @@ void App::initLayout()
button->on_click = [this,button](Node*) {
if (canvas)
{
//canvas->m_canvas->export_anim(data_path);
canvas->m_canvas->export_anim(data_path);
}
};
}
@@ -368,6 +368,29 @@ void App::initLayout()
{
toolbar->m_flood_events = true;
}
if (auto* slider = layout[main_id]->find<NodeSliderH>("frames-slider"))
{
slider->on_value_changed = [this](Node*, float value)
{
auto& c = *ui::Canvas::I;
for (int i = 0; i < c.m_layers.size(); i++)
{
auto l = layers->get_layer_at(i);
layers->handle_layer_opacity(l, .0f);
}
int current_layer = (int)floor(value * c.m_layers.size());
auto l = layers->get_layer_at(current_layer);
layers->handle_layer_selected(l);
layers->handle_layer_opacity(l, 1.f);
if (current_layer > 0)
{
auto l = layers->get_layer_at(current_layer - 1);
layers->handle_layer_opacity(l, .25f);
}
};
}
};
LOG("initializing layout xml");
if (layout.m_loaded)

View File

@@ -451,7 +451,6 @@ void ui::Canvas::resize(int width, int height)
{
l.create(width, height, "");
}
m_latlong.create(width * 4, height * 2); // NOTE: w and h must be equal to make sense
}
bool ui::Canvas::create(int width, int height)
{
@@ -473,7 +472,6 @@ bool ui::Canvas::create(int width, int height)
{
l.create(width, height, "");
}
m_latlong.create(width * 4, height * 2); // NOTE: w and h must be equal to make sense
return true;
}
@@ -506,7 +504,6 @@ void ui::Canvas::clear_context()
m_tex[i].destroy();
m_tex2[i].destroy();
}
m_latlong.destroy();
};
void ui::Canvas::export_equirectangular(std::string data_path)
@@ -522,6 +519,10 @@ void ui::Canvas::export_equirectangular(std::string data_path)
glViewport(0, 0, m_width, m_height);
glDisable(GL_BLEND);
RTT m_latlong;
m_latlong.create(m_width * 4, m_height * 2); // NOTE: w and h must be equal to make sense
GLuint cube_id;
glGenTextures(1, &cube_id);
glBindTexture(GL_TEXTURE_CUBE_MAP, cube_id);
for (GLuint i = 0; i < 6; i++)
@@ -603,6 +604,83 @@ void ui::Canvas::export_equirectangular(std::string data_path)
int ret = stbi_write_png(name, m_latlong.getWidth(), m_latlong.getHeight(), 4, latlong_data.get(), m_latlong.stride());
}
glDeleteTextures(1, &cube_id);
m_latlong.destroy();
// restore viewport and clear color states
blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
glViewport(vp[0], vp[1], vp[2], vp[3]);
glClearColor(cc[0], cc[1], cc[2], cc[3]);
glActiveTexture(GL_TEXTURE0);
}
void ui::Canvas::export_anim(std::string data_path)
{
// save viewport and clear color states
GLint vp[4];
GLfloat cc[4];
glGetIntegerv(GL_VIEWPORT, vp);
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
GLboolean blend = glIsEnabled(GL_BLEND);
// prepare common states
glViewport(0, 0, m_width, m_height);
glDisable(GL_BLEND);
glActiveTexture(GL_TEXTURE0);
RTT m_latlong;
m_latlong.create(m_width * 4, m_height * 2); // NOTE: w and h must be equal to make sense
GLuint cube_id;
glGenTextures(1, &cube_id);
glBindTexture(GL_TEXTURE_CUBE_MAP, cube_id);
for (GLuint i = 0; i < 6; i++)
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA8, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
int faces[]{
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, // front
GL_TEXTURE_CUBE_MAP_NEGATIVE_X, // right
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, // back
GL_TEXTURE_CUBE_MAP_POSITIVE_X, // left
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, // top
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, // bottom
};
for (auto layer_index : m_order)
{
for (int i = 0; i < 6; i++)
{
m_layers[layer_index].m_rtt[i].bindFramebuffer();
// copy result to cubemap
glBindTexture(GL_TEXTURE_CUBE_MAP, cube_id);
glCopyTexImage2D(faces[i], 0, GL_RGBA8, 0, 0, m_width, m_height, 0);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
m_layers[layer_index].m_rtt[i].unbindFramebuffer();
}
glViewport(0, 0, m_latlong.getWidth(), m_latlong.getHeight());
m_latlong.clear({ 1, 1, 1, 1 });
m_latlong.bindFramebuffer();
ui::ShaderManager::use(kShader::Equirect);
ui::ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f));
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
glBindTexture(GL_TEXTURE_CUBE_MAP, cube_id);
m_sampler.bind(0);
m_plane.draw_fill();
m_sampler.unbind();
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
m_latlong.unbindFramebuffer();
{
auto latlong_data = std::make_unique<uint8_t[]>(m_latlong.bytes());
m_latlong.readTextureData(latlong_data.get());
static char name[128];
sprintf(name, "%s/latlong-frame%02d.png", data_path.c_str(), layer_index);
LOG("writing %s", name);
int ret = stbi_write_png(name, m_latlong.getWidth(), m_latlong.getHeight(), 4, latlong_data.get(), m_latlong.stride());
}
}
glDeleteTextures(1, &cube_id);
m_latlong.destroy();
// restore viewport and clear color states
blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
glViewport(vp[0], vp[1], vp[2], vp[3]);

View File

@@ -89,9 +89,6 @@ public:
I->m_state = mode;
}
GLuint cube_id;
RTT m_latlong;
std::vector<Layer::Snapshot> m_layers_snapshot;
Canvas() { I = this; }
@@ -110,6 +107,7 @@ public:
void snapshot_restore();
void clear_context();
void export_equirectangular(std::string data_path);
void export_anim(std::string data_path);
void project_save(std::string data_path);
void project_open(std::string data_path);
ui::Image thumbnail_generate(int w, int h);

View File

@@ -8,10 +8,9 @@
bool LayoutManager::load(const char* path)
{
if (m_loaded)
return true; // already loaded
// if (m_loaded)
// return true; // already loaded
/*
#if !defined(__ANDROID__)
struct stat tmp_info;
if (stat(path, &tmp_info) != 0)
@@ -20,7 +19,6 @@ bool LayoutManager::load(const char* path)
return false;
m_file_info = tmp_info;
#endif // __ANDROID__
*/
m_path = path;

View File

@@ -251,6 +251,17 @@ int Node::get_child_index(Node* n)
return -1;
}
Node* Node::get_child_at(int index)
{
auto n = YGNodeGetChild(y_node, index);
for (auto& c : m_children)
{
if (c->y_node == n)
return c.get();
}
return nullptr;
}
glm::vec4 Node::get_children_rect() const
{
if (m_children.empty())

View File

@@ -184,6 +184,7 @@ public:
void move_child(Node* n, int index);
void move_child_offset(Node* n, int offset);
int get_child_index(Node* n);
Node* get_child_at(int index);
glm::vec4 get_children_rect() const;
void mouse_capture();
void mouse_release();

View File

@@ -177,6 +177,11 @@ void NodePanelLayer::add_layer()
add_layer(s);
}
NodeLayer* NodePanelLayer::get_layer_at(int index)
{
return static_cast<NodeLayer*>(m_layers_container->get_child_at(index));
}
void NodePanelLayer::remove_layer(NodeLayer* layer)
{
auto it = std::find(m_layers.begin(), m_layers.end(), m_current_layer);

View File

@@ -51,6 +51,7 @@ public:
virtual void init() override;
void add_layer();
void add_layer(const char* name);
NodeLayer* get_layer_at(int index);
void remove_layer(NodeLayer* layer);
void handle_layer_opacity(NodeLayer* target, float value);
void handle_layer_visibility(NodeLayer* target, bool visible);