diff --git a/android/src/main/java/com/omixlab/panopainter/MainActivity.java b/android/src/main/java/com/omixlab/panopainter/MainActivity.java index 4cb3ca8..be43c53 100644 --- a/android/src/main/java/com/omixlab/panopainter/MainActivity.java +++ b/android/src/main/java/com/omixlab/panopainter/MainActivity.java @@ -93,23 +93,23 @@ public class MainActivity extends NativeActivity { Log.v("PanoPainterJava", "create path failed: " + brush_thumbs.getAbsolutePath()); } - // patterns - File patterns = new File(pano_dir.getAbsolutePath(), "patterns"); - if (!patterns.exists()) + // textures + File textures = new File(pano_dir.getAbsolutePath(), "textures"); + if (!textures.exists()) { - if (patterns.mkdirs()) - Log.v("PanoPainterJava", "create path " + patterns.getAbsolutePath()); + if (textures.mkdirs()) + Log.v("PanoPainterJava", "create path " + textures.getAbsolutePath()); else - Log.v("PanoPainterJava", "create path failed: " + patterns.getAbsolutePath()); + Log.v("PanoPainterJava", "create path failed: " + textures.getAbsolutePath()); } - File patterns_thumbs = new File(patterns.getAbsolutePath(), "thumbs"); - if (!patterns_thumbs.exists()) + File textures_thumbs = new File(textures.getAbsolutePath(), "thumbs"); + if (!textures_thumbs.exists()) { - if (patterns_thumbs.mkdirs()) - Log.v("PanoPainterJava", "create path " + patterns_thumbs.getAbsolutePath()); + if (textures_thumbs.mkdirs()) + Log.v("PanoPainterJava", "create path " + textures_thumbs.getAbsolutePath()); else - Log.v("PanoPainterJava", "create path failed: " + patterns_thumbs.getAbsolutePath()); + Log.v("PanoPainterJava", "create path failed: " + textures_thumbs.getAbsolutePath()); } // settings diff --git a/data/thumbs/Round-Brush.png b/data/brushes/thumbs/Round-Brush.png similarity index 100% rename from data/thumbs/Round-Brush.png rename to data/brushes/thumbs/Round-Brush.png diff --git a/data/thumbs/Round-Hard.png b/data/brushes/thumbs/Round-Hard.png similarity index 100% rename from data/thumbs/Round-Hard.png rename to data/brushes/thumbs/Round-Hard.png diff --git a/data/thumbs/Square-Hard.png b/data/brushes/thumbs/Square-Hard.png similarity index 100% rename from data/thumbs/Square-Hard.png rename to data/brushes/thumbs/Square-Hard.png diff --git a/data/layout.xml b/data/layout.xml index 873c8df..5b7dfd8 100644 --- a/data/layout.xml +++ b/data/layout.xml @@ -286,17 +286,17 @@ - - + + - - - - - + + + + + diff --git a/src/app.cpp b/src/app.cpp index 05ac221..4cc591b 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -143,14 +143,14 @@ void App::initLog() { LOG("error creating brushes thumbs path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); } - // patterns - if (![[NSFileManager defaultManager] createDirectoryAtPath:[docpath stringByAppendingString:@"/patterns"] withIntermediateDirectories:YES attributes:nil error:&err]) + // textures + if (![[NSFileManager defaultManager] createDirectoryAtPath:[docpath stringByAppendingString:@"/textures"] withIntermediateDirectories:YES attributes:nil error:&err]) { - LOG("error creating patterns path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); + LOG("error creating textures path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); } - if (![[NSFileManager defaultManager] createDirectoryAtPath:[docpath stringByAppendingString:@"/patterns /thumbs"] withIntermediateDirectories:YES attributes:nil error:&err]) + if (![[NSFileManager defaultManager] createDirectoryAtPath:[docpath stringByAppendingString:@"/textures/thumbs"] withIntermediateDirectories:YES attributes:nil error:&err]) { - LOG("error creating patterns thumbs path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); + LOG("error creating textures thumbs path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); } // settings if (![[NSFileManager defaultManager] createDirectoryAtPath:[docpath stringByAppendingString:@"/settings"] withIntermediateDirectories:YES attributes:nil error:&err]) @@ -184,14 +184,14 @@ void App::initLog() { LOG("error creating brushes thumbs path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); } - // patterns - if (![[NSFileManager defaultManager] createDirectoryAtPath:[docpath stringByAppendingString:@"/patterns"] withIntermediateDirectories:YES attributes:nil error:&err]) + // textures + if (![[NSFileManager defaultManager] createDirectoryAtPath:[docpath stringByAppendingString:@"/textures"] withIntermediateDirectories:YES attributes:nil error:&err]) { LOG("error creating brushes path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); } - if (![[NSFileManager defaultManager] createDirectoryAtPath:[docpath stringByAppendingString:@"/patterns/thumbs"] withIntermediateDirectories:YES attributes:nil error:&err]) + if (![[NSFileManager defaultManager] createDirectoryAtPath:[docpath stringByAppendingString:@"/textures/thumbs"] withIntermediateDirectories:YES attributes:nil error:&err]) { - LOG("error creating patterns thumbs path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); + LOG("error creating textures thumbs path: %s", [[err localizedDescription] cStringUsingEncoding:NSASCIIStringEncoding]); } // settings if (![[NSFileManager defaultManager] createDirectoryAtPath:[docpath stringByAppendingString:@"/settings"] withIntermediateDirectories:YES attributes:nil error:&err]) @@ -237,10 +237,10 @@ void App::initLog() if (!PathFileExistsA((data_path + "\\brushes\\thumbs").c_str())) CreateDirectoryA((data_path + "\\brushes\\thumbs").c_str(), NULL); - if (!PathFileExistsA((data_path + "\\patterns").c_str())) - CreateDirectoryA((data_path + "\\patterns").c_str(), NULL); - if (!PathFileExistsA((data_path + "\\patterns\\thumbs").c_str())) - CreateDirectoryA((data_path + "\\patterns\\thumbs").c_str(), NULL); + if (!PathFileExistsA((data_path + "\\textures").c_str())) + CreateDirectoryA((data_path + "\\textures").c_str(), NULL); + if (!PathFileExistsA((data_path + "\\textures\\thumbs").c_str())) + CreateDirectoryA((data_path + "\\textures\\thumbs").c_str(), NULL); if (!PathFileExistsA((data_path + "\\settings").c_str())) CreateDirectoryA((data_path + "\\settings").c_str(), NULL); diff --git a/src/app_layout.cpp b/src/app_layout.cpp index a513b68..ba3f942 100644 --- a/src/app_layout.cpp +++ b/src/app_layout.cpp @@ -132,7 +132,7 @@ void App::init_sidebar() Canvas::I->m_current_brush->load_texture(path, thumb); stroke->m_preview->draw_stroke(); }; - stroke->on_stencil_changed = [this](Node*target, const std::string& path, const std::string& thumb) { + stroke->on_texture_changed = [this](Node*target, const std::string& path, const std::string& thumb) { Canvas::I->m_current_brush->load_stencil(path, thumb); stroke->m_preview->draw_stroke(); }; diff --git a/src/brush.cpp b/src/brush.cpp index bbf2837..3787447 100644 --- a/src/brush.cpp +++ b/src/brush.cpp @@ -262,7 +262,7 @@ void Stroke::add_point(glm::vec3 pos, float pressure) float dist = m_keypoints.empty() ? m_step : m_keypoints.back().dist + glm::distance(m_keypoints.back().pos, pos); if (m_keypoints.empty()) - m_prev_sample.origin = pos; + m_prev_sample = randomize_sample(pos, pressure, 0); else if (m_keypoints.back().pos == pos) return; // skip same point, leading to black samples (NaN values) Keypoint kp; diff --git a/src/canvas.cpp b/src/canvas.cpp index 39cbec4..2da9638 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -444,7 +444,7 @@ std::vector Canvas::stroke_draw_compute(Stroke& stroke) con B[j].uvs2 = p / mixer_sz; } - f.m_mixer_rect = { mixer_bb_min, mixer_bb_max - mixer_bb_min }; + f.m_mixer_rect = { glm::floor(mixer_bb_min), glm::ceil(mixer_bb_max - mixer_bb_min) }; f.col = glm::vec4(s.col, 1); f.pressure = s.flow; f.shapes = stroke_draw_project(B); diff --git a/src/node_panel_brush.cpp b/src/node_panel_brush.cpp index 59a9b0c..e2e089b 100644 --- a/src/node_panel_brush.cpp +++ b/src/node_panel_brush.cpp @@ -73,8 +73,11 @@ void NodePanelBrush::init() return; } - for (const auto& samp : abr.m_samples) + parallel_for(abr.m_samples.size(), [&](size_t i) { + auto ii = abr.m_samples.begin(); + std::advance(ii, i); + const auto& samp = *ii; std::string path_high = App::I.data_path + "/brushes/" + samp.first + ".png"; std::string path_thumb = App::I.data_path + "/brushes/thumbs/" + samp.first + ".png"; auto padded = samp.second->resize_squared(glm::u8vec4(255)); @@ -83,29 +86,32 @@ void NodePanelBrush::init() auto thumb = padded.resize(64, 64); thumb.save(path_thumb); - async_start(); - NodeButtonBrush* brush = new NodeButtonBrush; - m_container->add_child(brush); - brush->init(); - brush->create(); - brush->loaded(); - brush->set_icon(path_thumb.c_str()); - brush->thumb_path = path_thumb; - brush->high_path = path_high; - brush->brush_name = name; - brush->m_user_brush = true; - brush->on_click = std::bind(&NodePanelBrush::handle_click, this, std::placeholders::_1); - app_redraw(); - async_end(); - } - for (const auto& patt : abr.m_patterns) + //async_start(); + //NodeButtonBrush* brush = new NodeButtonBrush; + //m_container->add_child(brush); + //brush->init(); + //brush->create(); + //brush->loaded(); + //brush->set_icon(path_thumb.c_str()); + //brush->thumb_path = path_thumb; + //brush->high_path = path_high; + //brush->brush_name = name; + //brush->m_user_brush = true; + //brush->on_click = std::bind(&NodePanelBrush::handle_click, this, std::placeholders::_1); + //app_redraw(); + //async_end(); + }); + parallel_for(abr.m_patterns.size(), [&](size_t i) { - std::string path_high = App::I.data_path + "/patterns/" + patt.first + ".png"; - std::string path_thumb = App::I.data_path + "/patterns/thumbs/" + patt.first + ".png"; + auto ii = abr.m_patterns.begin(); + std::advance(ii, i); + const auto& patt = *ii; + std::string path_high = App::I.data_path + "/textures/" + patt.first + ".png"; + std::string path_thumb = App::I.data_path + "/textures/thumbs/" + patt.first + ".png"; patt.second->save(path_high); auto thumb = patt.second->resize(64, 64); thumb.save(path_thumb); - } + }); auto brushes = abr.compute_brushes(App::I.data_path); for (const auto& pr : brushes) { @@ -120,10 +126,10 @@ void NodePanelBrush::init() } //save(); } - else if (img.load_file(path)) + else if (!m_dir_name.empty() && img.load_file(path)) { - std::string path_high = App::I.data_path + "/brushes/" + name + ".png"; - std::string path_thumb = App::I.data_path + "/brushes/thumbs/" + name + ".png"; + std::string path_high = App::I.data_path + "/" + m_dir_name + "/" + name + ".png"; + std::string path_thumb = App::I.data_path + "/" + m_dir_name + "/thumbs/" + name + ".png"; img = img.resize_squared(glm::u8vec4(255)); //img.gayscale_alpha(); @@ -204,13 +210,13 @@ void NodePanelBrush::init() m_container = find("brushes"); restore(); - if (m_container->m_children.empty()) + if (m_container->m_children.empty() && !m_dir_name.empty()) { - auto icons = Asset::list_files("data/brushes", true, ".*\\.png$"); + auto icons = Asset::list_files("data/" + m_dir_name, true, ".*\\.png$"); for (auto& i : icons) { - std::string path = "data/thumbs/" + i; - std::string path_hi = "data/brushes/" + i; + std::string path = "data/" + m_dir_name + "/thumbs/" + i; + std::string path_hi = "data/" + m_dir_name + "/" + i; NodeButtonBrush* brush = new NodeButtonBrush; m_container->add_child(brush); brush->init(); @@ -224,11 +230,11 @@ void NodePanelBrush::init() brush->on_click = std::bind(&NodePanelBrush::handle_click, this, std::placeholders::_1); } - auto custom_icons = Asset::list_files(App::I.data_path + "/brushes", true, ".*\\.png$"); + auto custom_icons = Asset::list_files(App::I.data_path + "/" + m_dir_name, true, ".*\\.png$"); for (auto& i : custom_icons) { - std::string path_thumb = App::I.data_path + "/brushes/thumbs/" + i; - std::string path_high = App::I.data_path + "/brushes/" + i; + std::string path_thumb = App::I.data_path + "/" + m_dir_name + "/thumbs/" + i; + std::string path_high = App::I.data_path + "/" + m_dir_name + "/" + i; NodeButtonBrush* brush = new NodeButtonBrush; m_container->add_child(brush); brush->init(); @@ -290,17 +296,21 @@ int NodePanelBrush::find_brush(const std::string & name) const std::string NodePanelBrush::get_texture_path(int index) const { + if (index < 0 || index >= m_container->m_children.size()) + return ""; return ((NodeButtonBrush*)m_container->m_children[index].get())->high_path; } std::string NodePanelBrush::get_thumb_path(int index) const { + if (index < 0 || index >= m_container->m_children.size()) + return ""; return ((NodeButtonBrush*)m_container->m_children[index].get())->thumb_path; } bool NodePanelBrush::save() { - auto path = App::I.data_path + "/settings/brushes.bin"; + auto path = App::I.data_path + "/settings/" + m_dir_name + ".bin"; if (FILE* fp = fopen(path.c_str(), "wb")) { header_t h; @@ -334,7 +344,7 @@ bool NodePanelBrush::save() bool NodePanelBrush::restore() { - auto path = App::I.data_path + "/settings/brushes.bin"; + auto path = App::I.data_path + "/settings/" + m_dir_name + ".bin"; if (FILE* fp = fopen(path.c_str(), "rb")) { header_t h; diff --git a/src/node_panel_brush.h b/src/node_panel_brush.h index 63603ee..d175a4b 100644 --- a/src/node_panel_brush.h +++ b/src/node_panel_brush.h @@ -47,6 +47,7 @@ class NodePanelBrush : public Node bool m_user_brush = false; }; public: + std::string m_dir_name; std::function on_brush_changed; std::function on_popup_close; virtual Node* clone_instantiate() const override; diff --git a/src/node_panel_stroke.cpp b/src/node_panel_stroke.cpp index 6a35108..a1b97a0 100644 --- a/src/node_panel_stroke.cpp +++ b/src/node_panel_stroke.cpp @@ -77,6 +77,7 @@ void NodePanelStroke::init_controls() { m_brush_popup = std::make_shared(); m_brush_popup->m_manager = m_manager; + m_brush_popup->m_dir_name = "brushes"; m_brush_popup->init(); m_brush_popup->create(); m_brush_popup->loaded(); @@ -86,6 +87,18 @@ void NodePanelStroke::init_controls() m_brush_popup->m_flood_events = true; m_brush_popup->m_capture_children = false; + m_texture_popup = std::make_shared(); + m_texture_popup->m_manager = m_manager; + m_texture_popup->m_dir_name = "textures"; + m_texture_popup->init(); + m_texture_popup->create(); + m_texture_popup->loaded(); + m_texture_popup->SetPositioning(YGPositionTypeAbsolute); + m_texture_popup->SetSize(300, 400); + m_texture_popup->m_mouse_ignore = false; + m_texture_popup->m_flood_events = true; + m_texture_popup->m_capture_children = false; + m_presets_popup = std::make_shared(); m_presets_popup->m_manager = m_manager; m_presets_popup->init(); @@ -98,6 +111,7 @@ void NodePanelStroke::init_controls() m_presets_popup->m_capture_children = false; int br_idx = std::max(m_brush_popup->find_brush("Round-Hard"), 0); + // init main brush auto b = std::make_shared(); b->load_texture(m_brush_popup->get_texture_path(br_idx), m_brush_popup->get_thumb_path(br_idx)); @@ -219,11 +233,45 @@ void NodePanelStroke::init_controls() if (on_dual_changed) on_dual_changed(this, m_brush_popup->get_texture_path(index), m_brush_popup->get_thumb_path(index)); m_dual_brush_thumb->set_image(m_brush_popup->get_thumb_path(index)); - //m_brush_popup->mouse_release(); - //m_brush_popup->parent->remove_child(m_brush_popup.get()); }; }; + + // TEXTURE IMAGE + + m_texture_thumb = find("texture-change-thumb"); + m_texture_thumb->set_image(m_texture_popup->get_thumb_path(0)); + m_texture_button = find("texture-change"); + m_texture_button->on_click = [this](Node*) { + auto screen = root()->m_size; + glm::vec2 pos = m_texture_button->m_pos + glm::vec2(m_texture_button->m_size.x, 0); + root()->add_child(m_texture_popup); + auto tick = root()->add_child(); + tick->SetPositioning(YGPositionTypeAbsolute); + tick->SetSize(16, 32); + tick->SetPosition(pos.x, pos.y + (m_texture_button->m_size.y - 32) * 0.5f); + tick->set_image("data/ui/popup-tick.png"); + root()->update(); + if ((pos.y + m_texture_popup->m_size.y) > screen.y) + pos.y = screen.y - m_texture_popup->m_size.y; + if (pos.y < 0) + pos.y = 0; + m_texture_popup->SetPosition(pos.x + 16, pos.y); + m_texture_popup->mouse_capture(); + root()->update(); + + m_texture_popup->on_popup_close = [this, tick](Node*) { + tick->destroy(); + }; + + m_texture_popup->on_brush_changed = [this](Node*, int index) { + if (on_texture_changed) + on_texture_changed(this, m_texture_popup->get_texture_path(index), m_texture_popup->get_thumb_path(index)); + m_texture_thumb->set_image(m_texture_popup->get_thumb_path(index)); + }; + }; + + m_preview = find("canvas"); m_blend_mode = find("blend-mode"); m_blend_mode->on_select = [this](Node*, int index) { @@ -308,19 +356,21 @@ void NodePanelStroke::init_controls() m_preview->m_brush = Canvas::I->m_current_brush; m_preview->draw_stroke(); +/* auto load_stencil = find("tip-stencil-load"); load_stencil->on_click = [this](Node*) { App::I.pick_image([this](std::string path) { App::I.async_start(); if (TextureManager::load(path.c_str())) { - if (on_stencil_changed) - on_stencil_changed(this, path, ""); + if (on_texture_changed) + on_texture_changed(this, path, ""); } App::I.async_redraw(); App::I.async_end(); }); }; +*/ update_controls(); } diff --git a/src/node_panel_stroke.h b/src/node_panel_stroke.h index 4e43609..436d041 100644 --- a/src/node_panel_stroke.h +++ b/src/node_panel_stroke.h @@ -39,8 +39,10 @@ public: NodeCheckBox* m_tip_size_pressure; NodeButtonCustom* m_brush_button; NodeButtonCustom* m_dual_brush_button; + NodeButtonCustom* m_texture_button; NodeImage* m_brush_thumb; NodeImage* m_dual_brush_thumb; + NodeImage* m_texture_thumb; NodeImage* m_preset_thumb; NodeButtonCustom* m_preset_button; NodeStrokePreview* m_preset_preview; @@ -68,9 +70,10 @@ public: NodeButtonCustom* m_tip_aspect_reset; std::shared_ptr m_brush_popup; + std::shared_ptr m_texture_popup; std::shared_ptr m_presets_popup; std::function on_stroke_change; - std::function on_stencil_changed; + std::function on_texture_changed; std::function on_brush_changed; std::function on_dual_changed; std::map> m_curves;