enable rtt dtor, default values for <text> node, dual-brush wip, more brush options

This commit is contained in:
2019-02-14 02:08:29 +01:00
parent 8ad005de8b
commit 999723dd14
26 changed files with 998 additions and 389 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -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;

View File

@@ -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);

View File

@@ -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"

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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();

View File

@@ -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);

View File

@@ -94,6 +94,7 @@ bool LayoutManager::load(const char* path)
}
current = current->NextSiblingElement("layout");
}
if (on_loaded)
on_loaded();
m_loaded = true;

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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())

View File

@@ -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());

View File

@@ -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))
{

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -24,6 +24,7 @@ void NodeText::clone_copy(Node* dest) const
void NodeText::create()
{
Node::create();
if (!m_font.empty())
{
char font[64];

View File

@@ -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;

View File

@@ -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>();

View File

@@ -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>

View File

@@ -14,7 +14,7 @@ RTT::RTT()
RTT::~RTT()
{
//destroy();
destroy();
}
void RTT::resize(int width, int height)

View File

@@ -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"),

View File

@@ -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)
{

View File

@@ -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;
}