enable rtt dtor, default values for <text> node, dual-brush wip, more brush options
This commit is contained in:
730
data/layout.xml
730
data/layout.xml
File diff suppressed because it is too large
Load Diff
@@ -112,7 +112,7 @@ std::vector<std::shared_ptr<Brush>> ABR::compute_brushes(const std::string& path
|
||||
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 * 4.f);
|
||||
b->m_tip_size = samp->value<UnitFloat>("Dmtr") / 800.f;
|
||||
b->m_tip_spacing = samp->value<UnitFloat>("Spcn") * 0.01f;
|
||||
b->m_tip_flow = .25f;
|
||||
b->m_tip_opacity = 1.f;
|
||||
|
||||
@@ -664,7 +664,7 @@ void App::init_menu_about()
|
||||
b->on_click = [this, popup](Node*) {
|
||||
LOG("perf");
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
Canvas::I->stroke_start({ 0, 0, 0 }, 0.9f, Canvas::I->m_current_brush);
|
||||
Canvas::I->stroke_start({ 0, 0, 0 }, 0.9f);
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
Canvas::I->stroke_update({ 100, 100, 0 }, 0.9f);
|
||||
|
||||
@@ -218,7 +218,7 @@ void App::initShaders()
|
||||
"uniform bool lock;\n"
|
||||
"uniform bool mask;\n"
|
||||
"uniform bool fragUV2;\n"
|
||||
"uniform bool useDual;\n"
|
||||
"uniform bool use_dual;\n"
|
||||
"in mediump vec2 uv;\n"
|
||||
"out mediump vec4 frag;\n"
|
||||
SHADER_FUNCTION_BLUR
|
||||
@@ -227,6 +227,9 @@ void App::initShaders()
|
||||
" mediump vec2 uv2 = fragUV2 ? (gl_FragCoord.st / resolution) : uv;\n"
|
||||
" mediump vec4 base = texture(tex, uv2);\n"
|
||||
" mediump vec4 stroke = texture(tex_stroke, uv);\n"
|
||||
" mediump vec4 dual = texture(tex_dual, uv);\n"
|
||||
" if (use_dual)\n"
|
||||
" stroke.a = stroke.a * dual.a;\n"
|
||||
" stroke.a = mask ? stroke.a * stroke_alpha * blur(tex_mask, uv2).r : stroke.a * stroke_alpha;\n"
|
||||
" if (!lock && base.a == 0.0) { frag = stroke * vec4(1.0, 1.0, 1.0, alpha); return; }\n"
|
||||
" mediump vec4 blended = blend(base, stroke, blend_mode);\n"
|
||||
|
||||
@@ -132,21 +132,28 @@ StrokeSample Stroke::randomize_sample(const glm::vec3& pos, float pressure, floa
|
||||
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 size = glm::min(m_brush->m_tip_size / glm::tan(glm::radians(m_camera.fov * 0.5f)), m_max_size);
|
||||
|
||||
float randflipx = m_brush->m_tip_randflipx ? rnd_bneg() : 1.f;
|
||||
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) *
|
||||
(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.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);
|
||||
hsv.x = glm::clamp(glm::mix(hsv.x, (pressure - 0.5f) * 2.0f, m_brush->m_tip_hue * (float)m_brush->m_tip_hue_pressure) + (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 * (float)m_brush->m_tip_sat_pressure) + (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 * (float)m_brush->m_tip_val_pressure) + (rnd_nor() - 0.5f) * m_brush->m_jitter_val, 0.f, 1.f);
|
||||
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);
|
||||
m_hsv_jitter.add(hsv);
|
||||
s.col = convert_hsv2rgb(m_hsv_jitter.average());
|
||||
return s;
|
||||
@@ -159,13 +166,13 @@ std::vector<StrokeSample> Stroke::compute_samples()
|
||||
samples.reserve(nsamples); // preallocate the estimate number of samples
|
||||
while (m_keypoints.back().dist > (m_dist + m_step))
|
||||
{
|
||||
bool is_first = m_last_kp == 0;
|
||||
m_dist += m_step;
|
||||
m_dir_dist += m_step;
|
||||
int old_kp = m_last_kp;
|
||||
while (m_dist > m_keypoints[m_last_kp + 1].dist)
|
||||
m_last_kp++;
|
||||
const auto& A = m_keypoints[m_last_kp];
|
||||
const auto& B = m_keypoints[m_last_kp + 1]; // NOTE: this should be true when while is true
|
||||
const auto& A = m_keypoints[old_kp];
|
||||
const auto& B = m_keypoints[m_last_kp == old_kp ? m_last_kp + 1 : m_last_kp]; // NOTE: this should be true when while is true
|
||||
float t = (m_dist - A.dist) / (B.dist - A.dist); // NOTE: must be A != B
|
||||
auto pos = glm::lerp(A.pos, B.pos, t);
|
||||
float pressure = glm::lerp(A.pressure, B.pressure, t);
|
||||
@@ -175,16 +182,20 @@ std::vector<StrokeSample> Stroke::compute_samples()
|
||||
{
|
||||
if (m_brush->m_tip_angle_follow)
|
||||
{
|
||||
if (m_dir_dist > m_dir_step)
|
||||
if (m_dir_dist > m_dir_step && m_last_kp != m_dir_kp)
|
||||
{
|
||||
glm::vec2 v = glm::normalize(m_keypoints[m_last_kp].pos - m_keypoints[m_dir_kp].pos);
|
||||
m_dir_angle = -glm::orientedAngle(v, m_dir_ref);
|
||||
if (glm::abs(m_dir_angle) > glm::pi<float>() / 2.f || !m_dir_valid)
|
||||
if (m_brush->m_tip_angle_delay > 0 && (glm::abs(m_dir_angle) > glm::pi<float>() / 2.f || !m_dir_valid))
|
||||
{
|
||||
m_direction.clear();
|
||||
auto old_dir = m_dir_ref;
|
||||
m_dir_ref = v;
|
||||
m_dir_ref_angle = -glm::orientedAngle(m_dir_ref, { 1, 0 });
|
||||
m_dir_angle = 0;
|
||||
//m_direction.clear();
|
||||
auto angle_diff = -glm::orientedAngle(m_dir_ref, old_dir);
|
||||
for (int i = 0; i < m_direction.m_count; i++)
|
||||
m_direction.m_vec[i] -= angle_diff;
|
||||
}
|
||||
m_dir_kp = m_last_kp;
|
||||
m_dir_dist = 0;
|
||||
@@ -245,7 +256,7 @@ 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, 1.f);
|
||||
m_step = glm::max(m_brush->m_tip_spacing * size * pressure * 800.f, 0.1f);
|
||||
}
|
||||
|
||||
float dist = m_keypoints.empty() ? m_step :
|
||||
@@ -276,6 +287,7 @@ void Stroke::start(const std::shared_ptr<Brush>& brush)
|
||||
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);
|
||||
m_direction.resize(std::max<int>(1, m_brush->m_tip_angle_delay * 200.f / m_step));
|
||||
prng.seed(0);
|
||||
}
|
||||
|
||||
@@ -291,6 +303,18 @@ bool Brush::load_texture(const std::string& path, const std::string& thumb)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Brush::load_dual(const std::string& path, const std::string& thumb)
|
||||
{
|
||||
m_dual_texture = std::make_shared<Texture2D>();
|
||||
if (!m_dual_texture->load(path))
|
||||
return false;
|
||||
m_dual_texture->create_mipmaps();
|
||||
m_dual_texture->auto_destroy = true;
|
||||
m_dual_path = path;
|
||||
m_dual_thumb_path = thumb;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Brush::load_stencil(const std::string& path)
|
||||
{
|
||||
m_stencil_texture = std::make_shared<Texture2D>();
|
||||
@@ -316,6 +340,19 @@ bool Brush::load()
|
||||
m_tip_texture->create_mipmaps();
|
||||
m_tip_texture->auto_destroy = true;
|
||||
}
|
||||
if (!m_dual_path.empty())
|
||||
{
|
||||
m_dual_texture = std::make_shared<Texture2D>();
|
||||
if (!m_dual_texture->load(m_dual_path))
|
||||
{
|
||||
LOG("failed to load %s", m_dual_path.c_str());
|
||||
m_tip_texture = nullptr;
|
||||
m_dual_texture = nullptr;
|
||||
return false;
|
||||
}
|
||||
m_dual_texture->create_mipmaps();
|
||||
m_dual_texture->auto_destroy = true;
|
||||
}
|
||||
if (!m_stencil_path.empty())
|
||||
{
|
||||
m_stencil_texture = std::make_shared<Texture2D>();
|
||||
@@ -323,6 +360,7 @@ bool Brush::load()
|
||||
{
|
||||
LOG("failed to load %s", m_stencil_path.c_str());
|
||||
m_tip_texture = nullptr;
|
||||
m_dual_texture = nullptr;
|
||||
m_stencil_texture = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
49
src/brush.h
49
src/brush.h
@@ -6,22 +6,29 @@
|
||||
class Brush
|
||||
{
|
||||
public:
|
||||
Brush() = default;
|
||||
Brush(const Brush& brush) = default;
|
||||
//Brush() = default;
|
||||
//Brush(const Brush& brush) = default;
|
||||
std::string m_name;
|
||||
|
||||
std::shared_ptr<Texture2D> m_tip_texture;
|
||||
std::string m_brush_path;
|
||||
std::string m_brush_thumb_path;
|
||||
std::string m_stencil_path;
|
||||
std::shared_ptr<Texture2D> m_tip_texture;
|
||||
|
||||
std::shared_ptr<Texture2D> m_dual_texture;
|
||||
std::string m_dual_path;
|
||||
std::string m_dual_thumb_path;
|
||||
|
||||
std::shared_ptr<Texture2D> m_stencil_texture;
|
||||
//uint16_t m_tex_id = 0;
|
||||
//uint16_t m_tex_stencil_id = const_hash("data/paper.jpg");
|
||||
std::string m_stencil_path;
|
||||
std::string m_stencil_thumb_path;
|
||||
|
||||
glm::vec4 m_tip_color{0, 0, 0, 1};
|
||||
float m_tip_size = 0;
|
||||
float m_tip_spacing = 0;
|
||||
float m_tip_flow = 0;
|
||||
float m_tip_opacity = 0;
|
||||
float m_tip_angle = 0;
|
||||
float m_tip_angle_delay = 0;
|
||||
float m_tip_mix = 0;
|
||||
float m_tip_stencil = 0;
|
||||
float m_tip_wet = 0;
|
||||
@@ -32,9 +39,6 @@ public:
|
||||
bool m_tip_angle_follow = false;
|
||||
bool m_tip_flow_pressure = false;
|
||||
bool m_tip_size_pressure = false;
|
||||
bool m_tip_hue_pressure = false;
|
||||
bool m_tip_sat_pressure = false;
|
||||
bool m_tip_val_pressure = false;
|
||||
float m_jitter_scale = 0;
|
||||
float m_jitter_angle = 0;
|
||||
float m_jitter_spread = 0;
|
||||
@@ -43,7 +47,27 @@ public:
|
||||
float m_jitter_sat = 0;
|
||||
float m_jitter_val = 0;
|
||||
int m_blend_mode = 0;
|
||||
|
||||
bool m_tip_invert = false;
|
||||
bool m_tip_flipx = false;
|
||||
bool m_tip_flipy = false;
|
||||
bool m_tex_enabled = false;
|
||||
bool m_dual_enabled = false;
|
||||
int m_dual_blend_mode = 0;
|
||||
bool m_dual_randflip = false;
|
||||
float m_dual_size = 0;
|
||||
float m_dual_spacing = 0;
|
||||
float m_dual_scatter = 0;
|
||||
bool m_dual_scatter_axis = false;
|
||||
bool m_dual_invert = false;
|
||||
bool m_dual_flipx = false;
|
||||
bool m_dual_flipy = false;
|
||||
bool m_tip_randflipx = false;
|
||||
bool m_tip_randflipy = false;
|
||||
float m_tip_aspect = 0.5;
|
||||
|
||||
bool load_texture(const std::string& path, const std::string& thumb);
|
||||
bool load_dual(const std::string& path, const std::string& thumb);
|
||||
bool load_stencil(const std::string& path);
|
||||
bool load();
|
||||
};
|
||||
@@ -53,6 +77,7 @@ struct StrokeSample
|
||||
glm::vec3 col = { 0, 0, 0 };
|
||||
glm::vec3 pos = { 0, 0, 0 };
|
||||
glm::vec3 origin = { 0, 0, 0 };
|
||||
glm::vec2 scale = { 1, 1 };
|
||||
float size = 0;
|
||||
float flow = 0;
|
||||
float angle = 0;
|
||||
@@ -110,9 +135,9 @@ public:
|
||||
bool m_filter_points = true;
|
||||
Camera m_camera;
|
||||
std::shared_ptr<Brush> m_brush;
|
||||
cbuffer<float, 3> m_direction;
|
||||
cbuffer<float, 10> m_pressure_buff;
|
||||
cbuffer<glm::vec3, 3> m_hsv_jitter;
|
||||
cbuffer<float> m_direction{ 1 };
|
||||
cbuffer<float> m_pressure_buff{ 10 };
|
||||
cbuffer<glm::vec3> m_hsv_jitter{ 3 };
|
||||
StrokeSample m_prev_sample;
|
||||
std::vector<Keypoint> m_keypoints;
|
||||
std::vector<std::pair<glm::vec3, float>> m_hold_points;
|
||||
|
||||
166
src/canvas.cpp
166
src/canvas.cpp
@@ -252,6 +252,7 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
|
||||
ShaderManager::u_int(kShaderUniform::Lock, false/*m_layers[layer_index].m_alpha_locked*/);
|
||||
ShaderManager::u_int(kShaderUniform::Mask, false/*m_smask_active*/);
|
||||
ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false);
|
||||
ShaderManager::u_int(kShaderUniform::UseDual, false);
|
||||
ShaderManager::u_int(kShaderUniform::BlendMode, m_current_stroke->m_brush->m_blend_mode);
|
||||
ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
@@ -273,11 +274,11 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
|
||||
gl.restore();
|
||||
}
|
||||
|
||||
std::array<std::vector<vertex_t>, 6> Canvas::stroke_draw_project(std::array<vertex_t, 4>& B)
|
||||
std::array<std::vector<vertex_t>, 6> Canvas::stroke_draw_project(std::array<vertex_t, 4>& B) const
|
||||
{
|
||||
// intersect P with the current face to clip diverging points from the plane
|
||||
auto unp_vp = zw(m_box);
|
||||
auto unp_inv = glm::inverse(m_proj * m_mv);
|
||||
const auto unp_vp = zw(m_box);
|
||||
const auto unp_inv = glm::inverse(m_proj * m_mv);
|
||||
std::array<std::vector<vertex_t>, 6> ret;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
@@ -338,7 +339,7 @@ std::array<std::vector<vertex_t>, 6> Canvas::stroke_draw_project(std::array<vert
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Canvas::stroke_draw_samples(int i, std::vector<vertex_t>& P)
|
||||
glm::vec4 Canvas::stroke_draw_samples(int i, std::vector<vertex_t>& P)
|
||||
{
|
||||
if (!ShaderManager::ext_framebuffer_fetch)
|
||||
{
|
||||
@@ -364,9 +365,6 @@ void Canvas::stroke_draw_samples(int i, std::vector<vertex_t>& P)
|
||||
tex_pos.x, tex_pos.y, tex_sz.x, tex_sz.y);
|
||||
}
|
||||
|
||||
m_dirty_box[i] = glm::vec4(glm::min(xy(m_dirty_box[i]), (glm::vec2)tex_pos),
|
||||
glm::max(zw(m_dirty_box[i]), (glm::vec2)(tex_pos + tex_sz)));
|
||||
|
||||
if (P.size() == 4)
|
||||
{
|
||||
static vertex_t rect[6];
|
||||
@@ -394,13 +392,15 @@ void Canvas::stroke_draw_samples(int i, std::vector<vertex_t>& P)
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
m_tex[i].unbind();
|
||||
}
|
||||
|
||||
return glm::vec4(tex_pos, tex_pos + tex_sz);
|
||||
}
|
||||
|
||||
std::vector<Canvas::StrokeFrame> Canvas::stroke_draw_compute()
|
||||
std::vector<Canvas::StrokeFrame> Canvas::stroke_draw_compute(Stroke& stroke) const
|
||||
{
|
||||
std::vector<StrokeFrame> ret;
|
||||
const auto& m_brush = m_current_stroke->m_brush;
|
||||
auto samples = m_current_stroke->compute_samples();
|
||||
StrokeSample prev = stroke.m_prev_sample;
|
||||
auto samples = stroke.compute_samples();
|
||||
std::array<vertex_t, 4> B = {
|
||||
vertex_t{ {0, 0, 1, 1}, {0, 0}, {0, 0} },
|
||||
vertex_t{ {0, 0, 1, 1}, {0, 1}, {0, 1} },
|
||||
@@ -415,13 +415,7 @@ std::vector<Canvas::StrokeFrame> Canvas::stroke_draw_compute()
|
||||
ret.emplace_back();
|
||||
auto& f = ret.back();
|
||||
|
||||
if (m_mixer_idle)
|
||||
{
|
||||
m_mixer_sample = s;
|
||||
m_mixer_idle = false;
|
||||
}
|
||||
|
||||
glm::vec2 dx_mix(m_mixer_sample.size * 0.5f, 0), dy_mix(0, m_mixer_sample.size * 0.5f);
|
||||
glm::vec2 dx_mix(prev.size * 0.5f, 0), dy_mix(0, prev.size * 0.5f);
|
||||
glm::vec2 off_mix[4] = {
|
||||
-dx_mix - dy_mix, // A - bottom-left
|
||||
-dx_mix + dy_mix, // B - top-left
|
||||
@@ -442,20 +436,20 @@ std::vector<Canvas::StrokeFrame> Canvas::stroke_draw_compute()
|
||||
glm::vec2 mixer_bb_max(0, 0);
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
auto p = (xy(m_mixer_sample.pos) + off_mix[j] * glm::orientate2(-s.angle) + glm::vec2(0, 1));
|
||||
auto p = (xy(prev.pos) + s.scale * off_mix[j] * glm::orientate2(-s.angle));
|
||||
mixer_bb_min = glm::max({ 0, 0 }, glm::min(mixer_bb_min, p));
|
||||
mixer_bb_max = glm::min(mixer_sz, glm::max(mixer_bb_max, p));
|
||||
|
||||
B[j].pos = glm::vec4(xy(s.pos) + off[j] * glm::orientate2(-s.angle), 1, 1);
|
||||
B[j].pos = glm::vec4(xy(s.pos) + s.scale * off[j] * glm::orientate2(-s.angle) - glm::vec2(0, 1), 1, 1);
|
||||
B[j].uvs2 = p / mixer_sz;
|
||||
}
|
||||
|
||||
f.m_mixer_rect = { mixer_bb_min, mixer_bb_max - mixer_bb_min };
|
||||
f.col = glm::vec4(s.col, m_brush->m_tip_color.a);
|
||||
f.col = glm::vec4(s.col, 1);
|
||||
f.pressure = s.flow;
|
||||
f.shapes = stroke_draw_project(B);
|
||||
|
||||
m_mixer_sample = s;
|
||||
prev = s;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -475,29 +469,18 @@ void Canvas::stroke_draw()
|
||||
glGetIntegerv(GL_VIEWPORT, vp);
|
||||
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
|
||||
|
||||
const auto& m_brush = m_current_stroke->m_brush;
|
||||
auto& tex = *m_brush->m_tip_texture;
|
||||
const auto& brush = m_current_stroke->m_brush;
|
||||
const auto& dual_brush = m_dual_stroke->m_brush;
|
||||
auto ortho_proj = glm::ortho(0.f, (float)m_width, 0.f, (float)m_height, -1.f, 1.f);
|
||||
|
||||
glViewport(0, 0, m_width, m_height);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
tex.bind();
|
||||
m_sampler_brush.bind(0);
|
||||
m_sampler_bg.bind(1);
|
||||
m_sampler_stencil.bind(2);
|
||||
m_sampler.bind(3);
|
||||
//m_sampler_linear.bind(5);
|
||||
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
if (m_brush->m_stencil_texture)
|
||||
m_brush->m_stencil_texture->bind();
|
||||
else
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glActiveTexture(GL_TEXTURE3);
|
||||
m_mixer.bindTexture();
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
ShaderManager::use(kShader::Stroke);
|
||||
ShaderManager::u_int(kShaderUniform::Tex, 0); // brush
|
||||
@@ -508,21 +491,32 @@ void Canvas::stroke_draw()
|
||||
//ShaderManager::u_int(kShaderUniform::TexMixA, 4); // mixer
|
||||
ShaderManager::u_vec2(kShaderUniform::Resolution, { m_width, m_height });
|
||||
ShaderManager::u_vec2(kShaderUniform::StencilOffset, stencil_offset);
|
||||
ShaderManager::u_float(kShaderUniform::StencilAlpha, m_brush->m_tip_stencil);
|
||||
ShaderManager::u_float(kShaderUniform::MixAlpha, m_brush->m_tip_mix);
|
||||
ShaderManager::u_float(kShaderUniform::Wet, m_brush->m_tip_wet);
|
||||
ShaderManager::u_float(kShaderUniform::Noise, m_brush->m_tip_noise);
|
||||
ShaderManager::u_float(kShaderUniform::StencilAlpha, brush->m_tip_stencil);
|
||||
ShaderManager::u_float(kShaderUniform::MixAlpha, brush->m_tip_mix);
|
||||
ShaderManager::u_float(kShaderUniform::Wet, brush->m_tip_wet);
|
||||
ShaderManager::u_float(kShaderUniform::Noise, brush->m_tip_noise);
|
||||
ShaderManager::u_mat4(kShaderUniform::MVP, ortho_proj);
|
||||
|
||||
auto frames = stroke_draw_compute();
|
||||
// DRAW MAIN BRUSH
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
brush->m_tip_texture->bind();
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
if (brush->m_stencil_texture)
|
||||
brush->m_stencil_texture->bind();
|
||||
else
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glActiveTexture(GL_TEXTURE3);
|
||||
m_mixer.bindTexture();
|
||||
auto frames = stroke_draw_compute(*m_current_stroke);
|
||||
for (auto& f : frames)
|
||||
{
|
||||
if (m_brush->m_tip_mix > 0.f)
|
||||
if (brush->m_tip_mix > 0.f)
|
||||
{
|
||||
stroke_draw_mix(xy(f.m_mixer_rect), zw(f.m_mixer_rect));
|
||||
}
|
||||
|
||||
//ShaderManager::use(kShader::Stroke);
|
||||
ShaderManager::use(kShader::Stroke);
|
||||
ShaderManager::u_vec4(kShaderUniform::Col, f.col);
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, f.pressure);
|
||||
for (int i = 0; i < 6; i++)
|
||||
@@ -532,22 +526,56 @@ void Canvas::stroke_draw()
|
||||
continue;
|
||||
m_dirty_face[i] = true;
|
||||
m_tmp[i].bindFramebuffer();
|
||||
stroke_draw_samples(i, P);
|
||||
auto rect = stroke_draw_samples(i, P);
|
||||
m_tmp[i].unbindFramebuffer();
|
||||
m_dirty_box[i] = glm::clamp(box_union(m_dirty_box[i], rect), glm::vec4(0), glm::vec4(m_width));
|
||||
}
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
if (m_brush->m_stencil_texture)
|
||||
m_brush->m_stencil_texture->unbind();
|
||||
glActiveTexture(GL_TEXTURE3);
|
||||
m_mixer.unbindTexture();
|
||||
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
if (brush->m_stencil_texture)
|
||||
brush->m_stencil_texture->unbind();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
brush->m_tip_texture->unbind();
|
||||
|
||||
// DRAW DUAL BRUSH
|
||||
|
||||
if (brush->m_dual_enabled)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
dual_brush->m_tip_texture->bind();
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
if (dual_brush->m_stencil_texture)
|
||||
dual_brush->m_stencil_texture->bind();
|
||||
else
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
auto frames_dual = stroke_draw_compute(*m_dual_stroke);
|
||||
for (auto& f : frames_dual)
|
||||
{
|
||||
ShaderManager::use(kShader::Stroke);
|
||||
ShaderManager::u_vec4(kShaderUniform::Col, f.col);
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, f.pressure);
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
auto& P = f.shapes[i];
|
||||
if (P.size() < 3)
|
||||
continue;
|
||||
m_tmp_dual[i].bindFramebuffer();
|
||||
stroke_draw_samples(i, P);
|
||||
m_tmp_dual[i].unbindFramebuffer();
|
||||
}
|
||||
}
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
if (dual_brush->m_stencil_texture)
|
||||
dual_brush->m_stencil_texture->unbind();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
dual_brush->m_tip_texture->unbind();
|
||||
}
|
||||
|
||||
m_sampler_brush.unbind();
|
||||
m_sampler_bg.unbind();
|
||||
m_sampler_stencil.unbind();
|
||||
tex.unbind();
|
||||
|
||||
glViewport(vp[0], vp[1], vp[2], vp[3]);
|
||||
glClearColor(cc[0], cc[1], cc[2], cc[3]);
|
||||
@@ -665,7 +693,6 @@ void Canvas::stroke_commit()
|
||||
if (!m_dirty || m_layers.empty())
|
||||
return;
|
||||
|
||||
m_mixer_idle = true;
|
||||
m_dirty = false;
|
||||
m_dirty_stroke = true; // new stroke ready for timelapse capture
|
||||
App::I.redraw = true;
|
||||
@@ -763,6 +790,9 @@ void Canvas::stroke_commit()
|
||||
ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false);
|
||||
ShaderManager::u_int(kShaderUniform::BlendMode, m_current_stroke->m_brush->m_blend_mode);
|
||||
ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f));
|
||||
ShaderManager::u_int(kShaderUniform::TexDual, 3);
|
||||
ShaderManager::u_int(kShaderUniform::UseDual, true);
|
||||
ShaderManager::u_int(kShaderUniform::DualBlendMode, 1);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
m_tex2[i].bind();
|
||||
@@ -771,13 +801,11 @@ void Canvas::stroke_commit()
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
m_smask.m_rtt[i].bindTexture();
|
||||
glActiveTexture(GL_TEXTURE3);
|
||||
if (m_current_stroke->m_brush->m_stencil_texture)
|
||||
m_current_stroke->m_brush->m_stencil_texture->bind();
|
||||
else
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
m_current_stroke->m_brush->m_dual_enabled ?
|
||||
m_tmp_dual[i].bindTexture() : glBindTexture(GL_TEXTURE_2D, 0);
|
||||
m_plane.draw_fill();
|
||||
if (m_current_stroke->m_brush->m_stencil_texture)
|
||||
m_current_stroke->m_brush->m_stencil_texture->unbind();
|
||||
if (m_current_stroke->m_brush->m_dual_enabled)
|
||||
m_tmp_dual[i].unbindTexture();
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
m_smask.m_rtt[i].unbindTexture();
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
@@ -790,7 +818,7 @@ void Canvas::stroke_commit()
|
||||
// ShaderManager::use(kShader::StrokeLayer);
|
||||
// ShaderManager::u_int(kShaderUniform::TexBG, 1);
|
||||
// ShaderManager::u_int(kShaderUniform::Lock, m_layers[m_current_layer_idx].m_alpha_locked);
|
||||
// ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->m_brush->m_tip_opacity);
|
||||
// ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->brush->m_tip_opacity);
|
||||
//
|
||||
// ShaderManager::u_int(kShaderUniform::Tex, 0);
|
||||
// ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f));
|
||||
@@ -819,14 +847,16 @@ void Canvas::stroke_commit()
|
||||
void Canvas::stroke_update(glm::vec3 point, float pressure)
|
||||
{
|
||||
m_current_stroke->add_point(point, pressure);
|
||||
m_dual_stroke->add_point(point, pressure);
|
||||
}
|
||||
void Canvas::stroke_start(glm::vec3 point, float pressure, const std::shared_ptr<Brush>& brush)
|
||||
void Canvas::stroke_start(glm::vec3 point, float pressure)
|
||||
{
|
||||
// need to commit this now before starting a new stroke
|
||||
if (m_current_stroke && m_commit_delayed)
|
||||
{
|
||||
stroke_commit();
|
||||
m_current_stroke = nullptr;
|
||||
m_dual_stroke = nullptr;
|
||||
m_show_tmp = false;
|
||||
m_commit_delayed = false;
|
||||
}
|
||||
@@ -836,9 +866,15 @@ void Canvas::stroke_start(glm::vec3 point, float pressure, const std::shared_ptr
|
||||
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->start(brush);
|
||||
m_current_stroke->start(m_current_brush);
|
||||
m_current_stroke->add_point(point, pressure);
|
||||
|
||||
|
||||
m_dual_stroke = std::make_unique<Stroke>();
|
||||
m_dual_stroke->m_camera.rot = m_cam_rot;
|
||||
m_dual_stroke->m_camera.fov = m_cam_fov;
|
||||
m_dual_stroke->start(m_dual_brush);
|
||||
m_dual_stroke->add_point(point, pressure);
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
m_dirty_box[i] = glm::vec4(m_width, m_height, 0, 0); // reset bounding box
|
||||
@@ -847,6 +883,13 @@ void Canvas::stroke_start(glm::vec3 point, float pressure, const std::shared_ptr
|
||||
m_tmp[i].bindFramebuffer();
|
||||
m_tmp[i].clear({ 0, 0, 0, 0 });
|
||||
m_tmp[i].unbindFramebuffer();
|
||||
|
||||
if (m_current_stroke->m_brush->m_dual_enabled)
|
||||
{
|
||||
m_tmp_dual[i].bindFramebuffer();
|
||||
m_tmp_dual[i].clear({ 0, 0, 0, 0 });
|
||||
m_tmp_dual[i].unbindFramebuffer();
|
||||
}
|
||||
}
|
||||
m_show_tmp = true;
|
||||
}
|
||||
@@ -934,6 +977,7 @@ void Canvas::layer_merge(int source_idx, int dest_idx) // m_layer index
|
||||
ShaderManager::u_int(kShaderUniform::Lock, false);
|
||||
ShaderManager::u_int(kShaderUniform::BlendMode, m_layers[source_idx].m_blend_mode);
|
||||
ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f));
|
||||
ShaderManager::u_int(kShaderUniform::UseDual, false);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
m_tex2[i].bind();
|
||||
@@ -971,9 +1015,11 @@ void Canvas::resize(int width, int height)
|
||||
{
|
||||
#if defined(__IOS__) || defined(__ANDROID__)
|
||||
m_tmp[i].create(width, height, -1, GL_RGBA8);
|
||||
m_tmp_dual[i].create(width, height, -1, GL_RGBA8);
|
||||
m_tex[i].create(width, height, GL_RGBA8);
|
||||
#else
|
||||
m_tmp[i].create(width, height, -1, GL_RGBA32F);
|
||||
m_tmp_dual[i].create(width, height, -1, GL_RGBA32F);
|
||||
m_tex[i].create(width, height, GL_RGBA32F);
|
||||
#endif
|
||||
m_tex2[i].create(width, height, GL_RGBA8);
|
||||
@@ -992,10 +1038,12 @@ bool Canvas::create(int width, int height)
|
||||
{
|
||||
#if defined(__IOS__) || defined(__ANDROID__)
|
||||
m_tmp[i].create(width, height, -1, GL_RGBA8);
|
||||
m_tmp_dual[i].create(width, height, -1, GL_RGBA8);
|
||||
m_tex[i].create(width, height, GL_RGBA8);
|
||||
m_sampler_brush.create();
|
||||
#else
|
||||
m_tmp[i].create(width, height, -1, GL_RGBA32F);
|
||||
m_tmp_dual[i].create(width, height, -1, GL_RGBA32F);
|
||||
m_tex[i].create(width, height, GL_RGBA32F);
|
||||
m_sampler_brush.create(GL_LINEAR, GL_CLAMP_TO_BORDER);
|
||||
#endif
|
||||
|
||||
14
src/canvas.h
14
src/canvas.h
@@ -161,6 +161,7 @@ public:
|
||||
bool m_use_instanced = false;
|
||||
int m_current_layer_idx = 0;
|
||||
std::unique_ptr<Stroke> m_current_stroke;
|
||||
std::unique_ptr<Stroke> m_dual_stroke;
|
||||
bool m_show_tmp = false;
|
||||
std::vector<Layer> m_layers;
|
||||
std::vector<int> m_order;
|
||||
@@ -172,10 +173,9 @@ public:
|
||||
Layer m_smask; // selection mask
|
||||
bool m_smask_active = false;
|
||||
RTT m_tmp[6];
|
||||
RTT m_tmp_dual[6];
|
||||
RTT m_mixer;
|
||||
float m_mixer_scale = 1;
|
||||
StrokeSample m_mixer_sample;
|
||||
bool m_mixer_idle = true;
|
||||
Texture2D m_brush_mix;
|
||||
Texture2D m_tex[6];
|
||||
Texture2D m_tex2[6];
|
||||
@@ -200,6 +200,7 @@ public:
|
||||
glm::vec2 m_cur_pos;
|
||||
|
||||
std::shared_ptr<Brush> m_current_brush;
|
||||
std::shared_ptr<Brush> m_dual_brush;
|
||||
|
||||
static std::vector<CanvasMode*> modes[];
|
||||
std::vector<CanvasMode*>* m_mode = nullptr;
|
||||
@@ -229,12 +230,13 @@ public:
|
||||
void layer_add(std::string name);
|
||||
void layer_order(int idx, int pos);
|
||||
void layer_merge(int source_idx, int dest_idx);
|
||||
void stroke_start(glm::vec3 point, float pressure, const std::shared_ptr<Brush>& brush);
|
||||
void stroke_start(glm::vec3 point, float pressure);
|
||||
void stroke_update(glm::vec3 point, float pressure);
|
||||
void stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz);
|
||||
std::array<std::vector<vertex_t>, 6> stroke_draw_project(std::array<vertex_t, 4>& B);
|
||||
void stroke_draw_samples(int i, std::vector<vertex_t>& P);
|
||||
std::vector<StrokeFrame> stroke_draw_compute();
|
||||
std::array<std::vector<vertex_t>, 6> stroke_draw_project(std::array<vertex_t, 4>& B) const;
|
||||
// return rect {origin, size}
|
||||
glm::vec4 stroke_draw_samples(int i, std::vector<vertex_t>& P);
|
||||
std::vector<StrokeFrame> stroke_draw_compute(Stroke& stroke) const;
|
||||
void stroke_draw();
|
||||
void stroke_end();
|
||||
void stroke_cancel();
|
||||
|
||||
@@ -124,7 +124,7 @@ void CanvasModePen::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
||||
}
|
||||
else
|
||||
{
|
||||
Canvas::I->stroke_start({ loc, 0 }, me->m_pressure, Canvas::I->m_current_brush);
|
||||
Canvas::I->stroke_start({ loc, 0 }, me->m_pressure);
|
||||
}
|
||||
m_dragging = true;
|
||||
node->mouse_capture();
|
||||
@@ -203,22 +203,26 @@ void CanvasModePen::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const
|
||||
{
|
||||
if (m_draw_tip)
|
||||
{
|
||||
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 - Canvas::I->m_current_brush->m_tip_size * 500.f;
|
||||
pos.x = pos.x - brush->m_tip_size * 500.f;
|
||||
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_scale = Canvas::I->m_current_brush->m_tip_size * 800.f * tip_scale_fix;
|
||||
float tip_angle = Canvas::I->m_current_brush->m_tip_angle * (float)(M_PI * 2.0);
|
||||
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(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));
|
||||
glm::vec2 tip_offset = glm::vec2(0);
|
||||
auto tip_color = glm::vec4(glm::vec3(Canvas::I->m_current_brush->m_tip_color), 1);
|
||||
auto tip_color = glm::vec4(glm::vec3(brush->m_tip_color), 1.f);
|
||||
if (Canvas::I->m_current_stroke)
|
||||
{
|
||||
const auto& s = Canvas::I->m_current_stroke->m_prev_sample;
|
||||
if (s.size > 0.f)
|
||||
{
|
||||
tip_scale = s.size;
|
||||
tip_scale = (brush->m_tip_size * 800.f * tip_scale_fix) * s.scale;
|
||||
tip_angle = s.angle;
|
||||
tip_offset = s.pos - s.origin;
|
||||
tip_color = glm::vec4(s.col, s.flow);
|
||||
@@ -229,13 +233,13 @@ void CanvasModePen::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const
|
||||
glm::scale(glm::vec3(1, -1, 1)) *
|
||||
ortho *
|
||||
glm::translate(glm::vec3(pos + tip_offset, 0)) *
|
||||
glm::scale(glm::vec3(tip_scale)) *
|
||||
glm::eulerAngleZ(tip_angle)
|
||||
glm::eulerAngleZ(tip_angle) *
|
||||
glm::scale(glm::vec3(tip_scale, 1))
|
||||
);
|
||||
bool blend = glIsEnabled(GL_BLEND);
|
||||
glEnable(GL_BLEND);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
auto& tex = *Canvas::I->m_current_brush->m_tip_texture;
|
||||
auto& tex = *brush->m_tip_texture;
|
||||
tex.bind();
|
||||
Canvas::I->m_sampler_brush.bind(0);
|
||||
Canvas::I->m_plane.draw_fill();
|
||||
@@ -281,7 +285,7 @@ void CanvasModeLine::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
||||
node->mouse_release();
|
||||
if (m_dragging)
|
||||
{
|
||||
Canvas::I->stroke_start({ m_drag_start, 0 }, 1.f, Canvas::I->m_current_brush);
|
||||
Canvas::I->stroke_start({ m_drag_start, 0 }, 1.f);
|
||||
Canvas::I->stroke_update({ m_drag_pos, 0 }, 1.f);
|
||||
Canvas::I->stroke_end();
|
||||
}
|
||||
@@ -1156,6 +1160,7 @@ void CanvasModeTransform::leave()
|
||||
ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, true);
|
||||
ShaderManager::u_vec2(kShaderUniform::Resolution, Canvas::I->m_size);
|
||||
ShaderManager::u_int(kShaderUniform::BlendMode, 0);
|
||||
ShaderManager::u_int(kShaderUniform::UseDual, false);
|
||||
|
||||
Canvas::I->m_sampler_bg.bind(1);
|
||||
Canvas::I->m_sampler_bg.bind(0);
|
||||
|
||||
@@ -94,6 +94,7 @@ bool LayoutManager::load(const char* path)
|
||||
}
|
||||
current = current->NextSiblingElement("layout");
|
||||
}
|
||||
|
||||
if (on_loaded)
|
||||
on_loaded();
|
||||
m_loaded = true;
|
||||
|
||||
@@ -31,6 +31,7 @@ void NodeButton::clone_copy(Node* dest) const
|
||||
|
||||
void NodeButton::init()
|
||||
{
|
||||
Node::init();
|
||||
m_border = new NodeBorder();
|
||||
m_text = new NodeText();
|
||||
add_child(m_border);
|
||||
@@ -48,6 +49,7 @@ void NodeButton::init()
|
||||
|
||||
void NodeButton::create()
|
||||
{
|
||||
Node::create();
|
||||
m_border->create();
|
||||
m_text->create();
|
||||
m_border->m_mouse_ignore = false;
|
||||
@@ -56,6 +58,7 @@ void NodeButton::create()
|
||||
|
||||
void NodeButton::loaded()
|
||||
{
|
||||
Node::loaded();
|
||||
m_border->m_thinkness = 1;
|
||||
m_border->m_border_color = glm::vec4(0, 0, 0, 1);
|
||||
m_border->m_color = color_normal;
|
||||
|
||||
@@ -213,13 +213,24 @@ void NodeCanvas::draw()
|
||||
ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false);
|
||||
ShaderManager::u_int(kShaderUniform::BlendMode, m_canvas->m_current_stroke->m_brush->m_blend_mode);
|
||||
ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
|
||||
ShaderManager::u_int(kShaderUniform::TexDual, 3);
|
||||
ShaderManager::u_int(kShaderUniform::UseDual, true);
|
||||
ShaderManager::u_int(kShaderUniform::DualBlendMode, 1);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
m_canvas->m_layers[layer_index].m_rtt[plane_index].bindTexture();
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
m_canvas->m_tmp[plane_index].bindTexture();
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
m_canvas->m_smask.m_rtt[plane_index].bindTexture();
|
||||
glActiveTexture(GL_TEXTURE3);
|
||||
m_canvas->m_current_stroke->m_brush->m_dual_enabled ?
|
||||
m_canvas->m_tmp_dual[plane_index].bindTexture() :
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
m_face_plane.draw_fill();
|
||||
if (m_canvas->m_current_stroke->m_brush->m_dual_enabled)
|
||||
m_canvas->m_tmp_dual[plane_index].unbindTexture();
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
m_canvas->m_smask.m_rtt[plane_index].unbindTexture();
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
m_canvas->m_tmp[plane_index].unbindTexture();
|
||||
@@ -329,9 +340,9 @@ void NodeCanvas::draw()
|
||||
for (int plane_index = 0; plane_index < 6; plane_index++)
|
||||
{
|
||||
auto plane_mvp = proj * camera *
|
||||
glm::scale(glm::vec3(m_canvas->m_order.size() + 500)) *
|
||||
glm::scale(glm::vec3(m_canvas->m_order.size() + 500.f)) *
|
||||
m_canvas->m_plane_transform[plane_index] *
|
||||
glm::translate(glm::vec3(0, 0, -1));
|
||||
glm::translate(glm::vec3(0, 0, -1.f));
|
||||
|
||||
ShaderManager::use(kShader::Checkerboard);
|
||||
ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp);
|
||||
@@ -344,7 +355,7 @@ void NodeCanvas::draw()
|
||||
m_cache_rtt.bindTexture();
|
||||
ShaderManager::use(kShader::Texture);
|
||||
ShaderManager::u_int(kShaderUniform::Tex, 0);
|
||||
ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-1, 1, -1, 1));
|
||||
ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho<float>(-1, 1, -1, 1));
|
||||
m_face_plane.draw_fill();
|
||||
m_cache_rtt.unbindTexture();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ void NodeCheckBox::clone_children(Node* dest) const
|
||||
|
||||
void NodeCheckBox::init()
|
||||
{
|
||||
Node::init();
|
||||
m_outer = new NodeBorder();
|
||||
m_inner = new NodeBorder();
|
||||
add_child(m_outer);
|
||||
@@ -44,6 +45,7 @@ void NodeCheckBox::init()
|
||||
|
||||
void NodeCheckBox::create()
|
||||
{
|
||||
Node::create();
|
||||
m_outer->create();
|
||||
m_inner->create();
|
||||
if (!m_icon_path.empty())
|
||||
|
||||
@@ -34,6 +34,7 @@ void NodeImage::clone_copy(Node* dest) const
|
||||
|
||||
void NodeImage::create()
|
||||
{
|
||||
Node::create();
|
||||
if (!m_path.empty() && TextureManager::load(m_path.c_str(), m_use_mipmaps))
|
||||
{
|
||||
//LOG("load image node %s", m_path.c_str());
|
||||
|
||||
@@ -126,7 +126,7 @@ void NodePanelBrush::init()
|
||||
std::string path_thumb = App::I.data_path + "/brushes/thumbs/" + name + ".png";
|
||||
|
||||
img = img.resize_squared(glm::u8vec4(255));
|
||||
img.gayscale_alpha();
|
||||
//img.gayscale_alpha();
|
||||
|
||||
auto thumb = img.resize(64, 64);
|
||||
thumb.save(path_thumb);
|
||||
@@ -533,13 +533,17 @@ bool NodePanelBrushPreset::save()
|
||||
i.m_name_len = b->m_brush->m_name.size();
|
||||
i.m_brush_path_len = b->m_brush->m_brush_path.size();
|
||||
i.m_brush_thumb_path_len = b->m_brush->m_brush_thumb_path.size();
|
||||
i.m_dual_path_len = b->m_brush->m_brush_path.size();
|
||||
i.m_dual_thumb_path_len = b->m_brush->m_brush_thumb_path.size();
|
||||
i.m_stencil_path_len = b->m_brush->m_stencil_path.size();
|
||||
i.m_stencil_thumb_path_len = b->m_brush->m_stencil_thumb_path.size();
|
||||
i.m_tip_color = b->m_brush->m_tip_color;
|
||||
i.m_tip_size = b->m_brush->m_tip_size;
|
||||
i.m_tip_spacing = b->m_brush->m_tip_spacing;
|
||||
i.m_tip_flow = b->m_brush->m_tip_flow;
|
||||
i.m_tip_opacity = b->m_brush->m_tip_opacity;
|
||||
i.m_tip_angle = b->m_brush->m_tip_angle;
|
||||
i.m_tip_angle_delay = b->m_brush->m_tip_angle_delay;
|
||||
i.m_tip_mix = b->m_brush->m_tip_mix;
|
||||
i.m_tip_stencil = b->m_brush->m_tip_stencil;
|
||||
i.m_tip_wet = b->m_brush->m_tip_wet;
|
||||
@@ -550,9 +554,6 @@ bool NodePanelBrushPreset::save()
|
||||
i.m_tip_angle_follow = b->m_brush->m_tip_angle_follow;
|
||||
i.m_tip_flow_pressure = b->m_brush->m_tip_flow_pressure;
|
||||
i.m_tip_size_pressure = b->m_brush->m_tip_size_pressure;
|
||||
i.m_tip_hue_pressure = b->m_brush->m_tip_hue_pressure;
|
||||
i.m_tip_sat_pressure = b->m_brush->m_tip_sat_pressure;
|
||||
i.m_tip_val_pressure = b->m_brush->m_tip_val_pressure;
|
||||
i.m_jitter_scale = b->m_brush->m_jitter_scale;
|
||||
i.m_jitter_angle = b->m_brush->m_jitter_angle;
|
||||
i.m_jitter_spread = b->m_brush->m_jitter_spread;
|
||||
@@ -561,11 +562,33 @@ bool NodePanelBrushPreset::save()
|
||||
i.m_jitter_sat = b->m_brush->m_jitter_sat;
|
||||
i.m_jitter_val = b->m_brush->m_jitter_val;
|
||||
i.m_blend_mode = b->m_brush->m_blend_mode;
|
||||
|
||||
i.m_tip_invert = b->m_brush->m_tip_invert;
|
||||
i.m_tip_flipx = b->m_brush->m_tip_flipx;
|
||||
i.m_tip_flipy = b->m_brush->m_tip_flipy;
|
||||
i.m_tex_enabled = b->m_brush->m_tex_enabled;
|
||||
i.m_dual_enabled = b->m_brush->m_dual_enabled;
|
||||
i.m_dual_blend_mode = b->m_brush->m_dual_blend_mode;
|
||||
i.m_dual_randflip = b->m_brush->m_dual_randflip;
|
||||
i.m_dual_size = b->m_brush->m_dual_size;
|
||||
i.m_dual_spacing = b->m_brush->m_dual_spacing;
|
||||
i.m_dual_scatter = b->m_brush->m_dual_scatter;
|
||||
i.m_dual_scatter_axis = b->m_brush->m_dual_scatter_axis;
|
||||
i.m_dual_invert = b->m_brush->m_dual_invert;
|
||||
i.m_dual_flipx = b->m_brush->m_dual_flipx;
|
||||
i.m_dual_flipy = b->m_brush->m_dual_flipy;
|
||||
i.m_tip_randflipx = b->m_brush->m_tip_randflipx;
|
||||
i.m_tip_randflipy = b->m_brush->m_tip_randflipy;
|
||||
i.m_tip_aspect = b->m_brush->m_tip_aspect;
|
||||
|
||||
fwrite(&i, sizeof(i), 1, fp);
|
||||
fwrite(b->m_brush->m_name.c_str(), 1, b->m_brush->m_name.size(), fp);
|
||||
fwrite(b->m_brush->m_brush_path.c_str(), 1, b->m_brush->m_brush_path.size(), fp);
|
||||
fwrite(b->m_brush->m_brush_thumb_path.c_str(), 1, b->m_brush->m_brush_thumb_path.size(), fp);
|
||||
fwrite(b->m_brush->m_dual_path.c_str(), 1, b->m_brush->m_brush_path.size(), fp);
|
||||
fwrite(b->m_brush->m_dual_thumb_path.c_str(), 1, b->m_brush->m_brush_thumb_path.size(), fp);
|
||||
fwrite(b->m_brush->m_stencil_path.c_str(), 1, b->m_brush->m_stencil_path.size(), fp);
|
||||
fwrite(b->m_brush->m_stencil_thumb_path.c_str(), 1, b->m_brush->m_stencil_thumb_path.size(), fp);
|
||||
}
|
||||
fclose(fp);
|
||||
return true;
|
||||
@@ -604,6 +627,7 @@ bool NodePanelBrushPreset::restore()
|
||||
b->m_tip_flow = i.m_tip_flow;
|
||||
b->m_tip_opacity = i.m_tip_opacity;
|
||||
b->m_tip_angle = i.m_tip_angle;
|
||||
b->m_tip_angle_delay = i.m_tip_angle_delay;
|
||||
b->m_tip_mix = i.m_tip_mix;
|
||||
b->m_tip_stencil = i.m_tip_stencil;
|
||||
b->m_tip_wet = i.m_tip_wet;
|
||||
@@ -614,9 +638,6 @@ bool NodePanelBrushPreset::restore()
|
||||
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;
|
||||
@@ -625,14 +646,37 @@ bool NodePanelBrushPreset::restore()
|
||||
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_tip_invert = i.m_tip_invert;
|
||||
b->m_tip_flipx = i.m_tip_flipx;
|
||||
b->m_tip_flipy = i.m_tip_flipy;
|
||||
b->m_tex_enabled = i.m_tex_enabled;
|
||||
b->m_dual_enabled = i.m_dual_enabled;
|
||||
b->m_dual_blend_mode = i.m_dual_blend_mode;
|
||||
b->m_dual_randflip = i.m_dual_randflip;
|
||||
b->m_dual_size = i.m_dual_size;
|
||||
b->m_dual_spacing = i.m_dual_spacing;
|
||||
b->m_dual_scatter = i.m_dual_scatter;
|
||||
b->m_dual_scatter_axis = i.m_dual_scatter_axis;
|
||||
b->m_dual_invert = i.m_dual_invert;
|
||||
b->m_dual_flipx = i.m_dual_flipx;
|
||||
b->m_dual_flipy = i.m_dual_flipy;
|
||||
b->m_tip_aspect = i.m_tip_aspect;
|
||||
|
||||
b->m_name.resize(i.m_name_len);
|
||||
b->m_brush_path.resize(i.m_brush_path_len);
|
||||
b->m_brush_thumb_path.resize(i.m_brush_thumb_path_len);
|
||||
b->m_dual_path.resize(i.m_brush_path_len);
|
||||
b->m_dual_thumb_path.resize(i.m_brush_thumb_path_len);
|
||||
b->m_stencil_path.resize(i.m_stencil_path_len);
|
||||
b->m_stencil_thumb_path.resize(i.m_stencil_thumb_path_len);
|
||||
fread((char*)b->m_name.c_str(), 1, b->m_name.size(), fp);
|
||||
fread((char*)b->m_brush_path.c_str(), 1, b->m_brush_path.size(), fp);
|
||||
fread((char*)b->m_brush_thumb_path.c_str(), 1, b->m_brush_thumb_path.size(), fp);
|
||||
fread((char*)b->m_dual_path.c_str(), 1, b->m_brush_path.size(), fp);
|
||||
fread((char*)b->m_dual_thumb_path.c_str(), 1, b->m_brush_thumb_path.size(), fp);
|
||||
fread((char*)b->m_stencil_path.c_str(), 1, b->m_stencil_path.size(), fp);
|
||||
fread((char*)b->m_stencil_thumb_path.c_str(), 1, b->m_stencil_thumb_path.size(), fp);
|
||||
|
||||
if (b->load_texture(b->m_brush_path, b->m_brush_thumb_path))
|
||||
{
|
||||
|
||||
@@ -92,15 +92,23 @@ class NodePanelBrushPreset : public Node
|
||||
};
|
||||
struct item_t {
|
||||
int m_name_len = 0;
|
||||
|
||||
int m_brush_path_len = 0;
|
||||
int m_brush_thumb_path_len = 0;
|
||||
|
||||
int m_dual_path_len = 0;
|
||||
int m_dual_thumb_path_len = 0;
|
||||
|
||||
int m_stencil_path_len = 0;
|
||||
int m_stencil_thumb_path_len = 0;
|
||||
|
||||
glm::vec4 m_tip_color{ 0, 0, 0, 1 };
|
||||
float m_tip_size = 0;
|
||||
float m_tip_spacing = 0;
|
||||
float m_tip_flow = 0;
|
||||
float m_tip_opacity = 0;
|
||||
float m_tip_angle = 0;
|
||||
float m_tip_angle_delay = 0;
|
||||
float m_tip_mix = 0;
|
||||
float m_tip_stencil = 0;
|
||||
float m_tip_wet = 0;
|
||||
@@ -111,9 +119,6 @@ class NodePanelBrushPreset : public Node
|
||||
bool m_tip_angle_follow = false;
|
||||
bool m_tip_flow_pressure = false;
|
||||
bool m_tip_size_pressure = false;
|
||||
bool m_tip_hue_pressure = false;
|
||||
bool m_tip_sat_pressure = false;
|
||||
bool m_tip_val_pressure = false;
|
||||
float m_jitter_scale = 0;
|
||||
float m_jitter_angle = 0;
|
||||
float m_jitter_spread = 0;
|
||||
@@ -122,6 +127,24 @@ class NodePanelBrushPreset : public Node
|
||||
float m_jitter_sat = 0;
|
||||
float m_jitter_val = 0;
|
||||
int m_blend_mode = 0;
|
||||
|
||||
bool m_tip_invert = false;
|
||||
bool m_tip_flipx = false;
|
||||
bool m_tip_flipy = false;
|
||||
bool m_tex_enabled = false;
|
||||
bool m_dual_enabled = false;
|
||||
int m_dual_blend_mode = 0;
|
||||
bool m_dual_randflip = false;
|
||||
float m_dual_size = 0;
|
||||
float m_dual_spacing = 0;
|
||||
float m_dual_scatter = 0;
|
||||
bool m_dual_scatter_axis = false;
|
||||
bool m_dual_invert = false;
|
||||
bool m_dual_flipx = false;
|
||||
bool m_dual_flipy = false;
|
||||
bool m_tip_randflipx = false;
|
||||
bool m_tip_randflipy = false;
|
||||
float m_tip_aspect = 0;
|
||||
};
|
||||
public:
|
||||
std::function<void(Node* target, std::shared_ptr<Brush>& brush)> on_brush_changed;
|
||||
|
||||
@@ -26,10 +26,11 @@ 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) / 4.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_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;
|
||||
m_tip_stencil->m_value.x = b->m_tip_stencil;
|
||||
m_tip_wet->m_value.x = b->m_tip_wet;
|
||||
m_tip_noise->m_value.x = b->m_tip_noise;
|
||||
@@ -43,6 +44,28 @@ void NodePanelStroke::update_controls()
|
||||
m_tip_angle_follow->checked = b->m_tip_angle_follow;
|
||||
m_tip_flow_pressure->checked = b->m_tip_flow_pressure;
|
||||
m_tip_size_pressure->checked = b->m_tip_size_pressure;
|
||||
|
||||
m_tip_invert->checked = b->m_tip_invert;
|
||||
m_tip_flipx->checked = b->m_tip_flipx;
|
||||
m_tip_flipy->checked = b->m_tip_flipy;
|
||||
m_tex_enabled->checked = b->m_tex_enabled;
|
||||
m_dual_enabled->checked = b->m_dual_enabled;
|
||||
m_dual_scatter_axis->checked = b->m_dual_scatter_axis;
|
||||
m_dual_invert->checked = b->m_dual_invert;
|
||||
m_dual_flipx->checked = b->m_dual_flipx;
|
||||
m_dual_flipy->checked = b->m_dual_flipy;
|
||||
m_dual_randflip->checked = b->m_dual_randflip;
|
||||
m_tip_randflipx->checked = b->m_tip_randflipx;
|
||||
m_tip_randflipy->checked = b->m_tip_randflipy;
|
||||
|
||||
m_dual_size->m_value.x = b->m_dual_size;
|
||||
m_dual_spacing->m_value.x = b->m_dual_spacing;
|
||||
m_dual_scatter->m_value.x = b->m_dual_scatter;
|
||||
m_tip_aspect->m_value.x = b->m_tip_aspect;
|
||||
|
||||
m_blend_mode->set_index(b->m_blend_mode);
|
||||
m_dual_blend_mode->set_index(b->m_dual_blend_mode);
|
||||
|
||||
m_preview->m_brush = b;
|
||||
m_preview->draw_stroke();
|
||||
}
|
||||
@@ -71,17 +94,23 @@ void NodePanelStroke::init_controls()
|
||||
m_presets_popup->m_flood_events = true;
|
||||
m_presets_popup->m_capture_children = false;
|
||||
|
||||
int br_idx = std::max(m_brush_popup->find_brush("Round-Hard"), 0);
|
||||
// init main brush
|
||||
auto b = std::make_shared<Brush>();
|
||||
int br_idx = m_brush_popup->find_brush("Round-Hard");
|
||||
if (br_idx == -1)
|
||||
br_idx = 0;
|
||||
b->load_texture(m_brush_popup->get_texture_path(br_idx), m_brush_popup->get_thumb_path(br_idx));
|
||||
//b->load_stencil("data/paper.jpg");
|
||||
b->m_tip_size = .1f;
|
||||
b->m_tip_flow = .5f;
|
||||
b->m_tip_spacing = .1f;
|
||||
b->m_tip_opacity = 1.f;
|
||||
Canvas::I->m_current_brush = b;
|
||||
// init dual brush
|
||||
auto db = std::make_shared<Brush>();
|
||||
db->load_texture(m_brush_popup->get_texture_path(br_idx), m_brush_popup->get_thumb_path(br_idx));
|
||||
db->m_tip_size = .3f;
|
||||
db->m_tip_flow = .5f;
|
||||
db->m_tip_spacing = .1f;
|
||||
db->m_tip_opacity = 1.f;
|
||||
Canvas::I->m_dual_brush = db;
|
||||
|
||||
m_preset_thumb = find<NodeImage>("preset-thumb");
|
||||
m_preset_thumb->m_use_mipmaps = true;
|
||||
@@ -99,8 +128,10 @@ void NodePanelStroke::init_controls()
|
||||
tick->SetPosition(pos.x, pos.y + (m_preset_button->m_size.y - 32) * 0.5f);
|
||||
tick->set_image("data/ui/popup-tick.png");
|
||||
root()->update();
|
||||
if ((pos.y + m_presets_popup->m_size.y) > screen.y) pos.y = screen.y - m_presets_popup->m_size.y;
|
||||
if (pos.y < 0) pos.y = 0;
|
||||
if ((pos.y + m_presets_popup->m_size.y) > screen.y)
|
||||
pos.y = screen.y - m_presets_popup->m_size.y;
|
||||
if (pos.y < 0)
|
||||
pos.y = 0;
|
||||
m_presets_popup->SetPosition(pos.x + 16, pos.y);
|
||||
m_presets_popup->mouse_capture();
|
||||
root()->update();
|
||||
@@ -111,7 +142,7 @@ void NodePanelStroke::init_controls()
|
||||
|
||||
m_presets_popup->on_brush_changed = [this](Node* target, std::shared_ptr<Brush>& b) {
|
||||
// don't change some params
|
||||
//b->m_tip_size = Canvas::I->m_current_brush->m_tip_size;
|
||||
b->m_tip_size = Canvas::I->m_current_brush->m_tip_size;
|
||||
b->m_tip_color = Canvas::I->m_current_brush->m_tip_color;
|
||||
*Canvas::I->m_current_brush = *b;
|
||||
m_preview->draw_stroke();
|
||||
@@ -125,8 +156,54 @@ void NodePanelStroke::init_controls()
|
||||
};
|
||||
};
|
||||
|
||||
m_dual_preset_thumb = find<NodeImage>("dual-preset-thumb");
|
||||
m_dual_preset_thumb->m_use_mipmaps = true;
|
||||
m_dual_preset_preview = find<NodeStrokePreview>("dual-preset-preview");
|
||||
m_dual_preset_preview->m_brush = b;
|
||||
m_dual_preset_preview->draw_stroke();
|
||||
m_dual_preset_button = find<NodeButtonCustom>("dual-preset-button");
|
||||
m_dual_preset_button->on_click = [this](Node*) {
|
||||
auto screen = root()->m_size;
|
||||
glm::vec2 pos = m_dual_preset_button->m_pos + glm::vec2(m_dual_preset_button->m_size.x, 0);
|
||||
root()->add_child(m_presets_popup);
|
||||
auto tick = root()->add_child<NodeImage>();
|
||||
tick->SetPositioning(YGPositionTypeAbsolute);
|
||||
tick->SetSize(16, 32);
|
||||
tick->SetPosition(pos.x, pos.y + (m_dual_preset_button->m_size.y - 32) * 0.5f);
|
||||
tick->set_image("data/ui/popup-tick.png");
|
||||
root()->update();
|
||||
if ((pos.y + m_presets_popup->m_size.y) > screen.y)
|
||||
pos.y = screen.y - m_presets_popup->m_size.y;
|
||||
if (pos.y < 0)
|
||||
pos.y = 0;
|
||||
m_presets_popup->SetPosition(pos.x + 16, pos.y);
|
||||
m_presets_popup->mouse_capture();
|
||||
root()->update();
|
||||
|
||||
m_presets_popup->on_popup_close = [this, tick](Node*) {
|
||||
tick->destroy();
|
||||
};
|
||||
|
||||
m_presets_popup->on_brush_changed = [this](Node* target, std::shared_ptr<Brush>& b) {
|
||||
// don't change some params
|
||||
b->m_tip_size = Canvas::I->m_current_brush->m_tip_size;
|
||||
b->m_tip_color = { 0, 0, 0, 1 };
|
||||
*Canvas::I->m_dual_brush = *b;
|
||||
m_preview->draw_stroke();
|
||||
m_dual_preset_preview->draw_stroke();
|
||||
m_dual_brush_thumb->set_image(b->m_brush_thumb_path);
|
||||
m_dual_preset_thumb->set_image(b->m_brush_thumb_path);
|
||||
update_controls();
|
||||
|
||||
//m_presets_popup->mouse_release();
|
||||
//m_presets_popup->parent->remove_child(m_presets_popup.get());
|
||||
};
|
||||
};
|
||||
|
||||
m_brush_thumb = find<NodeImage>("tip-change-thumb");
|
||||
m_brush_thumb->set_image(m_brush_popup->get_thumb_path(br_idx));
|
||||
m_dual_brush_thumb = find<NodeImage>("dual-change-thumb");
|
||||
m_dual_brush_thumb->set_image(m_brush_popup->get_thumb_path(br_idx));
|
||||
|
||||
m_brush_button = find<NodeButtonCustom>("tip-change");
|
||||
m_brush_button->on_click = [this](Node*) {
|
||||
@@ -139,8 +216,10 @@ void NodePanelStroke::init_controls()
|
||||
tick->SetPosition(pos.x, pos.y + (m_brush_button->m_size.y - 32) * 0.5f);
|
||||
tick->set_image("data/ui/popup-tick.png");
|
||||
root()->update();
|
||||
if ((pos.y + m_brush_popup->m_size.y) > screen.y) pos.y = screen.y - m_brush_popup->m_size.y;
|
||||
if (pos.y < 0) pos.y = 0;
|
||||
if ((pos.y + m_brush_popup->m_size.y) > screen.y)
|
||||
pos.y = screen.y - m_brush_popup->m_size.y;
|
||||
if (pos.y < 0)
|
||||
pos.y = 0;
|
||||
m_brush_popup->SetPosition(pos.x + 16, pos.y);
|
||||
m_brush_popup->mouse_capture();
|
||||
root()->update();
|
||||
@@ -160,8 +239,11 @@ void NodePanelStroke::init_controls()
|
||||
|
||||
m_preview = find<NodeStrokePreview>("canvas");
|
||||
m_blend_mode = find<NodeComboBox>("blend-mode");
|
||||
m_blend_mode->on_select = [](Node*, int index) {
|
||||
m_blend_mode->on_select = [this](Node*, int index) {
|
||||
Canvas::I->m_current_brush->m_blend_mode = index;
|
||||
m_preview->draw_stroke();
|
||||
if (on_stroke_change)
|
||||
on_stroke_change(this);
|
||||
};
|
||||
|
||||
init_slider(m_tip_size, "tip-size", &Brush::m_tip_size);
|
||||
@@ -169,6 +251,7 @@ void NodePanelStroke::init_controls()
|
||||
init_slider(m_tip_flow, "tip-flow", &Brush::m_tip_flow);
|
||||
init_slider(m_tip_opacity, "tip-opacity", &Brush::m_tip_opacity);
|
||||
init_slider(m_tip_angle, "tip-angle", &Brush::m_tip_angle);
|
||||
init_slider(m_tip_angle_delay, "tip-angle-delay", &Brush::m_tip_angle_delay);
|
||||
init_slider(m_tip_mix, "tip-mix", &Brush::m_tip_mix);
|
||||
init_slider(m_tip_stencil, "tip-stencil", &Brush::m_tip_stencil);
|
||||
init_slider(m_tip_wet, "tip-wet", &Brush::m_tip_wet);
|
||||
@@ -184,15 +267,47 @@ void NodePanelStroke::init_controls()
|
||||
init_slider(m_jitter_sat, "jitter-sat", &Brush::m_jitter_sat);
|
||||
init_slider(m_jitter_val, "jitter-val", &Brush::m_jitter_val);
|
||||
m_curves[m_tip_size] = [](float v){ return glm::pow(v, 3.f); };
|
||||
m_curves[m_tip_spacing] = [](float v){ return glm::pow(v * 4.f, 2.f); };
|
||||
m_curves[m_tip_spacing] = [](float v){ return glm::pow(v, 2.f); };
|
||||
m_curves[m_tip_flow] = [](float v){ return glm::pow(v, 2.f); };
|
||||
|
||||
init_checkbox(m_tip_angle_follow, "tip-angle-follow", &Brush::m_tip_angle_follow);
|
||||
init_checkbox(m_tip_flow_pressure, "tip-flow-pressure", &Brush::m_tip_flow_pressure);
|
||||
init_checkbox(m_tip_size_pressure, "tip-size-pressure", &Brush::m_tip_size_pressure);
|
||||
init_checkbox(m_tip_hue_pressure, "tip-hue-pressure", &Brush::m_tip_hue_pressure);
|
||||
init_checkbox(m_tip_sat_pressure, "tip-sat-pressure", &Brush::m_tip_sat_pressure);
|
||||
init_checkbox(m_tip_val_pressure, "tip-val-pressure", &Brush::m_tip_val_pressure);
|
||||
|
||||
init_checkbox(m_tip_invert, "tip-invert", &Brush::m_tip_invert);
|
||||
init_checkbox(m_tip_flipx, "tip-flipx", &Brush::m_tip_flipx);
|
||||
init_checkbox(m_tip_flipy, "tip-flipy", &Brush::m_tip_flipy);
|
||||
init_checkbox(m_tex_enabled, "tex-enabled", &Brush::m_tex_enabled);
|
||||
init_checkbox(m_dual_enabled, "dual-enabled", &Brush::m_dual_enabled);
|
||||
init_checkbox(m_dual_scatter_axis, "dual-scatter-axis", &Brush::m_dual_scatter_axis);
|
||||
init_checkbox(m_dual_invert, "dual-invert", &Brush::m_dual_invert);
|
||||
init_checkbox(m_dual_flipx, "dual-flipx", &Brush::m_dual_flipx);
|
||||
init_checkbox(m_dual_flipy, "dual-flipy", &Brush::m_dual_flipy);
|
||||
init_checkbox(m_dual_randflip, "dual-randflip", &Brush::m_dual_randflip);
|
||||
init_checkbox(m_tip_randflipx, "tip-randflipx", &Brush::m_tip_randflipx);
|
||||
init_checkbox(m_tip_randflipy, "tip-randflipy", &Brush::m_tip_randflipy);
|
||||
|
||||
init_slider(m_dual_size, "dual-size", &Brush::m_dual_size);
|
||||
init_slider(m_dual_spacing, "dual-spacing", &Brush::m_dual_spacing);
|
||||
init_slider(m_dual_scatter, "dual-scatter", &Brush::m_dual_scatter);
|
||||
init_slider(m_tip_aspect, "tip-aspect", &Brush::m_tip_aspect);
|
||||
|
||||
m_tip_aspect_reset = find<NodeButtonCustom>("tip-aspect-reset");
|
||||
m_tip_aspect_reset->on_click = [this](Node*) {
|
||||
m_tip_aspect->set_value(0.5);
|
||||
Canvas::I->m_current_brush->m_tip_aspect = 0.5f;
|
||||
m_preview->draw_stroke();
|
||||
if (on_stroke_change)
|
||||
on_stroke_change(this);
|
||||
};
|
||||
|
||||
m_dual_blend_mode = find<NodeComboBox>("blend-mode");
|
||||
m_dual_blend_mode->on_select = [this](Node*, int index) {
|
||||
Canvas::I->m_current_brush->m_dual_blend_mode = index;
|
||||
m_preview->draw_stroke();
|
||||
if (on_stroke_change)
|
||||
on_stroke_change(this);
|
||||
};
|
||||
|
||||
m_preview->m_brush = Canvas::I->m_current_brush;
|
||||
m_preview->draw_stroke();
|
||||
@@ -226,7 +341,6 @@ void NodePanelStroke::handle_slide(float Brush::* prop, Node* target, float valu
|
||||
{
|
||||
auto curve = m_curves.find((NodeSliderH*)target);
|
||||
Canvas::I->m_current_brush.get()->*prop = curve != m_curves.end() ? curve->second(value) : value;
|
||||
m_preview->m_brush = Canvas::I->m_current_brush;
|
||||
m_preview->draw_stroke();
|
||||
if (on_stroke_change)
|
||||
on_stroke_change(this);
|
||||
@@ -243,7 +357,6 @@ void NodePanelStroke::init_checkbox(NodeCheckBox*& target, const char* id, bool
|
||||
void NodePanelStroke::handle_checkbox(bool Brush::* prop, Node *target, bool value)
|
||||
{
|
||||
Canvas::I->m_current_brush.get()->*prop = value;
|
||||
m_preview->m_brush = Canvas::I->m_current_brush;
|
||||
m_preview->draw_stroke();
|
||||
if (on_stroke_change)
|
||||
on_stroke_change(this);
|
||||
|
||||
@@ -19,6 +19,7 @@ public:
|
||||
NodeSliderH* m_tip_flow;
|
||||
NodeSliderH* m_tip_opacity;
|
||||
NodeSliderH* m_tip_angle;
|
||||
NodeSliderH* m_tip_angle_delay;
|
||||
NodeSliderH* m_tip_mix;
|
||||
NodeSliderH* m_tip_stencil;
|
||||
NodeSliderH* m_tip_wet;
|
||||
@@ -36,14 +37,35 @@ public:
|
||||
NodeCheckBox* m_tip_angle_follow;
|
||||
NodeCheckBox* m_tip_flow_pressure;
|
||||
NodeCheckBox* m_tip_size_pressure;
|
||||
NodeCheckBox* m_tip_hue_pressure;
|
||||
NodeCheckBox* m_tip_sat_pressure;
|
||||
NodeCheckBox* m_tip_val_pressure;
|
||||
NodeButtonCustom* m_brush_button;
|
||||
NodeImage* m_brush_thumb;
|
||||
NodeImage* m_dual_brush_thumb;
|
||||
NodeImage* m_preset_thumb;
|
||||
NodeImage* m_dual_preset_thumb;
|
||||
NodeButtonCustom* m_preset_button;
|
||||
NodeButtonCustom* m_dual_preset_button;
|
||||
NodeStrokePreview* m_preset_preview;
|
||||
NodeStrokePreview* m_dual_preset_preview;
|
||||
|
||||
NodeCheckBox* m_tip_invert;
|
||||
NodeCheckBox* m_tip_flipx;
|
||||
NodeCheckBox* m_tip_flipy;
|
||||
NodeCheckBox* m_tex_enabled;
|
||||
NodeCheckBox* m_dual_enabled;
|
||||
NodeCheckBox* m_dual_scatter_axis;
|
||||
NodeCheckBox* m_dual_invert;
|
||||
NodeCheckBox* m_dual_flipx;
|
||||
NodeCheckBox* m_dual_flipy;
|
||||
NodeCheckBox* m_dual_randflip;
|
||||
NodeCheckBox* m_tip_randflipx;
|
||||
NodeCheckBox* m_tip_randflipy;
|
||||
NodeSliderH* m_dual_size;
|
||||
NodeSliderH* m_dual_spacing;
|
||||
NodeSliderH* m_dual_scatter;
|
||||
NodeSliderH* m_tip_aspect;
|
||||
NodeComboBox* m_dual_blend_mode;
|
||||
NodeButtonCustom* m_tip_aspect_reset;
|
||||
|
||||
std::shared_ptr<NodePanelBrush> m_brush_popup;
|
||||
std::shared_ptr<NodePanelBrushPreset> m_presets_popup;
|
||||
std::function<void(Node* target)> on_stroke_change;
|
||||
|
||||
@@ -24,6 +24,7 @@ void NodeText::clone_copy(Node* dest) const
|
||||
|
||||
void NodeText::create()
|
||||
{
|
||||
Node::create();
|
||||
if (!m_font.empty())
|
||||
{
|
||||
char font[64];
|
||||
|
||||
@@ -7,9 +7,9 @@ class NodeText : public Node
|
||||
public:
|
||||
TextMesh m_text_mesh;
|
||||
std::string m_text;
|
||||
std::string m_font;
|
||||
std::string m_font = "arial";
|
||||
glm::vec4 m_color{ 1, 1, 1, 1 };
|
||||
int m_font_size;
|
||||
int m_font_size = 11;
|
||||
kFont font_id;
|
||||
virtual Node* clone_instantiate() const override;
|
||||
virtual void clone_copy(Node* dest) const override;
|
||||
|
||||
@@ -39,6 +39,7 @@ Node* NodeViewport::clone_instantiate() const
|
||||
}
|
||||
void NodeViewport::create()
|
||||
{
|
||||
Node::create();
|
||||
m_faces = std::make_unique<Plane>();
|
||||
m_faces->create<1>(10, 10);
|
||||
m_sampler = std::make_unique<Sampler>();
|
||||
|
||||
@@ -113,6 +113,7 @@
|
||||
#include <glm/gtx/intersect.hpp>
|
||||
#include <glm/gtx/component_wise.hpp>
|
||||
#include <glm/gtx/normal.hpp>
|
||||
#include <glm/gtx/matrix_transform_2d.hpp>
|
||||
|
||||
#include <tinyxml2.h>
|
||||
#include <jpge.h>
|
||||
|
||||
@@ -14,7 +14,7 @@ RTT::RTT()
|
||||
|
||||
RTT::~RTT()
|
||||
{
|
||||
//destroy();
|
||||
destroy();
|
||||
}
|
||||
|
||||
void RTT::resize(int width, int height)
|
||||
|
||||
@@ -11,6 +11,7 @@ enum class kShaderUniform : uint16_t
|
||||
TexMix = const_hash("tex_mix"),
|
||||
TexMixA = const_hash("tex_mix_alpha"),
|
||||
TexMask = const_hash("tex_mask"),
|
||||
TexDual = const_hash("tex_dual"),
|
||||
TexStroke = const_hash("tex_stroke"),
|
||||
TexStencil = const_hash("tex_stencil"),
|
||||
StencilOffset = const_hash("stencil_offset"),
|
||||
@@ -27,9 +28,11 @@ enum class kShaderUniform : uint16_t
|
||||
Resolution = const_hash("resolution"),
|
||||
Highlight = const_hash("highlight"),
|
||||
BlendMode = const_hash("blend_mode"),
|
||||
DualBlendMode = const_hash("blend_mode"),
|
||||
Noise = const_hash("noise"),
|
||||
Direction = const_hash("dir"),
|
||||
UseFragCoordUV2 = const_hash("fragUV2"),
|
||||
UseDual = const_hash("use_dual"),
|
||||
LightDir = const_hash("light_dir"),
|
||||
Mode = const_hash("mode"),
|
||||
Ambient = const_hash("ambient"),
|
||||
|
||||
13
src/util.cpp
13
src/util.cpp
@@ -14,6 +14,7 @@ std::vector<vertex_t> poly_remove_duplicate<vertex_t>(const std::vector<vertex_t
|
||||
return ret;
|
||||
}
|
||||
|
||||
// params {x, y} and {origin, size} form
|
||||
bool point_in_rect(const glm::vec2& p, const glm::vec4& r)
|
||||
{
|
||||
return p.x > r.x && p.x < r.x+r.z && p.y > r.y && p.y < r.y+r.w;
|
||||
@@ -45,6 +46,18 @@ glm::vec4 rect_union(glm::vec4 a, glm::vec4 b)
|
||||
return o;
|
||||
}
|
||||
|
||||
// params and returns {min, max} form
|
||||
glm::vec4 box_union(glm::vec4 a, glm::vec4 b)
|
||||
{
|
||||
return { glm::min(xy(a), xy(b)), glm::max(zw(a), zw(b)) };
|
||||
}
|
||||
|
||||
// params and returns {min, max} form
|
||||
glm::vec4 box_intersection(glm::vec4 a, glm::vec4 b)
|
||||
{
|
||||
return { glm::max(xy(a), xy(b)), glm::min(zw(a), zw(b)) };
|
||||
}
|
||||
|
||||
bool ray_intersect(glm::vec3 ray_origin, glm::vec3 ray_dir, glm::vec3 plane_origin,
|
||||
glm::vec3 plane_normal, glm::vec3 plane_tangent, glm::vec3& out_hit, float& out_t)
|
||||
{
|
||||
|
||||
23
src/util.h
23
src/util.h
@@ -45,9 +45,16 @@ std::vector<T> poly_remove_duplicate(const std::vector<T>& v, const float toller
|
||||
template<>
|
||||
std::vector<vertex_t> poly_remove_duplicate<vertex_t>(const std::vector<vertex_t>& v, const float tollerance);
|
||||
|
||||
// params {x, y} and {origin, size} form
|
||||
bool point_in_rect(const glm::vec2& point, const glm::vec4& rect);
|
||||
// params and returns {origin, size} form
|
||||
glm::vec4 rect_intersection(glm::vec4 a, glm::vec4 b);
|
||||
// params and returns {origin, size} form
|
||||
glm::vec4 rect_union(glm::vec4 a, glm::vec4 b);
|
||||
// params and returns {min, max} form
|
||||
glm::vec4 box_union(glm::vec4 a, glm::vec4 b);
|
||||
// params and returns {min, max} form
|
||||
glm::vec4 box_intersection(glm::vec4 a, glm::vec4 b);
|
||||
bool ray_intersect(glm::vec3 ray_origin, glm::vec3 ray_dir, glm::vec3 plane_origin,
|
||||
glm::vec3 plane_normal, glm::vec3 plane_tangent, glm::vec3& out_hit, float& out_t);
|
||||
bool segments_intersect(const glm::vec2& p0a, const glm::vec2& p0b,
|
||||
@@ -78,15 +85,23 @@ inline glm::vec2 xy(const glm::vec3& v) { return glm::vec2(v.x, v.y); }
|
||||
|
||||
void parallel_for(unsigned nb_elements, std::function<void(int i)> functor, bool use_threads = true);
|
||||
|
||||
template<typename T, int N> struct cbuffer
|
||||
template<typename T> struct cbuffer
|
||||
{
|
||||
T m_vec[N];
|
||||
std::unique_ptr<T[]> m_vec;
|
||||
int m_capacity = 0;
|
||||
int m_count = 0;
|
||||
int m_index = 0;
|
||||
cbuffer()
|
||||
cbuffer(int initial_capacity)
|
||||
{
|
||||
m_capacity = N;
|
||||
m_capacity = initial_capacity;
|
||||
m_index = 0;
|
||||
m_count = 0;
|
||||
m_vec = std::make_unique<T[]>(m_capacity);
|
||||
}
|
||||
void resize(int new_capacity)
|
||||
{
|
||||
m_capacity = new_capacity;
|
||||
m_vec = std::make_unique<T[]>(m_capacity);
|
||||
m_index = 0;
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user