implement basic paint canvas
This commit is contained in:
111
engine/layout.h
111
engine/layout.h
@@ -1664,43 +1664,8 @@ class NodeStrokePreview : public NodeBorder
|
||||
{
|
||||
RTT m_rtt;
|
||||
Sampler m_sampler;
|
||||
static ui::Shader m_shader;
|
||||
public:
|
||||
uint16_t m_tex_id;
|
||||
glm::vec4 m_tip_color;
|
||||
float m_tip_size;
|
||||
float m_tip_spacing;
|
||||
float m_tip_flow;
|
||||
float m_tip_angle;
|
||||
float m_jitter_scale;
|
||||
float m_jitter_angle;
|
||||
float m_jitter_spread;
|
||||
float m_jitter_flow;
|
||||
static void static_init()
|
||||
{
|
||||
static const char* shader_v =
|
||||
SHADER_VERSION
|
||||
"uniform mat4 mvp;"
|
||||
"in vec4 pos;"
|
||||
"in vec2 uvs;"
|
||||
"out vec3 uv;"
|
||||
"void main(){"
|
||||
" uv = vec3(uvs, pos.w);"
|
||||
" gl_Position = mvp * vec4(pos.xyz, 1.0);"
|
||||
"}";
|
||||
static const char* shader_f =
|
||||
SHADER_VERSION
|
||||
"uniform sampler2D tex;"
|
||||
"uniform vec4 col;"
|
||||
"uniform float alpha;"
|
||||
"in vec3 uv;"
|
||||
"out vec4 frag;"
|
||||
"void main(){"
|
||||
" float a = (1.0 - texture(tex, uv.xy).r) * alpha;"
|
||||
" frag = vec4(col.rgb, a);"
|
||||
"}";
|
||||
m_shader.create(shader_v, shader_f);
|
||||
}
|
||||
ui::Brush m_brush;
|
||||
virtual Node* clone_instantiate() const override { return new NodeStrokePreview(); }
|
||||
virtual void clone_copy(Node* dest) const override
|
||||
{
|
||||
@@ -1719,7 +1684,7 @@ public:
|
||||
{
|
||||
m_sampler.create();
|
||||
TextureManager::load("data/Icons/Round-Hard.png");
|
||||
m_tex_id = const_hash("data/Icons/Round-Hard.png");
|
||||
m_brush.m_tex_id = const_hash("data/Icons/Round-Hard.png");
|
||||
}
|
||||
void draw_stroke()
|
||||
{
|
||||
@@ -1740,13 +1705,13 @@ public:
|
||||
glViewport(0, 0, m_rtt.getWidth(), m_rtt.getHeight());
|
||||
glEnable(GL_BLEND);
|
||||
glm::mat4 proj = glm::ortho<float>(0, (float)m_rtt.getWidth(), 0, (float)m_rtt.getHeight(), -1, 1);
|
||||
auto& t = TextureManager::get(m_tex_id);
|
||||
auto& t = TextureManager::get(m_brush.m_tex_id);
|
||||
float alpha = 0;
|
||||
|
||||
std::minstd_rand prng;
|
||||
m_shader.use();
|
||||
m_shader.u_vec4(kShaderUniform::Col, m_tip_color);
|
||||
m_shader.u_int(kShaderUniform::Tex, 0);
|
||||
ShaderManager::use("stroke");
|
||||
ShaderManager::u_vec4(kShaderUniform::Col, m_brush.m_tip_color);
|
||||
ShaderManager::u_int(kShaderUniform::Tex, 0);
|
||||
t.bind();
|
||||
m_sampler.bind(0);
|
||||
while (alpha < 1.f)
|
||||
@@ -1756,19 +1721,19 @@ public:
|
||||
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::vec2(cosf(rad), sinf(rad)); }; // normalized direction vector
|
||||
|
||||
float angle = (m_tip_angle + rnd_nor() * m_jitter_angle) * (float)(M_PI * 2.0);
|
||||
glm::vec2 pos = BezierCurve::Bezier2D(kp, alpha) + (rnd_vec() * m_jitter_spread * 100.f);
|
||||
float size = 100.f * m_tip_size * (1.f - rnd_nor() * m_jitter_scale);
|
||||
float flow = m_tip_flow * (1.f - rnd_nor() * m_jitter_flow);
|
||||
float angle = (m_brush.m_tip_angle + rnd_nor() * m_brush.m_jitter_angle) * (float)(M_PI * 2.0);
|
||||
glm::vec2 pos = BezierCurve::Bezier2D(kp, alpha) + (rnd_vec() * m_brush.m_jitter_spread * 100.f);
|
||||
float size = 100.f * m_brush.m_tip_size * (1.f - rnd_nor() * m_brush.m_jitter_scale);
|
||||
float flow = m_brush.m_tip_flow * (1.f - rnd_nor() * m_brush.m_jitter_flow);
|
||||
|
||||
alpha += glm::max(m_tip_spacing * .2f, .01f);
|
||||
alpha += glm::max(m_brush.m_tip_spacing * .2f, .01f);
|
||||
auto mvp = proj *
|
||||
//glm::translate(glm::vec3(i * 40 * m_tip_spacing, m_rtt.getHeight() / 2, 0)) *
|
||||
glm::translate(glm::vec3(pos, 0)) *
|
||||
glm::scale(glm::vec3(size, size, 1)) *
|
||||
glm::eulerAngleZ(angle);
|
||||
m_shader.u_mat4(kShaderUniform::MVP, mvp);
|
||||
m_shader.u_float(kShaderUniform::Alpha, flow);
|
||||
ShaderManager::u_mat4(kShaderUniform::MVP, mvp);
|
||||
ShaderManager::u_float(kShaderUniform::Alpha, flow);
|
||||
m_plane.draw_fill();
|
||||
}
|
||||
m_sampler.unbind();
|
||||
@@ -1828,26 +1793,26 @@ public:
|
||||
{
|
||||
m_canvas = find<NodeStrokePreview>("canvas");
|
||||
|
||||
init_slider(m_tip_size, "tip-size", &NodeStrokePreview::m_tip_size);
|
||||
init_slider(m_tip_spacing, "tip-spacing", &NodeStrokePreview::m_tip_spacing);
|
||||
init_slider(m_tip_flow, "tip-flow", &NodeStrokePreview::m_tip_flow);
|
||||
init_slider(m_tip_angle, "tip-angle", &NodeStrokePreview::m_tip_angle);
|
||||
init_slider(m_jitter_scale, "jitter-scale", &NodeStrokePreview::m_jitter_scale);
|
||||
init_slider(m_jitter_angle, "jitter-angle", &NodeStrokePreview::m_jitter_angle);
|
||||
init_slider(m_jitter_spread, "jitter-spread", &NodeStrokePreview::m_jitter_spread);
|
||||
init_slider(m_jitter_flow, "jitter-flow", &NodeStrokePreview::m_jitter_flow);
|
||||
init_slider(m_tip_size, "tip-size", &ui::Brush::m_tip_size);
|
||||
init_slider(m_tip_spacing, "tip-spacing", &ui::Brush::m_tip_spacing);
|
||||
init_slider(m_tip_flow, "tip-flow", &ui::Brush::m_tip_flow);
|
||||
init_slider(m_tip_angle, "tip-angle", &ui::Brush::m_tip_angle);
|
||||
init_slider(m_jitter_scale, "jitter-scale", &ui::Brush::m_jitter_scale);
|
||||
init_slider(m_jitter_angle, "jitter-angle", &ui::Brush::m_jitter_angle);
|
||||
init_slider(m_jitter_spread, "jitter-spread", &ui::Brush::m_jitter_spread);
|
||||
init_slider(m_jitter_flow, "jitter-flow", &ui::Brush::m_jitter_flow);
|
||||
//m_canvas->draw_stroke();
|
||||
}
|
||||
void init_slider(NodeSliderH*& slider, const char* id, float NodeStrokePreview::* prop)
|
||||
void init_slider(NodeSliderH*& slider, const char* id, float ui::Brush::* prop)
|
||||
{
|
||||
slider = find<NodeSliderH>(id);
|
||||
slider->on_value_changed = std::bind(&NodePanelStroke::handle_slide,
|
||||
this, prop, std::placeholders::_1, std::placeholders::_2);
|
||||
m_canvas->*prop = slider->m_value.x;
|
||||
m_canvas->m_brush.*prop = slider->m_value.x;
|
||||
}
|
||||
void handle_slide(float NodeStrokePreview::* prop, Node* target, float value)
|
||||
void handle_slide(float ui::Brush::* prop, Node* target, float value)
|
||||
{
|
||||
m_canvas->*prop = value;
|
||||
m_canvas->m_brush.*prop = value;
|
||||
m_canvas->draw_stroke();
|
||||
if (on_stroke_change)
|
||||
on_stroke_change(this);
|
||||
@@ -1859,6 +1824,7 @@ class NodeCanvas : public Node
|
||||
bool m_dragging = false;
|
||||
public:
|
||||
std::unique_ptr<ui::Canvas> m_canvas;
|
||||
ui::Brush m_brush;
|
||||
virtual Node* clone_instantiate() const override { return new NodeCanvas(); }
|
||||
virtual void init() override
|
||||
{
|
||||
@@ -1880,14 +1846,16 @@ public:
|
||||
|
||||
glClearColor(1, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
auto box = m_clip * root()->m_zoom;
|
||||
float zoom = root()->m_zoom;
|
||||
auto box = m_clip * zoom;
|
||||
glm::ivec4 c = (glm::ivec4)glm::vec4(box.x, (int)(vp[3] - box.y - box.w), box.z, box.w);
|
||||
glViewport(c.x, c.y, c.z, c.w);
|
||||
|
||||
glm::vec2 sz = { m_canvas->m_width, m_canvas->m_height };
|
||||
auto mvp = glm::ortho(0.f, box.z, box.w, 0.f, -1.f, 1.f) *
|
||||
glm::translate(glm::vec3((m_size - sz) * 0.5f, 0)) *
|
||||
glm::scale(glm::vec3(sz, 1)) *
|
||||
//glm::translate(glm::vec3((m_size - sz) * 0.5f, 0)) * // center
|
||||
glm::translate(glm::vec3(0)) * // corner
|
||||
glm::scale(glm::vec3(sz * zoom, 1)) *
|
||||
glm::translate(glm::vec3(.5f, .5f, 0.f)); // pivot
|
||||
|
||||
m_canvas->m_fb.bindTexture();
|
||||
@@ -1905,28 +1873,35 @@ public:
|
||||
}
|
||||
virtual void handle_resize(glm::vec2 old_size, glm::vec2 new_size) override
|
||||
{
|
||||
if (new_size.x > m_canvas->m_width)
|
||||
{
|
||||
m_canvas->create(new_size.x, new_size.y);
|
||||
m_canvas->clear();
|
||||
}
|
||||
}
|
||||
virtual kEventResult handle_event(Event* e) override
|
||||
{
|
||||
MouseEvent* me = static_cast<MouseEvent*>(e);
|
||||
Node::handle_event(e);
|
||||
MouseEvent* me = static_cast<MouseEvent*>(e);
|
||||
auto loc = me->m_pos - m_pos;
|
||||
auto cur = glm::vec2(loc.x, m_canvas->m_height - loc.y - 1);
|
||||
switch (e->m_type)
|
||||
{
|
||||
case kEventType::MouseDownL:
|
||||
{
|
||||
auto b = std::make_shared<ui::Brush>();
|
||||
b->m_texture_id = const_hash("data/Icons/Round-Brush.png");
|
||||
m_canvas->stroke_start(me->m_pos, 1.f, b);
|
||||
m_canvas->stroke_start(cur, 1.f, m_brush);
|
||||
m_dragging = true;
|
||||
mouse_capture();
|
||||
break;
|
||||
}
|
||||
case kEventType::MouseUpL:
|
||||
m_canvas->stroke_end();
|
||||
m_dragging = false;
|
||||
mouse_release();
|
||||
break;
|
||||
case kEventType::MouseMove:
|
||||
if (m_dragging)
|
||||
m_canvas->stroke_update(me->m_pos, 1.f);
|
||||
m_canvas->stroke_update(cur, 1.f);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user