diff --git a/data/shaders/comp-draw.glsl b/data/shaders/comp-draw.glsl index b660741..825a1b1 100644 --- a/data/shaders/comp-draw.glsl +++ b/data/shaders/comp-draw.glsl @@ -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); diff --git a/data/shaders/stroke.glsl b/data/shaders/stroke.glsl index 631ceea..a9fc43d 100644 --- a/data/shaders/stroke.glsl +++ b/data/shaders/stroke.glsl @@ -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); diff --git a/src/abr.cpp b/src/abr.cpp index 24e1f33..930ae2d 100644 --- a/src/abr.cpp +++ b/src/abr.cpp @@ -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> ABR::compute_brushes(const std::string& path continue; auto b = std::make_shared(); b->m_name = wstr2str(p->value("Nm ")); - //b->m_tip_color = i.m_tip_color; - b->m_tip_size = samp->value("Dmtr") / 800.f; - b->m_tip_spacing = samp->value("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("Angl") / 360.f + 0.5f; // [-180,180] -> [0, 1] + + b->m_tip_aspect = (1.f - samp->value("Rndn") * 0.01) * 0.5f + 0.5f; + b->m_tip_size = samp->value("Dmtr"); + b->m_tip_spacing = samp->value("Spcn") * 0.01f; + b->m_tip_angle = samp->value("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("Wtdg"); b->m_tip_noise = (float)samp->value("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("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("Txtr")) { auto patt_uid = wstr2str(patt->value("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("textureDepth") * 0.01f; + + b->m_pattern_invert = p->value("InvT"); + b->m_pattern_eachsample = p->value("TxtC"); + b->m_pattern_depth = p->value("textureDepth") * 0.01f; // [0, 100] -> [0, 1] + b->m_pattern_scale = p->value("textureScale") * 0.01f; // [0, 1000] -> [0, 1] + b->m_pattern_brightness = (float)(p->value("textureBrightness") + 150) / 300.f; // [-150, 150] -> [0, 1] + + int raw_contrast = p->value("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("textureBlendMode"); + std::vector 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); diff --git a/src/abr.h b/src/abr.h index a3ba9e4..97b1eb4 100644 --- a/src/abr.h +++ b/src/abr.h @@ -360,7 +360,7 @@ class ABR : private BinaryStream std::vector channels; VMArray() = default; VMArray(uint32_t version, const Rectangle& rect) : version(version), rect(rect) { } - std::shared_ptr image(bool grayscale) const + std::shared_ptr 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; diff --git a/src/app.cpp b/src/app.cpp index dc92f1a..5f6ab5b 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -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 diff --git a/src/app_vr.cpp b/src/app_vr.cpp index 26efbd9..38831f3 100644 --- a/src/app_vr.cpp +++ b/src/app_vr.cpp @@ -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); diff --git a/src/brush.cpp b/src/brush.cpp index 939f30a..cd4d8ed 100644 --- a/src/brush.cpp +++ b/src/brush.cpp @@ -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) 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(1, m_brush->m_tip_angle_delay * 200.f / m_step)); prng.seed(0); } diff --git a/src/brush.h b/src/brush.h index 85dd37f..f8b23d9 100644 --- a/src/brush.h +++ b/src/brush.h @@ -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; diff --git a/src/canvas_modes.cpp b/src/canvas_modes.cpp index 2bb2e79..00302e2 100644 --- a/src/canvas_modes.cpp +++ b/src/canvas_modes.cpp @@ -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); diff --git a/src/node_panel_brush.cpp b/src/node_panel_brush.cpp index 764c755..7c23c93 100644 --- a/src/node_panel_brush.cpp +++ b/src/node_panel_brush.cpp @@ -344,6 +344,7 @@ void NodeBrushPresetItem::init() m_color = color_normal; m_thumb = find("thumb"); m_preview = find("canvas"); + m_preview->m_min_flow = 1.f; } void NodeBrushPresetItem::draw() diff --git a/src/node_panel_brush.h b/src/node_panel_brush.h index ec26420..aeb3c42 100644 --- a/src/node_panel_brush.h +++ b/src/node_panel_brush.h @@ -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; diff --git a/src/node_panel_stroke.cpp b/src/node_panel_stroke.cpp index 9dc8660..112d934 100644 --- a/src/node_panel_stroke.cpp +++ b/src/node_panel_stroke.cpp @@ -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("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); diff --git a/src/node_panel_stroke.h b/src/node_panel_stroke.h index 5ef07b4..25dfe63 100644 --- a/src/node_panel_stroke.h +++ b/src/node_panel_stroke.h @@ -87,7 +87,15 @@ public: std::function on_brush_changed; std::function on_dual_changed; //std::function on_texture_changed; - std::map> m_curves; + + struct SliderCurve + { + std::function m_fn; + std::function m_inv; + inline float to_value(float v) { return m_fn(v); } + inline float to_slider(float v) { return m_inv(v); } + }; + std::map m_curves; virtual Node* clone_instantiate() const override; virtual void clone_finalize(Node* dest) const override; diff --git a/src/node_stroke_preview.cpp b/src/node_stroke_preview.cpp index 161e2ed..825218b 100644 --- a/src/node_stroke_preview.cpp +++ b/src/node_stroke_preview.cpp @@ -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 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(); } diff --git a/src/node_stroke_preview.h b/src/node_stroke_preview.h index 314d417..e84ee67 100644 --- a/src/node_stroke_preview.h +++ b/src/node_stroke_preview.h @@ -30,6 +30,7 @@ public: Stroke m_stroke; Stroke m_dual_stroke; std::vector 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;