diff --git a/data/layout.xml b/data/layout.xml index 41e58d2..da48052 100644 --- a/data/layout.xml +++ b/data/layout.xml @@ -1483,6 +1483,9 @@ Here's a list of what's available in this release. + + + diff --git a/src/app.cpp b/src/app.cpp index 596ece9..15cc3d9 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -495,7 +495,7 @@ bool App::update_ui_observer(Node *n) n->handle_on_screen(false, true); n->m_on_screen = true; } - glm::ivec4 c = glm::vec4(box.x, (height / zoom - box.y - box.w), box.z, box.w) * zoom; + glm::ivec4 c = glm::vec4(box.x - 1, (height / zoom - box.y - box.w - 1), box.z + 2, box.w + 2) * zoom; glScissor(floorf(c.x + off_x), floorf(c.y + off_y), ceilf(c.z), ceilf(c.w)); n->draw(); return true; @@ -532,7 +532,7 @@ void App::draw(float dt) glBindFramebuffer(GL_FRAMEBUFFER, 0); #endif glViewport(off_x, off_y, (GLsizei)width, (GLsizei)height); - //glEnable(GL_SCISSOR_TEST); + glEnable(GL_SCISSOR_TEST); for (int i = 0; i < layout[main_id]->m_children.size(); i++) layout[main_id]->m_children[i]->watch(observer); //msgbox->watch(observer); diff --git a/src/app.h b/src/app.h index 2a5f967..c06dd70 100644 --- a/src/app.h +++ b/src/app.h @@ -205,7 +205,7 @@ public: bool key_char(char key); void toggle_ui(); void set_stylus(); - NodeMessageBox* message_box(const std::string& title, const std::string& text, bool cancel_button = false); + std::shared_ptr message_box(const std::string& title, const std::string& text, bool cancel_button = false); void rec_clear(); void rec_loop(); @@ -232,7 +232,7 @@ public: void dialog_export(std::string ext); void dialog_export_layers(); void dialog_export_depth(); - void dialog_export_cubes(); + void dialog_export_cube_faces(); void dialog_layer_rename(); void dialog_resize(); @@ -243,7 +243,7 @@ public: void download(std::string url, std::string dest_filepath, std::function progress = nullptr); bool check_license(); - std::shared_ptr show_progress(const std::string& title); + std::shared_ptr show_progress(const std::string& title, int total = 0); void brush_update(bool update_color, bool update_brush); void title_update(); @@ -284,8 +284,8 @@ public: // don't capture a reference to this ptr as the object may be destroyed // by the time the task is executed - template - std::future render_task_async(T task, bool unique = false) + template + std::future render_task_async(T task, bool unique = false) { AppTask pt(task); auto f = pt.get_future(); @@ -308,8 +308,8 @@ public: return f; } - template - R render_task(T task) + template + void render_task(T task) { AppTask pt(task); auto f = pt.get_future(); @@ -325,7 +325,8 @@ public: } render_cv.notify_all(); } - return render_running ? f.get() : R(); + if (render_running) + f.get(); } void render_sync() @@ -354,8 +355,8 @@ public: // don't capture a reference to this ptr as the object may be destroyed // by the time the task is executed - template - std::future ui_task_async(T task, bool unique = false) + template + std::future ui_task_async(T task, bool unique = false) { AppTask pt(task); auto f = pt.get_future(); @@ -378,8 +379,8 @@ public: return f; } - template - R ui_task(T task) + template + void ui_task(T task) { AppTask pt(task); auto f = pt.get_future(); @@ -395,7 +396,9 @@ public: } ui_cv.notify_all(); } - return ui_running ? f.get() : R(); + if (ui_running) + f.get(); + redraw = true; } void ui_sync() diff --git a/src/app_cloud.cpp b/src/app_cloud.cpp index aadf262..d79e45c 100644 --- a/src/app_cloud.cpp +++ b/src/app_cloud.cpp @@ -31,7 +31,7 @@ void App::cloud_upload() auto pb = show_progress("Uploading"); upload(doc_path, doc_filename, [this,pb](float p){ - pb->m_progress->SetWidthP(p * 100.f); + pb->set_progress(p); }); pb->destroy(); @@ -70,32 +70,20 @@ void App::cloud_upload_all() gl_state gl; std::shared_ptr pb; if (layout.m_loaded) - { - pb = show_progress("Export Pano Image"); - } - - int progress = 0; - int total = (int)names.size(); + pb = show_progress("Export Pano Image", names.size()); for (const auto& n : names) { std::string path = data_path + "/" + n; upload(path); - progress++; - float p = (float)progress / total * 100.f; - LOG("progress: %f", p); - if (layout.m_loaded) - { - pb->m_progress->SetWidthP(p); - } + pb->increment(); } if (layout.m_loaded) - { pb->destroy(); - } + }).detach(); } diff --git a/src/app_dialogs.cpp b/src/app_dialogs.cpp index def5f1a..acb70f9 100644 --- a/src/app_dialogs.cpp +++ b/src/app_dialogs.cpp @@ -13,7 +13,7 @@ #include "oculus_vr.h" #endif -std::shared_ptr App::show_progress(const std::string& title) +std::shared_ptr App::show_progress(const std::string& title, int total /*= 0*/) { auto pb = std::make_shared(); pb->m_manager = &layout; @@ -22,18 +22,25 @@ std::shared_ptr App::show_progress(const std::string& title) pb->loaded(); pb->m_progress->SetWidthP(0); pb->m_title->set_text(title.c_str()); + pb->m_total = total; + pb->m_count = 0; layout[main_id]->add_child(pb); return pb; } -NodeMessageBox* App::message_box(const std::string &title, const std::string& text, bool cancel_button) +std::shared_ptr App::message_box(const std::string &title, const std::string& text, bool cancel_button) { - auto* m = layout[main_id]->add_child(); + auto m = std::make_shared(); + m->m_manager = &layout; + m->init(); + m->create(); + m->loaded(); m->m_title->set_text(title.c_str()); m->m_message->set_text(text.c_str()); m->btn_ok->m_text->set_text("Ok"); if (!cancel_button) m->btn_cancel->destroy(); + layout[main_id]->add_child(m); return m; } @@ -501,12 +508,20 @@ void App::dialog_resize() }; } -void App::dialog_export_cubes() +void App::dialog_export_cube_faces() { if (canvas) { - canvas->m_canvas->export_cubes(); - } + canvas->m_canvas->export_cube_faces(doc_name, [this] { +#if defined(__IOS__) + message_box("Export Cube Faces", "Image and depth exported to Files/PanoPainter"); +#elif defined(__OSX__) + message_box("Export Cube Faces", "Image and depth exported to Pictures/PanoPainter folder"); +#elif defined(_WIN32) + message_box("Export Cube Faces", "Image and depth exported to " + work_path); +#endif + }); + } } void App::dialog_layer_rename() diff --git a/src/app_layout.cpp b/src/app_layout.cpp index 4e43ad5..48c5a76 100644 --- a/src/app_layout.cpp +++ b/src/app_layout.cpp @@ -636,6 +636,13 @@ void App::init_menu_file() popup->mouse_release(); popup->destroy(); }; + subpopup->find("file-submenu-export-cube")->on_click = [this, subpopup, popup](Node*) { + dialog_export_cube_faces(); + subpopup->mouse_release(); + subpopup->destroy(); + popup->mouse_release(); + popup->destroy(); + }; subpopup->find("file-submenu-export-depth")->on_click = [this, subpopup, popup](Node*) { dialog_export_depth(); subpopup->mouse_release(); @@ -656,13 +663,7 @@ void App::init_menu_file() popup->mouse_release(); popup->destroy(); }; - if (auto b = popup->find("file-export-cubes")) - b->on_click = [this, popup](Node*) { - dialog_export_cubes(); - popup->mouse_release(); - popup->destroy(); - }; - if (auto b = popup->find("file-cloud-upload")) + if (auto b = popup->find("file-cloud-upload")) b->on_click = [this, popup](Node*) { cloud_upload(); popup->mouse_release(); diff --git a/src/canvas.cpp b/src/canvas.cpp index 9beb7d2..a85a0b2 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -1921,183 +1921,69 @@ void Canvas::export_layers(std::string file_name, std::function on_compl void Canvas::export_layers_thread(std::string file_name) { - std::shared_ptr pb; - if (App::I->layout.m_loaded) + auto pb = App::I->show_progress("Export Layers", m_layers.size()); + for (int i = 0; i < m_layers.size(); i++) { - pb = std::make_shared(); - pb->m_manager = &App::I->layout; - pb->init(); - pb->create(); - pb->loaded(); - pb->m_progress->SetWidthP(0); - pb->m_title->set_text("Export Pano Layers"); - App::I->layout[App::I->main_id]->add_child(pb); + auto l = m_layers[i]; + Image img = l->gen_equirect().get_image(); + img.save_png(fmt::format("{}/{}-layer{:02d}-{}.png", App::I->work_path, file_name, i, l->m_name)); + pb->increment(); } - int progress = 0; - int total = (int)(m_layers.size() + 1) * 6; + pb->destroy(); +} - 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; - 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 - }; - App::I->render_task([&] +void Canvas::export_cube_faces(std::string file_name, std::function on_complete) +{ + if (App::I->check_license()) { - 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 seq = 0; - for (int layer_index = 0; layer_index < m_layers.size(); layer_index++) - { - for (int i = 0; i < 6; i++) - { - App::I->render_task([&] - { - // copy layer to cubemap - m_layers[layer_index]->m_rtt[i].bindFramebuffer(); - 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(); + std::thread t([=] { + BT_SetTerminate(); + export_cube_faces_thread(file_name); + if (on_complete) + on_complete(); }); - - progress++; - float p = (float)progress / total * 100.f; - LOG("progress: %f", p); - - if (App::I->layout.m_loaded) - { - pb->m_progress->SetWidthP(p); - } - } - - App::I->render_task([&] - { - glViewport(0, 0, m_latlong.getWidth(), m_latlong.getHeight()); - glActiveTexture(GL_TEXTURE0); - m_latlong.bindFramebuffer(); - m_latlong.clear({ 1, 1, 1, 0 }); - ShaderManager::use(kShader::Equirect); - ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); - ShaderManager::u_int(kShaderUniform::Tex, 0); - glBindTexture(GL_TEXTURE_CUBE_MAP, cube_id); - glDisable(GL_BLEND); - m_sampler_linear.bind(0); - m_plane.draw_fill(); - glBindTexture(GL_TEXTURE_CUBE_MAP, 0); - m_latlong.unbindFramebuffer(); - }); - - { - auto latlong_data = std::make_unique(m_latlong.bytes()); - m_latlong.readTextureData(latlong_data.get()); - static char name[128]; - sprintf(name, "%s/%s-layer-%02d.png", App::I->work_path.c_str(), file_name.c_str(), seq); - seq++; - LOG("writing %s", name); - int ret = stbi_write_png(name, m_latlong.getWidth(), m_latlong.getHeight(), 4, latlong_data.get(), m_latlong.stride()); - } - - progress++; - float p = (float)progress / total * 100.f; - LOG("progress: %f", p); - - if (App::I->layout.m_loaded) - { - pb->m_progress->SetWidthP(p); - } - } - - App::I->render_task([&] - { - glDeleteTextures(1, &cube_id); - m_latlong.destroy(); - }); - - if (App::I->layout.m_loaded) - { - pb->destroy(); + t.detach(); } } -void Canvas::export_cubes() +void Canvas::export_cube_faces_thread(std::string file_name) { - if (!App::I->check_license()) - return; #ifdef __OBJC__ NSMutableArray* files = [NSMutableArray array]; #endif - 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 (int layer = 0; layer < m_layers.size(); layer++) + static std::array plane_names{ "front", "right", "back", "left", "top", "bottom" }; + + auto pb = App::I->show_progress("Export Cube Faces", 7); + + App::I->render_task([this] { + draw_merge(false); + }); + pb->increment(); + + for (int i = 0; i < 6; i++) { - for (int plane = 0; plane < 6; plane++) - { - auto& l = m_layers[layer]; - 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", App::I->work_path.c_str(), layer, plane); - int ret = stbi_write_png(name, m_width, m_height, 4, buffer.get(), 0); - + Image face = m_layers_merge.m_rtt[i].get_image(); + std::string path = fmt::format("{}/{}-{}.png", App::I->work_path, file_name, plane_names[i]); + face.save_png(path); + pb->increment(); #ifdef __IOS__ - save_image_library(name); + save_image_library(path); #endif #ifdef __OBJC__ - [files addObject:[NSString stringWithUTF8String : name]]; + [files addObject : [NSString stringWithUTF8String:path.c_str()] ]; #endif - } - } + } + + pb->destroy(); + #ifdef __OBJC__ static char name[128]; sprintf(name, "%s.zip", App::I->work_path.c_str()); - auto zip_path = [NSString stringWithUTF8String : name]; + auto zip_path = [NSString stringWithUTF8String:name]; //[SSZipArchive createZipFileAtPath:zip_path withFilesAtPaths:files]; - for (NSString* f : files) - [[NSFileManager defaultManager] removeItemAtPath:f error:nil]; + //for (NSString* f : files) + // [[NSFileManager defaultManager] removeItemAtPath:f error:nil]; #endif } diff --git a/src/canvas.h b/src/canvas.h index 2fd7ba3..9d54f61 100644 --- a/src/canvas.h +++ b/src/canvas.h @@ -204,10 +204,11 @@ public: void export_equirectangular(std::string file_path, std::function on_complete = nullptr); void export_equirectangular_thread(std::string file_path); void export_layers(std::string file_name, std::function on_complete = nullptr); - void export_layers_thread(std::string file_name); + void export_layers_thread(std::string file_name); void export_depth(std::string file_name, std::function on_complete = nullptr); void export_depth_thread(std::string file_name); - void export_cubes(); + void export_cube_faces(std::string file_name, std::function on_complete); + void export_cube_faces_thread(std::string file_name); void project_save(std::function on_complete = nullptr); void project_save(std::string file_path, std::function on_complete = nullptr); bool project_save_thread(std::string file_path, bool show_progress); diff --git a/src/node.cpp b/src/node.cpp index 02984fa..47b182b 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -40,7 +40,7 @@ void Node::app_redraw() { App::I->redraw = true; - App::I->ui_cv.notify_all(); + App::I->render_cv.notify_all(); } void Node::watch(std::function observer) @@ -82,11 +82,11 @@ kEventResult Node::on_event(Event* e) { kEventResult ret = kEventResult::Available; - if (current_mouse_capture && current_mouse_capture != this) + if (current_mouse_capture && current_mouse_capture.get() != this) { if (e->m_cat == kEventCategory::MouseEvent && child_mouse_focus != current_mouse_capture && - is_child(current_mouse_capture)) + is_child(current_mouse_capture.get())) { MouseEvent* me = static_cast(e); if (child_mouse_focus) @@ -115,7 +115,7 @@ kEventResult Node::on_event(Event* e) } skip_children |= (e->m_cat == kEventCategory::MouseEvent || e->m_cat == kEventCategory::GestureEvent) && - (m_mouse_captured) && (root()->current_mouse_capture == this) && m_capture_children; // <-- THIS IS WRONG "!m_capture_children" is correct, but it breaks everything if changed + (m_mouse_captured) && (root()->current_mouse_capture.get() == this) && m_capture_children; // <-- THIS IS WRONG "!m_capture_children" is correct, but it breaks everything if changed if (!m_display || glm::any(glm::lessThanEqual(zw(m_clip), { 0, 0 }))) return kEventResult::Available; @@ -134,7 +134,7 @@ kEventResult Node::on_event(Event* e) } else { - if (e->m_cat == kEventCategory::MouseEvent && child_mouse_focus != it->get()) + if (e->m_cat == kEventCategory::MouseEvent && child_mouse_focus.get() != it->get()) { MouseEvent* me = static_cast(e); if (child_mouse_focus) @@ -147,7 +147,7 @@ kEventResult Node::on_event(Event* e) MouseEvent e2 = *me; e2.m_type = kEventType::MouseFocus; (*it)->handle_event(&e2); - child_mouse_focus = it->get(); + child_mouse_focus = *it; child_mouse_focus->m_mouse_focus = true; } ret = kEventResult::Consumed; @@ -401,7 +401,7 @@ void Node::remove_child(Node* n) YGNodeRemoveChild(y_node, n->y_node); on_child_removed(n); m_children.erase(i); - if (child_mouse_focus == n) + if (child_mouse_focus.get() == n) child_mouse_focus = nullptr; }); } @@ -542,7 +542,8 @@ void Node::mouse_capture() auto& s = root()->m_capture_stack; // already owner of capture - if (c == this || std::find(s.begin(), s.end(), this) != s.end()) + if (c.get() == this || std::find_if(s.begin(), s.end(), + [this](const auto& a) { return a.get() == this; }) != s.end()) return; if (c) @@ -570,7 +571,7 @@ void Node::mouse_capture() } // make current - c = this; + c = shared_from_this(); m_mouse_captured = true; } @@ -582,8 +583,9 @@ void Node::mouse_release() auto& c = root()->current_mouse_capture; auto& s = root()->m_capture_stack; - s.erase(std::remove(s.begin(), s.end(), this), s.end()); - if (c == this) + s.erase(std::remove_if(s.begin(), s.end(), + [this](const auto& a) { return a.get() == this; }), s.end()); + if (c.get() == this) { if (s.empty()) { @@ -604,7 +606,7 @@ void Node::key_capture() if (!m_parent) return; - root()->current_key_capture = this; + root()->current_key_capture = shared_from_this(); m_key_captured = true; } @@ -1376,8 +1378,6 @@ void Node::clone_copy(Node* dest) const dest->m_pos_offset = m_pos_offset; dest->m_pos_offset_childred = m_pos_offset_childred; dest->m_clip_uncut = m_clip_uncut; - - } void Node::clone_children(Node* dest) const diff --git a/src/node.h b/src/node.h index 1d9b3bb..2b25c5b 100644 --- a/src/node.h +++ b/src/node.h @@ -103,9 +103,9 @@ public: uint16_t m_nodeID; std::string m_nodeID_s; std::vector> m_children; - Node* current_mouse_capture = nullptr; - Node* current_key_capture = nullptr; - Node* child_mouse_focus = nullptr; + std::shared_ptr current_mouse_capture = nullptr; + std::shared_ptr current_key_capture = nullptr; + std::shared_ptr child_mouse_focus = nullptr; bool m_mouse_captured = false; bool m_key_captured = false; @@ -117,7 +117,7 @@ public: bool m_force_mouse_capture = false; bool m_capture_children = true; // wether to capture children events when xx_capture() is used bool m_destroyed = false; - std::vector m_capture_stack; + std::vector> m_capture_stack; bool m_mouse_ignore = true; float m_zoom = 1.f; diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp index bacff9b..1cf2194 100644 --- a/src/node_canvas.cpp +++ b/src/node_canvas.cpp @@ -63,6 +63,14 @@ void NodeCanvas::clear_context() void NodeCanvas::draw() { + // sanity checks + float zoom = root()->m_zoom; + if (zoom == 0.f) + zoom = 1.f; + auto box = m_clip * zoom; + if (box.z == 0 || box.w == 0) + return; + GLint vp[4]; GLfloat cc[4]; glGetIntegerv(GL_VIEWPORT, vp); @@ -73,8 +81,6 @@ void NodeCanvas::draw() glDisable(GL_SCISSOR_TEST); - float zoom = root()->m_zoom; - auto box = m_clip * zoom; glm::ivec4 c = (glm::ivec4)glm::vec4(box.x, (int)(vp[3] - box.y - box.w), box.z, box.w); //m_canvas->m_cam_rot = m_pan * 0.003f; diff --git a/src/node_combobox.cpp b/src/node_combobox.cpp index 2240f27..3c742ea 100644 --- a/src/node_combobox.cpp +++ b/src/node_combobox.cpp @@ -53,10 +53,10 @@ void NodeComboBox::loaded() m_current_index = index; m_selected_child_index = popup->get_child_index(target); m_text->set_text(m_items[index].c_str()); - popup->mouse_release(); - popup->destroy(); if (on_select) on_select(btn, index); + popup->mouse_release(); + popup->destroy(); }; } } diff --git a/src/node_panel_brush.cpp b/src/node_panel_brush.cpp index ea5f4eb..ea51c91 100644 --- a/src/node_panel_brush.cpp +++ b/src/node_panel_brush.cpp @@ -442,8 +442,7 @@ void NodePanelBrushPreset::init() if (!m_current) return; int index = m_container->get_child_index(m_current); - m_current->destroy_immediate(); - m_container->remove_child(m_current); + m_current->destroy(); if (m_container->m_children.empty()) { m_current = nullptr; diff --git a/src/node_panel_grid.cpp b/src/node_panel_grid.cpp index eb1ae31..69e3dd1 100644 --- a/src/node_panel_grid.cpp +++ b/src/node_panel_grid.cpp @@ -467,7 +467,7 @@ void NodePanelGrid::bake_uvs() ); while (pb_value < fb.getHeight()) { - pb->m_progress->SetWidthP((float)pb_value / (float)fb.getHeight() * 100.f); + pb->set_progress((float)pb_value / (float)fb.getHeight()); std::this_thread::sleep_for(std::chrono::milliseconds(100)); } worker.join(); diff --git a/src/node_panel_stroke.cpp b/src/node_panel_stroke.cpp index 4f14009..8fb93f4 100644 --- a/src/node_panel_stroke.cpp +++ b/src/node_panel_stroke.cpp @@ -76,8 +76,7 @@ bool NodePanelStroke::import_abr(const std::string& path) brush->m_user_brush = true; brush->on_click = std::bind(&NodePanelBrush::handle_click, m_brush_popup, std::placeholders::_1); count++; - float prog = (float)count / (float)tot; - pb->m_progress->SetWidthP(prog * 100.f); + pb->set_progress((float)count / (float)tot); }); m_brush_popup->save(); @@ -105,8 +104,7 @@ bool NodePanelStroke::import_abr(const std::string& path) brush->m_user_brush = true; brush->on_click = std::bind(&NodePanelBrush::handle_click, m_pattern_popup, std::placeholders::_1); count++; - float prog = (float)count / (float)tot; - pb->m_progress->SetWidthP(prog * 100.f); + pb->set_progress((float)count / (float)tot); }); m_pattern_popup->save(); @@ -119,8 +117,7 @@ bool NodePanelStroke::import_abr(const std::string& path) App::I->presets->add_brush(pr); } count++; - float prog = (float)count / (float)tot; - pb->m_progress->SetWidthP(prog * 100.f); + pb->set_progress((float)count / (float)tot); } App::I->presets->save(); diff --git a/src/node_progress_bar.cpp b/src/node_progress_bar.cpp index 32e98d9..f3a5501 100644 --- a/src/node_progress_bar.cpp +++ b/src/node_progress_bar.cpp @@ -20,5 +20,17 @@ void NodeProgressBar::init() btn_cancel->on_click = [&](Node*) { destroy(); }; m_progress = find("progress"); - m_progress->SetWidthP(10); + m_progress->SetWidthP(0); +} + +void NodeProgressBar::increment() noexcept +{ + m_count++; + if (m_total != 0) + m_progress->SetWidthP(((float)m_count / m_total) * 100.f); +} + +void NodeProgressBar::set_progress(float p) noexcept +{ + m_progress->SetWidthP(p * 100.f); } diff --git a/src/node_progress_bar.h b/src/node_progress_bar.h index f5133e3..f8436e1 100644 --- a/src/node_progress_bar.h +++ b/src/node_progress_bar.h @@ -11,6 +11,11 @@ public: NodeButton* btn_cancel; NodeText* m_title; NodeBorder* m_progress; + int m_total = 0; + int m_count = 0; virtual Node* clone_instantiate() const override; virtual void init() override; + void increment() noexcept; + // set progress where p [0, 1] + void set_progress(float p) noexcept; }; diff --git a/src/rtt.cpp b/src/rtt.cpp index d8e7cd7..9da0f1d 100644 --- a/src/rtt.cpp +++ b/src/rtt.cpp @@ -274,7 +274,7 @@ void RTT::clear_mask(glm::bool4 mask, glm::vec4 color) glColorMask(old_mask[0], old_mask[1], old_mask[2], old_mask[3]); } -glm::ivec4 RTT::calc_bounds() +glm::ivec4 RTT::calc_bounds() const noexcept { auto data = std::unique_ptr(reinterpret_cast(readTextureData())); glm::ivec2 bbmin(w, h); @@ -293,7 +293,7 @@ glm::ivec4 RTT::calc_bounds() return { bbmin, bbmax }; } -uint8_t* RTT::readTextureData(uint8_t* buffer) +uint8_t* RTT::readTextureData(uint8_t* buffer) const noexcept { if (!buffer) buffer = createBuffer(); @@ -308,7 +308,7 @@ uint8_t* RTT::readTextureData(uint8_t* buffer) return buffer; } -float* RTT::readTextureDataFloat(float* buffer) +float* RTT::readTextureDataFloat(float* buffer) const noexcept { if (!buffer) buffer = createBufferFloat(); @@ -323,12 +323,12 @@ float* RTT::readTextureDataFloat(float* buffer) return buffer; } -uint8_t* RTT::createBuffer() +uint8_t* RTT::createBuffer() const noexcept { return new uint8_t[w * h * 4]; } -float * RTT::createBufferFloat() +float * RTT::createBufferFloat() const noexcept { return new float[w * h * 4]; } @@ -345,4 +345,10 @@ void RTT::unbindTexture() glBindTexture(GL_TEXTURE_2D, 0); } +Image RTT::get_image() const noexcept +{ + Image ret; + ret.create(w, h, readTextureData()); + return ret; +} diff --git a/src/rtt.h b/src/rtt.h index e17405f..aeaa869 100644 --- a/src/rtt.h +++ b/src/rtt.h @@ -1,4 +1,5 @@ #pragma once +#include "image.h" class RTT { @@ -28,20 +29,21 @@ public: bool recreate() { return create(w, h); } void clear(glm::vec4 color = glm::vec4(0)); void clear_mask(glm::bool4 mask, glm::vec4 color = glm::vec4(0)); - glm::ivec4 calc_bounds(); - uint8_t* readTextureData(uint8_t* buffer = nullptr); - float* readTextureDataFloat(float* buffer = nullptr); - uint8_t* createBuffer(); - float* createBufferFloat(); + glm::ivec4 calc_bounds() const noexcept; + uint8_t* readTextureData(uint8_t* buffer = nullptr) const noexcept; + float* readTextureDataFloat(float* buffer = nullptr) const noexcept; + uint8_t* createBuffer() const noexcept; + float* createBufferFloat() const noexcept; void bindFramebuffer(); void unbindFramebuffer(); void bindTexture(); void unbindTexture(); - GLuint getTextureID() const { return texID; } - int getWidth() const { return w; } - int getHeight() const { return h; } - glm::ivec2 getSize() const { return { w, h }; } - int bytes() const { return w * h * 4; } - int stride() const { return w * 4; } - GLuint getFBO() const { return fboID; } + GLuint getTextureID() const noexcept { return texID; } + int getWidth() const noexcept { return w; } + int getHeight() const noexcept { return h; } + glm::ivec2 getSize() const noexcept { return { w, h }; } + int bytes() const noexcept { return w * h * 4; } + int stride() const noexcept { return w * 4; } + GLuint getFBO() const noexcept { return fboID; } + Image get_image() const noexcept; };