From fbb73ccbbb165404ed7288112268cf767e083fd9 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Wed, 10 May 2017 01:27:57 +0100 Subject: [PATCH] compress file when saving, using bbox, dirty flags and PNG compression --- data/layout.xml | 16 +------- engine/app.cpp | 2 +- engine/canvas.cpp | 91 +++++++++++++++++++++++++++++++++++++---- engine/canvas.h | 12 +++++- engine/canvas_modes.cpp | 2 +- engine/pch.cpp | 6 +-- engine/pch.h | 1 + 7 files changed, 100 insertions(+), 30 deletions(-) diff --git a/data/layout.xml b/data/layout.xml index cf21783..775f905 100644 --- a/data/layout.xml +++ b/data/layout.xml @@ -307,21 +307,9 @@ - - - - - - - - - - - - - + - + diff --git a/engine/app.cpp b/engine/app.cpp index e75f7db..8963bc4 100644 --- a/engine/app.cpp +++ b/engine/app.cpp @@ -580,7 +580,7 @@ void App::initLayout() button->on_click = [this,button](Node*) { if (canvas) { - canvas->m_canvas->save(data_path); + canvas->m_canvas->export_equirectangular(data_path); } }; } diff --git a/engine/canvas.cpp b/engine/canvas.cpp index d51d79b..9900a1b 100644 --- a/engine/canvas.cpp +++ b/engine/canvas.cpp @@ -334,6 +334,13 @@ void ui::Canvas::stroke_commit() glReadPixels(m_dirty_box[i].x, m_dirty_box[i].y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, action->m_image[i].get()); action->m_box[i] = m_dirty_box[i]; + action->m_old_box[i] = m_layers[m_current_layer_idx].m_dirty_box[i]; + action->m_old_dirty[i] = m_layers[m_current_layer_idx].m_dirty_face[i]; + + auto& lbox = m_layers[m_current_layer_idx].m_dirty_box[i]; + lbox.xy = glm::min(m_dirty_box[i].xy(), lbox.xy()); + lbox.zw = glm::max(m_dirty_box[i].zw(), lbox.zw()); + m_layers[m_current_layer_idx].m_dirty_face[i] = true; // copy to tmp2 for layer blending glActiveTexture(GL_TEXTURE0); @@ -495,7 +502,7 @@ void ui::Canvas::clear_context() m_latlong.destroy(); }; -void ui::Canvas::save(std::string data_path) +void ui::Canvas::export_equirectangular(std::string data_path) { // save viewport and clear color states GLint vp[4]; @@ -632,7 +639,28 @@ void ui::Canvas::project_save(std::string data_path) auto snap = m_layers[i].snapshot(data_path); for (int plane_index = 0; plane_index < 6; plane_index++) { - fwrite(snap.image[plane_index].get(), 1, m_width * m_height * 4, fp); + int has_data = snap.m_dirty_face[plane_index] ? 1 : 0; + fwrite(&has_data, sizeof(int), 1, fp); + if (has_data) + { + glm::ivec4 b = snap.m_dirty_box[plane_index]; + glm::vec2 sz = b.zw() - b.xy(); + int box[4] = { b.x, b.y, b.z, b.w }; + fwrite(&box, sizeof(box), 1, fp); + + std::vector compressed; + auto callback = [](void *context, void *data, int size) + { + std::vector* buffer = static_cast*>(context); + buffer->insert(buffer->end(), (uint8_t*)data, (uint8_t*)data + size); + }; + int ret = stbi_write_png_to_func(callback, &compressed, sz.x, sz.y, 4, snap.image[plane_index].get(), sz.x * 4); + + int data_size = compressed.size(); + fwrite(&data_size, sizeof(int), 1, fp); + + fwrite(compressed.data(), 1, compressed.size(), fp); + } } } fclose(fp); @@ -665,7 +693,7 @@ void ui::Canvas::project_open(std::string data_path) const int bytes = m_width * m_height * 4; Layer::Snapshot snap; - snap.create(m_width, m_height); + snap.create(m_width, m_height); // allocate single data, no box should be bigger m_layers.clear(); m_order.clear(); @@ -681,7 +709,26 @@ void ui::Canvas::project_open(std::string data_path) fread((char*)name.data(), name_len, 1, fp); for (int plane_index = 0; plane_index < 6; plane_index++) { - fread(snap.image[plane_index].get(), 1, bytes, fp); + int has_data; + fread(&has_data, sizeof(int), 1, fp); + snap.m_dirty_face[plane_index] = has_data; + if (has_data) + { + int b[4]; + fread(&b, sizeof(b), 1, fp); + snap.m_dirty_box[plane_index] = glm::vec4(b[0], b[1], b[2], b[3]); + glm::vec2 sz = snap.m_dirty_box[plane_index].zw() - snap.m_dirty_box[plane_index].xy(); + + int data_size; + fread(&data_size, sizeof(int), 1, fp); + std::vector compressed(data_size); + + fread(compressed.data(), 1, data_size, fp); + int imgw, imgh, imgc; + uint8_t* rgba = stbi_load_from_memory(compressed.data(), data_size, &imgw, &imgh, &imgc, 4); + std::copy(rgba, rgba + (imgw*imgh * 4), snap.image[plane_index].get()); + delete rgba; + } } m_layers.emplace_back(); m_layers.back().create(m_width, m_height, name.c_str()); @@ -814,15 +861,21 @@ void ui::Layer::destroy() void ui::Layer::restore(const Snapshot& snap) { + //clear({ 0, 0, 0, 0 }); for (int i = 0; i < 6; i++) { - if (!snap.image[i]) + if (snap.image[i] == nullptr || snap.m_dirty_face[i] == false) continue; + + m_dirty_box[i] = snap.m_dirty_box[i]; + m_dirty_face[i] = snap.m_dirty_face[i]; + m_rtt[i].recreate(); // TODO: this should not be recreated here! Sorry I messed up with this, just quick fix DON'T SHIP!! m_rtt[i].bindTexture(); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_rtt[i].getWidth(), m_rtt[i].getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, snap.image[i].get()); + glm::vec2 box_sz = m_dirty_box[i].zw() - m_dirty_box[i].xy(); + 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, m_rtt[i].bytes(), m_rtt[i].getWidth(), m_rtt[i].getHeight()); + 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); } } @@ -835,9 +888,22 @@ ui::Layer::Snapshot ui::Layer::snapshot(std::string data_path) glBindFramebuffer(GL_FRAMEBUFFER, 0); for (int i = 0; i < 6; i++) { + snap.m_dirty_box[i] = m_dirty_box[i]; + snap.m_dirty_face[i] = m_dirty_face[i]; + + if (!m_dirty_face[i]) + continue; + snap.image[i] = std::make_unique(m_rtt[i].bytes()); - m_rtt[i].readTextureData(snap.image[i].get()); - LOG("snapshot face %d - %d bytes (%dx%d)", i, m_rtt[i].bytes(), m_rtt[i].getWidth(), m_rtt[i].getHeight()); + + glReadBuffer(GL_BACK); + m_rtt[i].bindFramebuffer(); + glm::vec2 box_sz = m_dirty_box[i].zw() - m_dirty_box[i].xy(); + glReadPixels(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].unbindFramebuffer(); + glReadBuffer(GL_NONE); + + LOG("snapshot face %d - %d bytes (%dx%d)", i, (int)box_sz.x * (int)box_sz.y * 4, (int)box_sz.x, (int)box_sz.y); static char name[128]; sprintf(name, "%s/Layer%d-%d.png", data_path.c_str(), counter, i); //int ret = stbi_write_png(name, m_rtt[i].getWidth(), m_rtt[i].getHeight(), 4, snap.image[i].get(), m_rtt[i].stride()); @@ -858,6 +924,9 @@ void ui::Layer::clear(const glm::vec4& c) m_rtt[i].bindFramebuffer(); glClear(GL_COLOR_BUFFER_BIT); m_rtt[i].unbindFramebuffer(); + + m_dirty_box[i] = glm::vec4(w, h, 0, 0); // reset bounding box + m_dirty_face[i] = false; } // restore clear color state @@ -867,12 +936,16 @@ void ui::Layer::clear(const glm::vec4& c) bool ui::Layer::create(int width, int height, std::string name) { m_name = name; + w = width; + h = height; for (int i = 0; i < 6; i++) { m_rtt[i].create(width, height); m_rtt[i].bindFramebuffer(); m_rtt[i].clear(); m_rtt[i].unbindFramebuffer(); + m_dirty_box[i] = glm::vec4(w, h, 0, 0); // reset bounding box + m_dirty_face[i] = false; } return true; } diff --git a/engine/canvas.h b/engine/canvas.h index 692ecca..df730b5 100644 --- a/engine/canvas.h +++ b/engine/canvas.h @@ -13,13 +13,18 @@ class Layer { public: RTT m_rtt[6]; + glm::vec4 m_dirty_box[6]; + bool m_dirty_face[6]; bool m_visible = true; bool m_alpha_locked = false; float m_opacity = 1.f; std::string m_name; + int w, h; struct Snapshot { std::unique_ptr image[6]; + glm::vec4 m_dirty_box[6]; + bool m_dirty_face[6]; void create(int w, int h) { for (int i = 0; i < 6; i++) @@ -103,7 +108,7 @@ public: void snapshot_save(std::string data_path); void snapshot_restore(); void clear_context(); - void save(std::string data_path); + void export_equirectangular(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); @@ -125,6 +130,8 @@ class ActionStroke : public Action public: std::unique_ptr m_stroke; std::unique_ptr m_image[6]; + glm::ivec4 m_old_box[6]; + bool m_old_dirty[6]; glm::ivec4 m_box[6]; bool m_dirty[6]; int m_layer_idx; @@ -141,6 +148,9 @@ public: if (!m_image[i]) continue; + m_canvas->m_layers[m_layer_idx].m_dirty_box[i] = m_old_box[i]; + m_canvas->m_layers[m_layer_idx].m_dirty_face[i] = m_old_dirty[i]; + m_canvas->m_layers[m_layer_idx].m_rtt[i].bindTexture(); glm::vec2 box_sz = m_box[i].zw() - m_box[i].xy(); glTexSubImage2D(GL_TEXTURE_2D, 0, m_box[i].x, m_box[i].y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, m_image[i].get()); diff --git a/engine/canvas_modes.cpp b/engine/canvas_modes.cpp index 5bbded6..1d8753f 100644 --- a/engine/canvas_modes.cpp +++ b/engine/canvas_modes.cpp @@ -168,7 +168,7 @@ void CanvasModeCamera::on_MouseEvent(MouseEvent* me, glm::vec2& loc) case kEventType::MouseUpL: m_dragging = false; node->mouse_release(); - canvas->m_cam_pos.xy = m_pos_start; + canvas->m_cam_pos = { 0, 0, 0 }; break; case kEventType::MouseMove: if (m_dragging) diff --git a/engine/pch.cpp b/engine/pch.cpp index 21cf628..a0859d7 100644 --- a/engine/pch.cpp +++ b/engine/pch.cpp @@ -1,12 +1,10 @@ #include "pch.h" #define STB_TRUETYPE_IMPLEMENTATION -#include - #define STB_IMAGE_IMPLEMENTATION -#include - #define STB_IMAGE_WRITE_IMPLEMENTATION +#include +#include #include #ifdef DEBUG diff --git a/engine/pch.h b/engine/pch.h index 9db773e..eebac77 100644 --- a/engine/pch.h +++ b/engine/pch.h @@ -42,6 +42,7 @@ #elif _WIN32 #define _USE_MATH_DEFINES #define _CRT_SECURE_NO_WARNINGS + #define _SCL_SECURE_NO_WARNINGS #include #include #include