implement basic paint canvas
This commit is contained in:
@@ -322,7 +322,7 @@
|
|||||||
</border>
|
</border>
|
||||||
<!-- toolbar -->
|
<!-- toolbar -->
|
||||||
<border id="toolbar" height="50" width="100%" pad="5" dir="row" color=".2">
|
<border id="toolbar" height="50" width="100%" pad="5" dir="row" color=".2">
|
||||||
<button id="btn-close" width="50" height="100%" margin="0 5 0 0" text="Close"/>
|
<button id="btn-close" width="50" height="100%" margin="0 5 0 0" text="Clear"/>
|
||||||
<button id="btn-popup" width="50" height="100%" margin="0 5 0 0" text="Popup"/>
|
<button id="btn-popup" width="50" height="100%" margin="0 5 0 0" text="Popup"/>
|
||||||
<ref id="multi-button"/>
|
<ref id="multi-button"/>
|
||||||
<border width="50" margin="0 5 0 0" color=".1" thickness="1" border-color=".5" justify="center" align="center">
|
<border width="50" margin="0 5 0 0" color=".1" thickness="1" border-color=".5" justify="center" align="center">
|
||||||
@@ -394,7 +394,7 @@
|
|||||||
</node>
|
</node>
|
||||||
<!-- content panel -->
|
<!-- content panel -->
|
||||||
<node grow="1" color=".1" pad="10">
|
<node grow="1" color=".1" pad="10">
|
||||||
<canvas grow="1"/>
|
<canvas id="paint-canvas" grow="1"/>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
<!-- status bar -->
|
<!-- status bar -->
|
||||||
|
|||||||
@@ -153,6 +153,7 @@
|
|||||||
<ClCompile Include="engine\app.cpp" />
|
<ClCompile Include="engine\app.cpp" />
|
||||||
<ClCompile Include="engine\asset.cpp" />
|
<ClCompile Include="engine\asset.cpp" />
|
||||||
<ClCompile Include="engine\bezier.cpp" />
|
<ClCompile Include="engine\bezier.cpp" />
|
||||||
|
<ClCompile Include="engine\brush.cpp" />
|
||||||
<ClCompile Include="engine\canvas.cpp" />
|
<ClCompile Include="engine\canvas.cpp" />
|
||||||
<ClCompile Include="engine\font.cpp" />
|
<ClCompile Include="engine\font.cpp" />
|
||||||
<ClCompile Include="engine\image.cpp" />
|
<ClCompile Include="engine\image.cpp" />
|
||||||
@@ -192,6 +193,7 @@
|
|||||||
<ClInclude Include="engine\app.h" />
|
<ClInclude Include="engine\app.h" />
|
||||||
<ClInclude Include="engine\asset.h" />
|
<ClInclude Include="engine\asset.h" />
|
||||||
<ClInclude Include="engine\bezier.h" />
|
<ClInclude Include="engine\bezier.h" />
|
||||||
|
<ClInclude Include="engine\brush.h" />
|
||||||
<ClInclude Include="engine\canvas.h" />
|
<ClInclude Include="engine\canvas.h" />
|
||||||
<ClInclude Include="engine\font.h" />
|
<ClInclude Include="engine\font.h" />
|
||||||
<ClInclude Include="engine\image.h" />
|
<ClInclude Include="engine\image.h" />
|
||||||
|
|||||||
@@ -66,6 +66,9 @@
|
|||||||
<ClCompile Include="engine\canvas.cpp">
|
<ClCompile Include="engine\canvas.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="engine\brush.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="engine\app.h">
|
<ClInclude Include="engine\app.h">
|
||||||
@@ -107,6 +110,9 @@
|
|||||||
<ClInclude Include="engine\canvas.h">
|
<ClInclude Include="engine\canvas.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="engine\brush.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="engine\bezier" />
|
<None Include="engine\bezier" />
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ void App::initShaders()
|
|||||||
"void main(){"
|
"void main(){"
|
||||||
" frag = vec4(uv.xy, 0.0, 1.0);"
|
" frag = vec4(uv.xy, 0.0, 1.0);"
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
|
// TEXTURE ATLAS
|
||||||
static const char* shader_atlas_v =
|
static const char* shader_atlas_v =
|
||||||
SHADER_VERSION
|
SHADER_VERSION
|
||||||
"uniform mat4 mvp;"
|
"uniform mat4 mvp;"
|
||||||
@@ -67,6 +69,8 @@ void App::initShaders()
|
|||||||
"void main(){"
|
"void main(){"
|
||||||
" frag = texture(tex, uv);"
|
" frag = texture(tex, uv);"
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
|
// SOLID COLOR
|
||||||
static const char* shader_color_v =
|
static const char* shader_color_v =
|
||||||
SHADER_VERSION
|
SHADER_VERSION
|
||||||
"uniform mat4 mvp;"
|
"uniform mat4 mvp;"
|
||||||
@@ -81,6 +85,8 @@ void App::initShaders()
|
|||||||
"void main(){"
|
"void main(){"
|
||||||
" frag = col;"
|
" frag = col;"
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
|
// COLOR QUAD
|
||||||
static const char* shader_color_quad_v =
|
static const char* shader_color_quad_v =
|
||||||
SHADER_VERSION
|
SHADER_VERSION
|
||||||
"uniform mat4 mvp;"
|
"uniform mat4 mvp;"
|
||||||
@@ -100,6 +106,8 @@ void App::initShaders()
|
|||||||
" vec4 gradient_x = mix(col, vec4(1.0, 1.0, 1.0, 1.0), uv.x);"
|
" vec4 gradient_x = mix(col, vec4(1.0, 1.0, 1.0, 1.0), uv.x);"
|
||||||
" frag = mix(gradient_x, vec4(0.0, 0.0, 0.0, 1.0), uv.y);"
|
" frag = mix(gradient_x, vec4(0.0, 0.0, 0.0, 1.0), uv.y);"
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
|
// HUE
|
||||||
static const char* shader_color_hue_v =
|
static const char* shader_color_hue_v =
|
||||||
SHADER_VERSION
|
SHADER_VERSION
|
||||||
"uniform mat4 mvp;"
|
"uniform mat4 mvp;"
|
||||||
@@ -123,6 +131,8 @@ void App::initShaders()
|
|||||||
"void main(){"
|
"void main(){"
|
||||||
" frag = vec4(hsv2rgb(vec3(uv.y, 1.0, 1.0)), 1.0);"
|
" frag = vec4(hsv2rgb(vec3(uv.y, 1.0, 1.0)), 1.0);"
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
|
// FONT
|
||||||
static const char* shader_font_v =
|
static const char* shader_font_v =
|
||||||
SHADER_VERSION
|
SHADER_VERSION
|
||||||
"uniform mat4 mvp;"
|
"uniform mat4 mvp;"
|
||||||
@@ -144,6 +154,29 @@ void App::initShaders()
|
|||||||
" frag = vec4(col.rgb, a);"
|
" frag = vec4(col.rgb, a);"
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
|
// STROKE
|
||||||
|
static const char* shader_stroke_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_stroke_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);"
|
||||||
|
"}";
|
||||||
|
|
||||||
LOG("initializing shaders");
|
LOG("initializing shaders");
|
||||||
if (!ShaderManager::create(kShader::Texture, shader_v, shader_f))
|
if (!ShaderManager::create(kShader::Texture, shader_v, shader_f))
|
||||||
LOG("Failed to create shader Texture");
|
LOG("Failed to create shader Texture");
|
||||||
@@ -159,6 +192,8 @@ void App::initShaders()
|
|||||||
LOG("Failed to create shader Font");
|
LOG("Failed to create shader Font");
|
||||||
if (!ShaderManager::create(kShader::Atlas, shader_atlas_v, shader_atlas_f))
|
if (!ShaderManager::create(kShader::Atlas, shader_atlas_v, shader_atlas_f))
|
||||||
LOG("Failed to create shader Atlas");
|
LOG("Failed to create shader Atlas");
|
||||||
|
if (!ShaderManager::create(kShader::Stroke, shader_stroke_v, shader_stroke_f))
|
||||||
|
LOG("Failed to create shader Stroke");
|
||||||
LOG("shaders initialized");
|
LOG("shaders initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,6 +228,7 @@ void App::initLayout()
|
|||||||
LOG("initializing layout components");
|
LOG("initializing layout components");
|
||||||
sidebar = layout[main_id]->find<NodeBorder>("sidebar");
|
sidebar = layout[main_id]->find<NodeBorder>("sidebar");
|
||||||
panels = layout[main_id]->find<Node>("panels");
|
panels = layout[main_id]->find<Node>("panels");
|
||||||
|
canvas = layout[main_id]->find<NodeCanvas>("paint-canvas");
|
||||||
|
|
||||||
//brushes = layout[main_id]->find<NodePanelBrush>("panel-brush");
|
//brushes = layout[main_id]->find<NodePanelBrush>("panel-brush");
|
||||||
//layers = layout[main_id]->find<NodePanelLayer>("panel-layer");
|
//layers = layout[main_id]->find<NodePanelLayer>("panel-layer");
|
||||||
@@ -225,20 +261,23 @@ void App::initLayout()
|
|||||||
|
|
||||||
brushes->on_brush_changed = [this](Node* target, int index) {
|
brushes->on_brush_changed = [this](Node* target, int index) {
|
||||||
auto tid = brushes->get_texture_id(index);
|
auto tid = brushes->get_texture_id(index);
|
||||||
stroke->m_canvas->m_tex_id = tid;
|
stroke->m_canvas->m_brush.m_tex_id = tid;
|
||||||
stroke->m_canvas->draw_stroke();
|
stroke->m_canvas->draw_stroke();
|
||||||
|
canvas->m_brush = stroke->m_canvas->m_brush;
|
||||||
if (on_brush_select)
|
if (on_brush_select)
|
||||||
on_brush_select(index);
|
on_brush_select(index);
|
||||||
};
|
};
|
||||||
|
|
||||||
color->on_color_changed = [this](Node* target, glm::vec4 color) {
|
color->on_color_changed = [this](Node* target, glm::vec4 color) {
|
||||||
stroke->m_canvas->m_tip_color = color;
|
stroke->m_canvas->m_brush.m_tip_color = color;
|
||||||
stroke->m_canvas->draw_stroke();
|
stroke->m_canvas->draw_stroke();
|
||||||
|
canvas->m_brush = stroke->m_canvas->m_brush;
|
||||||
if (on_color_change)
|
if (on_color_change)
|
||||||
on_color_change(color);
|
on_color_change(color);
|
||||||
};
|
};
|
||||||
|
|
||||||
stroke->on_stroke_change = [this](Node*target) {
|
stroke->on_stroke_change = [this](Node*target) {
|
||||||
|
canvas->m_brush = stroke->m_canvas->m_brush;
|
||||||
if (on_stroke_change)
|
if (on_stroke_change)
|
||||||
on_stroke_change();
|
on_stroke_change();
|
||||||
};
|
};
|
||||||
@@ -306,7 +345,10 @@ void App::initLayout()
|
|||||||
|
|
||||||
if (auto* button = layout[main_id]->find<NodeButton>("btn-close"))
|
if (auto* button = layout[main_id]->find<NodeButton>("btn-close"))
|
||||||
{
|
{
|
||||||
button->on_click = [](Node*) { exit(0); };
|
button->on_click = [this](Node*) {
|
||||||
|
//exit(0);
|
||||||
|
canvas->m_canvas->clear();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (auto* button = layout[main_id]->find<NodeButton>("btn-popup"))
|
if (auto* button = layout[main_id]->find<NodeButton>("btn-popup"))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ public:
|
|||||||
std::shared_ptr<NodePanelLayer> layers;
|
std::shared_ptr<NodePanelLayer> layers;
|
||||||
std::shared_ptr<NodePanelColor> color;
|
std::shared_ptr<NodePanelColor> color;
|
||||||
std::shared_ptr<NodePanelStroke> stroke;
|
std::shared_ptr<NodePanelStroke> stroke;
|
||||||
|
NodeCanvas* canvas;
|
||||||
Node* current_panel = nullptr;
|
Node* current_panel = nullptr;
|
||||||
Node* panels;
|
Node* panels;
|
||||||
std::function<void(int)> on_brush_select;
|
std::function<void(int)> on_brush_select;
|
||||||
|
|||||||
5
engine/brush.cpp
Normal file
5
engine/brush.cpp
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "brush.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
58
engine/brush.h
Normal file
58
engine/brush.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "rtt.h"
|
||||||
|
|
||||||
|
NS_START
|
||||||
|
|
||||||
|
class Brush
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int id;
|
||||||
|
std::string m_name;
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Stroke
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Keypoint
|
||||||
|
{
|
||||||
|
glm::vec2 pos;
|
||||||
|
float pressure;
|
||||||
|
};
|
||||||
|
int m_layer;
|
||||||
|
float m_dist;
|
||||||
|
ui::Brush m_brush;
|
||||||
|
std::vector<Keypoint> m_keypoints;
|
||||||
|
void add_point(glm::vec2 pos, float pressure)
|
||||||
|
{
|
||||||
|
m_keypoints.emplace_back();
|
||||||
|
m_keypoints.back().pos = pos;
|
||||||
|
m_keypoints.back().pressure = pressure;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Layer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RTT m_rtt;
|
||||||
|
bool m_visible = true;
|
||||||
|
bool m_locked = false;
|
||||||
|
float m_alpha = 1.f;
|
||||||
|
std::string m_name;
|
||||||
|
bool create(int width, int height, std::string name)
|
||||||
|
{
|
||||||
|
m_rtt.create(width, height);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_END
|
||||||
@@ -3,52 +3,10 @@
|
|||||||
#include "texture.h"
|
#include "texture.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "shape.h"
|
#include "shape.h"
|
||||||
|
#include "brush.h"
|
||||||
|
|
||||||
NS_START
|
NS_START
|
||||||
|
|
||||||
class Brush
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::string m_name;
|
|
||||||
int id;
|
|
||||||
uint16_t m_texture_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Stroke
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct Keypoint
|
|
||||||
{
|
|
||||||
glm::vec2 pos;
|
|
||||||
float pressure;
|
|
||||||
};
|
|
||||||
int m_layer;
|
|
||||||
float m_dist;
|
|
||||||
std::shared_ptr<Brush> m_brush;
|
|
||||||
std::vector<Keypoint> m_keypoints;
|
|
||||||
void add_point(glm::vec2 pos, float pressure)
|
|
||||||
{
|
|
||||||
m_keypoints.emplace_back();
|
|
||||||
m_keypoints.back().pos = pos;
|
|
||||||
m_keypoints.back().pressure = pressure;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class Layer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RTT m_rtt;
|
|
||||||
bool m_visible = true;
|
|
||||||
bool m_locked = false;
|
|
||||||
float m_alpha = 1.f;
|
|
||||||
std::string m_name;
|
|
||||||
bool create(int width, int height, std::string name)
|
|
||||||
{
|
|
||||||
m_rtt.create(width, height);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class Canvas
|
class Canvas
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -62,7 +20,8 @@ public:
|
|||||||
RTT m_fb;
|
RTT m_fb;
|
||||||
Sampler m_sampler;
|
Sampler m_sampler;
|
||||||
Plane m_plane;
|
Plane m_plane;
|
||||||
bool create(int width, int height)
|
std::minstd_rand prng;
|
||||||
|
bool create(int width, int height)
|
||||||
{
|
{
|
||||||
m_width = width;
|
m_width = width;
|
||||||
m_height = height;
|
m_height = height;
|
||||||
@@ -78,8 +37,9 @@ public:
|
|||||||
m_layers.emplace_back();
|
m_layers.emplace_back();
|
||||||
m_layers.back().create(m_width, m_height, name);
|
m_layers.back().create(m_width, m_height, name);
|
||||||
}
|
}
|
||||||
void stroke_start(glm::vec2 point, float pressure, std::shared_ptr<Brush> brush)
|
void stroke_start(glm::vec2 point, float pressure, const ui::Brush& brush)
|
||||||
{
|
{
|
||||||
|
prng.seed(0);
|
||||||
m_strokes.emplace_back();
|
m_strokes.emplace_back();
|
||||||
m_strokes.back().m_brush = brush;
|
m_strokes.back().m_brush = brush;
|
||||||
m_strokes.back().add_point(point, pressure);
|
m_strokes.back().add_point(point, pressure);
|
||||||
@@ -97,21 +57,56 @@ public:
|
|||||||
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
|
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
|
||||||
|
|
||||||
glViewport(0, 0, m_width, m_height);
|
glViewport(0, 0, m_width, m_height);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
|
||||||
auto mvp = glm::ortho(0.f, (float)m_width, (float)m_height, 0.f, -1.f, 1.f) *
|
//auto mvp = glm::ortho(0.f, (float)m_width, (float)m_height, 0.f, -1.f, 1.f) *
|
||||||
glm::translate(glm::vec3(point, 0)) *
|
// glm::translate(glm::vec3(point, 0)) *
|
||||||
glm::scale(glm::vec3(30, 30, 1));
|
// glm::scale(glm::vec3(30, 30, 1));
|
||||||
|
//auto& tex = TextureManager::get(m_current_stroke->m_brush.m_tex_id);
|
||||||
|
//tex.bind();
|
||||||
|
//m_sampler.bind(0);
|
||||||
|
//ui::ShaderManager::use(kShader::Stroke);
|
||||||
|
//ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
|
||||||
|
//ui::ShaderManager::u_mat4(kShaderUniform::MVP, mvp);
|
||||||
|
//ui::ShaderManager::u_float(kShaderUniform::Alpha, 1.f);
|
||||||
|
//ui::ShaderManager::u_vec4(kShaderUniform::Col, { 0, 0, 0, 1 });
|
||||||
|
//m_plane.draw_fill();
|
||||||
|
//m_sampler.unbind();
|
||||||
|
//tex.unbind();
|
||||||
|
|
||||||
auto& tex = TextureManager::get(m_current_stroke->m_brush->m_texture_id);
|
auto proj = glm::ortho(0.f, (float)m_width, (float)m_height, 0.f, -1.f, 1.f);
|
||||||
|
auto m_brush = m_current_stroke->m_brush;
|
||||||
|
|
||||||
|
auto rnd_nor = [&] { return float((double)prng() / (double)prng.max()); }; // normalized [0, +1]
|
||||||
|
auto rnd_neg = [&] { return float((double)prng() / (double)prng.max() * 2.0 - 1.0); }; // normalized [-1, +1]
|
||||||
|
auto rnd_rad = [&] { return float((double)prng() / (double)prng.max() * M_PI * 2.0); }; // normalized [0, 2pi]
|
||||||
|
auto rnd_vec = [&] { float rad = rnd_rad(); return glm::vec2(cosf(rad), sinf(rad)); }; // normalized direction vector
|
||||||
|
|
||||||
|
float angle = (m_brush.m_tip_angle + rnd_nor() * m_brush.m_jitter_angle) * (float)(M_PI * 2.0);
|
||||||
|
glm::vec2 pos = point + (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_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);
|
||||||
|
|
||||||
|
auto& tex = TextureManager::get(m_brush.m_tex_id);
|
||||||
tex.bind();
|
tex.bind();
|
||||||
m_sampler.bind(0);
|
m_sampler.bind(0);
|
||||||
ui::ShaderManager::use(kShader::Texture);
|
ShaderManager::use("stroke");
|
||||||
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
|
ShaderManager::u_vec4(kShaderUniform::Col, m_brush.m_tip_color);
|
||||||
ui::ShaderManager::u_mat4(kShaderUniform::MVP, mvp);
|
ShaderManager::u_int(kShaderUniform::Tex, 0);
|
||||||
|
ShaderManager::u_mat4(kShaderUniform::MVP, mvp);
|
||||||
|
ShaderManager::u_float(kShaderUniform::Alpha, flow);
|
||||||
m_plane.draw_fill();
|
m_plane.draw_fill();
|
||||||
m_sampler.unbind();
|
m_sampler.unbind();
|
||||||
tex.unbind();
|
tex.unbind();
|
||||||
|
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
glViewport(vp[0], vp[1], vp[2], vp[3]);
|
glViewport(vp[0], vp[1], vp[2], vp[3]);
|
||||||
glClearColor(cc[0], cc[1], cc[2], cc[3]);
|
glClearColor(cc[0], cc[1], cc[2], cc[3]);
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ Plane NodeBorder::m_plane;
|
|||||||
Plane NodeImage::m_plane;
|
Plane NodeImage::m_plane;
|
||||||
Sampler NodeImage::m_sampler;
|
Sampler NodeImage::m_sampler;
|
||||||
std::map<std::string, glm::vec4> NodeIcon::m_icons;
|
std::map<std::string, glm::vec4> NodeIcon::m_icons;
|
||||||
ui::Shader NodeStrokePreview::m_shader;
|
|
||||||
|
|
||||||
kEventResult Node::on_event(Event* e)
|
kEventResult Node::on_event(Event* e)
|
||||||
{
|
{
|
||||||
|
|||||||
111
engine/layout.h
111
engine/layout.h
@@ -1664,43 +1664,8 @@ class NodeStrokePreview : public NodeBorder
|
|||||||
{
|
{
|
||||||
RTT m_rtt;
|
RTT m_rtt;
|
||||||
Sampler m_sampler;
|
Sampler m_sampler;
|
||||||
static ui::Shader m_shader;
|
|
||||||
public:
|
public:
|
||||||
uint16_t m_tex_id;
|
ui::Brush m_brush;
|
||||||
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);
|
|
||||||
}
|
|
||||||
virtual Node* clone_instantiate() const override { return new NodeStrokePreview(); }
|
virtual Node* clone_instantiate() const override { return new NodeStrokePreview(); }
|
||||||
virtual void clone_copy(Node* dest) const override
|
virtual void clone_copy(Node* dest) const override
|
||||||
{
|
{
|
||||||
@@ -1719,7 +1684,7 @@ public:
|
|||||||
{
|
{
|
||||||
m_sampler.create();
|
m_sampler.create();
|
||||||
TextureManager::load("data/Icons/Round-Hard.png");
|
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()
|
void draw_stroke()
|
||||||
{
|
{
|
||||||
@@ -1740,13 +1705,13 @@ public:
|
|||||||
glViewport(0, 0, m_rtt.getWidth(), m_rtt.getHeight());
|
glViewport(0, 0, m_rtt.getWidth(), m_rtt.getHeight());
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glm::mat4 proj = glm::ortho<float>(0, (float)m_rtt.getWidth(), 0, (float)m_rtt.getHeight(), -1, 1);
|
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;
|
float alpha = 0;
|
||||||
|
|
||||||
std::minstd_rand prng;
|
std::minstd_rand prng;
|
||||||
m_shader.use();
|
ShaderManager::use("stroke");
|
||||||
m_shader.u_vec4(kShaderUniform::Col, m_tip_color);
|
ShaderManager::u_vec4(kShaderUniform::Col, m_brush.m_tip_color);
|
||||||
m_shader.u_int(kShaderUniform::Tex, 0);
|
ShaderManager::u_int(kShaderUniform::Tex, 0);
|
||||||
t.bind();
|
t.bind();
|
||||||
m_sampler.bind(0);
|
m_sampler.bind(0);
|
||||||
while (alpha < 1.f)
|
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_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
|
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);
|
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_jitter_spread * 100.f);
|
glm::vec2 pos = BezierCurve::Bezier2D(kp, alpha) + (rnd_vec() * m_brush.m_jitter_spread * 100.f);
|
||||||
float size = 100.f * m_tip_size * (1.f - rnd_nor() * m_jitter_scale);
|
float size = 100.f * m_brush.m_tip_size * (1.f - rnd_nor() * m_brush.m_jitter_scale);
|
||||||
float flow = m_tip_flow * (1.f - rnd_nor() * m_jitter_flow);
|
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 *
|
auto mvp = proj *
|
||||||
//glm::translate(glm::vec3(i * 40 * m_tip_spacing, m_rtt.getHeight() / 2, 0)) *
|
//glm::translate(glm::vec3(i * 40 * m_tip_spacing, m_rtt.getHeight() / 2, 0)) *
|
||||||
glm::translate(glm::vec3(pos, 0)) *
|
glm::translate(glm::vec3(pos, 0)) *
|
||||||
glm::scale(glm::vec3(size, size, 1)) *
|
glm::scale(glm::vec3(size, size, 1)) *
|
||||||
glm::eulerAngleZ(angle);
|
glm::eulerAngleZ(angle);
|
||||||
m_shader.u_mat4(kShaderUniform::MVP, mvp);
|
ShaderManager::u_mat4(kShaderUniform::MVP, mvp);
|
||||||
m_shader.u_float(kShaderUniform::Alpha, flow);
|
ShaderManager::u_float(kShaderUniform::Alpha, flow);
|
||||||
m_plane.draw_fill();
|
m_plane.draw_fill();
|
||||||
}
|
}
|
||||||
m_sampler.unbind();
|
m_sampler.unbind();
|
||||||
@@ -1828,26 +1793,26 @@ public:
|
|||||||
{
|
{
|
||||||
m_canvas = find<NodeStrokePreview>("canvas");
|
m_canvas = find<NodeStrokePreview>("canvas");
|
||||||
|
|
||||||
init_slider(m_tip_size, "tip-size", &NodeStrokePreview::m_tip_size);
|
init_slider(m_tip_size, "tip-size", &ui::Brush::m_tip_size);
|
||||||
init_slider(m_tip_spacing, "tip-spacing", &NodeStrokePreview::m_tip_spacing);
|
init_slider(m_tip_spacing, "tip-spacing", &ui::Brush::m_tip_spacing);
|
||||||
init_slider(m_tip_flow, "tip-flow", &NodeStrokePreview::m_tip_flow);
|
init_slider(m_tip_flow, "tip-flow", &ui::Brush::m_tip_flow);
|
||||||
init_slider(m_tip_angle, "tip-angle", &NodeStrokePreview::m_tip_angle);
|
init_slider(m_tip_angle, "tip-angle", &ui::Brush::m_tip_angle);
|
||||||
init_slider(m_jitter_scale, "jitter-scale", &NodeStrokePreview::m_jitter_scale);
|
init_slider(m_jitter_scale, "jitter-scale", &ui::Brush::m_jitter_scale);
|
||||||
init_slider(m_jitter_angle, "jitter-angle", &NodeStrokePreview::m_jitter_angle);
|
init_slider(m_jitter_angle, "jitter-angle", &ui::Brush::m_jitter_angle);
|
||||||
init_slider(m_jitter_spread, "jitter-spread", &NodeStrokePreview::m_jitter_spread);
|
init_slider(m_jitter_spread, "jitter-spread", &ui::Brush::m_jitter_spread);
|
||||||
init_slider(m_jitter_flow, "jitter-flow", &NodeStrokePreview::m_jitter_flow);
|
init_slider(m_jitter_flow, "jitter-flow", &ui::Brush::m_jitter_flow);
|
||||||
//m_canvas->draw_stroke();
|
//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 = find<NodeSliderH>(id);
|
||||||
slider->on_value_changed = std::bind(&NodePanelStroke::handle_slide,
|
slider->on_value_changed = std::bind(&NodePanelStroke::handle_slide,
|
||||||
this, prop, std::placeholders::_1, std::placeholders::_2);
|
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();
|
m_canvas->draw_stroke();
|
||||||
if (on_stroke_change)
|
if (on_stroke_change)
|
||||||
on_stroke_change(this);
|
on_stroke_change(this);
|
||||||
@@ -1859,6 +1824,7 @@ class NodeCanvas : public Node
|
|||||||
bool m_dragging = false;
|
bool m_dragging = false;
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<ui::Canvas> m_canvas;
|
std::unique_ptr<ui::Canvas> m_canvas;
|
||||||
|
ui::Brush m_brush;
|
||||||
virtual Node* clone_instantiate() const override { return new NodeCanvas(); }
|
virtual Node* clone_instantiate() const override { return new NodeCanvas(); }
|
||||||
virtual void init() override
|
virtual void init() override
|
||||||
{
|
{
|
||||||
@@ -1880,14 +1846,16 @@ public:
|
|||||||
|
|
||||||
glClearColor(1, 0, 0, 1);
|
glClearColor(1, 0, 0, 1);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
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);
|
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);
|
glViewport(c.x, c.y, c.z, c.w);
|
||||||
|
|
||||||
glm::vec2 sz = { m_canvas->m_width, m_canvas->m_height };
|
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) *
|
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::translate(glm::vec3((m_size - sz) * 0.5f, 0)) * // center
|
||||||
glm::scale(glm::vec3(sz, 1)) *
|
glm::translate(glm::vec3(0)) * // corner
|
||||||
|
glm::scale(glm::vec3(sz * zoom, 1)) *
|
||||||
glm::translate(glm::vec3(.5f, .5f, 0.f)); // pivot
|
glm::translate(glm::vec3(.5f, .5f, 0.f)); // pivot
|
||||||
|
|
||||||
m_canvas->m_fb.bindTexture();
|
m_canvas->m_fb.bindTexture();
|
||||||
@@ -1905,28 +1873,35 @@ public:
|
|||||||
}
|
}
|
||||||
virtual void handle_resize(glm::vec2 old_size, glm::vec2 new_size) override
|
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
|
virtual kEventResult handle_event(Event* e) override
|
||||||
{
|
{
|
||||||
MouseEvent* me = static_cast<MouseEvent*>(e);
|
|
||||||
Node::handle_event(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)
|
switch (e->m_type)
|
||||||
{
|
{
|
||||||
case kEventType::MouseDownL:
|
case kEventType::MouseDownL:
|
||||||
{
|
{
|
||||||
auto b = std::make_shared<ui::Brush>();
|
m_canvas->stroke_start(cur, 1.f, m_brush);
|
||||||
b->m_texture_id = const_hash("data/Icons/Round-Brush.png");
|
|
||||||
m_canvas->stroke_start(me->m_pos, 1.f, b);
|
|
||||||
m_dragging = true;
|
m_dragging = true;
|
||||||
|
mouse_capture();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kEventType::MouseUpL:
|
case kEventType::MouseUpL:
|
||||||
m_canvas->stroke_end();
|
m_canvas->stroke_end();
|
||||||
m_dragging = false;
|
m_dragging = false;
|
||||||
|
mouse_release();
|
||||||
break;
|
break;
|
||||||
case kEventType::MouseMove:
|
case kEventType::MouseMove:
|
||||||
if (m_dragging)
|
if (m_dragging)
|
||||||
m_canvas->stroke_update(me->m_pos, 1.f);
|
m_canvas->stroke_update(cur, 1.f);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ enum class kShader : uint16_t
|
|||||||
UVs = const_hash("uvs"),
|
UVs = const_hash("uvs"),
|
||||||
Font = const_hash("font"),
|
Font = const_hash("font"),
|
||||||
Atlas = const_hash("atlas"),
|
Atlas = const_hash("atlas"),
|
||||||
|
Stroke = const_hash("stroke"),
|
||||||
};
|
};
|
||||||
|
|
||||||
class ShaderManager
|
class ShaderManager
|
||||||
|
|||||||
Reference in New Issue
Block a user