Route stroke panel view through app core

This commit is contained in:
2026-06-05 01:01:56 +02:00
parent 75fd7faeb0
commit d5403f082c
8 changed files with 556 additions and 80 deletions

View File

@@ -6,6 +6,8 @@
#include <cmath>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
namespace pp::app {
@@ -175,6 +177,41 @@ struct BrushStrokeControlPlan {
bool notifies_stroke_change = false;
};
struct BrushStrokeFloatValue {
BrushStrokeFloatSetting setting = BrushStrokeFloatSetting::tip_size;
float value = 0.0F;
};
struct BrushStrokeBoolValue {
BrushStrokeBoolSetting setting = BrushStrokeBoolSetting::tip_angle_init;
bool value = false;
};
struct BrushStrokeBlendValue {
BrushStrokeBlendSetting setting = BrushStrokeBlendSetting::tip;
int blend_mode = 0;
};
struct BrushStrokePanelInput {
std::vector<BrushStrokeFloatValue> float_values;
std::vector<BrushStrokeBoolValue> bool_values;
std::vector<BrushStrokeBlendValue> blend_values;
std::string tip_thumbnail_path;
std::string dual_thumbnail_path;
std::string pattern_thumbnail_path;
};
struct BrushStrokePanelView {
std::vector<BrushStrokeFloatValue> float_values;
std::vector<BrushStrokeBoolValue> bool_values;
std::vector<BrushStrokeBlendValue> blend_values;
std::string tip_thumbnail_path;
std::string dual_thumbnail_path;
std::string pattern_thumbnail_path;
bool updates_preview = true;
bool updates_thumbnails = true;
};
class BrushUiServices {
public:
virtual ~BrushUiServices() = default;
@@ -278,6 +315,33 @@ public:
return pp::foundation::Status::success();
}
[[nodiscard]] inline pp::foundation::Result<BrushStrokePanelView> plan_brush_stroke_panel_view(
BrushStrokePanelInput input)
{
for (const auto& value : input.float_values) {
const auto status = validate_brush_stroke_float(value.value);
if (!status.ok()) {
return pp::foundation::Result<BrushStrokePanelView>::failure(status);
}
}
for (const auto& value : input.blend_values) {
const auto status = validate_brush_stroke_blend_mode(value.blend_mode);
if (!status.ok()) {
return pp::foundation::Result<BrushStrokePanelView>::failure(status);
}
}
BrushStrokePanelView view;
view.float_values = std::move(input.float_values);
view.bool_values = std::move(input.bool_values);
view.blend_values = std::move(input.blend_values);
view.tip_thumbnail_path = std::move(input.tip_thumbnail_path);
view.dual_thumbnail_path = std::move(input.dual_thumbnail_path);
view.pattern_thumbnail_path = std::move(input.pattern_thumbnail_path);
return pp::foundation::Result<BrushStrokePanelView>::success(std::move(view));
}
[[nodiscard]] inline pp::foundation::Result<BrushUiPlan> plan_brush_ui_color(
float r,
float g,

View File

@@ -8,6 +8,115 @@
#include "app.h"
#include "abr.h"
namespace {
void add_stroke_float(
pp::app::BrushStrokePanelInput& input,
pp::app::BrushStrokeFloatSetting setting,
float value)
{
input.float_values.push_back(pp::app::BrushStrokeFloatValue {
.setting = setting,
.value = value,
});
}
void add_stroke_bool(
pp::app::BrushStrokePanelInput& input,
pp::app::BrushStrokeBoolSetting setting,
bool value)
{
input.bool_values.push_back(pp::app::BrushStrokeBoolValue {
.setting = setting,
.value = value,
});
}
void add_stroke_blend(
pp::app::BrushStrokePanelInput& input,
pp::app::BrushStrokeBlendSetting setting,
int blend_mode)
{
input.blend_values.push_back(pp::app::BrushStrokeBlendValue {
.setting = setting,
.blend_mode = blend_mode,
});
}
pp::app::BrushStrokePanelInput make_stroke_panel_input(const Brush& brush)
{
pp::app::BrushStrokePanelInput input;
input.float_values.reserve(29);
input.bool_values.reserve(24);
input.blend_values.reserve(3);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::tip_size, brush.m_tip_size);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::tip_spacing, brush.m_tip_spacing);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::tip_flow, brush.m_tip_flow);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::tip_opacity, brush.m_tip_opacity);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::tip_angle, brush.m_tip_angle);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::tip_angle_smooth, brush.m_tip_angle_smooth);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::tip_mix, brush.m_tip_mix);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::tip_wet, brush.m_tip_wet);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::tip_noise, brush.m_tip_noise);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::jitter_scale, brush.m_jitter_scale);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::jitter_angle, brush.m_jitter_angle);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::jitter_scatter, brush.m_jitter_scatter);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::jitter_flow, brush.m_jitter_flow);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::jitter_opacity, brush.m_jitter_opacity);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::jitter_hue, brush.m_jitter_hue);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::jitter_saturation, brush.m_jitter_sat);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::jitter_value, brush.m_jitter_val);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::jitter_aspect, brush.m_jitter_aspect);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::dual_size, brush.m_dual_size);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::dual_spacing, brush.m_dual_spacing);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::dual_flow, brush.m_dual_flow);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::dual_scatter, brush.m_dual_scatter);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::tip_aspect, brush.m_tip_aspect);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::dual_opacity, brush.m_dual_opacity);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::dual_rotate, brush.m_dual_rotate);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::pattern_scale, brush.m_pattern_scale);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::pattern_brightness, brush.m_pattern_brightness);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::pattern_contrast, brush.m_pattern_contrast);
add_stroke_float(input, pp::app::BrushStrokeFloatSetting::pattern_depth, brush.m_pattern_depth);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::jitter_hsv_each_sample, brush.m_jitter_hsv_eachsample);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::tip_angle_follow, brush.m_tip_angle_follow);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::tip_angle_init, brush.m_tip_angle_init);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::tip_flow_pressure, brush.m_tip_flow_pressure);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::tip_opacity_pressure, brush.m_tip_opacity_pressure);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::tip_size_pressure, brush.m_tip_size_pressure);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::jitter_aspect_both_axis, brush.m_jitter_aspect_bothaxis);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::tip_invert, brush.m_tip_invert);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::tip_flip_x, brush.m_tip_flipx);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::tip_flip_y, brush.m_tip_flipy);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::pattern_enabled, brush.m_pattern_enabled);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::dual_enabled, brush.m_dual_enabled);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::dual_scatter_both_axis, brush.m_dual_scatter_bothaxis);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::dual_invert, brush.m_dual_invert);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::dual_flip_x, brush.m_dual_flipx);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::dual_flip_y, brush.m_dual_flipy);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::dual_random_flip, brush.m_dual_randflip);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::tip_random_flip_x, brush.m_tip_randflipx);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::tip_random_flip_y, brush.m_tip_randflipy);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::pattern_each_sample, brush.m_pattern_eachsample);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::pattern_invert, brush.m_pattern_invert);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::pattern_flip_x, brush.m_pattern_flipx);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::pattern_flip_y, brush.m_pattern_flipy);
add_stroke_bool(input, pp::app::BrushStrokeBoolSetting::pattern_random_offset, brush.m_pattern_rand_offset);
add_stroke_blend(input, pp::app::BrushStrokeBlendSetting::tip, brush.m_blend_mode);
add_stroke_blend(input, pp::app::BrushStrokeBlendSetting::dual, brush.m_dual_blend_mode);
add_stroke_blend(input, pp::app::BrushStrokeBlendSetting::pattern, brush.m_pattern_blend_mode);
input.tip_thumbnail_path = brush.m_brush_thumb_path;
input.dual_thumbnail_path = brush.m_dual_thumb_path;
input.pattern_thumbnail_path = brush.m_pattern_thumb_path;
return input;
}
} // namespace
Node* NodePanelStroke::clone_instantiate() const
{
return new NodePanelStroke();
@@ -27,77 +136,106 @@ void NodePanelStroke::init()
void NodePanelStroke::update_controls()
{
const auto& b = Canvas::I->m_current_brush;
m_tip_size->m_value = m_curves[m_tip_size].to_slider(b->m_tip_size);
m_tip_spacing->m_value = m_curves[m_tip_spacing].to_slider(b->m_tip_spacing);
m_tip_flow->m_value = m_curves[m_tip_flow].to_slider(b->m_tip_flow);
m_tip_opacity->m_value = b->m_tip_opacity;
m_tip_angle->m_value = b->m_tip_angle;
m_tip_angle_smooth->m_value = b->m_tip_angle_smooth;
m_tip_mix->m_value = m_curves[m_tip_mix].to_slider(b->m_tip_mix);
m_tip_wet->m_value = b->m_tip_wet;
m_tip_noise->m_value = b->m_tip_noise;
m_jitter_scale->m_value = b->m_jitter_scale;
m_jitter_angle->m_value = b->m_jitter_angle;
m_jitter_scatter->m_value = m_curves[m_jitter_scatter].to_slider(b->m_jitter_scatter);;
m_jitter_flow->m_value = b->m_jitter_flow;
m_jitter_opacity->m_value = b->m_jitter_opacity;
m_jitter_hue->m_value = b->m_jitter_hue;
m_jitter_sat->m_value = b->m_jitter_sat;
m_jitter_val->m_value = b->m_jitter_val;
m_jitter_hsv_eachsample->set_value(b->m_jitter_hsv_eachsample);
m_jitter_aspect->m_value = b->m_jitter_aspect;
m_tip_angle_follow->set_value(b->m_tip_angle_follow);
m_tip_angle_init->set_value(b->m_tip_angle_init);
m_tip_flow_pressure->set_value(b->m_tip_flow_pressure);
m_tip_opacity_pressure->set_value(b->m_tip_opacity_pressure);
m_tip_size_pressure->set_value(b->m_tip_size_pressure);
m_jitter_aspect_bothaxis->set_value(b->m_jitter_aspect_bothaxis);
if (!Canvas::I || !Canvas::I->m_current_brush) {
return;
}
m_tip_invert->set_value(b->m_tip_invert);
m_tip_flipx->set_value(b->m_tip_flipx);
m_tip_flipy->set_value(b->m_tip_flipy);
m_pattern_enabled->set_value(b->m_pattern_enabled);
m_dual_enabled->set_value(b->m_dual_enabled);
m_dual_scatter_bothaxis->set_value(b->m_dual_scatter_bothaxis);
m_dual_invert->set_value(b->m_dual_invert);
m_dual_flipx->set_value(b->m_dual_flipx);
m_dual_flipy->set_value(b->m_dual_flipy);
m_dual_randflip->set_value(b->m_dual_randflip);
m_tip_randflipx->set_value(b->m_tip_randflipx);
m_tip_randflipy->set_value(b->m_tip_randflipy);
m_dual_size->m_value = m_curves[m_dual_size].to_slider(b->m_dual_size);
m_dual_spacing->m_value = m_curves[m_dual_spacing].to_slider(b->m_dual_spacing);
m_dual_flow->m_value = m_curves[m_dual_flow].to_slider(b->m_dual_flow);
m_dual_scatter->m_value = m_curves[m_dual_scatter].to_slider(b->m_dual_scatter);
m_tip_aspect->m_value = b->m_tip_aspect;
m_dual_opacity->m_value = b->m_dual_opacity;
m_dual_rotate->m_value = b->m_dual_rotate;
const auto view = pp::app::plan_brush_stroke_panel_view(
make_stroke_panel_input(*Canvas::I->m_current_brush));
if (!view) {
LOG("Brush stroke panel view failed: %s", view.status().message);
return;
}
m_pattern_eachsample->set_value(b->m_pattern_eachsample);
m_pattern_invert->set_value(b->m_pattern_invert);
m_pattern_flipx->set_value(b->m_pattern_flipx);
m_pattern_flipy->set_value(b->m_pattern_flipy);
m_pattern_rand_offset->set_value(b->m_pattern_rand_offset);
m_pattern_scale->m_value = m_curves[m_pattern_scale].to_slider(b->m_pattern_scale);
m_pattern_brightness->m_value = b->m_pattern_brightness;
m_pattern_contrast->m_value = b->m_pattern_contrast;
m_pattern_depth->m_value = b->m_pattern_depth;
const auto set_slider = [this](NodeSliderH* slider, float value) {
const auto curve = m_curves.find(slider);
slider->m_value = curve != m_curves.end() ? curve->second.to_slider(value) : value;
};
m_blend_mode->set_index(b->m_blend_mode);
m_dual_blend_mode->set_index(b->m_dual_blend_mode);
m_pattern_blend_mode->set_index(b->m_pattern_blend_mode);
for (const auto& value : view.value().float_values) {
switch (value.setting) {
case pp::app::BrushStrokeFloatSetting::tip_size: set_slider(m_tip_size, value.value); break;
case pp::app::BrushStrokeFloatSetting::tip_spacing: set_slider(m_tip_spacing, value.value); break;
case pp::app::BrushStrokeFloatSetting::tip_flow: set_slider(m_tip_flow, value.value); break;
case pp::app::BrushStrokeFloatSetting::tip_opacity: set_slider(m_tip_opacity, value.value); break;
case pp::app::BrushStrokeFloatSetting::tip_angle: set_slider(m_tip_angle, value.value); break;
case pp::app::BrushStrokeFloatSetting::tip_angle_smooth: set_slider(m_tip_angle_smooth, value.value); break;
case pp::app::BrushStrokeFloatSetting::tip_mix: set_slider(m_tip_mix, value.value); break;
case pp::app::BrushStrokeFloatSetting::tip_wet: set_slider(m_tip_wet, value.value); break;
case pp::app::BrushStrokeFloatSetting::tip_noise: set_slider(m_tip_noise, value.value); break;
case pp::app::BrushStrokeFloatSetting::jitter_scale: set_slider(m_jitter_scale, value.value); break;
case pp::app::BrushStrokeFloatSetting::jitter_angle: set_slider(m_jitter_angle, value.value); break;
case pp::app::BrushStrokeFloatSetting::jitter_scatter: set_slider(m_jitter_scatter, value.value); break;
case pp::app::BrushStrokeFloatSetting::jitter_flow: set_slider(m_jitter_flow, value.value); break;
case pp::app::BrushStrokeFloatSetting::jitter_opacity: set_slider(m_jitter_opacity, value.value); break;
case pp::app::BrushStrokeFloatSetting::jitter_hue: set_slider(m_jitter_hue, value.value); break;
case pp::app::BrushStrokeFloatSetting::jitter_saturation: set_slider(m_jitter_sat, value.value); break;
case pp::app::BrushStrokeFloatSetting::jitter_value: set_slider(m_jitter_val, value.value); break;
case pp::app::BrushStrokeFloatSetting::jitter_aspect: set_slider(m_jitter_aspect, value.value); break;
case pp::app::BrushStrokeFloatSetting::dual_size: set_slider(m_dual_size, value.value); break;
case pp::app::BrushStrokeFloatSetting::dual_spacing: set_slider(m_dual_spacing, value.value); break;
case pp::app::BrushStrokeFloatSetting::dual_flow: set_slider(m_dual_flow, value.value); break;
case pp::app::BrushStrokeFloatSetting::dual_scatter: set_slider(m_dual_scatter, value.value); break;
case pp::app::BrushStrokeFloatSetting::tip_aspect: set_slider(m_tip_aspect, value.value); break;
case pp::app::BrushStrokeFloatSetting::dual_opacity: set_slider(m_dual_opacity, value.value); break;
case pp::app::BrushStrokeFloatSetting::dual_rotate: set_slider(m_dual_rotate, value.value); break;
case pp::app::BrushStrokeFloatSetting::pattern_scale: set_slider(m_pattern_scale, value.value); break;
case pp::app::BrushStrokeFloatSetting::pattern_brightness: set_slider(m_pattern_brightness, value.value); break;
case pp::app::BrushStrokeFloatSetting::pattern_contrast: set_slider(m_pattern_contrast, value.value); break;
case pp::app::BrushStrokeFloatSetting::pattern_depth: set_slider(m_pattern_depth, value.value); break;
default: break;
}
}
m_preview->m_brush = b;
m_preview->draw_stroke();
for (const auto& value : view.value().bool_values) {
switch (value.setting) {
case pp::app::BrushStrokeBoolSetting::jitter_hsv_each_sample: m_jitter_hsv_eachsample->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::tip_angle_follow: m_tip_angle_follow->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::tip_angle_init: m_tip_angle_init->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::tip_flow_pressure: m_tip_flow_pressure->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::tip_opacity_pressure: m_tip_opacity_pressure->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::tip_size_pressure: m_tip_size_pressure->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::jitter_aspect_both_axis: m_jitter_aspect_bothaxis->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::tip_invert: m_tip_invert->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::tip_flip_x: m_tip_flipx->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::tip_flip_y: m_tip_flipy->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::pattern_enabled: m_pattern_enabled->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::dual_enabled: m_dual_enabled->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::dual_scatter_both_axis: m_dual_scatter_bothaxis->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::dual_invert: m_dual_invert->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::dual_flip_x: m_dual_flipx->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::dual_flip_y: m_dual_flipy->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::dual_random_flip: m_dual_randflip->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::tip_random_flip_x: m_tip_randflipx->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::tip_random_flip_y: m_tip_randflipy->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::pattern_each_sample: m_pattern_eachsample->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::pattern_invert: m_pattern_invert->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::pattern_flip_x: m_pattern_flipx->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::pattern_flip_y: m_pattern_flipy->set_value(value.value); break;
case pp::app::BrushStrokeBoolSetting::pattern_random_offset: m_pattern_rand_offset->set_value(value.value); break;
default: break;
}
}
if (m_brush_thumb->m_path != b->m_brush_thumb_path)
m_brush_thumb->set_image(b->m_brush_thumb_path);
if (m_dual_brush_thumb->m_path != b->m_dual_thumb_path)
m_dual_brush_thumb->set_image(b->m_dual_thumb_path);
if (m_pattern_thumb->m_path != b->m_pattern_thumb_path)
m_pattern_thumb->set_image(b->m_pattern_thumb_path);
for (const auto& value : view.value().blend_values) {
switch (value.setting) {
case pp::app::BrushStrokeBlendSetting::tip: m_blend_mode->set_index(value.blend_mode); break;
case pp::app::BrushStrokeBlendSetting::dual: m_dual_blend_mode->set_index(value.blend_mode); break;
case pp::app::BrushStrokeBlendSetting::pattern: m_pattern_blend_mode->set_index(value.blend_mode); break;
}
}
if (view.value().updates_preview) {
m_preview->m_brush = Canvas::I->m_current_brush;
m_preview->draw_stroke();
}
if (m_brush_thumb->m_path != view.value().tip_thumbnail_path)
m_brush_thumb->set_image(view.value().tip_thumbnail_path);
if (m_dual_brush_thumb->m_path != view.value().dual_thumbnail_path)
m_dual_brush_thumb->set_image(view.value().dual_thumbnail_path);
if (m_pattern_thumb->m_path != view.value().pattern_thumbnail_path)
m_pattern_thumb->set_image(view.value().pattern_thumbnail_path);
}
void NodePanelStroke::set_flow(float value, bool normalized, bool propagate)
@@ -162,15 +300,15 @@ void NodePanelStroke::init_controls()
const int br_idx = m_default_brush_index;
// init main brush
auto b = std::make_shared<Brush>();
b->load_tip(m_brush_popup->get_texture_path(br_idx), m_brush_popup->get_thumb_path(br_idx));
//b->load_dual(m_brush_popup->get_texture_path(br_idx), m_brush_popup->get_thumb_path(br_idx));
//b->load_pattern(m_pattern_popup->get_texture_path(0), m_pattern_popup->get_thumb_path(0));
b->m_tip_size = 30;
b->m_tip_flow = .9f;
b->m_tip_spacing = .1f;
b->m_tip_opacity = 1.f;
Canvas::I->m_current_brush = b;
auto default_brush = std::make_shared<Brush>();
default_brush->load_tip(m_brush_popup->get_texture_path(br_idx), m_brush_popup->get_thumb_path(br_idx));
//default_brush->load_dual(m_brush_popup->get_texture_path(br_idx), m_brush_popup->get_thumb_path(br_idx));
//default_brush->load_pattern(m_pattern_popup->get_texture_path(0), m_pattern_popup->get_thumb_path(0));
default_brush->m_tip_size = 30;
default_brush->m_tip_flow = .9f;
default_brush->m_tip_spacing = .1f;
default_brush->m_tip_opacity = 1.f;
Canvas::I->m_current_brush = default_brush;
// BRUSH PRESETS