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;