pixel based brush size, Photoshop slider curve, improve abr import
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
72
src/abr.cpp
72
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<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);
|
||||
|
||||
26
src/abr.h
26
src/abr.h
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user