Files
panopainter/src/node_panel_brush.cpp

401 lines
13 KiB
C++

#include "pch.h"
#include "log.h"
#include "node_panel_brush.h"
#include "asset.h"
#include "texture.h"
#ifdef __APPLE__
#include <Foundation/Foundation.h>
#endif
#include "canvas.h"
#include "app.h"
Node* NodeButtonBrush::clone_instantiate() const
{
return new NodeButtonBrush();
}
void NodeButtonBrush::init()
{
init_template("tpl-brush-icon");
color_hover = glm::vec4(.7, .7, .7, 1);
color_normal = glm::vec4(.3, .3, .3, 1);
m_color = color_normal;
img = (NodeImage*)m_children[0].get();
}
void NodeButtonBrush::set_icon(const char* path)
{
img->m_path = path;
img->m_tex_id = const_hash(img->m_path.c_str());
img->m_use_mipmaps = true;
img->create();
}
void NodeButtonBrush::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* NodePanelBrush::clone_instantiate() const
{
return new NodePanelBrush();
}
void NodePanelBrush::init()
{
init_template("tpl-panel-brushes");
//m_layers_container = find<NodeBorder>("layers-container");
static auto icons = Asset::list_files("data/thumbs", true, ".*\\.png$");
if ((m_container = find<NodeBorder>("brushes")))
{
int count = 0;
for (auto& i : icons)
{
std::string path = "data/thumbs/" + i;
std::string path_hi = "data/brushes/" + i;
NodeButtonBrush* brush = new NodeButtonBrush;
m_container->add_child(brush);
brush->init();
brush->create();
brush->loaded();
brush->set_icon(path.c_str());
brush->m_brushID = count++;
brush->thumb_path = path;
brush->high_path = path_hi;
brush->brush_name = i;
brush->high_id = const_hash(path_hi.c_str());
m_brushes.push_back(brush);
brush->on_click = std::bind(&NodePanelBrush::handle_click, this, std::placeholders::_1);
}
}
}
kEventResult NodePanelBrush::handle_event(Event* e)
{
switch (e->m_type)
{
case kEventType::MouseUpL:
if (!m_mouse_inside)
{
mouse_release();
parent->remove_child(this);
}
break;
default:
return kEventResult::Available;
break;
}
return kEventResult::Consumed;
}
void NodePanelBrush::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);
}
int NodePanelBrush::find_brush(const std::string & name) const
{
for (int i = 0; i < m_brushes.size(); i++)
{
if (m_brushes[i]->brush_name.find(name) != std::string::npos)
{
return i;
}
}
return -1;
}
std::string NodePanelBrush::get_texture_path(int index) const
{
return m_brushes[index]->high_path;
}
std::string NodePanelBrush::get_thumb_path(int index) const
{
return m_brushes[index]->thumb_path;
}
// select the current brush based on the texture id
void NodePanelBrush::select_brush(int brush_id)
{
if (m_current)
m_current->m_selected = false;
for (auto b : m_brushes)
{
if (b->m_brushID == brush_id)
{
b->m_selected = true;
m_current = b;
TextureManager::load(b->high_path.c_str(), true);
}
}
}
// -----------------------------------------------------------------------
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 = find<NodeImage>("thumb");
m_preview = find<NodeStrokePreview>("canvas");
}
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();
}
NodeBrushPresetItem::~NodeBrushPresetItem()
{
bool u = m_brush.unique();
}
//---
Node* NodePanelBrushPreset::clone_instantiate() const
{
return new NodePanelBrushPreset();
}
void NodePanelBrushPreset::init()
{
init_template("tpl-panel-brush-preset");
m_container = find<Node>("brushes");
m_btn_add = find<NodeButtonCustom>("btn-add");
m_btn_add->on_click = [this] (Node*) {
NodeBrushPresetItem* brush = new NodeBrushPresetItem;
m_container->add_child(brush);
brush->init();
brush->create();
brush->loaded();
brush->thumb_path = Canvas::I->m_current_brush->m_brush_thumb_path;
brush->high_path = Canvas::I->m_current_brush->m_brush_path;
brush->m_brush = std::make_shared<Brush>(*Canvas::I->m_current_brush);
//brush->m_brush->m_tip_size = .05f;
brush->m_preview->m_brush = brush->m_brush;
brush->m_preview->draw_stroke();
brush->m_thumb->m_use_mipmaps = true;
brush->m_thumb->set_image(brush->m_brush->m_brush_thumb_path);
brush->on_click = std::bind(&NodePanelBrushPreset::handle_click, this, std::placeholders::_1);
save();
};
m_btn_up = find<NodeButtonCustom>("btn-up");
m_btn_up->on_click = [this](Node*) {
if (m_current)
m_container->move_child(m_current, std::max(m_container->get_child_index(m_current) - 1, 0));
};
m_btn_down = find<NodeButtonCustom>("btn-down");
m_btn_down->on_click = [this](Node*) {
if (m_current)
m_container->move_child(m_current,
std::min(m_container->get_child_index(m_current) + 1, (int)m_container->m_children.size() - 1));
};
m_btn_save = find<NodeButtonCustom>("btn-save");
m_btn_save->on_click = [this](Node*) {
if (m_current)
{
*m_current->m_brush = *Canvas::I->m_current_brush;
m_current->m_preview->draw_stroke();
m_current->m_thumb->set_image(m_current->m_brush->m_brush_thumb_path);
}
};
m_btn_delete = find<NodeButtonCustom>("btn-remove");
m_btn_delete->on_click = [this](Node*) {
if (!m_current)
return;
int index = m_container->get_child_index(m_current);
m_current->destroy();
if (m_container->m_children.empty())
{
m_current = nullptr;
}
else
{
int next = std::min<int>(m_container->m_children.size() - 1, index);
m_current = (NodeBrushPresetItem*)m_container->m_children[next].get();
m_current->m_selected = true;
}
save();
};
restore();
}
kEventResult NodePanelBrushPreset::handle_event(Event* e)
{
switch (e->m_type)
{
case kEventType::MouseUpL:
if (!m_mouse_inside)
{
mouse_release();
parent->remove_child(this);
}
break;
default:
return kEventResult::Available;
break;
}
return kEventResult::Consumed;
}
void NodePanelBrushPreset::handle_click(Node* target)
{
if (target == m_current)
return;
if (m_current)
m_current->m_selected = false;
m_current = (NodeBrushPresetItem*)target;
m_current->m_selected = true;
if (on_brush_changed)
on_brush_changed(this, m_current->m_brush);
}
bool NodePanelBrushPreset::save()
{
auto path = App::I.data_path + "/presets.bin";
if (FILE* fp = fopen(path.c_str(), "wb"))
{
header_t h;
h.count = m_container->m_children.size();
fwrite(&h, sizeof(h), 1, fp);
for (const auto& child : m_container->m_children)
{
auto b = std::static_pointer_cast<NodeBrushPresetItem>(child);
item_t i;
i.m_name_len = b->m_brush->m_name.size();
i.m_brush_path_len = b->m_brush->m_brush_path.size();
i.m_brush_thumb_path_len = b->m_brush->m_brush_thumb_path.size();
i.m_stencil_path_len = b->m_brush->m_stencil_path.size();
i.m_tip_color = b->m_brush->m_tip_color;
i.m_tip_size = b->m_brush->m_tip_size;
i.m_tip_spacing = b->m_brush->m_tip_spacing;
i.m_tip_flow = b->m_brush->m_tip_flow;
i.m_tip_opacity = b->m_brush->m_tip_opacity;
i.m_tip_angle = b->m_brush->m_tip_angle;
i.m_tip_mix = b->m_brush->m_tip_mix;
i.m_tip_stencil = b->m_brush->m_tip_stencil;
i.m_tip_wet = b->m_brush->m_tip_wet;
i.m_tip_noise = b->m_brush->m_tip_noise;
i.m_tip_hue = b->m_brush->m_tip_hue;
i.m_tip_sat = b->m_brush->m_tip_sat;
i.m_tip_val = b->m_brush->m_tip_val;
i.m_tip_angle_follow = b->m_brush->m_tip_angle_follow;
i.m_tip_flow_pressure = b->m_brush->m_tip_flow_pressure;
i.m_tip_size_pressure = b->m_brush->m_tip_size_pressure;
i.m_tip_hue_pressure = b->m_brush->m_tip_hue_pressure;
i.m_tip_sat_pressure = b->m_brush->m_tip_sat_pressure;
i.m_tip_val_pressure = b->m_brush->m_tip_val_pressure;
i.m_jitter_scale = b->m_brush->m_jitter_scale;
i.m_jitter_angle = b->m_brush->m_jitter_angle;
i.m_jitter_spread = b->m_brush->m_jitter_spread;
i.m_jitter_flow = b->m_brush->m_jitter_flow;
i.m_jitter_hue = b->m_brush->m_jitter_hue;
i.m_jitter_sat = b->m_brush->m_jitter_sat;
i.m_jitter_val = b->m_brush->m_jitter_val;
i.m_blend_mode = b->m_brush->m_blend_mode;
fwrite(&i, sizeof(i), 1, fp);
fwrite(b->m_brush->m_name.c_str(), 1, b->m_brush->m_name.size(), fp);
fwrite(b->m_brush->m_brush_path.c_str(), 1, b->m_brush->m_brush_path.size(), fp);
fwrite(b->m_brush->m_brush_thumb_path.c_str(), 1, b->m_brush->m_brush_thumb_path.size(), fp);
fwrite(b->m_brush->m_stencil_path.c_str(), 1, b->m_brush->m_stencil_path.size(), fp);
}
fclose(fp);
}
return false;
}
bool NodePanelBrushPreset::restore()
{
auto path = App::I.data_path + "/presets.bin";
if (FILE* fp = fopen(path.c_str(), "rb"))
{
header_t h;
fread(&h, sizeof(h), 1, fp);
for (int k = 0; k < h.count; k++)
{
item_t i;
fread(&i, sizeof(i), 1, fp);
auto b = std::make_shared<Brush>();
b->m_tip_color = i.m_tip_color;
b->m_tip_size = i.m_tip_size;
b->m_tip_spacing = i.m_tip_spacing;
b->m_tip_flow = i.m_tip_flow;
b->m_tip_opacity = i.m_tip_opacity;
b->m_tip_angle = i.m_tip_angle;
b->m_tip_mix = i.m_tip_mix;
b->m_tip_stencil = i.m_tip_stencil;
b->m_tip_wet = i.m_tip_wet;
b->m_tip_noise = i.m_tip_noise;
b->m_tip_hue = i.m_tip_hue;
b->m_tip_sat = i.m_tip_sat;
b->m_tip_val = i.m_tip_val;
b->m_tip_angle_follow = i.m_tip_angle_follow;
b->m_tip_flow_pressure = i.m_tip_flow_pressure;
b->m_tip_size_pressure = i.m_tip_size_pressure;
b->m_tip_hue_pressure = i.m_tip_hue_pressure;
b->m_tip_sat_pressure = i.m_tip_sat_pressure;
b->m_tip_val_pressure = i.m_tip_val_pressure;
b->m_jitter_scale = i.m_jitter_scale;
b->m_jitter_angle = i.m_jitter_angle;
b->m_jitter_spread = i.m_jitter_spread;
b->m_jitter_flow = i.m_jitter_flow;
b->m_jitter_hue = i.m_jitter_hue;
b->m_jitter_sat = i.m_jitter_sat;
b->m_jitter_val = i.m_jitter_val;
b->m_blend_mode = i.m_blend_mode;
b->m_name.resize(i.m_name_len);
b->m_brush_path.resize(i.m_brush_path_len);
b->m_brush_thumb_path.resize(i.m_brush_thumb_path_len);
b->m_stencil_path.resize(i.m_stencil_path_len);
fread((char*)b->m_name.c_str(), 1, b->m_name.size(), fp);
fread((char*)b->m_brush_path.c_str(), 1, b->m_brush_path.size(), fp);
fread((char*)b->m_brush_thumb_path.c_str(), 1, b->m_brush_thumb_path.size(), fp);
fread((char*)b->m_stencil_path.c_str(), 1, b->m_stencil_path.size(), fp);
b->load_texture(b->m_brush_path, b->m_brush_thumb_path);
if (!b->m_stencil_path.empty())
b->load_stencil(b->m_stencil_path);
NodeBrushPresetItem* brush = new NodeBrushPresetItem;
m_container->add_child(brush);
brush->init();
brush->create();
brush->loaded();
brush->thumb_path = b->m_brush_thumb_path;
brush->high_path = b->m_brush_path;
brush->m_brush = b;
brush->m_brush->m_tip_size = .05f;
brush->m_preview->m_brush = b;
brush->m_preview->draw_stroke();
brush->m_thumb->set_image(brush->m_brush->m_brush_thumb_path);
brush->on_click = std::bind(&NodePanelBrushPreset::handle_click, this, std::placeholders::_1);
}
fclose(fp);
}
return false;
}