diff --git a/data/layout.xml b/data/layout.xml index 1460f08..5b7e1cf 100644 --- a/data/layout.xml +++ b/data/layout.xml @@ -81,10 +81,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/engine.xcodeproj/project.pbxproj b/engine.xcodeproj/project.pbxproj index 68f421c..25f1edd 100644 --- a/engine.xcodeproj/project.pbxproj +++ b/engine.xcodeproj/project.pbxproj @@ -163,7 +163,6 @@ ADC6F4661F3E66FB004177FA /* app_dialogs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADC6F4651F3E66FA004177FA /* app_dialogs.cpp */; }; ADC6F4671F3E66FB004177FA /* app_dialogs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADC6F4651F3E66FA004177FA /* app_dialogs.cpp */; }; ADC6F4681F3E66FB004177FA /* app_dialogs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADC6F4651F3E66FA004177FA /* app_dialogs.cpp */; }; - ADCB41B61F6FF2DD006D46FE /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD58E0521E107411006ACC15 /* main.cpp */; }; ADD7D26F1EBF9AE300D5A897 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = ADD7D26E1EBF9AE300D5A897 /* main.m */; }; ADD7D2721EBF9AE300D5A897 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = ADD7D2711EBF9AE300D5A897 /* AppDelegate.m */; }; ADD7D2791EBF9AE300D5A897 /* GameViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = ADD7D2781EBF9AE300D5A897 /* GameViewController.m */; }; @@ -186,7 +185,6 @@ ADD7D29A1EBF9E1C00D5A897 /* pch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD95AEC51E41EDEC002DD03A /* pch.cpp */; }; ADD7D29B1EBF9E1C00D5A897 /* layout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD3B1EBE1E3B8B7600E918E3 /* layout.cpp */; }; ADD7D29C1EBF9E1C00D5A897 /* shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD58E0631E2A76FD006ACC15 /* shader.cpp */; }; - ADD7D29D1EBF9E1C00D5A897 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD58E0521E107411006ACC15 /* main.cpp */; }; ADD7D29E1EBF9E1C00D5A897 /* shape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD58E06D1E2A80BC006ACC15 /* shape.cpp */; }; ADD7D29F1EBF9E1C00D5A897 /* app.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD58E0701E2A90EF006ACC15 /* app.cpp */; }; ADD7D2A01EBF9E1C00D5A897 /* image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD58E0661E2A7741006ACC15 /* image.cpp */; }; @@ -802,7 +800,6 @@ files = ( AD58E0791E342205006ACC15 /* tinyxml2.cpp in Sources */, AD10638B1EC7ADFA002A525F /* node_panel_color.cpp in Sources */, - ADCB41B61F6FF2DD006D46FE /* main.cpp in Sources */, AD10638C1EC7ADFA002A525F /* node_panel_layer.cpp in Sources */, AD29CC621EA2B214008C8BFA /* action.cpp in Sources */, AD1063891EC7ADFA002A525F /* node_message_box.cpp in Sources */, @@ -878,7 +875,6 @@ AD10639E1EC7AE92002A525F /* node_icon.cpp in Sources */, AD1063A71EC7AE92002A525F /* node_settings.cpp in Sources */, AD0E119E1ECA215600CDA6BB /* app_shaders.cpp in Sources */, - ADD7D29D1EBF9E1C00D5A897 /* main.cpp in Sources */, ADD7D29F1EBF9E1C00D5A897 /* app.cpp in Sources */, AD1063A41EC7AE92002A525F /* node_panel_layer.cpp in Sources */, AD1063AA1EC7AE92002A525F /* node_text_input.cpp in Sources */, diff --git a/engine/app.h b/engine/app.h index 45f9a74..cf24bb9 100644 --- a/engine/app.h +++ b/engine/app.h @@ -41,6 +41,7 @@ public: std::shared_ptr layers; std::shared_ptr color; std::shared_ptr stroke; + std::shared_ptr presets; NodeCanvas* canvas; Node* current_panel = nullptr; NodeScroll* panels; diff --git a/engine/app_layout.cpp b/engine/app_layout.cpp index fe93052..a0c81e2 100644 --- a/engine/app_layout.cpp +++ b/engine/app_layout.cpp @@ -121,6 +121,12 @@ void App::init_sidebar() stroke->create(); stroke->loaded(); + presets = std::make_shared(); + presets->m_manager = &layout; + presets->init(); + presets->create(); + presets->loaded(); + if (canvas) { stroke->m_canvas->m_brush.m_tip_color = color->m_color; @@ -136,6 +142,16 @@ void App::init_sidebar() if (on_brush_select) on_brush_select(index); }; + presets->on_brush_changed = [this](Node* target, int index) { + auto b = presets->get_brush(index); + // don't change some params + b.m_tip_size = stroke->m_canvas->m_brush.m_tip_size; + b.m_tip_color = stroke->m_canvas->m_brush.m_tip_color; + stroke->set_params(b); + canvas->m_brush = stroke->m_canvas->m_brush; + if (on_brush_select) + on_brush_select(index); + }; color->on_color_changed = [this](Node* target, glm::vec4 color) { stroke->m_canvas->m_brush.m_tip_color = color; @@ -196,6 +212,14 @@ void App::init_sidebar() button->set_color(panels->get_child_index(brushes.get()) == -1 ? color_button_normal : color_button_hlight); }; } + if (auto* button = layout[main_id]->find("btn-brush-preset")) + { + button->on_click = [this, button](Node*) { + panels->get_child_index(presets.get()) == -1 ? panels->add_child(presets) : panels->remove_child(presets.get()); + panels->fix_scroll(); + button->set_color(panels->get_child_index(presets.get()) == -1 ? color_button_normal : color_button_hlight); + }; + } if (auto* button = layout[main_id]->find("btn-color")) { button->on_click = [this, button](Node*) { diff --git a/engine/node_panel_brush.cpp b/engine/node_panel_brush.cpp index 86b48b0..03ecf8e 100644 --- a/engine/node_panel_brush.cpp +++ b/engine/node_panel_brush.cpp @@ -106,3 +106,105 @@ void NodePanelBrush::select_brush(int brush_id) } } } + +// ----------------------------------------------------------------------- + + +Node* NodeBrushPresetItem::clone_instantiate() const +{ + return new NodeBrushPresetItem(); +} + +void NodeBrushPresetItem::init() +{ + init_template("tpl-brush-preset"); + color_hover = glm::vec4(.7, .7, .7, 1); + color_normal = glm::vec4(.3, .3, .3, 1); + m_color = color_normal; + m_thumb = (NodeImage*)m_children[0].get(); + m_preview = (NodeStrokePreview*)m_children[1].get(); +} + +void NodeBrushPresetItem::draw() +{ + m_color = m_mouse_inside ? color_hover : color_normal; + m_color = m_selected ? glm::vec4(.9, 0, 0, 1) : m_color; + NodeButtonCustom::draw(); +} + +//--- + +Node* NodePanelBrushPreset::clone_instantiate() const +{ + return new NodePanelBrushPreset(); +} + +void NodePanelBrushPreset::init() +{ + init_template("tpl-panel-brush-preset"); + + static auto icons = Asset::list_files("data/thumbs", true, ".*\\.png$"); + + if ((m_container = find("brushes"))) + { + int count = 0; + for (auto& i : icons) + { + std::string path = "data/thumbs/" + i; + std::string path_hi = "data/brushes/" + i; + NodeBrushPresetItem* brush = new NodeBrushPresetItem; + m_container->add_child(brush); + brush->init(); + brush->create(); + brush->loaded(); +// brush->set_icon(path.c_str()); + brush->m_brushID = count++; + brush->high_path = path_hi; + brush->high_id = const_hash(path_hi.c_str()); + brush->m_brush.m_tex_id = const_hash(path.c_str()); + brush->m_brush.m_tip_size = .05; + brush->m_brush.m_tip_flow = .2; + brush->m_brush.m_tip_opacity = 1; + brush->m_brush.m_tip_spacing = 0.03; + brush->m_brush.m_jitter_spread = (rand() % 1000) * 0.0001; + brush->m_preview->m_brush = brush->m_brush; + brush->m_preview->draw_stroke(); + brush->m_thumb->m_path = path; + brush->m_thumb->m_tex_id = const_hash(path.c_str()); + brush->m_thumb->create(); + m_brushes.push_back(brush); + brush->on_click = std::bind(&NodePanelBrushPreset::handle_click, this, std::placeholders::_1); + } + } +} + +void NodePanelBrushPreset::handle_click(Node* target) +{ + if (target == m_current) + return; + if (m_current) + m_current->m_selected = false; + m_current = (NodeButtonBrush*)target; + m_current->m_selected = true; + if (on_brush_changed) + on_brush_changed(this, m_current->m_brushID); +} + +ui::Brush NodePanelBrushPreset::get_brush(int index) const +{ + auto b = m_brushes[index]->m_brush; + TextureManager::load(m_brushes[index]->high_path.c_str(), true); + b.m_tex_id = m_brushes[index]->high_id; + return b; +} + +uint16_t NodePanelBrushPreset::get_texture_id(int index) const +{ + TextureManager::load(m_brushes[index]->high_path.c_str(), true); + return m_brushes[index]->high_id; +} + +int NodePanelBrushPreset::get_brush_id(int index) const +{ + return m_brushes[index]->m_brushID; +} diff --git a/engine/node_panel_brush.h b/engine/node_panel_brush.h index a766615..6317b2c 100644 --- a/engine/node_panel_brush.h +++ b/engine/node_panel_brush.h @@ -2,6 +2,8 @@ #include "node.h" #include "node_button_custom.h" #include "node_image.h" +#include "node_stroke_preview.h" +#include "brush.h" class NodeButtonBrush : public NodeButtonCustom { @@ -32,3 +34,38 @@ public: int get_brush_id(int index) const; void select_brush(int brush_id); }; + +// ----------------------------------------------------------------------- + +class NodeBrushPresetItem : public NodeButtonCustom +{ +public: + int m_brushID; + ui::Brush m_brush; + std::string high_path; + uint16_t high_id; + bool m_selected = false; + NodeStrokePreview* m_preview; + NodeImage* m_thumb; + virtual Node* clone_instantiate() const override; + virtual void init() override; + virtual void draw() override; +}; + +class NodePanelBrushPreset : public Node +{ + std::vector m_brushes; + NodeButtonBrush* m_current = nullptr; + Node* m_container; +public: + std::function on_brush_changed; + virtual Node* clone_instantiate() const override; + virtual void init() override; + void handle_click(Node* target); + std::vector FindAllBrushes(const std::string& folder); + uint16_t get_texture_id(int index) const; + ui::Brush get_brush(int index) const; + int get_brush_id(int index) const; + void select_brush(int brush_id); +}; + diff --git a/engine/node_stroke_preview.cpp b/engine/node_stroke_preview.cpp index b32123f..ee19145 100644 --- a/engine/node_stroke_preview.cpp +++ b/engine/node_stroke_preview.cpp @@ -31,9 +31,9 @@ void NodeStrokePreview::init_controls() m_mesh.create(); m_sampler.create(); m_sampler_brush.create(); - m_sampler_brush.set_filter(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR); - TextureManager::load("data/Icons/Round-Hard.png"); - m_brush.m_tex_id = const_hash("data/Icons/Round-Hard.png"); + m_sampler_brush.set_filter(GL_LINEAR, GL_LINEAR); + TextureManager::load("data/thumbs/Round-Hard.png"); + m_brush.m_tex_id = const_hash("data/thumbs/Round-Hard.png"); } void NodeStrokePreview::restore_context()