implement export/import ppbr
This commit is contained in:
@@ -38,6 +38,46 @@
|
|||||||
</border>
|
</border>
|
||||||
</layout>
|
</layout>
|
||||||
|
|
||||||
|
<!-- PANEL BRUSH UPLOAD -->
|
||||||
|
<layout id="dialog-brush-upload">
|
||||||
|
<border id="background" positioning="absolute" position="0 0" color=".4 .4 .4 .8" width="100%" height="100%" align="center" justify="center" mouse-capture="true">
|
||||||
|
<border id="form" thickness="1" border-color=".2" pad="3" width="650" dir="col">
|
||||||
|
<border id="title-bar" width="100%" height="30" color=".2 .2 .2 .9" dir="row" align="center" justify="center">
|
||||||
|
<text text="Upload Brushes"></text>
|
||||||
|
</border>
|
||||||
|
<border width="100%" color="0 0 0 .9" pad="10" dir="row" grow="1">
|
||||||
|
<border id="files-list" dir="row" wrap="1" flood-events="1" grow="1" height="100%" margin="0 0 0 0" pad="10" color=".2 .2 .2 1">
|
||||||
|
<node dir="col" margin="0 20 0 0">
|
||||||
|
<image width="200" height="100"/>
|
||||||
|
<node dir="row" width="200" height="30" justify="center" margin="10 0 0 0">
|
||||||
|
<button text="Generate" grow="1" height="100%"/>
|
||||||
|
<button text="Open..." grow="1" height="100%"/>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
|
<node grow="1">
|
||||||
|
<node dir="row" height="30" align="center" grow="1">
|
||||||
|
<text text="Author" margin="0 5 0 0"/>
|
||||||
|
<text-input align="center" pad="5" grow="1" height="30" color=".3"/>
|
||||||
|
</node>
|
||||||
|
<node dir="row" height="30" align="center" grow="1">
|
||||||
|
<text text="URL" margin="0 5 0 0"/>
|
||||||
|
<text-input align="center" pad="5" grow="1" height="30" color=".3"/>
|
||||||
|
</node>
|
||||||
|
<node dir="row" height="30" align="center" grow="1">
|
||||||
|
<text text="Description" margin="0 5 0 0"/>
|
||||||
|
<text-input align="center" pad="5" grow="1" height="30" color=".3"/>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
|
</border>
|
||||||
|
</border>
|
||||||
|
<node id="footer" height="50" dir="row" align="flex-end" justify="flex-end" pad="10">
|
||||||
|
<button id="btn-ok" text="Share" width="100" height="30" margin="0 10 0 0"/>
|
||||||
|
<button id="btn-cancel" text="Cancel" width="60" height="30"/>
|
||||||
|
</node>
|
||||||
|
</border>
|
||||||
|
</border>
|
||||||
|
</layout>
|
||||||
|
|
||||||
<!-- PANEL LAYERS -->
|
<!-- PANEL LAYERS -->
|
||||||
<layout id="tpl-panel-layers">
|
<layout id="tpl-panel-layers">
|
||||||
<node width="300" margin="0 0 10 0" rtl="ltr">
|
<node width="300" margin="0 0 10 0" rtl="ltr">
|
||||||
@@ -1944,6 +1984,6 @@ Here's a list of what's available in this release.
|
|||||||
<image-texture id="tex-debug" width="100%" height="100%"></image-texture>
|
<image-texture id="tex-debug" width="100%" height="100%"></image-texture>
|
||||||
</border>
|
</border>
|
||||||
-->
|
-->
|
||||||
<!--<ref id="dialog-brush-download"/>-->
|
<!--<ref id="dialog-brush-upload"/>-->
|
||||||
</layout>
|
</layout>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ void App::open_document(std::string path)
|
|||||||
|
|
||||||
if (str_iequals(m[3].str(), "abr"))
|
if (str_iequals(m[3].str(), "abr"))
|
||||||
{
|
{
|
||||||
std::thread(&NodePanelStroke::import_abr, stroke, path).detach();
|
std::thread(&NodePanelBrushPreset::import_abr, presets, path).detach();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -537,7 +537,7 @@ void App::init_menu_file()
|
|||||||
|
|
||||||
if (str_iequals(ext, "abr"))
|
if (str_iequals(ext, "abr"))
|
||||||
{
|
{
|
||||||
std::thread([this,path] { stroke->import_abr(path); }).detach();
|
std::thread([this,path] { presets->import_abr(path); }).detach();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -373,6 +373,30 @@ bool Brush::valid()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Brush::relocate_paths(std::string base)
|
||||||
|
{
|
||||||
|
if (!Asset::is_asset(m_brush_path))
|
||||||
|
m_brush_path = replace_path(m_brush_path, base + "/brushes/");
|
||||||
|
if (!Asset::is_asset(m_dual_path))
|
||||||
|
m_dual_path = replace_path(m_dual_path, base + "/brushes/");
|
||||||
|
if (!Asset::is_asset(m_pattern_path))
|
||||||
|
m_pattern_path = replace_path(m_pattern_path, base + "/patterns/");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Brush::replace_path(std::string path, std::string new_base)
|
||||||
|
{
|
||||||
|
if (path.empty())
|
||||||
|
return path;
|
||||||
|
std::regex r(R"((.*)[\\/]([^\\/]+)\.(\w+)$)");
|
||||||
|
std::smatch m;
|
||||||
|
if (!std::regex_search(path, m, r))
|
||||||
|
return path;
|
||||||
|
std::string base = m[1].str();
|
||||||
|
std::string name = m[2].str();
|
||||||
|
std::string ext = m[3].str();
|
||||||
|
return new_base + "/" + name + "." + ext;
|
||||||
|
}
|
||||||
|
|
||||||
bool Brush::read(BinaryStreamReader& r)
|
bool Brush::read(BinaryStreamReader& r)
|
||||||
{
|
{
|
||||||
Serializer::Descriptor d;
|
Serializer::Descriptor d;
|
||||||
|
|||||||
@@ -102,6 +102,8 @@ public:
|
|||||||
bool preload();
|
bool preload();
|
||||||
void unload();
|
void unload();
|
||||||
bool valid();
|
bool valid();
|
||||||
|
void relocate_paths(std::string base);
|
||||||
|
std::string replace_path(std::string path, std::string new_base);
|
||||||
|
|
||||||
virtual bool read(BinaryStreamReader& r) override;
|
virtual bool read(BinaryStreamReader& r) override;
|
||||||
virtual void write(BinaryStreamWriter& w) const override;
|
virtual void write(BinaryStreamWriter& w) const override;
|
||||||
|
|||||||
@@ -197,9 +197,9 @@ Image Image::resize_squared(const glm::u8vec4& bg) const
|
|||||||
bool Image::read(BinaryStreamReader& r)
|
bool Image::read(BinaryStreamReader& r)
|
||||||
{
|
{
|
||||||
Serializer::Descriptor d;
|
Serializer::Descriptor d;
|
||||||
|
r >> d;
|
||||||
if (d.class_id != "image_png")
|
if (d.class_id != "image_png")
|
||||||
return false;
|
return false;
|
||||||
r >> d;
|
|
||||||
d.value<Serializer::Integer>("width", width);
|
d.value<Serializer::Integer>("width", width);
|
||||||
d.value<Serializer::Integer>("height", height);
|
d.value<Serializer::Integer>("height", height);
|
||||||
d.value<Serializer::Integer>("comp", comp);
|
d.value<Serializer::Integer>("comp", comp);
|
||||||
@@ -230,7 +230,7 @@ void Image::write(BinaryStreamWriter& w) const
|
|||||||
stbi_write_png_to_func([](void* context, void* data, int size) {
|
stbi_write_png_to_func([](void* context, void* data, int size) {
|
||||||
Serializer::Descriptor& d = *static_cast<Serializer::Descriptor*>(context);
|
Serializer::Descriptor& d = *static_cast<Serializer::Descriptor*>(context);
|
||||||
d.props["data"] = std::make_shared<Serializer::RawData>(std::vector<uint8_t>((uint8_t*)data, (uint8_t*)data + size));
|
d.props["data"] = std::make_shared<Serializer::RawData>(std::vector<uint8_t>((uint8_t*)data, (uint8_t*)data + size));
|
||||||
}, &d, width, height, comp, m_data.get(), 0);
|
}, &d, width, height, comp, m_data.get(), 0);
|
||||||
|
|
||||||
w << d;
|
w << d;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -288,7 +288,7 @@ std::string win32_save_file(const char* filter)
|
|||||||
ofn.lpstrFilter = filter;
|
ofn.lpstrFilter = filter;
|
||||||
ofn.lpstrFile = fileName;
|
ofn.lpstrFile = fileName;
|
||||||
ofn.nMaxFile = MAX_PATH;
|
ofn.nMaxFile = MAX_PATH;
|
||||||
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
|
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_OVERWRITEPROMPT;
|
||||||
ofn.lpstrDefExt = "";
|
ofn.lpstrDefExt = "";
|
||||||
ofn.lpstrInitialDir = "";
|
ofn.lpstrInitialDir = "";
|
||||||
if (GetSaveFileNameA(&ofn) != NULL)
|
if (GetSaveFileNameA(&ofn) != NULL)
|
||||||
|
|||||||
@@ -469,18 +469,42 @@ void NodePanelBrushPreset::init()
|
|||||||
popup->on_select = [this, popup] (Node* target, int index) {
|
popup->on_select = [this, popup] (Node* target, int index) {
|
||||||
switch (index)
|
switch (index)
|
||||||
{
|
{
|
||||||
case 0: // download
|
case 0: // import file
|
||||||
break;
|
|
||||||
case 1: // import
|
|
||||||
App::I->pick_file({"abr", "ppbr"}, [this] (std::string path) {
|
App::I->pick_file({"abr", "ppbr"}, [this] (std::string path) {
|
||||||
std::thread([this, path] {
|
std::thread([this, path] {
|
||||||
BT_SetTerminate();
|
BT_SetTerminate();
|
||||||
App::I->stroke->import_abr(path);
|
|
||||||
m_notification->SetVisibility(m_container->m_children.size() == 0);
|
std::regex r(R"((.*)[\\/]([^\\/]+)\.(\w+)$)");
|
||||||
|
std::smatch m;
|
||||||
|
if (!std::regex_search(path, m, r))
|
||||||
|
return;
|
||||||
|
std::string base = m[1].str();
|
||||||
|
std::string name = m[2].str();
|
||||||
|
std::string ext = m[3].str();
|
||||||
|
|
||||||
|
if (ext == "ppbr")
|
||||||
|
{
|
||||||
|
import_ppbr(path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
import_abr(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
App::I->ui_task([this] {
|
||||||
|
m_notification->SetVisibility(m_container->m_children.size() == 0);
|
||||||
|
});
|
||||||
}).detach();
|
}).detach();
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 2: // export
|
case 1: // export file
|
||||||
|
App::I->pick_file_save({ "ppbr" }, [this] (std::string path) {
|
||||||
|
export_ppbr(path, {});
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 2: // download
|
||||||
|
break;
|
||||||
|
case 3: // upload
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
popup->destroy();
|
popup->destroy();
|
||||||
@@ -491,7 +515,7 @@ void NodePanelBrushPreset::init()
|
|||||||
App::I->pick_file({ "abr", "ppbr" }, [this](std::string path) {
|
App::I->pick_file({ "abr", "ppbr" }, [this](std::string path) {
|
||||||
std::thread([this, path] {
|
std::thread([this, path] {
|
||||||
BT_SetTerminate();
|
BT_SetTerminate();
|
||||||
App::I->stroke->import_abr(path);
|
import_abr(path);
|
||||||
m_notification->SetVisibility(m_container->m_children.size() == 0);
|
m_notification->SetVisibility(m_container->m_children.size() == 0);
|
||||||
}).detach();
|
}).detach();
|
||||||
});
|
});
|
||||||
@@ -555,7 +579,8 @@ void NodePanelBrushPreset::handle_click(Node* target)
|
|||||||
|
|
||||||
bool NodePanelBrushPreset::save()
|
bool NodePanelBrushPreset::save()
|
||||||
{
|
{
|
||||||
std::ofstream f(App::I->data_path + "/settings/presets.bin", std::ios::binary);
|
auto path = App::I->data_path + "/settings/presets.bin";
|
||||||
|
std::ofstream f(path, std::ios::binary);
|
||||||
if (f.good())
|
if (f.good())
|
||||||
{
|
{
|
||||||
BinaryStreamWriter sw;
|
BinaryStreamWriter sw;
|
||||||
@@ -577,8 +602,8 @@ bool NodePanelBrushPreset::save()
|
|||||||
|
|
||||||
bool NodePanelBrushPreset::restore()
|
bool NodePanelBrushPreset::restore()
|
||||||
{
|
{
|
||||||
Asset f;
|
|
||||||
auto path = App::I->data_path + "/settings/presets.bin";
|
auto path = App::I->data_path + "/settings/presets.bin";
|
||||||
|
Asset f;
|
||||||
if (f.open(path.c_str()))
|
if (f.open(path.c_str()))
|
||||||
{
|
{
|
||||||
f.read_all();
|
f.read_all();
|
||||||
@@ -587,10 +612,11 @@ bool NodePanelBrushPreset::restore()
|
|||||||
sr.init(f.m_data, f.m_len);
|
sr.init(f.m_data, f.m_len);
|
||||||
|
|
||||||
// sanity checks
|
// sanity checks
|
||||||
if (sr.rstring(4) != "PPVR")
|
auto magic = sr.rstring(4);
|
||||||
|
if (magic != "PPVR")
|
||||||
{
|
{
|
||||||
LOG("PPVR tag not found")
|
LOG("PPVR tag not found")
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto vmaj = sr.ru16();
|
auto vmaj = sr.ru16();
|
||||||
auto vmin = sr.ru16();
|
auto vmin = sr.ru16();
|
||||||
@@ -613,19 +639,21 @@ bool NodePanelBrushPreset::restore()
|
|||||||
|
|
||||||
if (b->valid())
|
if (b->valid())
|
||||||
{
|
{
|
||||||
NodeBrushPresetItem* brush = new NodeBrushPresetItem;
|
App::I->ui_task([this, b] {
|
||||||
m_container->add_child(brush);
|
NodeBrushPresetItem* brush = new NodeBrushPresetItem;
|
||||||
brush->init();
|
m_container->add_child(brush);
|
||||||
brush->create();
|
brush->init();
|
||||||
brush->loaded();
|
brush->create();
|
||||||
brush->thumb_path = b->m_brush_thumb_path;
|
brush->loaded();
|
||||||
brush->high_path = b->m_brush_path;
|
brush->thumb_path = b->m_brush_thumb_path;
|
||||||
brush->m_brush = b;
|
brush->high_path = b->m_brush_path;
|
||||||
brush->m_preview->m_brush = b;
|
brush->m_brush = b;
|
||||||
brush->m_preview->draw_stroke();
|
brush->m_preview->m_brush = b;
|
||||||
brush->m_caption_size->set_text_format("%d", (int)b->m_tip_size);
|
brush->m_preview->draw_stroke();
|
||||||
brush->m_thumb->set_image(brush->m_brush->m_brush_thumb_path);
|
brush->m_caption_size->set_text_format("%d", (int)b->m_tip_size);
|
||||||
brush->on_click = std::bind(&NodePanelBrushPreset::handle_click, this, std::placeholders::_1);
|
brush->m_thumb->set_image(brush->m_brush->m_brush_thumb_path);
|
||||||
|
brush->on_click = std::bind(&NodePanelBrushPreset::handle_click, this, std::placeholders::_1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_notification->SetVisibility(m_container->m_children.size() == 0);
|
m_notification->SetVisibility(m_container->m_children.size() == 0);
|
||||||
@@ -654,6 +682,268 @@ void NodePanelBrushPreset::add_brush(std::shared_ptr<Brush> brush)
|
|||||||
m_notification->SetVisibility(m_container->m_children.size() == 0);
|
m_notification->SetVisibility(m_container->m_children.size() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NodePanelBrushPreset::export_ppbr(const std::string& path, const Image& header_image)
|
||||||
|
{
|
||||||
|
std::ofstream f(path, std::ios::binary);
|
||||||
|
if (f.good())
|
||||||
|
{
|
||||||
|
BinaryStreamWriter sw;
|
||||||
|
sw.init(BinaryStream::ByteOrder::LittleEndian);
|
||||||
|
sw.wstring_raw("PPBR");
|
||||||
|
sw.wu16(0);
|
||||||
|
sw.wu16(1);
|
||||||
|
|
||||||
|
// header image
|
||||||
|
sw << header_image;
|
||||||
|
|
||||||
|
// create previews
|
||||||
|
sw.wu32((int)m_container->m_children.size());
|
||||||
|
auto pr = std::make_unique<NodeStrokePreview>();
|
||||||
|
pr->m_preview_size = pr->m_size = { 256, 128 };
|
||||||
|
for (auto& c : m_container->m_children)
|
||||||
|
{
|
||||||
|
auto bpi = std::static_pointer_cast<NodeBrushPresetItem>(c);
|
||||||
|
pr->m_brush = std::make_shared<Brush>(*bpi->m_brush); // create copy
|
||||||
|
pr->m_brush->load();
|
||||||
|
Image img = pr->render_to_image();
|
||||||
|
img.file_name = pr->m_brush->m_name;
|
||||||
|
sw << img;
|
||||||
|
}
|
||||||
|
|
||||||
|
// list of images
|
||||||
|
std::set<std::string> img_brushes;
|
||||||
|
std::set<std::string> img_patterns;
|
||||||
|
for (auto& c : m_container->m_children)
|
||||||
|
{
|
||||||
|
auto bpi = std::static_pointer_cast<NodeBrushPresetItem>(c);
|
||||||
|
if (!bpi->m_brush->m_brush_path.empty() && !Asset::is_asset(bpi->m_brush->m_brush_path))
|
||||||
|
img_brushes.insert(bpi->m_brush->m_brush_path);
|
||||||
|
if (!bpi->m_brush->m_dual_path.empty() && !Asset::is_asset(bpi->m_brush->m_dual_path))
|
||||||
|
img_brushes.insert(bpi->m_brush->m_dual_path);
|
||||||
|
if (!bpi->m_brush->m_pattern_path.empty() && !Asset::is_asset(bpi->m_brush->m_pattern_path))
|
||||||
|
img_patterns.insert(bpi->m_brush->m_pattern_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write brushes
|
||||||
|
sw.wu32((int)img_brushes.size());
|
||||||
|
for (std::string image_path : img_brushes)
|
||||||
|
{
|
||||||
|
Image img;
|
||||||
|
if (!img.load(image_path))
|
||||||
|
LOG("export_ppbr failed to load image: %s", image_path.c_str());
|
||||||
|
sw << img;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write patterns
|
||||||
|
sw.wu32((int)img_patterns.size());
|
||||||
|
for (std::string image_path : img_patterns)
|
||||||
|
{
|
||||||
|
Image img;
|
||||||
|
if (!img.load(image_path))
|
||||||
|
LOG("export_ppbr failed to load image: %s", image_path.c_str());
|
||||||
|
sw << img;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write brush settings
|
||||||
|
sw.wu32((int)m_container->m_children.size());
|
||||||
|
for (auto& c : m_container->m_children)
|
||||||
|
{
|
||||||
|
auto bpi = std::static_pointer_cast<NodeBrushPresetItem>(c);
|
||||||
|
sw << *bpi->m_brush;
|
||||||
|
}
|
||||||
|
f.write((char*)sw.m_data.data(), sw.m_data.size());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NodePanelBrushPreset::import_ppbr(const std::string& path)
|
||||||
|
{
|
||||||
|
Asset f;
|
||||||
|
if (f.open(path.c_str()))
|
||||||
|
{
|
||||||
|
f.read_all();
|
||||||
|
|
||||||
|
BinaryStreamReader sr;
|
||||||
|
sr.init(f.m_data, f.m_len, BinaryStream::ByteOrder::LittleEndian);
|
||||||
|
|
||||||
|
// sanity checks
|
||||||
|
auto magic = sr.rstring(4);
|
||||||
|
if (magic != "PPBR")
|
||||||
|
{
|
||||||
|
LOG("PPBR tag not found")
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto vmaj = sr.ru16();
|
||||||
|
auto vmin = sr.ru16();
|
||||||
|
if (vmaj != 0 && vmin != 1)
|
||||||
|
{
|
||||||
|
LOG("unrecognised version %d.%d", vmaj, vmin);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// header image
|
||||||
|
Image header_image;
|
||||||
|
sr >> header_image;
|
||||||
|
|
||||||
|
// stroke previews
|
||||||
|
auto previews_count = sr.ru32();
|
||||||
|
for (int i = 0; i < previews_count; i++)
|
||||||
|
{
|
||||||
|
Image img;
|
||||||
|
sr >> img;
|
||||||
|
}
|
||||||
|
|
||||||
|
// list of images
|
||||||
|
std::set<std::string> img_brushes;
|
||||||
|
std::set<std::string> img_patterns;
|
||||||
|
|
||||||
|
// brush tips
|
||||||
|
auto tips_count = sr.ru32();
|
||||||
|
for (int i = 0; i < tips_count; i++)
|
||||||
|
{
|
||||||
|
Image img;
|
||||||
|
sr >> img;
|
||||||
|
std::string path = App::I->data_path + "/brushes/" + img.file_name + "." + img.file_ext;
|
||||||
|
if (!Asset::exist(path))
|
||||||
|
{
|
||||||
|
img.save_png(path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG("import_ppbr: brush image already exists in %s", path.c_str());
|
||||||
|
}
|
||||||
|
img_brushes.insert(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// brush patterns
|
||||||
|
auto patt_count = sr.ru32();
|
||||||
|
for (int i = 0; i < patt_count; i++)
|
||||||
|
{
|
||||||
|
Image img;
|
||||||
|
sr >> img;
|
||||||
|
std::string path = App::I->data_path + "/patterns/" + img.file_name + "." + img.file_ext;
|
||||||
|
if (!Asset::exist(path))
|
||||||
|
{
|
||||||
|
img.save_png(path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG("import_ppbr: brush image already exists in %s", path.c_str());
|
||||||
|
}
|
||||||
|
img_patterns.insert(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// brush settings
|
||||||
|
auto brushes_count = sr.ru32();
|
||||||
|
for (int i = 0; i < brushes_count; i++)
|
||||||
|
{
|
||||||
|
auto b = std::make_shared<Brush>();
|
||||||
|
sr >> *b;
|
||||||
|
b->relocate_paths(App::I->data_path);
|
||||||
|
LOG("import_ppbr brush name %s", b->m_name.c_str());
|
||||||
|
if (b->valid())
|
||||||
|
{
|
||||||
|
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_preview->m_brush = b;
|
||||||
|
brush->m_preview->draw_stroke();
|
||||||
|
brush->m_caption_size->set_text_format("%d", (int)b->m_tip_size);
|
||||||
|
brush->m_thumb->set_image(brush->m_brush->m_brush_thumb_path);
|
||||||
|
brush->on_click = std::bind(&NodePanelBrushPreset::handle_click, this, std::placeholders::_1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NodePanelBrushPreset::import_abr(const std::string& path)
|
||||||
|
{
|
||||||
|
BT_SetTerminate();
|
||||||
|
|
||||||
|
ABR abr;
|
||||||
|
LOG("ABR detected");
|
||||||
|
|
||||||
|
std::string name, base, ext;
|
||||||
|
std::regex r(R"((.*)[\\/]([^\\/]+)\.(\w+)$)");
|
||||||
|
std::smatch m;
|
||||||
|
if (!std::regex_search(path, m, r))
|
||||||
|
return false;
|
||||||
|
base = m[1].str();
|
||||||
|
name = m[2].str();
|
||||||
|
ext = m[3].str();
|
||||||
|
|
||||||
|
if (!str_iequals(ext, "abr") || !Asset::exist(path))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto pb = App::I->show_progress("Importing ABR");
|
||||||
|
|
||||||
|
abr.open(path);
|
||||||
|
|
||||||
|
int tot = (int)(abr.m_samples.size() + abr.m_patterns.size() + abr.m_presets.size());
|
||||||
|
std::atomic_int count(0);
|
||||||
|
|
||||||
|
parallel_for(abr.m_samples.size(), [&](size_t i)
|
||||||
|
//for (const auto& samp : abr.m_samples)
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
//auto high = padded.resize_power2();
|
||||||
|
//high.save(path_high);
|
||||||
|
samp.second->save_png(path_high);
|
||||||
|
auto thumb = padded.resize(64, 64);
|
||||||
|
thumb.save_png(path_thumb);
|
||||||
|
|
||||||
|
count++;
|
||||||
|
pb->set_progress((float)count / (float)tot);
|
||||||
|
});
|
||||||
|
|
||||||
|
parallel_for(abr.m_patterns.size(), [&](size_t i)
|
||||||
|
//for (const auto& patt : abr.m_patterns)
|
||||||
|
{
|
||||||
|
auto ii = abr.m_patterns.begin();
|
||||||
|
std::advance(ii, i);
|
||||||
|
const auto& patt = *ii;
|
||||||
|
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";
|
||||||
|
patt.second->save_png(path_high);
|
||||||
|
auto thumb = patt.second->resize(64, 64);
|
||||||
|
thumb.save_png(path_thumb);
|
||||||
|
|
||||||
|
count++;
|
||||||
|
pb->set_progress((float)count / (float)tot);
|
||||||
|
});
|
||||||
|
|
||||||
|
auto brushes = abr.compute_brushes(App::I->data_path);
|
||||||
|
for (const auto& pr : brushes)
|
||||||
|
{
|
||||||
|
if (pr->valid())
|
||||||
|
{
|
||||||
|
LOG("add preset %s", pr->m_name.c_str());
|
||||||
|
App::I->presets->add_brush(pr);
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
pb->set_progress((float)count / (float)tot);
|
||||||
|
}
|
||||||
|
|
||||||
|
App::I->presets->save();
|
||||||
|
pb->destroy();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void NodePanelBrushPreset::clear_brushes()
|
void NodePanelBrushPreset::clear_brushes()
|
||||||
{
|
{
|
||||||
m_container->remove_all_children();
|
m_container->remove_all_children();
|
||||||
|
|||||||
@@ -98,6 +98,10 @@ public:
|
|||||||
bool save();
|
bool save();
|
||||||
bool restore();
|
bool restore();
|
||||||
void add_brush(std::shared_ptr<Brush> brush);
|
void add_brush(std::shared_ptr<Brush> brush);
|
||||||
|
bool export_ppbr(const std::string& path, const Image& header_image);
|
||||||
|
bool import_ppbr(const std::string& path);
|
||||||
|
bool import_abr(const std::string& path);
|
||||||
|
std::string replace_path(std::string path, std::string new_base);
|
||||||
void clear_brushes();
|
void clear_brushes();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -23,110 +23,6 @@ void NodePanelStroke::init()
|
|||||||
init_controls();
|
init_controls();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NodePanelStroke::import_abr(const std::string& path)
|
|
||||||
{
|
|
||||||
BT_SetTerminate();
|
|
||||||
|
|
||||||
ABR abr;
|
|
||||||
LOG("ABR detected");
|
|
||||||
|
|
||||||
std::string name, base, ext;
|
|
||||||
std::regex r(R"((.*)[\\/]([^\\/]+)\.(\w+)$)");
|
|
||||||
std::smatch m;
|
|
||||||
if (!std::regex_search(path, m, r))
|
|
||||||
return false;
|
|
||||||
base = m[1].str();
|
|
||||||
name = m[2].str();
|
|
||||||
ext = m[3].str();
|
|
||||||
|
|
||||||
if (!str_iequals(ext, "abr") || !Asset::exist(path))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto pb = App::I->show_progress("Importing ABR");
|
|
||||||
|
|
||||||
abr.open(path);
|
|
||||||
|
|
||||||
int tot = (int)(abr.m_samples.size() + abr.m_patterns.size() + abr.m_presets.size());
|
|
||||||
std::atomic_int count(0);
|
|
||||||
|
|
||||||
parallel_for(abr.m_samples.size(), [&](size_t i)
|
|
||||||
//for (const auto& samp : abr.m_samples)
|
|
||||||
{
|
|
||||||
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));
|
|
||||||
//auto high = padded.resize_power2();
|
|
||||||
//high.save(path_high);
|
|
||||||
samp.second->save_png(path_high);
|
|
||||||
auto thumb = padded.resize(64, 64);
|
|
||||||
thumb.save_png(path_thumb);
|
|
||||||
|
|
||||||
NodeButtonBrush* brush = new NodeButtonBrush;
|
|
||||||
m_brush_popup->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, m_brush_popup, std::placeholders::_1);
|
|
||||||
count++;
|
|
||||||
pb->set_progress((float)count / (float)tot);
|
|
||||||
});
|
|
||||||
m_brush_popup->save();
|
|
||||||
|
|
||||||
parallel_for(abr.m_patterns.size(), [&](size_t i)
|
|
||||||
//for (const auto& patt : abr.m_patterns)
|
|
||||||
{
|
|
||||||
auto ii = abr.m_patterns.begin();
|
|
||||||
std::advance(ii, i);
|
|
||||||
const auto& patt = *ii;
|
|
||||||
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";
|
|
||||||
patt.second->save_png(path_high);
|
|
||||||
auto thumb = patt.second->resize(64, 64);
|
|
||||||
thumb.save_png(path_thumb);
|
|
||||||
|
|
||||||
NodeButtonBrush* brush = new NodeButtonBrush;
|
|
||||||
m_pattern_popup->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, m_pattern_popup, std::placeholders::_1);
|
|
||||||
count++;
|
|
||||||
pb->set_progress((float)count / (float)tot);
|
|
||||||
});
|
|
||||||
m_pattern_popup->save();
|
|
||||||
|
|
||||||
auto brushes = abr.compute_brushes(App::I->data_path);
|
|
||||||
for (const auto& pr : brushes)
|
|
||||||
{
|
|
||||||
if (pr->valid())
|
|
||||||
{
|
|
||||||
LOG("add preset %s", pr->m_name.c_str());
|
|
||||||
App::I->presets->add_brush(pr);
|
|
||||||
}
|
|
||||||
count++;
|
|
||||||
pb->set_progress((float)count / (float)tot);
|
|
||||||
}
|
|
||||||
|
|
||||||
App::I->presets->save();
|
|
||||||
pb->destroy();
|
|
||||||
//save();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodePanelStroke::update_controls()
|
void NodePanelStroke::update_controls()
|
||||||
{
|
{
|
||||||
const auto& b = Canvas::I->m_current_brush;
|
const auto& b = Canvas::I->m_current_brush;
|
||||||
|
|||||||
@@ -109,7 +109,6 @@ public:
|
|||||||
virtual void init() override;
|
virtual void init() override;
|
||||||
virtual kEventResult handle_event(Event* e) override;
|
virtual kEventResult handle_event(Event* e) override;
|
||||||
|
|
||||||
bool import_abr(const std::string& path);
|
|
||||||
void init_controls();
|
void init_controls();
|
||||||
void update_controls();
|
void update_controls();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user