diff --git a/.gitignore b/.gitignore index f6309c6..c54bd13 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ data/thumbs PanoPainter.aps panopainter-log.txt *.pano +frames/ diff --git a/data/layout.xml b/data/layout.xml index b9e121c..da43b25 100644 --- a/data/layout.xml +++ b/data/layout.xml @@ -127,7 +127,7 @@ - + @@ -559,6 +559,10 @@ + + + + diff --git a/data/spritesheet_names.png b/data/spritesheet_names.png new file mode 100644 index 0000000..1800909 Binary files /dev/null and b/data/spritesheet_names.png differ diff --git a/engine.vcxproj b/engine.vcxproj index 9428af5..6a6bc43 100644 --- a/engine.vcxproj +++ b/engine.vcxproj @@ -22,7 +22,7 @@ {6D5028CE-4D76-4B6A-A7C2-DE5A3268D433} Win32Proj engine - 10.0.16299.0 + 10.0.17134.0 @@ -353,6 +353,9 @@ + + + diff --git a/engine.vcxproj.filters b/engine.vcxproj.filters index 6b5e266..8c602a4 100644 --- a/engine.vcxproj.filters +++ b/engine.vcxproj.filters @@ -445,4 +445,9 @@ extras + + + extras + + \ No newline at end of file diff --git a/engine/app.h b/engine/app.h index 08f0013..b857c2a 100644 --- a/engine/app.h +++ b/engine/app.h @@ -139,7 +139,8 @@ public: void dialog_save_ver(); void dialog_open(); void dialog_browse(); - void dialog_export(); + void dialog_export(); + void dialog_export_cubes(); void dialog_layer_rename(); void cloud_upload(); diff --git a/engine/app_dialogs.cpp b/engine/app_dialogs.cpp index 6dc5c0f..72c34ae 100644 --- a/engine/app_dialogs.cpp +++ b/engine/app_dialogs.cpp @@ -258,6 +258,14 @@ void App::dialog_export() } } +void App::dialog_export_cubes() +{ + if (canvas) + { + canvas->m_canvas->export_cubes(data_path + "/" + doc_name); + } +} + void App::dialog_layer_rename() { auto dialog = std::make_shared(); diff --git a/engine/app_layout.cpp b/engine/app_layout.cpp index c569ce5..954a39f 100644 --- a/engine/app_layout.cpp +++ b/engine/app_layout.cpp @@ -31,7 +31,7 @@ void App::init_toolbar_main() } }; } - if (auto* button = layout[main_id]->find("btn-anim")) + if (auto* button = layout[main_id]->find("btn-anim")) { button->on_click = [this, button](Node*) { if (canvas) @@ -402,7 +402,12 @@ void App::init_menu_file() popup->mouse_release(); popup->destroy(); }; - popup->find("file-cloud-upload")->on_click = [this](Node*) { + popup->find("file-export-cubes")->on_click = [this](Node*) { + dialog_export_cubes(); + popup->mouse_release(); + popup->destroy(); + }; + popup->find("file-cloud-upload")->on_click = [this](Node*) { cloud_upload(); popup->mouse_release(); popup->destroy(); diff --git a/engine/canvas.cpp b/engine/canvas.cpp index 33e5464..5d5e488 100644 --- a/engine/canvas.cpp +++ b/engine/canvas.cpp @@ -1254,6 +1254,72 @@ void ui::Canvas::export_anim(std::string data_path) glActiveTexture(GL_TEXTURE0); } +void ui::Canvas::export_cubes(std::string data_path) +{ + std::array names { + "pz", "px", "nz", "nx", + "py", "ny" + }; + const int stride = m_width * 4; + auto buffer = std::make_unique(m_width * m_height * 4); + auto flipped = std::make_unique(m_width * m_height * 4); + for (auto i : m_order) + { + for (int plane = 0; plane < 6; plane++) + { + auto& l = m_layers[i]; + l.m_rtt[plane].bindFramebuffer(); + glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, buffer.get()); + l.m_rtt[plane].unbindFramebuffer(); + + if (plane < 4) + { + for (int y = 0; y < m_height; y++) + { + int y_rev = m_height - y - 1; + std::copy_n(buffer.get() + y * stride, stride, flipped.get() + y_rev * stride); + } + std::swap(buffer, flipped); + } + else + { + for (int y = 0; y < m_height; y++) + { + auto src = (glm::u8vec4*)(buffer.get() + y * stride); + auto dst = (glm::u8vec4*)(flipped.get() + y * stride); + for (int x = 0; x < m_width; x++) + { + int x_rev = m_width - x - 1; + dst[x_rev] = src[x]; + } + //std::copy_backward(src + stride, src, dst + stride); + } + std::swap(buffer, flipped); + } + + static char name[128]; + sprintf(name, "%s-%02d-%d.png", data_path.c_str(), i, plane); + int ret = stbi_write_png(name, m_width, m_height, 4, buffer.get(), 0); + + +#ifdef __IOS__ + [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ + NSURL* url = [NSURL fileURLWithPath : [NSString stringWithUTF8String : name]]; + PHAssetChangeRequest *changeRequest = [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL : url]; + changeRequest.creationDate = [NSDate date]; + } completionHandler: ^ (BOOL success, NSError *error) { + if (success) { + NSLog(@"successfully saved"); + } + else { + NSLog(@"error saving to photos : %@", error); + } + }]; +#endif + } + } +} + void ui::Canvas::project_save(std::string file_path) { std::thread t(&ui::Canvas::project_save_thread, this, file_path); diff --git a/engine/canvas.h b/engine/canvas.h index bdc1cc7..90835e1 100644 --- a/engine/canvas.h +++ b/engine/canvas.h @@ -138,7 +138,8 @@ public: void import_equirectangular_thread(std::string file_path); void export_equirectangular(std::string file_path); void export_equirectangular_thread(std::string file_path); - void export_anim(std::string data_path); + void export_anim(std::string data_path); + void export_cubes(std::string data_path); void project_save(std::string file_path); void project_save_thread(std::string file_path); void project_open(std::string file_path, std::function on_complete = nullptr); diff --git a/engine/node_popup_menu.cpp b/engine/node_popup_menu.cpp index f197dc9..7ff3d78 100644 --- a/engine/node_popup_menu.cpp +++ b/engine/node_popup_menu.cpp @@ -12,7 +12,7 @@ void NodePopupMenu::init() m_flood_events = true; SetPosition(0, 0); SetWidth(100); - SetHeight(400); + SetHeight(500); SetPositioning(YGPositionTypeAbsolute); m_mouse_ignore = false; m_capture_children = false;