implement load/unload frames
This commit is contained in:
@@ -1349,7 +1349,7 @@ void App::initLayout()
|
|||||||
{
|
{
|
||||||
auto& l = Canvas::I->layer();
|
auto& l = Canvas::I->layer();
|
||||||
l.m_frame_index = (int)glm::clamp<int>(
|
l.m_frame_index = (int)glm::clamp<int>(
|
||||||
floor(value * l.m_frames.size()), 0, (int)l.m_frames.size() - 1);
|
floor(value * l.frames_count()), 0, l.frames_count() - 1);
|
||||||
/*
|
/*
|
||||||
auto& c = *Canvas::I;
|
auto& c = *Canvas::I;
|
||||||
for (int i = 0; i < c.m_layers.size(); i++)
|
for (int i = 0; i < c.m_layers.size(); i++)
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ void Canvas::clear(const glm::vec4& c/*={0,0,0,1}*/)
|
|||||||
auto a = new ActionLayerClear;
|
auto a = new ActionLayerClear;
|
||||||
a->m_layer = m_layers[m_current_layer_idx];
|
a->m_layer = m_layers[m_current_layer_idx];
|
||||||
a->m_frame = layer().m_frame_index;
|
a->m_frame = layer().m_frame_index;
|
||||||
a->m_snap = std::make_shared<Layer::Snapshot>(a->m_layer->snapshot());
|
a->m_snap = std::make_shared<LayerFrame::Snapshot>(a->m_layer->snapshot());
|
||||||
a->m_color = c;
|
a->m_color = c;
|
||||||
ActionManager::add(a);
|
ActionManager::add(a);
|
||||||
|
|
||||||
@@ -1703,7 +1703,7 @@ void Canvas::import_equirectangular_thread(std::string file_path, std::shared_pt
|
|||||||
auto a = new ActionImportEquirect;
|
auto a = new ActionImportEquirect;
|
||||||
a->m_layer = layer;
|
a->m_layer = layer;
|
||||||
a->m_frame = frame;
|
a->m_frame = frame;
|
||||||
a->m_snap = std::make_shared<Layer::Snapshot>(layer->snapshot(frame));
|
a->m_snap = std::make_shared<LayerFrame::Snapshot>(layer->snapshot(frame));
|
||||||
a->m_path = file_path;
|
a->m_path = file_path;
|
||||||
ActionManager::add(a);
|
ActionManager::add(a);
|
||||||
|
|
||||||
@@ -2137,7 +2137,7 @@ bool Canvas::project_save_thread(std::string file_path, bool show_progress)
|
|||||||
fwrite(&n_layers, sizeof(int), 1, fp);
|
fwrite(&n_layers, sizeof(int), 1, fp);
|
||||||
|
|
||||||
int n_frames = std::accumulate(m_layers.begin(), m_layers.end(), 0,
|
int n_frames = std::accumulate(m_layers.begin(), m_layers.end(), 0,
|
||||||
[](int tot, auto& l) { return tot + l->m_frames.size(); });
|
[](int tot, auto& l) { return tot + l->frames_count(); });
|
||||||
if (ppi_header.doc_version.minor >= 3)
|
if (ppi_header.doc_version.minor >= 3)
|
||||||
fwrite(&n_frames, sizeof(int), 1, fp);
|
fwrite(&n_frames, sizeof(int), 1, fp);
|
||||||
|
|
||||||
@@ -2166,14 +2166,17 @@ bool Canvas::project_save_thread(std::string file_path, bool show_progress)
|
|||||||
int frames = 1;
|
int frames = 1;
|
||||||
if (ppi_header.doc_version.minor >= 3)
|
if (ppi_header.doc_version.minor >= 3)
|
||||||
{
|
{
|
||||||
frames = (int)m_layers[i]->m_frames.size();
|
frames = (int)m_layers[i]->frames_count();
|
||||||
fwrite(&frames, sizeof(int), 1, fp);
|
fwrite(&frames, sizeof(int), 1, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int fi = 0; fi < frames; fi++)
|
for (int fi = 0; fi < frames; fi++)
|
||||||
{
|
{
|
||||||
if (ppi_header.doc_version.minor >= 3)
|
if (ppi_header.doc_version.minor >= 3)
|
||||||
fwrite(&m_layers[i]->m_frames[fi].m_duration, sizeof(int), 1, fp);
|
{
|
||||||
|
int duration = m_layers[i]->frame_duration(fi);
|
||||||
|
fwrite(&duration, sizeof(int), 1, fp);
|
||||||
|
}
|
||||||
|
|
||||||
m_layers[i]->optimize(fi);
|
m_layers[i]->optimize(fi);
|
||||||
auto snap = m_layers[i]->snapshot(fi);
|
auto snap = m_layers[i]->snapshot(fi);
|
||||||
@@ -2315,7 +2318,7 @@ bool Canvas::project_open_thread(std::string file_path)
|
|||||||
fread(&n_frames, sizeof(int), 1, fp);
|
fread(&n_frames, sizeof(int), 1, fp);
|
||||||
|
|
||||||
const int bytes = m_width * m_height * 4;
|
const int bytes = m_width * m_height * 4;
|
||||||
Layer::Snapshot snap;
|
LayerFrame::Snapshot snap;
|
||||||
snap.create(m_width, m_height); // allocate single data, no box should be bigger
|
snap.create(m_width, m_height); // allocate single data, no box should be bigger
|
||||||
|
|
||||||
int progress = 0;
|
int progress = 0;
|
||||||
@@ -2365,7 +2368,10 @@ bool Canvas::project_open_thread(std::string file_path)
|
|||||||
if (fi > 0)
|
if (fi > 0)
|
||||||
layer->add_frame();
|
layer->add_frame();
|
||||||
if (ppi_header.doc_version.minor >= 3)
|
if (ppi_header.doc_version.minor >= 3)
|
||||||
fread(&layer->m_frames[fi].m_duration, sizeof(int), 1, fp);
|
{
|
||||||
|
int duration = layer->frame_duration(fi);
|
||||||
|
fread(&duration, sizeof(int), 1, fp);
|
||||||
|
}
|
||||||
snap.clear();
|
snap.clear();
|
||||||
for (int plane_index = 0; plane_index < 6; plane_index++)
|
for (int plane_index = 0; plane_index < 6; plane_index++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ public:
|
|||||||
I->on_mode_changed(prev, mode);
|
I->on_mode_changed(prev, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Layer::Snapshot> m_layers_snapshot;
|
std::vector<LayerFrame::Snapshot> m_layers_snapshot;
|
||||||
|
|
||||||
Canvas() { I = this; }
|
Canvas() { I = this; }
|
||||||
~Canvas() { destroy(); }
|
~Canvas() { destroy(); }
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ public:
|
|||||||
|
|
||||||
struct ActionLayerClear : public Action
|
struct ActionLayerClear : public Action
|
||||||
{
|
{
|
||||||
std::shared_ptr<Layer::Snapshot> m_snap;
|
std::shared_ptr<LayerFrame::Snapshot> m_snap;
|
||||||
std::shared_ptr<Layer> m_layer;
|
std::shared_ptr<Layer> m_layer;
|
||||||
int m_frame = 0;
|
int m_frame = 0;
|
||||||
glm::vec4 m_color;
|
glm::vec4 m_color;
|
||||||
@@ -34,7 +34,7 @@ struct ActionLayerClear : public Action
|
|||||||
|
|
||||||
struct ActionImportEquirect : public Action
|
struct ActionImportEquirect : public Action
|
||||||
{
|
{
|
||||||
std::shared_ptr<Layer::Snapshot> m_snap;
|
std::shared_ptr<LayerFrame::Snapshot> m_snap;
|
||||||
std::shared_ptr<Layer> m_layer;
|
std::shared_ptr<Layer> m_layer;
|
||||||
int m_frame = 0;
|
int m_frame = 0;
|
||||||
std::string m_path;
|
std::string m_path;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ RTT& Layer::rtt(int i, int frame /*= -1*/)
|
|||||||
{
|
{
|
||||||
if (frame == -1)
|
if (frame == -1)
|
||||||
frame = m_frame_index;
|
frame = m_frame_index;
|
||||||
|
assert(m_frames[frame].m_rtt[i].valid());
|
||||||
return m_frames[frame].m_rtt[i];
|
return m_frames[frame].m_rtt[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,71 +146,22 @@ void Layer::optimize(int frame /*= -1*/)
|
|||||||
LOG("optimized %d bytes", saved_bytes);
|
LOG("optimized %d bytes", saved_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Layer::restore(const Snapshot& snap, int frame /*= -1*/)
|
void Layer::restore(const LayerFrame::Snapshot& snap, int frame /*= -1*/)
|
||||||
{
|
{
|
||||||
if (frame == -1)
|
if (frame == -1)
|
||||||
frame = m_frame_index;
|
frame = m_frame_index;
|
||||||
clear({ 0, 0, 0, 0 }, frame);
|
auto loaded = m_frames[frame].gpu_load();
|
||||||
for (int i = 0; i < 6; i++)
|
m_frames[frame].restore(snap);
|
||||||
{
|
if (!loaded) m_frames[frame].gpu_unload();
|
||||||
if (snap.image[i] == nullptr || snap.m_dirty_face[i] == false || box_area(snap.m_dirty_box[i]) <= 0)
|
|
||||||
{
|
|
||||||
box(i, frame) = glm::vec4(snap.width, snap.height, 0, 0);
|
|
||||||
face(i, frame) = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
box(i, frame) = snap.m_dirty_box[i];
|
|
||||||
face(i, frame) = snap.m_dirty_face[i];
|
|
||||||
|
|
||||||
// TODO: this should not be recreated here!
|
|
||||||
// Sorry I messed up with this,
|
|
||||||
// it's just a quick fix DON'T SHIP!!
|
|
||||||
//m_rtt[i].recreate();
|
|
||||||
|
|
||||||
App::I->render_task_async([this, i, &snap, frame]
|
|
||||||
{
|
|
||||||
rtt(i, frame).bindTexture();
|
|
||||||
glm::vec2 box_sz = zw(box(i, frame)) - xy(box(i, frame));
|
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0,
|
|
||||||
box(i, frame).x, box(i, frame).y,
|
|
||||||
box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE,
|
|
||||||
snap.image[i].get());
|
|
||||||
rtt(i, frame).unbindTexture();
|
|
||||||
LOG("restore frame %d face %d - %d bytes (%dx%d)", frame, i,
|
|
||||||
(int)box_sz.x * (int)box_sz.y * 4, (int)box_sz.x, (int)box_sz.y);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
App::I->render_sync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Layer::Snapshot Layer::snapshot(int frame /*= -1*/, std::array<glm::vec4, 6>* dirty_box /*= nullptr*/, std::array<bool, 6>* dirty_face /*= nullptr*/)
|
LayerFrame::Snapshot Layer::snapshot(int frame /*= -1*/, std::array<glm::vec4, 6>* dirty_box /*= nullptr*/, std::array<bool, 6>* dirty_face /*= nullptr*/)
|
||||||
{
|
{
|
||||||
if (frame == -1)
|
if (frame == -1)
|
||||||
frame = m_frame_index;
|
frame = m_frame_index;
|
||||||
Snapshot snap;
|
auto loaded = m_frames[frame].gpu_load();
|
||||||
snap.width = w;
|
auto snap = m_frames[frame].snapshot(dirty_box, dirty_face);
|
||||||
snap.height = h;
|
if (!loaded) m_frames[frame].gpu_unload();
|
||||||
for (int i = 0; i < 6; i++)
|
|
||||||
{
|
|
||||||
snap.m_dirty_box[i] = dirty_box ? dirty_box->at(i) : box(i, frame);
|
|
||||||
snap.m_dirty_face[i] = dirty_face ? dirty_face->at(i) : face(i, frame);
|
|
||||||
|
|
||||||
if (!snap.m_dirty_face[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
snap.image[i] = std::make_unique<uint8_t[]>(rtt(i, frame).bytes());
|
|
||||||
|
|
||||||
App::I->render_task_async([this, i, &snap, frame]
|
|
||||||
{
|
|
||||||
rtt(i, frame).bindFramebuffer();
|
|
||||||
glm::vec2 box_sz = zw(snap.m_dirty_box[i]) - xy(snap.m_dirty_box[i]);
|
|
||||||
glReadPixels(snap.m_dirty_box[i].x, snap.m_dirty_box[i].y,
|
|
||||||
box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, snap.image[i].get());
|
|
||||||
rtt(i, frame).unbindFramebuffer();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
App::I->render_sync();
|
|
||||||
return snap;
|
return snap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,24 +181,45 @@ bool Layer::create(int width, int height, std::string name)
|
|||||||
m_frames.clear();
|
m_frames.clear();
|
||||||
m_frames.emplace_back();
|
m_frames.emplace_back();
|
||||||
m_frames.back().create(width, height);
|
m_frames.back().create(width, height);
|
||||||
|
frames_gpu_update();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Layer::add_frame()
|
bool Layer::add_frame()
|
||||||
{
|
{
|
||||||
m_frames.emplace_back();
|
m_frames.emplace_back();
|
||||||
return m_frames.back().create(w, h);
|
m_frames.back().create(w, h);
|
||||||
|
frames_gpu_update();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Layer::remove_frame(int frame)
|
void Layer::remove_frame(int frame)
|
||||||
{
|
{
|
||||||
m_frames.erase(m_frames.begin() + frame);
|
m_frames.erase(m_frames.begin() + frame);
|
||||||
m_frame_index = glm::clamp(m_frame_index, 0, (int)m_frames.size() - 1);
|
m_frame_index = glm::clamp(m_frame_index, 0, (int)m_frames.size() - 1);
|
||||||
|
frames_gpu_update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Layer::duplicate_frame(int frame)
|
void Layer::duplicate_frame(int frame)
|
||||||
{
|
{
|
||||||
m_frames.insert(m_frames.begin() + frame + 1, m_frames[frame].clone());
|
m_frames.insert(m_frames.begin() + frame + 1, m_frames[frame].clone());
|
||||||
|
frames_gpu_update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layer::frames_gpu_update()
|
||||||
|
{
|
||||||
|
App::I->render_task_async([=]
|
||||||
|
{
|
||||||
|
for (int j = 0; j < m_frames.size(); j++)
|
||||||
|
{
|
||||||
|
int dist = glm::abs(j - m_frame_index);
|
||||||
|
int onion = App::I->animation ? App::I->animation->get_onion_size() : 1;
|
||||||
|
if (dist <= onion)
|
||||||
|
m_frames[j].gpu_load();
|
||||||
|
else
|
||||||
|
m_frames[j].gpu_unload();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
int Layer::total_duration() const noexcept
|
int Layer::total_duration() const noexcept
|
||||||
@@ -263,6 +236,8 @@ void Layer::goto_frame(int frame) noexcept
|
|||||||
for (i = 0; i < m_frames.size() && frame >= 0; i++)
|
for (i = 0; i < m_frames.size() && frame >= 0; i++)
|
||||||
frame -= m_frames[i].m_duration;
|
frame -= m_frames[i].m_duration;
|
||||||
m_frame_index = i - 1;
|
m_frame_index = i - 1;
|
||||||
|
m_frames[m_frame_index].gpu_load();
|
||||||
|
frames_gpu_update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Layer::resize(int width, int height)
|
void Layer::resize(int width, int height)
|
||||||
@@ -275,7 +250,7 @@ void Layer::resize(int width, int height)
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void Layer::Snapshot::create(int w, int h)
|
void LayerFrame::Snapshot::create(int w, int h)
|
||||||
{
|
{
|
||||||
width = w;
|
width = w;
|
||||||
height = h;
|
height = h;
|
||||||
@@ -288,7 +263,7 @@ void Layer::Snapshot::create(int w, int h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Layer::Snapshot::clear()
|
void LayerFrame::Snapshot::clear()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 6; i++)
|
for (int i = 0; i < 6; i++)
|
||||||
{
|
{
|
||||||
@@ -298,7 +273,7 @@ void Layer::Snapshot::clear()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Layer::Snapshot::optimize()
|
void LayerFrame::Snapshot::optimize()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 6; i++)
|
for (int i = 0; i < 6; i++)
|
||||||
{
|
{
|
||||||
@@ -322,7 +297,7 @@ void Layer::Snapshot::optimize()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Layer::Snapshot::memsize() const
|
int LayerFrame::Snapshot::memsize() const
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
for (int i = 0; i < 6; i++)
|
for (int i = 0; i < 6; i++)
|
||||||
@@ -372,22 +347,28 @@ LayerFrame& LayerFrame::operator=(LayerFrame&& other)
|
|||||||
bool LayerFrame::create(int width, int height, int duration /*= 1*/)
|
bool LayerFrame::create(int width, int height, int duration /*= 1*/)
|
||||||
{
|
{
|
||||||
bool success = true;
|
bool success = true;
|
||||||
App::I->render_task([&]
|
//App::I->render_task([&]
|
||||||
|
//{
|
||||||
|
// for (int i = 0; i < 6; i++)
|
||||||
|
// {
|
||||||
|
// if (!m_rtt[i].create(width, height))
|
||||||
|
// {
|
||||||
|
// success = false;
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// m_rtt[i].bindFramebuffer();
|
||||||
|
// m_rtt[i].clear();
|
||||||
|
// m_rtt[i].unbindFramebuffer();
|
||||||
|
// m_dirty_box[i] = glm::vec4(width, height, 0, 0); // reset bounding box
|
||||||
|
// m_dirty_face[i] = false;
|
||||||
|
// }
|
||||||
|
//});
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 6; i++)
|
m_dirty_box[i] = glm::vec4(width, height, 0, 0); // reset bounding box
|
||||||
{
|
m_dirty_face[i] = false;
|
||||||
if (!m_rtt[i].create(width, height))
|
}
|
||||||
{
|
m_gpu_data = nullptr;
|
||||||
success = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_rtt[i].bindFramebuffer();
|
|
||||||
m_rtt[i].clear();
|
|
||||||
m_rtt[i].unbindFramebuffer();
|
|
||||||
m_dirty_box[i] = glm::vec4(width, height, 0, 0); // reset bounding box
|
|
||||||
m_dirty_face[i] = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
m_duration = duration;
|
m_duration = duration;
|
||||||
w = width;
|
w = width;
|
||||||
h = height;
|
h = height;
|
||||||
@@ -396,6 +377,7 @@ bool LayerFrame::create(int width, int height, int duration /*= 1*/)
|
|||||||
|
|
||||||
bool LayerFrame::resize(int width, int height)
|
bool LayerFrame::resize(int width, int height)
|
||||||
{
|
{
|
||||||
|
bool loaded = gpu_load();
|
||||||
glm::vec2 ratio = glm::vec2(width, height) / glm::vec2(w, h);
|
glm::vec2 ratio = glm::vec2(width, height) / glm::vec2(w, h);
|
||||||
for (int i = 0; i < 6; i++)
|
for (int i = 0; i < 6; i++)
|
||||||
{
|
{
|
||||||
@@ -405,6 +387,7 @@ bool LayerFrame::resize(int width, int height)
|
|||||||
}
|
}
|
||||||
w = width;
|
w = width;
|
||||||
h = height;
|
h = height;
|
||||||
|
if (!loaded) gpu_unload();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,17 +425,113 @@ void LayerFrame::clear(const glm::vec4& c)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
LayerFrame LayerFrame::clone() const noexcept
|
LayerFrame LayerFrame::clone() noexcept
|
||||||
{
|
{
|
||||||
LayerFrame dup;
|
LayerFrame dup;
|
||||||
dup.m_duration = m_duration;
|
dup.m_duration = m_duration;
|
||||||
dup.w = w;
|
dup.w = w;
|
||||||
dup.h = h;
|
dup.h = h;
|
||||||
|
bool loaded = gpu_load();
|
||||||
for (int i = 0; i < 6; i++)
|
for (int i = 0; i < 6; i++)
|
||||||
{
|
{
|
||||||
dup.m_rtt[i] = m_rtt[i].clone();
|
dup.m_rtt[i] = m_rtt[i].clone();
|
||||||
dup.m_dirty_box[i] = m_dirty_box[i];
|
dup.m_dirty_box[i] = m_dirty_box[i];
|
||||||
dup.m_dirty_face[i] = m_dirty_face[i];
|
dup.m_dirty_face[i] = m_dirty_face[i];
|
||||||
}
|
}
|
||||||
|
if (!loaded) gpu_unload();
|
||||||
return dup;
|
return dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LayerFrame::restore(const Snapshot& snap)
|
||||||
|
{
|
||||||
|
App::I->render_task([this, &snap]
|
||||||
|
{
|
||||||
|
clear({ 0, 0, 0, 0 });
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
if (!m_rtt[i].valid())
|
||||||
|
m_rtt[i].create(w, h);
|
||||||
|
|
||||||
|
if (snap.image[i] == nullptr || snap.m_dirty_face[i] == false || box_area(snap.m_dirty_box[i]) <= 0)
|
||||||
|
{
|
||||||
|
m_dirty_box[i] = glm::vec4(snap.width, snap.height, 0, 0);
|
||||||
|
m_dirty_face[i] = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dirty_box[i] = snap.m_dirty_box[i];
|
||||||
|
m_dirty_face[i] = snap.m_dirty_face[i];
|
||||||
|
|
||||||
|
// TODO: this should not be recreated here!
|
||||||
|
// Sorry I messed up with this,
|
||||||
|
// it's just a quick fix DON'T SHIP!!
|
||||||
|
//m_rtt[i].recreate();
|
||||||
|
|
||||||
|
m_rtt[i].bindTexture();
|
||||||
|
glm::vec2 box_sz = zw(m_dirty_box[i]) - xy(m_dirty_box[i]);
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, 0,
|
||||||
|
m_dirty_box[i].x, m_dirty_box[i].y,
|
||||||
|
box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||||
|
snap.image[i].get());
|
||||||
|
m_rtt[i].unbindTexture();
|
||||||
|
LOG("restore face %d - %d bytes (%dx%d)", i,
|
||||||
|
(int)box_sz.x * (int)box_sz.y * 4, (int)box_sz.x, (int)box_sz.y);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
LayerFrame::Snapshot LayerFrame::snapshot(std::array<glm::vec4, 6>* dirty_box /*= nullptr*/, std::array<bool, 6>* dirty_face /*= nullptr*/)
|
||||||
|
{
|
||||||
|
Snapshot snap;
|
||||||
|
snap.width = w;
|
||||||
|
snap.height = h;
|
||||||
|
App::I->render_task([this, &snap, dirty_face, dirty_box]
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
snap.m_dirty_box[i] = dirty_box ? dirty_box->at(i) : m_dirty_box[i];
|
||||||
|
snap.m_dirty_face[i] = dirty_face ? dirty_face->at(i) : m_dirty_face[i];
|
||||||
|
|
||||||
|
if (!snap.m_dirty_face[i] || !m_rtt[i].valid())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
snap.image[i] = std::make_unique<uint8_t[]>(m_rtt[i].bytes());
|
||||||
|
|
||||||
|
m_rtt[i].bindFramebuffer();
|
||||||
|
glm::vec2 box_sz = zw(snap.m_dirty_box[i]) - xy(snap.m_dirty_box[i]);
|
||||||
|
glReadPixels(snap.m_dirty_box[i].x, snap.m_dirty_box[i].y,
|
||||||
|
box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, snap.image[i].get());
|
||||||
|
m_rtt[i].unbindFramebuffer();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return snap;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LayerFrame::gpu_load() noexcept
|
||||||
|
{
|
||||||
|
if (m_gpu_data)
|
||||||
|
{
|
||||||
|
restore(*m_gpu_data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (auto& rtt : m_rtt)
|
||||||
|
if (!rtt.valid())
|
||||||
|
rtt.create(w, h);
|
||||||
|
}
|
||||||
|
m_gpu_data.reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LayerFrame::gpu_unload() noexcept
|
||||||
|
{
|
||||||
|
bool ret = false; // already unloaded from gpu
|
||||||
|
if (!m_gpu_data)
|
||||||
|
{
|
||||||
|
m_gpu_data = std::make_unique<Snapshot>(snapshot());
|
||||||
|
ret = true; // previous state was loaded on gpu
|
||||||
|
}
|
||||||
|
for (auto& rtt : m_rtt)
|
||||||
|
rtt.destroy();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,9 +5,23 @@
|
|||||||
|
|
||||||
struct LayerFrame
|
struct LayerFrame
|
||||||
{
|
{
|
||||||
|
struct Snapshot
|
||||||
|
{
|
||||||
|
std::unique_ptr<uint8_t[]> image[6] = SIXPLETTE(0);
|
||||||
|
std::array<glm::vec4, 6> m_dirty_box = SIXPLETTE(glm::vec4(0));
|
||||||
|
std::array<bool, 6> m_dirty_face = SIXPLETTE(false);
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
void create(int w, int h);
|
||||||
|
void clear();
|
||||||
|
void optimize();
|
||||||
|
int memsize() const;
|
||||||
|
};
|
||||||
|
|
||||||
std::array<RTT, 6> m_rtt;
|
std::array<RTT, 6> m_rtt;
|
||||||
std::array<glm::vec4, 6> m_dirty_box = SIXPLETTE(glm::vec4(0));
|
std::array<glm::vec4, 6> m_dirty_box = SIXPLETTE(glm::vec4(0));
|
||||||
std::array<bool, 6> m_dirty_face = SIXPLETTE(false);
|
std::array<bool, 6> m_dirty_face = SIXPLETTE(false);
|
||||||
|
std::unique_ptr<Snapshot> m_gpu_data;
|
||||||
int m_duration = 1;
|
int m_duration = 1;
|
||||||
int w = 0, h = 0;
|
int w = 0, h = 0;
|
||||||
|
|
||||||
@@ -23,17 +37,23 @@ struct LayerFrame
|
|||||||
bool create(int width, int height, int duration = 1);
|
bool create(int width, int height, int duration = 1);
|
||||||
bool resize(int width, int height);
|
bool resize(int width, int height);
|
||||||
void clear(const glm::vec4& c);
|
void clear(const glm::vec4& c);
|
||||||
LayerFrame clone() const noexcept;
|
LayerFrame clone() noexcept;
|
||||||
|
// return previous state
|
||||||
|
bool gpu_load() noexcept;
|
||||||
|
// return if succesfully loaded on gpu
|
||||||
|
bool gpu_unload() noexcept;
|
||||||
|
Snapshot snapshot(std::array<glm::vec4, 6>* dirty_box = nullptr, std::array<bool, 6>* dirty_face = nullptr);
|
||||||
|
void restore(const Snapshot& snap);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Layer
|
class Layer
|
||||||
{
|
{
|
||||||
static uint32_t s_count;
|
static uint32_t s_count;
|
||||||
|
std::vector<LayerFrame> m_frames;
|
||||||
public:
|
public:
|
||||||
Layer() { id = s_count++; }
|
Layer() { id = s_count++; }
|
||||||
Layer(const Layer&) = delete;
|
Layer(const Layer&) = delete;
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
std::vector<LayerFrame> m_frames;
|
|
||||||
int m_frame_index = 0;
|
int m_frame_index = 0;
|
||||||
bool m_visible = true;
|
bool m_visible = true;
|
||||||
bool m_alpha_locked = false;
|
bool m_alpha_locked = false;
|
||||||
@@ -43,18 +63,6 @@ public:
|
|||||||
std::string m_name;
|
std::string m_name;
|
||||||
int w = 0;
|
int w = 0;
|
||||||
int h = 0;
|
int h = 0;
|
||||||
struct Snapshot
|
|
||||||
{
|
|
||||||
std::unique_ptr<uint8_t[]> image[6] = SIXPLETTE(0);
|
|
||||||
std::array<glm::vec4, 6> m_dirty_box = SIXPLETTE(glm::vec4(0));
|
|
||||||
std::array<bool, 6> m_dirty_face = SIXPLETTE(false);
|
|
||||||
int width = 0;
|
|
||||||
int height = 0;
|
|
||||||
void create(int w, int h);
|
|
||||||
void clear();
|
|
||||||
void optimize();
|
|
||||||
int memsize() const;
|
|
||||||
};
|
|
||||||
RTT& rtt(int i, int frame = -1);
|
RTT& rtt(int i, int frame = -1);
|
||||||
glm::vec4& box(int i, int frame = -1);
|
glm::vec4& box(int i, int frame = -1);
|
||||||
bool& face(int i, int frame = -1);
|
bool& face(int i, int frame = -1);
|
||||||
@@ -64,13 +72,17 @@ public:
|
|||||||
bool add_frame();
|
bool add_frame();
|
||||||
void remove_frame(int frame);
|
void remove_frame(int frame);
|
||||||
void duplicate_frame(int frame);
|
void duplicate_frame(int frame);
|
||||||
|
void frames_gpu_update();
|
||||||
|
int frames_count() const noexcept { return m_frames.size(); }
|
||||||
|
int frame_duration(int frame) const noexcept { return m_frames[frame].m_duration; }
|
||||||
|
void set_frame_duration(int frame, int duration) noexcept { m_frames[frame].m_duration = duration; }
|
||||||
int total_duration() const noexcept;
|
int total_duration() const noexcept;
|
||||||
void goto_frame(int frame) noexcept;
|
void goto_frame(int frame) noexcept;
|
||||||
void clear(const glm::vec4& c, int frame = -1);
|
void clear(const glm::vec4& c, int frame = -1);
|
||||||
Snapshot snapshot(int frame = -1, std::array<glm::vec4, 6>* dirty_box = nullptr, std::array<bool, 6>* dirty_face = nullptr);
|
LayerFrame::Snapshot snapshot(int frame = -1, std::array<glm::vec4, 6>* dirty_box = nullptr, std::array<bool, 6>* dirty_face = nullptr);
|
||||||
TextureCube gen_cube();
|
TextureCube gen_cube();
|
||||||
Texture2D gen_equirect();
|
Texture2D gen_equirect();
|
||||||
void restore(const Snapshot& snap, int frame = -1);
|
void restore(const LayerFrame::Snapshot& snap, int frame = -1);
|
||||||
void destroy();
|
void destroy();
|
||||||
void optimize(int frame = -1);
|
void optimize(int frame = -1);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1611,7 +1611,7 @@ void CanvasModeFloodFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
|||||||
struct ActionFloodFill : public Action
|
struct ActionFloodFill : public Action
|
||||||
{
|
{
|
||||||
std::shared_ptr<Layer> m_layer;
|
std::shared_ptr<Layer> m_layer;
|
||||||
std::shared_ptr<Layer::Snapshot> m_snap;
|
std::shared_ptr<LayerFrame::Snapshot> m_snap;
|
||||||
std::array<bool, 6> m_dirty_face = SIXPLETTE(false);
|
std::array<bool, 6> m_dirty_face = SIXPLETTE(false);
|
||||||
std::array<glm::vec4, 6> m_dirty_box = SIXPLETTE(glm::vec4(0));
|
std::array<glm::vec4, 6> m_dirty_box = SIXPLETTE(glm::vec4(0));
|
||||||
glm::ivec2 m_pos;
|
glm::ivec2 m_pos;
|
||||||
@@ -1670,7 +1670,7 @@ void CanvasModeFloodFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
|||||||
auto a = new ActionFloodFill;
|
auto a = new ActionFloodFill;
|
||||||
a->m_direction = Action::Direction::Undo;
|
a->m_direction = Action::Direction::Undo;
|
||||||
a->m_layer = plane_data.layer;
|
a->m_layer = plane_data.layer;
|
||||||
a->m_snap = std::make_shared<Layer::Snapshot>(plane_data.layer->snapshot());
|
a->m_snap = std::make_shared<LayerFrame::Snapshot>(plane_data.layer->snapshot());
|
||||||
a->m_pos = (glm::ivec2)pos;
|
a->m_pos = (glm::ivec2)pos;
|
||||||
a->m_color = Canvas::I->m_current_brush->m_tip_color;
|
a->m_color = Canvas::I->m_current_brush->m_tip_color;
|
||||||
a->m_layer_index = Canvas::I->m_current_layer_idx;
|
a->m_layer_index = Canvas::I->m_current_layer_idx;
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ void NodeCanvas::draw()
|
|||||||
int onion_size = App::I->animation->get_onion_size();
|
int onion_size = App::I->animation->get_onion_size();
|
||||||
int frame_current = m_canvas->m_layers[layer_index]->m_frame_index;
|
int frame_current = m_canvas->m_layers[layer_index]->m_frame_index;
|
||||||
int frame_start = glm::max<int>(frame_current - onion_size, 0);
|
int frame_start = glm::max<int>(frame_current - onion_size, 0);
|
||||||
int frame_end = glm::min<int>(frame_current + onion_size, m_canvas->m_layers[layer_index]->m_frames.size() - 1);
|
int frame_end = glm::min<int>(frame_current + onion_size, m_canvas->m_layers[layer_index]->frames_count() - 1);
|
||||||
bool faces = false;
|
bool faces = false;
|
||||||
for (int frame = frame_start; frame <= frame_end; frame++)
|
for (int frame = frame_start; frame <= frame_end; frame++)
|
||||||
faces |= m_canvas->m_layers[layer_index]->face(plane_index, frame);
|
faces |= m_canvas->m_layers[layer_index]->face(plane_index, frame);
|
||||||
|
|||||||
@@ -55,14 +55,12 @@ void NodePanelAnimation::init_controls()
|
|||||||
};
|
};
|
||||||
btn_up->on_click = [this](Node*) {
|
btn_up->on_click = [this](Node*) {
|
||||||
if (auto layer = Canvas::I->layer_with_id(m_selected_frame_layer_id))
|
if (auto layer = Canvas::I->layer_with_id(m_selected_frame_layer_id))
|
||||||
layer->m_frames[m_selected_frame_index].m_duration =
|
layer->set_frame_duration(m_selected_frame_index, glm::max(layer->frame_duration(m_selected_frame_index) + 1, 1));
|
||||||
glm::max(layer->m_frames[m_selected_frame_index].m_duration + 1, 1);
|
|
||||||
load_layers();
|
load_layers();
|
||||||
};
|
};
|
||||||
btn_down->on_click = [this](Node*) {
|
btn_down->on_click = [this](Node*) {
|
||||||
if (auto layer = Canvas::I->layer_with_id(m_selected_frame_layer_id))
|
if (auto layer = Canvas::I->layer_with_id(m_selected_frame_layer_id))
|
||||||
layer->m_frames[m_selected_frame_index].m_duration =
|
layer->set_frame_duration(m_selected_frame_index, glm::max(layer->frame_duration(m_selected_frame_index) - 1, 1));
|
||||||
glm::max(layer->m_frames[m_selected_frame_index].m_duration - 1, 1);
|
|
||||||
load_layers();
|
load_layers();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -120,9 +118,9 @@ void NodePanelAnimation::load_layers()
|
|||||||
l->set_selected(Canvas::I->m_current_layer_idx == i);
|
l->set_selected(Canvas::I->m_current_layer_idx == i);
|
||||||
l->set_chekcbox(layers[i]->m_visible);
|
l->set_chekcbox(layers[i]->m_visible);
|
||||||
auto film = m_frames_container->add_child_ref<NodeAnimationFilm>();
|
auto film = m_frames_container->add_child_ref<NodeAnimationFilm>();
|
||||||
for (int fi = 0; fi < layers[i]->m_frames.size(); fi++)
|
for (int fi = 0; fi < layers[i]->frames_count(); fi++)
|
||||||
{
|
{
|
||||||
auto b = film->add_frame(layers[i]->m_frames[fi].m_duration);
|
auto b = film->add_frame(layers[i]->frame_duration(fi));
|
||||||
|
|
||||||
if (m_selected_frame_layer_id == layers[i]->id && m_selected_frame_index == fi)
|
if (m_selected_frame_layer_id == layers[i]->id && m_selected_frame_index == fi)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -408,7 +408,7 @@ void NodePanelLayer::merge(int src_index, int dst_index, bool create_history)
|
|||||||
a->m_dirty_box[i] = Canvas::I->m_layers[dst_index]->box(i);
|
a->m_dirty_box[i] = Canvas::I->m_layers[dst_index]->box(i);
|
||||||
a->m_dirty_face[i] = Canvas::I->m_layers[dst_index]->face(i);
|
a->m_dirty_face[i] = Canvas::I->m_layers[dst_index]->face(i);
|
||||||
}
|
}
|
||||||
a->m_snap = std::make_shared<Layer::Snapshot>();
|
a->m_snap = std::make_shared<LayerFrame::Snapshot>();
|
||||||
*a->m_snap = Canvas::I->m_layers[dst_index]->snapshot(-1,
|
*a->m_snap = Canvas::I->m_layers[dst_index]->snapshot(-1,
|
||||||
&Canvas::I->m_layers[src_index]->frame().m_dirty_box, &Canvas::I->m_layers[src_index]->frame().m_dirty_face);
|
&Canvas::I->m_layers[src_index]->frame().m_dirty_box, &Canvas::I->m_layers[src_index]->frame().m_dirty_face);
|
||||||
a->m_layer = Canvas::I->m_layers[src_index];
|
a->m_layer = Canvas::I->m_layers[src_index];
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ public:
|
|||||||
|
|
||||||
struct ActionLayerMerge : public Action
|
struct ActionLayerMerge : public Action
|
||||||
{
|
{
|
||||||
std::shared_ptr<Layer::Snapshot> m_snap;
|
std::shared_ptr<LayerFrame::Snapshot> m_snap;
|
||||||
std::shared_ptr<Layer> m_layer;
|
std::shared_ptr<Layer> m_layer;
|
||||||
std::shared_ptr<NodeLayer> m_layer_node;
|
std::shared_ptr<NodeLayer> m_layer_node;
|
||||||
std::shared_ptr<NodePanelLayer> m_panel;
|
std::shared_ptr<NodePanelLayer> m_panel;
|
||||||
|
|||||||
Reference in New Issue
Block a user