pixel based brush size, Photoshop slider curve, improve abr import

This commit is contained in:
2019-02-23 20:46:20 +01:00
parent e1f82373c6
commit 3a1a48a0d0
15 changed files with 218 additions and 104 deletions

View File

@@ -62,7 +62,7 @@ void main()
{
//mediump vec2 uv2 = draw_on_screen ? gl_FragCoord.st / resolution : uv;
mediump vec2 rscale = resolution / vec2(512.0);
mediump float patt = texture(tex_pattern, uv * (0.5 / pattern_scale) * rscale + pattern_offset).r;
mediump float patt = texture(tex_pattern, uv * (1.0 / pattern_scale) * rscale + pattern_offset).r;
if (pattern_invert)
patt = 1.0 - patt;
//patt = patt * pattern_alpha + (1.0 - pattern_alpha);

View File

@@ -66,7 +66,7 @@ void main()
if (use_pattern)
{
mediump vec2 rscale = resolution / vec2(512.0);
mediump float patt = texture(tex_pattern, uv2 * (0.5 / pattern_scale) * rscale + pattern_offset).r;
mediump float patt = texture(tex_pattern, uv2 * (1.0 / pattern_scale) * rscale + pattern_offset).r;
if (pattern_invert)
patt = 1.0 - patt;
patt = patt * pattern_depth + (1.0 - pattern_depth);

View File

@@ -44,7 +44,7 @@ bool ABR::section_samp()
auto vm = parse_vmem();
if (vm)
{
if (auto img = vm->image(true))
if (auto img = vm->image(true, true))
{
// TODO: check if uid already exists in map
m_samples[uid] = img;
@@ -91,7 +91,7 @@ bool ABR::section_patt()
LOG("PATT: image_mode (%d) and number of channels (%d) not matching\n",
image_mode, vm->channels.size());
}
if (auto img = vm->image(true))
if (auto img = vm->image(true, false))
{
// TODO: check if uid already exists in map
m_patterns[uid] = img;
@@ -111,45 +111,65 @@ std::vector<std::shared_ptr<Brush>> ABR::compute_brushes(const std::string& path
continue;
auto b = std::make_shared<Brush>();
b->m_name = wstr2str(p->value<String>("Nm "));
//b->m_tip_color = i.m_tip_color;
b->m_tip_size = samp->value<UnitFloat>("Dmtr") / 800.f;
b->m_tip_spacing = samp->value<UnitFloat>("Spcn") * 0.01f;
// default values
b->m_tip_color = { 0, 0, 0, 1 };
b->m_tip_flow = .25f;
b->m_tip_opacity = 1.f;
b->m_tip_angle = samp->value<UnitFloat>("Angl") / 360.f + 0.5f; // [-180,180] -> [0, 1]
b->m_tip_aspect = (1.f - samp->value<UnitFloat>("Rndn") * 0.01) * 0.5f + 0.5f;
b->m_tip_size = samp->value<UnitFloat>("Dmtr");
b->m_tip_spacing = samp->value<UnitFloat>("Spcn") * 0.01f;
b->m_tip_angle = samp->value<UnitFloat>("Angl") / 360.f + 0.5f; // [-180, 180] -> [0, 1]
//b->m_tip_mix = i.m_tip_mix;
//b->m_tip_stencil = i.m_tip_stencil;
b->m_tip_wet = p->value<UnitFloat>("Wtdg");
b->m_tip_noise = (float)samp->value<UnitFloat>("Nose");
//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_texture_path.resize(i.m_stencil_path_len);
// brush sample
auto tip_uid = wstr2str(samp->value<String>("sampledData"));
LOG("tip uid %d %s", tip_uid.size(), tip_uid.c_str());
b->m_brush_path = path + "/brushes/" + tip_uid + ".png";
b->m_brush_thumb_path = path + "/brushes/thumbs/" + tip_uid + ".png";
const auto& samp_img = m_samples[tip_uid];
b->m_tip_width = (float)samp_img->width / (float)samp_img->height;
// pattern
if (auto patt = p->get<Descriptor>("Txtr"))
{
auto patt_uid = wstr2str(patt->value<String>("Idnt"));
b->m_pattern_path = path + "/patterns/" + patt_uid + ".png";
b->m_pattern_thumb_path = path + "/patterns/thumbs/" + patt_uid + ".png";
b->m_pattern_depth = p->value<UnitFloat>("textureDepth") * 0.01f;
b->m_pattern_invert = p->value<Boolean>("InvT");
b->m_pattern_eachsample = p->value<Boolean>("TxtC");
b->m_pattern_depth = p->value<UnitFloat>("textureDepth") * 0.01f; // [0, 100] -> [0, 1]
b->m_pattern_scale = p->value<UnitFloat>("textureScale") * 0.01f; // [0, 1000] -> [0, 1]
b->m_pattern_brightness = (float)(p->value<Integer>("textureBrightness") + 150) / 300.f; // [-150, 150] -> [0, 1]
int raw_contrast = p->value<Integer>("textureContrast"); // [-50, 0, 100] -> [0, 1]
b->m_pattern_contrast = raw_contrast / (raw_contrast < 0 ? 100.f : 200.f) + 0.5f;
// blending mode
std::string blend_mode = p->value<Enum>("textureBlendMode");
std::vector<std::string> modes = {
"normal", // normal (not in Photoshop)
"Mltp", // multiply
"Sbtr", // subtract
"Drkn", // darken
"Ovrl", // overlay
"CDdg", // color dodge
"CBrn", // color burn
"linearBurn", // linear burn
"hardMix", // hard mix
"linearHeight", // linear height
"Hght", // height
};
auto bm_it = std::find(modes.begin(), modes.end(), blend_mode);
if (bm_it != modes.end())
b->m_pattern_blend_mode = std::distance(modes.begin(), bm_it);
b->m_pattern_enabled = true;
}
ret.push_back(b);

View File

@@ -360,7 +360,7 @@ class ABR : private BinaryStream
std::vector<Channel> channels;
VMArray() = default;
VMArray(uint32_t version, const Rectangle& rect) : version(version), rect(rect) { }
std::shared_ptr<Image> image(bool grayscale) const
std::shared_ptr<Image> image(bool grayscale, bool invert) const
{
int nc = channels.size();
auto pixels = (channels[0].depth >> 3) * rect.area();
@@ -375,8 +375,16 @@ class ABR : private BinaryStream
if (grayscale)
{
auto const& raw = channels[0].data;
for (int i = 0; i < raw.size(); i++)
out[i] = glm::u8vec4(glm::u8vec3(255 - raw[i]), 255);
if (invert)
{
for (int i = 0; i < raw.size(); i++)
out[i] = glm::u8vec4(glm::u8vec3(255 - raw[i]), 255);
}
else
{
for (int i = 0; i < raw.size(); i++)
out[i] = glm::u8vec4(glm::u8vec3(raw[i]), 255);
}
}
else
{
@@ -384,8 +392,16 @@ class ABR : private BinaryStream
for (int ch = 0; ch < std::min(nc, 3); ch++)
{
auto const& raw = channels[ch].data;
for (int i = 0; i < raw.size(); i++)
out[i][ch] = 255 - raw[i];
if (invert)
{
for (int i = 0; i < raw.size(); i++)
out[i][ch] = 255 - raw[i];
}
else
{
for (int i = 0; i < raw.size(); i++)
out[i][ch] = raw[i];
}
}
}
return img;

View File

@@ -530,9 +530,9 @@ void App::update(float dt)
if (reload_timer > 1.0)
{
reload_timer = 0;
ShaderManager::reload();
if (ShaderManager::reload())
stroke->update_controls();
layout.reload();
stroke->update_controls();
}
#endif

View File

@@ -193,7 +193,7 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat
glm::scale(glm::vec3(100)) *
glm::transpose(canvas->m_canvas->m_cam_rot) *
glm::translate(glm::vec3(cur * glm::vec2(aspect * tan_fov), -1)) *
glm::scale(glm::vec3(canvas->m_canvas->m_current_brush->m_tip_size * 800.f / App::I.height)) *
glm::scale(glm::vec3(canvas->m_canvas->m_current_brush->m_tip_size / App::I.height)) *
glm::eulerAngleZ(canvas->m_canvas->m_current_brush->m_tip_angle * (float)(M_PI * 2.0))
);
glEnable(GL_BLEND);
@@ -262,7 +262,7 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat
proj * camera * pos *
glm::inverse(glm::lookAt({ 0, 0, 0 }, vr_controller_pos, { 0, 1, 0 })) *
//glm::scale(glm::vec3(0.1)) *
glm::scale(glm::vec3(canvas->m_canvas->m_current_brush->m_tip_size * 800.f / App::I.height)) *
glm::scale(glm::vec3(canvas->m_canvas->m_current_brush->m_tip_size / App::I.height)) *
glm::eulerAngleZ(canvas->m_canvas->m_current_brush->m_tip_angle * (float)(M_PI * 2.0))
);
glEnable(GL_BLEND);

View File

@@ -141,13 +141,13 @@ StrokeSample Stroke::randomize_sample(const glm::vec3& pos, float pressure, floa
float randflipy = m_brush->m_tip_randflipy ? rnd_bneg() : 1.f;
StrokeSample s;
s.scale.x = randflipx * (m_brush->m_tip_flipx ? -1.f : 1.f) *
s.scale.x = m_brush->m_tip_width * randflipx * (m_brush->m_tip_flipx ? -1.f : 1.f) *
(m_brush->m_tip_aspect <= 0.5 ? m_brush->m_tip_aspect * 2.f : 1.f);
s.scale.y = randflipy * (m_brush->m_tip_flipy ? -1.f : 1.f) *
(m_brush->m_tip_aspect > 0.5 ? 1.f - (m_brush->m_tip_aspect - .5f) * 2.f : 1.f);
s.origin = pos;
s.angle = -curve_angle + (m_brush->m_tip_angle + rnd_neg() * m_brush->m_jitter_angle) * (float)(M_PI * 2.0);
s.size = 800.f * size * (1.f - rnd_nor() * m_brush->m_jitter_scale) * size_dyn;
s.size = size * (1.f - rnd_nor() * m_brush->m_jitter_scale) * size_dyn;
s.pos = pos + (rnd_vec() * m_brush->m_jitter_spread * s.size);
s.flow = m_brush->m_tip_flow * (1.f - rnd_nor() * m_brush->m_jitter_flow) * flow_dyn;
auto hsv = convert_rgb2hsv(m_brush->m_tip_color);
@@ -255,8 +255,22 @@ void Stroke::add_point(glm::vec3 pos, float pressure)
if (m_brush->m_tip_size_pressure)
{
float size = glm::min(m_brush->m_tip_size / glm::tan(glm::radians(m_camera.fov * 0.5f)), m_max_size);
m_step = glm::max(m_brush->m_tip_spacing * size * pressure * 800.f, 0.1f);
float aspect_width = glm::min(1.f, m_brush->m_tip_aspect * 2.f);
float raw_size = aspect_width * m_brush->m_tip_width * m_brush->m_tip_size;
float size = glm::clamp(raw_size / glm::tan(glm::radians(m_camera.fov * 0.5f)), 1.f, m_max_size);
if (raw_size < 2.f)
m_step = glm::max(0.5f, m_brush->m_tip_spacing) * size;
else if (raw_size < 10.f)
m_step = glm::max(0.2f, m_brush->m_tip_spacing) * size;
else if (raw_size < 30.f)
m_step = glm::max(0.1f, m_brush->m_tip_spacing) * size;
else if (raw_size < 50.f)
m_step = glm::max(0.05f, m_brush->m_tip_spacing) * size;
else if (raw_size < 200.f)
m_step = glm::max(0.01f, m_brush->m_tip_spacing) * size;
else
m_step = m_brush->m_tip_spacing * size;
}
float dist = m_keypoints.empty() ? m_step :
@@ -285,8 +299,24 @@ void Stroke::start(const std::shared_ptr<Brush>& brush)
m_dir_valid = false;
m_dir_dist = 0;
m_brush = brush;
float size = glm::min(m_brush->m_tip_size / glm::tan(glm::radians(m_camera.fov * 0.5f)), m_max_size);
m_step = glm::max(m_brush->m_tip_spacing * size * 800.f, 1.f);
float aspect_width = glm::min(1.f, m_brush->m_tip_aspect * 2.f);
float raw_size = aspect_width * m_brush->m_tip_width * m_brush->m_tip_size;
float size = glm::clamp(raw_size / glm::tan(glm::radians(m_camera.fov * 0.5f)), 1.f, m_max_size);
if (raw_size < 2.f)
m_step = glm::max(0.5f, m_brush->m_tip_spacing) * size;
else if (raw_size < 10.f)
m_step = glm::max(0.2f, m_brush->m_tip_spacing) * size;
else if (raw_size < 30.f)
m_step = glm::max(0.1f, m_brush->m_tip_spacing) * size;
else if (raw_size < 50.f)
m_step = glm::max(0.05f, m_brush->m_tip_spacing) * size;
else if (raw_size < 200.f)
m_step = glm::max(0.01f, m_brush->m_tip_spacing) * size;
else
m_step = m_brush->m_tip_spacing * size;
m_direction.resize(std::max<int>(1, m_brush->m_tip_angle_delay * 200.f / m_step));
prng.seed(0);
}

View File

@@ -23,10 +23,11 @@ public:
std::string m_pattern_thumb_path;
glm::vec4 m_tip_color{0, 0, 0, 1};
float m_tip_size = .25f;
float m_tip_width = 1.f;
float m_tip_size = 50;
float m_tip_spacing = .25;
float m_tip_flow = 1;
float m_tip_opacity = 1;
float m_tip_flow = 1.f;
float m_tip_opacity = 1.f;
float m_tip_angle = 0;
float m_tip_angle_delay = 0;
float m_tip_mix = 0;
@@ -54,7 +55,7 @@ public:
bool m_dual_enabled = false;
int m_dual_blend_mode = 1;
bool m_dual_randflip = false;
float m_dual_size = .25;
float m_dual_size = 100;
float m_dual_spacing = .25;
float m_dual_scatter = 0;
bool m_dual_scatter_axis = false;

View File

@@ -152,7 +152,8 @@ void CanvasModePen::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
m_resizing = true;
m_dragging = true;
m_size_pos_start = m_cur_pos;
m_size_value_start = Canvas::I->m_current_brush->m_tip_size;
auto curve = App::I.stroke->m_curves[App::I.stroke->m_tip_size];
m_size_value_start = curve.to_slider(Canvas::I->m_current_brush->m_tip_size);
node->mouse_capture();
}
break;
@@ -176,7 +177,8 @@ void CanvasModePen::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
if (m_dragging && m_resizing)
{
auto diff = m_cur_pos - m_size_pos_start;
Canvas::I->m_current_brush->m_tip_size = glm::max(m_size_value_start + diff.x * 0.001f, 0.001f);
auto curve = App::I.stroke->m_curves[App::I.stroke->m_tip_size];
Canvas::I->m_current_brush->m_tip_size = glm::max(curve.to_value(m_size_value_start + diff.x * 0.001f), 0.001f);
if (App::I.stroke)
App::I.stroke->update_controls();
}
@@ -205,13 +207,14 @@ void CanvasModePen::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const
{
const auto& brush = Canvas::I->m_current_brush;
auto pos = m_resizing ? m_size_pos_start : m_cur_pos;
if (App::I.keys[(int)kKey::KeyAlt] && !m_resizing)
pos.x = pos.x - brush->m_tip_size * 500.f;
//if (App::I.keys[(int)kKey::KeyAlt] && !m_resizing)
// pos.x = pos.x - brush->m_tip_size * .5f;
ShaderManager::use(kShader::StrokePreview);
ShaderManager::u_int(kShaderUniform::Tex, 0);
float tip_scale_fix = 1.f / glm::tan(glm::radians(Canvas::I->m_cam_fov * 0.5f));
float tip_angle = brush->m_tip_angle * (float)(M_PI * 2.0);
glm::vec2 tip_scale = glm::vec2(brush->m_tip_size * 800.f * tip_scale_fix) *
glm::vec2 tip_scale = glm::vec2(brush->m_tip_width, 1.f) *
glm::vec2(brush->m_tip_size * tip_scale_fix) *
glm::vec2(brush->m_tip_flipx ? -1 : 1, brush->m_tip_flipy ? -1.f : 1.f) *
glm::vec2((brush->m_tip_aspect <= 0.5 ? brush->m_tip_aspect * 2.f : 1.f),
(brush->m_tip_aspect > 0.5 ? 1.f - (brush->m_tip_aspect - .5f) * 2.f : 1.f));
@@ -222,7 +225,8 @@ void CanvasModePen::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const
const auto& s = Canvas::I->m_current_stroke->m_prev_sample;
if (s.size > 0.f)
{
tip_scale = (brush->m_tip_size * 800.f * tip_scale_fix) * s.scale;
tip_scale = glm::vec2(brush->m_tip_width, 1.f) *
(brush->m_tip_size * tip_scale_fix) * s.scale;
tip_angle = s.angle;
tip_offset = s.pos - s.origin;
tip_color = glm::vec4(s.col, s.flow);

View File

@@ -344,6 +344,7 @@ void NodeBrushPresetItem::init()
m_color = color_normal;
m_thumb = find<NodeImage>("thumb");
m_preview = find<NodeStrokePreview>("canvas");
m_preview->m_min_flow = 1.f;
}
void NodeBrushPresetItem::draw()

View File

@@ -104,6 +104,7 @@ class NodePanelBrushPreset : public Node
int m_stencil_thumb_path_len = 0;
glm::vec4 m_tip_color{ 0, 0, 0, 1 };
float m_tip_width = 1.f;
float m_tip_size = 0;
float m_tip_spacing = 0;
float m_tip_flow = 0;

View File

@@ -63,8 +63,9 @@ bool NodePanelStroke::import_abr(const std::string& path)
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);
//auto high = padded.resize_power2();
//high.save(path_high);
samp.second->save(path_high);
auto thumb = padded.resize(64, 64);
thumb.save(path_thumb);
@@ -136,9 +137,9 @@ bool NodePanelStroke::import_abr(const std::string& path)
void NodePanelStroke::update_controls()
{
const auto& b = Canvas::I->m_current_brush;
m_tip_size->m_value.x = glm::pow(b->m_tip_size, 1.f/3.f);
m_tip_spacing->m_value.x = glm::pow(b->m_tip_spacing, 1.f/2.f);
m_tip_flow->m_value.x = glm::pow(b->m_tip_flow, 1.f/2.f);
m_tip_size->m_value.x = m_curves[m_tip_size].to_slider(b->m_tip_size);
m_tip_spacing->m_value.x = m_curves[m_tip_spacing].to_slider(b->m_tip_spacing);
m_tip_flow->m_value.x = m_curves[m_tip_flow].to_slider(b->m_tip_flow);
m_tip_opacity->m_value.x = b->m_tip_opacity;
m_tip_angle->m_value.x = b->m_tip_angle;
m_tip_angle_delay->m_value.x = b->m_tip_angle_delay;
@@ -168,9 +169,9 @@ void NodePanelStroke::update_controls()
m_tip_randflipx->checked = b->m_tip_randflipx;
m_tip_randflipy->checked = b->m_tip_randflipy;
m_dual_size->m_value.x = glm::pow(b->m_dual_size, 1.f / 3.f);
m_dual_spacing->m_value.x = glm::pow(b->m_dual_spacing, 1.f / 2.f);
m_dual_flow->m_value.x = glm::pow(b->m_dual_flow, 1.f / 2.f);
m_dual_size->m_value.x = m_curves[m_dual_size].to_slider(b->m_dual_size);
m_dual_spacing->m_value.x = m_curves[m_dual_spacing].to_slider(b->m_dual_spacing);
m_dual_flow->m_value.x = m_curves[m_dual_flow].to_slider(b->m_dual_flow);
m_dual_scatter->m_value.x = b->m_dual_scatter;
m_tip_aspect->m_value.x = b->m_tip_aspect;
m_dual_opacity->m_value.x = b->m_dual_opacity;
@@ -181,7 +182,7 @@ void NodePanelStroke::update_controls()
m_pattern_flipx->checked = b->m_pattern_flipx;
m_pattern_flipy->checked = b->m_pattern_flipy;
m_pattern_rand_offset->checked = b->m_pattern_rand_offset;
m_pattern_scale->m_value.x = b->m_pattern_scale;
m_pattern_scale->m_value.x = m_curves[m_pattern_scale].to_slider(b->m_pattern_scale);
m_pattern_brightness->m_value.x = b->m_pattern_brightness;
m_pattern_contrast->m_value.x = b->m_pattern_contrast;
m_pattern_depth->m_value.x = b->m_pattern_depth;
@@ -247,8 +248,8 @@ void NodePanelStroke::init_controls()
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 = .1f;
b->m_tip_flow = .5f;
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;
@@ -470,14 +471,62 @@ void NodePanelStroke::init_controls()
init_slider(m_pattern_contrast, "pattern-contrast", &Brush::m_pattern_contrast);
init_slider(m_pattern_depth, "pattern-depth", &Brush::m_pattern_depth);
auto curve_cubic = [](float v) { return glm::pow(v, 3.f); };
auto curve_quad = [](float v) { return glm::pow(v, 2.f); };
m_curves[m_tip_size] = curve_cubic;
m_curves[m_tip_spacing] = curve_quad;
SliderCurve curve_cubic {
[](float v) { return glm::pow(v, 3.f); },
[](float v) { return glm::pow(v, 1.f / 3.f); },
};
SliderCurve curve_quad {
[](float v) { return glm::pow(v, 2.f); },
[](float v) { return glm::pow(v, 1.f / 2.f); },
};
SliderCurve curve_size1k_perc {
[](float v) {
float ret = 0;
if (v > 0.00f) ret += glm::pow(glm::min(1.f, (v - 0.00f) / 0.50f), 2.f) * 1.f;
if (v > 0.50f) ret += glm::min(1.f, (v - 0.50f) / 0.25f) * 2.f;
if (v > 0.75f) ret += glm::min(1.f, (v - 0.75f) / 0.10f) * 4.f;
if (v > 0.85f) ret += glm::min(1.f, (v - 0.85f) / 0.05f) * 5.f;
if (v > 0.90f) ret += glm::min(1.f, (v - 0.90f) / 0.10f) * 10.f;
return glm::max(.01f, ret);
},
[](float v) {
float ret = 0;
if (v > 0.f) ret += glm::pow(glm::min(1.f, (v - 0.f) / 1.f), 1.f / 2.f) * 0.50f;
if (v > 1.f) ret += glm::min(1.f, (v - 1.f) / 2.f) * 0.25f;
if (v > 2.f) ret += glm::min(1.f, (v - 2.f) / 4.f) * 0.10f;
if (v > 4.f) ret += glm::min(1.f, (v - 4.f) / 5.f) * 0.05f;
if (v > 5.f) ret += glm::min(1.f, (v - 5.f) / 10.f) * 0.10f;
return ret;
},
};
SliderCurve curve_size5k_pix {
[](float v) {
float ret = 0;
if (v > 0.00f) ret += glm::pow(glm::min(1.f, (v - 0.00f) / 0.50f), 2.f) * 100.f;
if (v > 0.50f) ret += glm::min(1.f, (v - 0.50f) / 0.25f) * 200.f;
if (v > 0.75f) ret += glm::min(1.f, (v - 0.75f) / 0.10f) * 400.f;
if (v > 0.85f) ret += glm::min(1.f, (v - 0.85f) / 0.05f) * 1000.f;
if (v > 0.90f) ret += glm::min(1.f, (v - 0.90f) / 0.10f) * 5000.f;
return glm::max(1.f, ret);
},
[](float v) {
float ret = 0;
if (v > 0.f) ret += glm::pow(glm::min(1.f, (v - 0.f) / 100.f), 1.f / 2.f) * 0.50f;
if (v > 100.f) ret += glm::min(1.f, (v - 100.f) / 200.f) * 0.25f;
if (v > 200.f) ret += glm::min(1.f, (v - 200.f) / 400.f) * 0.10f;
if (v > 400.f) ret += glm::min(1.f, (v - 400.f) / 1000.f) * 0.05f;
if (v > 1000.f) ret += glm::min(1.f, (v - 1000.f) / 5000.f) * 0.10f;
return ret;
},
};
m_curves[m_tip_size] = curve_size5k_pix;
m_curves[m_tip_spacing] = curve_size1k_perc;
m_curves[m_tip_flow] = curve_quad;
m_curves[m_dual_size] = curve_cubic;
m_curves[m_dual_spacing] = curve_quad;
m_curves[m_dual_size] = curve_size5k_pix;
m_curves[m_dual_spacing] = curve_size1k_perc;
m_curves[m_dual_flow] = curve_quad;
m_curves[m_pattern_scale] = curve_size1k_perc;
m_tip_aspect_reset = find<NodeButtonCustom>("tip-aspect-reset");
m_tip_aspect_reset->on_click = [this](Node*) {
@@ -529,7 +578,7 @@ void NodePanelStroke::init_slider(NodeSliderH*& target, const char* id, float Br
void NodePanelStroke::handle_slide(float Brush::* prop, Node* target, float value)
{
auto curve = m_curves.find((NodeSliderH*)target);
Canvas::I->m_current_brush.get()->*prop = curve != m_curves.end() ? curve->second(value) : value;
Canvas::I->m_current_brush.get()->*prop = curve != m_curves.end() ? curve->second.to_value(value) : value;
m_preview->draw_stroke();
if (on_stroke_change)
on_stroke_change(this);

View File

@@ -87,7 +87,15 @@ public:
std::function<void(Node* target, const std::string& path, const std::string& thumb)> on_brush_changed;
std::function<void(Node* target, const std::string& path, const std::string& thumb)> on_dual_changed;
//std::function<void(Node* target, const std::string& path, const std::string& thumb)> on_texture_changed;
std::map<NodeSliderH*, std::function<float(float)>> m_curves;
struct SliderCurve
{
std::function<float(float)> m_fn;
std::function<float(float)> m_inv;
inline float to_value(float v) { return m_fn(v); }
inline float to_slider(float v) { return m_inv(v); }
};
std::map<NodeSliderH*, SliderCurve> m_curves;
virtual Node* clone_instantiate() const override;
virtual void clone_finalize(Node* dest) const override;

View File

@@ -246,7 +246,7 @@ void NodeStrokePreview::draw_stroke()
const auto& b = m_brush;
m_stroke.m_filter_points = false;
m_stroke.m_max_size = m_size.y / 800.f * App::I.zoom;
m_stroke.m_max_size = m_size.y * App::I.zoom;
m_stroke.m_camera.fov = Canvas::I->m_cam_fov;
m_stroke.m_camera.rot = Canvas::I->m_cam_rot;
m_stroke.reset(true);
@@ -266,11 +266,15 @@ void NodeStrokePreview::draw_stroke()
dual_brush->m_jitter_spread = b->m_dual_scatter;
dual_brush->m_jitter_angle = b->m_dual_rotate;
dual_brush->m_tip_texture = b->m_dual_texture;
m_dual_stroke.m_filter_points = false;
m_dual_stroke.m_camera.fov = Canvas::I->m_cam_fov;
m_dual_stroke.m_camera.rot = Canvas::I->m_cam_rot;
m_dual_stroke.reset(true);
m_dual_stroke.start(dual_brush);
if (b->m_dual_enabled)
{
m_dual_stroke.m_filter_points = false;
m_dual_stroke.m_camera.fov = Canvas::I->m_cam_fov;
m_dual_stroke.m_camera.rot = Canvas::I->m_cam_rot;
m_dual_stroke.reset(true);
m_dual_stroke.start(dual_brush);
}
{
float w = m_size.x;
@@ -282,7 +286,8 @@ void NodeStrokePreview::draw_stroke()
float t = (float)i / 20.f;
float p = 1.f - glm::abs(t * 2.f - 1.f);
m_stroke.add_point(glm::vec3(BezierCurve::Bezier2D(kp, t), 0), p);
m_dual_stroke.add_point(glm::vec3(BezierCurve::Bezier2D(kp, t), 0), p);
if (b->m_dual_enabled)
m_dual_stroke.add_point(glm::vec3(BezierCurve::Bezier2D(kp, t), 0), p);
}
}
@@ -363,8 +368,8 @@ void NodeStrokePreview::draw_stroke()
}
ShaderManager::use(kShader::Stroke);
ShaderManager::u_vec4(kShaderUniform::Col, f.col);
ShaderManager::u_float(kShaderUniform::Alpha, f.pressure);
ShaderManager::u_vec4(kShaderUniform::Col, { 0, 0, 0, 1 } /*f.col*/);
ShaderManager::u_float(kShaderUniform::Alpha, glm::max(f.pressure, m_min_flow));
auto rect = stroke_draw_samples(f.shapes, m_tex);
}
glActiveTexture(GL_TEXTURE3);
@@ -383,6 +388,7 @@ void NodeStrokePreview::draw_stroke()
float aspect = size.x / size.y;
ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f / aspect, .5f / aspect, -1.f, 1.f));
m_plane.draw_fill();
//m_rtt.clear({ .3f, .3f, .3f, 1.f });
m_tex_background.bind();
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, size.x, size.y);
@@ -462,28 +468,5 @@ void NodeStrokePreview::handle_resize(glm::vec2 old_size, glm::vec2 new_size)
m_tex_dual.create((int)new_size.x, (int)new_size.y);
m_tex_background.create((int)new_size.x, (int)new_size.y);
float w = new_size.x;
float h = new_size.y;
m_stroke.m_filter_points = false;
m_stroke.m_max_size = m_size.y / 800.f * App::I.zoom;
m_stroke.m_camera.fov = Canvas::I->m_cam_fov;
m_stroke.m_camera.rot = Canvas::I->m_cam_rot;
m_stroke.reset(true);
m_stroke.start(m_brush);
m_dual_stroke.m_filter_points = false;
//m_dual_stroke.m_max_size = m_size.y / 800.f * App::I.zoom;
m_dual_stroke.m_camera.fov = Canvas::I->m_cam_fov;
m_dual_stroke.m_camera.rot = Canvas::I->m_cam_rot;
m_dual_stroke.reset(true);
m_dual_stroke.start(m_brush);
std::vector<glm::vec2> kp = { { pad, pad },{ pad, h - pad },{ w - pad, pad },{ w - pad, h - pad } };
for (int i = 0; i < 20; i++)
{
float t = (float)i / 20.f;
float p = 1.f - glm::abs(t * 2.f - 1.f);
m_stroke.add_point(glm::vec3(BezierCurve::Bezier2D(kp, t), 0), p);
m_dual_stroke.add_point(glm::vec3(BezierCurve::Bezier2D(kp, t), 0), p);
}
draw_stroke();
}

View File

@@ -30,6 +30,7 @@ public:
Stroke m_stroke;
Stroke m_dual_stroke;
std::vector<glm::vec2> m_bez_points;
float m_min_flow = 0.f;
virtual Node* clone_instantiate() const override;
virtual void clone_copy(Node* dest) const override;
virtual void clone_children(Node* dest) const override;