add abr color dynamics
This commit is contained in:
@@ -583,6 +583,9 @@
|
||||
<node height="20" justify="center">
|
||||
<text text="Val"/>
|
||||
</node>
|
||||
<node height="20" justify="center">
|
||||
<text text="HSV Jitter"/>
|
||||
</node>
|
||||
</node>
|
||||
<node dir="col" grow="1" width="1">
|
||||
<node align="center" dir="row">
|
||||
@@ -626,6 +629,10 @@
|
||||
<node height="20" pad="1" width="100%">
|
||||
<slider-h id="jitter-val"/>
|
||||
</node>
|
||||
<node height="20" pad="1" width="100%" dir="row" align="center">
|
||||
<checkbox width="20" height="19" id="jitter-hsv-eachsample"/>
|
||||
<text text="each sample"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
||||
|
||||
@@ -225,6 +225,15 @@ std::vector<std::shared_ptr<Brush>> ABR::compute_brushes(const std::string& path
|
||||
|
||||
}
|
||||
|
||||
// Color Dynamics
|
||||
if (p->value<Boolean>("useColorDynamics"))
|
||||
{
|
||||
b->m_jitter_sat = p->value<UnitFloat>("Strt") * 0.01f;
|
||||
b->m_jitter_hue = p->value<UnitFloat>("H ") * 0.01f;
|
||||
b->m_jitter_val = p->value<UnitFloat>("Brgh") * 0.01f;
|
||||
b->m_jitter_hsv_eachsample = p->value<Boolean>("colorDynamicsPerTip");
|
||||
}
|
||||
|
||||
std::vector<std::string> modes = {
|
||||
"normal", // normal (not in Photoshop)
|
||||
"Mltp", // multiply
|
||||
|
||||
@@ -150,7 +150,9 @@ void App::init_sidebar()
|
||||
stroke->set_size(value, true, true);
|
||||
};
|
||||
quick->on_brush_change = [this](Node*, std::shared_ptr<Brush> b) {
|
||||
auto c = Canvas::I->m_current_brush->m_tip_color;
|
||||
*Canvas::I->m_current_brush = *b;
|
||||
Canvas::I->m_current_brush->m_tip_color = c;
|
||||
brush_update();
|
||||
};
|
||||
|
||||
|
||||
@@ -129,12 +129,6 @@ bool BrushMesh::create()
|
||||
}
|
||||
StrokeSample Stroke::randomize_sample(const glm::vec3& pos, float pressure, float dir_angle)
|
||||
{
|
||||
auto rnd_nor = [&] { return float((double)prng() / (double)prng.max()); }; // normalized [0, +1]
|
||||
auto rnd_neg = [&] { return float((double)prng() / (double)prng.max() * 2.0 - 1.0); }; // normalized [-1, +1]
|
||||
auto rnd_rad = [&] { return float((double)prng() / (double)prng.max() * M_PI * 2.0); }; // normalized [0, 2pi]
|
||||
auto rnd_vec = [&] { float rad = rnd_rad(); return glm::vec3(cosf(rad), sinf(rad), 0); }; // normalized direction vector
|
||||
auto rnd_bneg = [&] { return prng() % 2 == 0 ? -1.f : 1.f; }; // -1 or 1
|
||||
|
||||
float size_dyn = m_brush->m_tip_size_pressure ? pressure : 1.f;
|
||||
float flow_dyn = m_brush->m_tip_flow_pressure ? pressure : 1.f;
|
||||
float opacity_dyn = m_brush->m_tip_opacity_pressure ? pressure : 1.f;
|
||||
@@ -162,14 +156,24 @@ StrokeSample Stroke::randomize_sample(const glm::vec3& pos, float pressure, floa
|
||||
s.pos = pos + (scatter_scale * rnd_vec() * m_brush->m_jitter_scatter * s.size * 0.5f); // 0.5 because PS scatters by half size
|
||||
s.flow = m_brush->m_tip_flow * (1.f - rnd_nor() * m_brush->m_jitter_flow) * flow_dyn;
|
||||
s.opacity = m_brush->m_tip_opacity * (1.f - rnd_nor() * m_brush->m_jitter_opacity) * opacity_dyn;
|
||||
auto hsv = convert_rgb2hsv(m_brush->m_tip_color);
|
||||
hsv.x = glm::clamp(glm::mix(hsv.x, (pressure - 0.5f) * 2.0f, m_brush->m_tip_hue) + (rnd_nor() - 0.5f) * m_brush->m_jitter_hue, 0.f, 1.f);
|
||||
hsv.y = glm::clamp(glm::mix(hsv.y, (1.f - pressure - 0.5f) * 2.0f, m_brush->m_tip_sat) + (rnd_nor() - 0.5f) * m_brush->m_jitter_sat, 0.f, 1.f);
|
||||
hsv.z = glm::clamp(glm::mix(hsv.z, (pressure - 0.5f) * 2.0f, m_brush->m_tip_val) + (rnd_nor() - 0.5f) * m_brush->m_jitter_val, 0.f, 1.f);
|
||||
|
||||
auto hsv = m_tip_color;
|
||||
float eachtip = m_brush->m_jitter_hsv_eachsample ? 1.f : 0.f;
|
||||
hsv.x = glm::fract(glm::mix(hsv.x, (pressure - 0.5f) * 2.0f, m_brush->m_tip_hue) + (rnd_nor() - 0.5f) * m_brush->m_jitter_hue * eachtip);
|
||||
hsv.y = glm::clamp(glm::mix(hsv.y, (1.f - pressure - 0.5f) * 2.0f, m_brush->m_tip_sat) + (rnd_nor() - 0.5f) * m_brush->m_jitter_sat * eachtip, 0.f, 1.f);
|
||||
hsv.z = glm::clamp(glm::mix(hsv.z, (pressure - 0.5f) * 2.0f, m_brush->m_tip_val) + (rnd_nor() - 0.5f) * m_brush->m_jitter_val * eachtip, 0.f, 1.f);
|
||||
m_hsv_jitter.add(hsv);
|
||||
s.col = convert_hsv2rgb(m_hsv_jitter.average());
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void Stroke::randomize_prng()
|
||||
{
|
||||
std::random_device rd;
|
||||
prng.seed(rd());
|
||||
}
|
||||
|
||||
std::vector<StrokeSample> Stroke::compute_samples()
|
||||
{
|
||||
if (m_keypoints.empty()) return {};
|
||||
@@ -320,6 +324,12 @@ void Stroke::start(const std::shared_ptr<Brush>& brush)
|
||||
float raw_size = glm::clamp(m_brush->m_tip_size / glm::tan(glm::radians(m_camera.fov * 0.5f)), 1.f, m_max_size);
|
||||
float size = aspect_width * glm::min(m_brush->m_tip_scale.x, m_brush->m_tip_scale.y) * raw_size;
|
||||
m_step = glm::max(0.5f, m_brush->m_tip_spacing * size);
|
||||
|
||||
auto hsv = convert_rgb2hsv(m_brush->m_tip_color);
|
||||
hsv.x = glm::fract(hsv.x + (rnd_nor() - 0.5f) * m_brush->m_jitter_hue);
|
||||
hsv.y = glm::clamp(hsv.y + (rnd_nor() - 0.5f) * m_brush->m_jitter_sat, 0.f, 1.f);
|
||||
hsv.z = glm::clamp(hsv.z + (rnd_nor() - 0.5f) * m_brush->m_jitter_val, 0.f, 1.f);
|
||||
m_tip_color = hsv;
|
||||
|
||||
m_direction.resize(std::max<int>(1, m_brush->m_tip_angle_smooth * 200.f / m_step));
|
||||
prng.seed(0);
|
||||
|
||||
11
src/brush.h
11
src/brush.h
@@ -54,6 +54,7 @@ public:
|
||||
float m_jitter_hue = 0;
|
||||
float m_jitter_sat = 0;
|
||||
float m_jitter_val = 0;
|
||||
bool m_jitter_hsv_eachsample = false;
|
||||
float m_jitter_aspect = 0;
|
||||
bool m_jitter_aspect_bothaxis = false;
|
||||
int m_blend_mode = 0;
|
||||
@@ -172,6 +173,7 @@ public:
|
||||
float m_step = 0;
|
||||
float m_max_size = FLT_MAX;
|
||||
bool m_filter_points = true;
|
||||
glm::vec3 m_tip_color;
|
||||
Camera m_camera;
|
||||
std::shared_ptr<Brush> m_brush;
|
||||
cbuffer<float> m_direction{ 1 };
|
||||
@@ -182,11 +184,18 @@ public:
|
||||
std::vector<std::pair<glm::vec3, float>> m_hold_points;
|
||||
std::vector<StrokeSample> m_samples;
|
||||
int m_last_kp;
|
||||
std::minstd_rand prng;
|
||||
std::mt19937 prng;
|
||||
void start(const std::shared_ptr<Brush>& brush);
|
||||
void add_point(glm::vec3 pos, float pressure);
|
||||
void reset(bool clear_keypoints = false);
|
||||
bool has_sample();
|
||||
std::vector<StrokeSample> compute_samples();
|
||||
StrokeSample randomize_sample(const glm::vec3& pos, float pressure, float curve_angle);
|
||||
|
||||
void randomize_prng();
|
||||
float rnd_nor() { return float((double)prng() / (double)prng.max()); }; // normalized [0, +1]
|
||||
float rnd_neg() { return float((double)prng() / (double)prng.max() * 2.0 - 1.0); }; // normalized [-1, +1]
|
||||
float rnd_rad() { return float((double)prng() / (double)prng.max() * M_PI * 2.0); }; // normalized [0, 2pi]
|
||||
glm::vec3 rnd_vec() { float rad = rnd_rad(); return glm::vec3(cosf(rad), sinf(rad), 0); }; // normalized direction vector
|
||||
float rnd_bneg() { return prng() % 2 == 0 ? -1.f : 1.f; }; // -1 or 1
|
||||
};
|
||||
|
||||
@@ -900,6 +900,7 @@ void Canvas::stroke_start(glm::vec3 point, float pressure)
|
||||
m_current_stroke = std::make_unique<Stroke>();
|
||||
m_current_stroke->m_camera.rot = m_cam_rot;
|
||||
m_current_stroke->m_camera.fov = m_cam_fov;
|
||||
m_current_stroke->randomize_prng();
|
||||
m_current_stroke->start(m_current_brush);
|
||||
m_current_stroke->add_point(point, pressure);
|
||||
|
||||
|
||||
@@ -239,7 +239,7 @@ void CanvasModePen::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const
|
||||
tip_color = glm::vec4(s.col, s.flow);
|
||||
}
|
||||
}
|
||||
ShaderManager::u_int(kShaderUniform::DrawOutline, glm::min(tip_scale.x, tip_scale.y) < 20 ? false : m_draw_outline);
|
||||
ShaderManager::u_int(kShaderUniform::DrawOutline, glm::min(tip_scale.x, tip_scale.y) < 20 || m_resizing ? false : m_draw_outline);
|
||||
ShaderManager::u_vec4(kShaderUniform::Col, tip_color);
|
||||
ShaderManager::u_mat4(kShaderUniform::MVP,
|
||||
glm::scale(glm::vec3(1, -1, 1)) *
|
||||
|
||||
26
src/main.cpp
26
src/main.cpp
@@ -34,7 +34,6 @@ std::thread hmd_renderer;
|
||||
std::thread renderer;
|
||||
int running = -1;
|
||||
std::mutex render_mutex;
|
||||
std::mutex wnd_mutex;
|
||||
std::condition_variable render_cv;
|
||||
|
||||
int gl_count = 0;
|
||||
@@ -687,12 +686,11 @@ int main(int argc, char** argv)
|
||||
static wchar_t title_fps[512];
|
||||
swprintf_s(title_fps, L"%s - %d fps", window_title, frames);
|
||||
|
||||
// lock if
|
||||
if (wnd_mutex.try_lock())
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(main_task_mutex);
|
||||
main_tasklist.emplace_back([=] {
|
||||
SetWindowText(hWnd, title_fps);
|
||||
wnd_mutex.unlock();
|
||||
}
|
||||
});
|
||||
|
||||
one_sec = 0;
|
||||
frames = 0;
|
||||
}
|
||||
@@ -869,18 +867,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
||||
{
|
||||
running = 0;
|
||||
render_cv.notify_all();
|
||||
|
||||
{
|
||||
// avoid deadlock
|
||||
// nobody should call windows API on this window at this time
|
||||
std::lock_guard<std::mutex> lock(wnd_mutex);
|
||||
|
||||
if (renderer.joinable())
|
||||
renderer.join();
|
||||
if (hmd_renderer.joinable())
|
||||
hmd_renderer.join();
|
||||
}
|
||||
|
||||
if (renderer.joinable())
|
||||
renderer.join();
|
||||
if (hmd_renderer.joinable())
|
||||
hmd_renderer.join();
|
||||
App::I.terminate();
|
||||
}
|
||||
break;
|
||||
|
||||
14
src/node.cpp
14
src/node.cpp
@@ -94,7 +94,9 @@ kEventResult Node::on_event(Event* e)
|
||||
|
||||
if (current_mouse_capture)
|
||||
{
|
||||
if (e->m_cat == kEventCategory::MouseEvent && child_mouse_focus != current_mouse_capture)
|
||||
if (e->m_cat == kEventCategory::MouseEvent &&
|
||||
child_mouse_focus != current_mouse_capture &&
|
||||
is_child(current_mouse_capture))
|
||||
{
|
||||
MouseEvent* me = static_cast<MouseEvent*>(e);
|
||||
if (child_mouse_focus)
|
||||
@@ -432,6 +434,16 @@ bool Node::is_child_recursive(Node* o) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Node::is_child(Node* o) const
|
||||
{
|
||||
for (const auto& c : m_children)
|
||||
{
|
||||
if (c.get() == o)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Node::mouse_capture()
|
||||
{
|
||||
auto& c = root()->current_mouse_capture;
|
||||
|
||||
@@ -259,6 +259,7 @@ public:
|
||||
// returns {origin, size} form
|
||||
glm::vec4 get_children_rect() const;
|
||||
bool is_child_recursive(Node* o) const;
|
||||
bool is_child(Node* o) const;
|
||||
void mouse_capture();
|
||||
void mouse_release();
|
||||
void key_capture();
|
||||
|
||||
@@ -517,6 +517,7 @@ bool NodePanelBrushPreset::save()
|
||||
i.m_jitter_hue = b->m_jitter_hue;
|
||||
i.m_jitter_sat = b->m_jitter_sat;
|
||||
i.m_jitter_val = b->m_jitter_val;
|
||||
i.m_jitter_hsv_eachsample = b->m_jitter_hsv_eachsample;
|
||||
i.m_jitter_aspect = b->m_jitter_aspect;
|
||||
i.m_jitter_aspect_bothaxis = b->m_jitter_aspect_bothaxis;
|
||||
i.m_blend_mode = b->m_blend_mode;
|
||||
@@ -624,6 +625,7 @@ bool NodePanelBrushPreset::restore()
|
||||
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_jitter_hsv_eachsample = i.m_jitter_hsv_eachsample;
|
||||
b->m_jitter_aspect = i.m_jitter_aspect;
|
||||
b->m_jitter_aspect_bothaxis = i.m_jitter_aspect_bothaxis;
|
||||
b->m_blend_mode = i.m_blend_mode;
|
||||
|
||||
@@ -137,6 +137,7 @@ class NodePanelBrushPreset : public Node
|
||||
float m_jitter_hue = 0;
|
||||
float m_jitter_sat = 0;
|
||||
float m_jitter_val = 0;
|
||||
bool m_jitter_hsv_eachsample = false;
|
||||
float m_jitter_aspect = 0;
|
||||
bool m_jitter_aspect_bothaxis = false;
|
||||
int m_blend_mode = 0;
|
||||
|
||||
@@ -163,6 +163,7 @@ void NodePanelStroke::update_controls()
|
||||
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->checked = b->m_jitter_hsv_eachsample;
|
||||
m_jitter_aspect->m_value = b->m_jitter_aspect;
|
||||
m_tip_angle_follow->checked = b->m_tip_angle_follow;
|
||||
m_tip_angle_init->checked = b->m_tip_angle_init;
|
||||
@@ -484,6 +485,7 @@ void NodePanelStroke::init_controls()
|
||||
init_checkbox(m_tip_size_pressure, "tip-size-pressure", &Brush::m_tip_size_pressure);
|
||||
init_checkbox(m_jitter_scatter_bothaxis, "jitter-scatter-bothaxis", &Brush::m_jitter_scatter_bothaxis);
|
||||
init_checkbox(m_jitter_aspect_bothaxis, "jitter-aspect-bothaxis", &Brush::m_jitter_aspect_bothaxis);
|
||||
init_checkbox(m_jitter_hsv_eachsample, "jitter-hsv-eachsample", &Brush::m_jitter_hsv_eachsample);
|
||||
|
||||
init_checkbox(m_tip_invert, "tip-invert", &Brush::m_tip_invert);
|
||||
init_checkbox(m_tip_flipx, "tip-flipx", &Brush::m_tip_flipx);
|
||||
|
||||
@@ -34,6 +34,7 @@ public:
|
||||
NodeSliderH* m_jitter_hue;
|
||||
NodeSliderH* m_jitter_sat;
|
||||
NodeSliderH* m_jitter_val;
|
||||
NodeCheckBox* m_jitter_hsv_eachsample;
|
||||
NodeSliderH* m_jitter_aspect;
|
||||
NodeCheckBox* m_tip_angle_init;
|
||||
NodeCheckBox* m_tip_angle_follow;
|
||||
|
||||
Reference in New Issue
Block a user