implement brush presets save and restore from file, fix stencil nullptr, limit preview stroke max size

This commit is contained in:
2019-01-23 16:53:58 +01:00
parent e26fcf1163
commit 879be9d4fe
17 changed files with 282 additions and 65 deletions

3
.gitmodules vendored
View File

@@ -46,3 +46,6 @@
[submodule "libs/nanort"] [submodule "libs/nanort"]
path = libs/nanort path = libs/nanort
url = https://github.com/lighttransport/nanort.git url = https://github.com/lighttransport/nanort.git
[submodule "libs/hash-library"]
path = libs/hash-library
url = https://github.com/stbrumme/hash-library

View File

@@ -77,7 +77,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental> <LinkIncremental>true</LinkIncremental>
<IncludePath>libs\glm;libs\glew-2.0.0\include;libs\stb;libs\tinyxml2;libs\yoga;libs\curl-win\include;libs\jpeg;libs\wacom;libs\bugtrap-client\include;libs\poly2tri\poly2tri;libs\base64;libs\sqlite3;libs\openvr\headers;libs\nanort;$(IncludePath)</IncludePath> <IncludePath>libs\glm;libs\glew-2.0.0\include;libs\stb;libs\tinyxml2;libs\yoga;libs\curl-win\include;libs\jpeg;libs\wacom;libs\bugtrap-client\include;libs\poly2tri\poly2tri;libs\base64;libs\sqlite3;libs\openvr\headers;libs\nanort;libs\hash-library;$(IncludePath)</IncludePath>
<LibraryPath>libs\curl-win\lib\dll-$(Configuration)-$(PlatformShortName);libs\glew-2.0.0\lib\Release\$(Platform);libs\bugtrap-client\lib;libs\openvr\lib\win64;$(LibraryPath)</LibraryPath> <LibraryPath>libs\curl-win\lib\dll-$(Configuration)-$(PlatformShortName);libs\glew-2.0.0\lib\Release\$(Platform);libs\bugtrap-client\lib;libs\openvr\lib\win64;$(LibraryPath)</LibraryPath>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -87,7 +87,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental> <LinkIncremental>false</LinkIncremental>
<IncludePath>libs\glm;libs\glew-2.0.0\include;libs\stb;libs\tinyxml2;libs\yoga;libs\curl-win\include;libs\jpeg;libs\wacom;libs\bugtrap-client\include;libs\poly2tri\poly2tri;libs\base64;libs\sqlite3;libs\openvr\headers;libs\nanort;$(IncludePath)</IncludePath> <IncludePath>libs\glm;libs\glew-2.0.0\include;libs\stb;libs\tinyxml2;libs\yoga;libs\curl-win\include;libs\jpeg;libs\wacom;libs\bugtrap-client\include;libs\poly2tri\poly2tri;libs\base64;libs\sqlite3;libs\openvr\headers;libs\nanort;libs\hash-library;$(IncludePath)</IncludePath>
<LibraryPath>libs\curl-win\lib\dll-$(Configuration)-$(PlatformShortName);libs\glew-2.0.0\lib\Release\$(Platform);libs\bugtrap-client\lib;libs\openvr\lib\win64;$(LibraryPath)</LibraryPath> <LibraryPath>libs\curl-win\lib\dll-$(Configuration)-$(PlatformShortName);libs\glew-2.0.0\lib\Release\$(Platform);libs\bugtrap-client\lib;libs\openvr\lib\win64;$(LibraryPath)</LibraryPath>
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@@ -169,6 +169,10 @@
</PreBuildEvent> </PreBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="libs\hash-library\md5.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="libs\nanort\nanort.cc"> <ClCompile Include="libs\nanort\nanort.cc">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
@@ -304,6 +308,7 @@
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="libs\hash-library\md5.h" />
<ClInclude Include="libs\nanort\nanort.h" /> <ClInclude Include="libs\nanort\nanort.h" />
<ClInclude Include="libs\sqlite3\sqlite3.h" /> <ClInclude Include="libs\sqlite3\sqlite3.h" />
<ClInclude Include="libs\sqlite3\sqlite3ext.h" /> <ClInclude Include="libs\sqlite3\sqlite3ext.h" />

View File

@@ -46,6 +46,9 @@
<Filter Include="libs\nanort"> <Filter Include="libs\nanort">
<UniqueIdentifier>{be0c0053-abd8-4e2d-a294-7c54511b05a6}</UniqueIdentifier> <UniqueIdentifier>{be0c0053-abd8-4e2d-a294-7c54511b05a6}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="libs\hash">
<UniqueIdentifier>{2a784067-6741-47a3-b668-cc45f2224286}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\app.cpp"> <ClCompile Include="src\app.cpp">
@@ -282,6 +285,9 @@
<ClCompile Include="libs\nanort\nanort.cc"> <ClCompile Include="libs\nanort\nanort.cc">
<Filter>libs\nanort</Filter> <Filter>libs\nanort</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="libs\hash-library\md5.cpp">
<Filter>libs\hash</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="src\app.h"> <ClInclude Include="src\app.h">
@@ -503,6 +509,9 @@
<ClInclude Include="libs\nanort\nanort.h"> <ClInclude Include="libs\nanort\nanort.h">
<Filter>libs\nanort</Filter> <Filter>libs\nanort</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="libs\hash-library\md5.h">
<Filter>libs\hash</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="PanoPainter.rc"> <ResourceCompile Include="PanoPainter.rc">

View File

@@ -1127,7 +1127,7 @@ Here's a list of what's available in this release.
<button-custom id="btn-stroke" width="50" height="50" margin="0 0 5 0" thickness="1" border-color=".1" pad="2"> <button-custom id="btn-stroke" width="50" height="50" margin="0 0 5 0" thickness="1" border-color=".1" pad="2">
<image path="data/ui/stroke.png" width="100%" height="100%" align="center" justify="flex-end"/> <image path="data/ui/stroke.png" width="100%" height="100%" align="center" justify="flex-end"/>
</button-custom> </button-custom>
<!--<button id="btn-brush-preset" width="50" height="50" margin="0 0 5 0" text="Preset" thickness="1" border-color=".1" pad="2"/>--> <button id="btn-brush-preset" width="50" height="50" margin="0 0 5 0" text="Preset" thickness="1" border-color=".1" pad="2"/>
<!-- <!--
<button-custom id="btn-brush" width="50" height="50" margin="0 0 5 0" thickness="1" border-color=".1" pad="2"> <button-custom id="btn-brush" width="50" height="50" margin="0 0 5 0" thickness="1" border-color=".1" pad="2">
<image path="data/ui/brushes.png" width="100%" height="100%" align="center" justify="flex-end"/> <image path="data/ui/brushes.png" width="100%" height="100%" align="center" justify="flex-end"/>

1
libs/hash-library Submodule

Submodule libs/hash-library added at a8a88f8acb

View File

@@ -132,19 +132,20 @@ void App::init_sidebar()
// stroke->m_canvas->draw_stroke(); // stroke->m_canvas->draw_stroke();
// } // }
presets->on_brush_changed = [this](Node* target, int index) { presets->on_brush_changed = [this](Node* target, std::shared_ptr<Brush>& b) {
auto b = presets->get_brush(index);
// don't change some params // 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; b->m_tip_color = Canvas::I->m_current_brush->m_tip_color;
Canvas::I->m_current_brush = b; *Canvas::I->m_current_brush = *b;
stroke->m_preview->draw_stroke(); stroke->m_preview->draw_stroke();
stroke->m_brush_thumb->set_image(b->m_brush_thumb_path);
stroke->update_controls();
}; };
color->on_color_changed = [this](Node* target, glm::vec4 color) { color->on_color_changed = [this](Node* target, glm::vec4 color) {
Canvas::I->m_current_brush->m_tip_color = color; Canvas::I->m_current_brush->m_tip_color = color;
}; };
stroke->on_brush_changed = [this](Node* target, const std::string& path) { stroke->on_brush_changed = [this](Node* target, const std::string& path, const std::string& thumb) {
Canvas::I->m_current_brush->load_texture(path); Canvas::I->m_current_brush->load_texture(path, thumb);
stroke->m_preview->draw_stroke(); stroke->m_preview->draw_stroke();
}; };
stroke->on_stencil_changed = [this](Node*target, const std::string& path) { stroke->on_stencil_changed = [this](Node*target, const std::string& path) {

View File

@@ -86,7 +86,6 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat
else if (canvas->m_canvas->m_show_tmp && canvas->m_canvas->m_current_layer_idx == layer_index) else if (canvas->m_canvas->m_show_tmp && canvas->m_canvas->m_current_layer_idx == layer_index)
{ {
sampler.bind(0); sampler.bind(0);
auto& paper = *canvas->m_canvas->m_current_stroke->m_brush->m_stencil_texture;
ShaderManager::use(kShader::CompDraw); ShaderManager::use(kShader::CompDraw);
ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_int(kShaderUniform::Tex, 0);
ShaderManager::u_int(kShaderUniform::TexStroke, 1); ShaderManager::u_int(kShaderUniform::TexStroke, 1);
@@ -106,9 +105,13 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat
glActiveTexture(GL_TEXTURE2); glActiveTexture(GL_TEXTURE2);
canvas->m_canvas->m_smask.m_rtt[plane_index].bindTexture(); canvas->m_canvas->m_smask.m_rtt[plane_index].bindTexture();
glActiveTexture(GL_TEXTURE3); glActiveTexture(GL_TEXTURE3);
paper.bind(); if (canvas->m_canvas->m_current_stroke->m_brush->m_stencil_texture)
canvas->m_canvas->m_current_stroke->m_brush->m_stencil_texture->bind();
else
glBindTexture(GL_TEXTURE_2D, 0);
m_face_plane.draw_fill(); m_face_plane.draw_fill();
paper.unbind(); if (canvas->m_canvas->m_current_stroke->m_brush->m_stencil_texture)
canvas->m_canvas->m_current_stroke->m_brush->m_stencil_texture->unbind();
glActiveTexture(GL_TEXTURE2); glActiveTexture(GL_TEXTURE2);
canvas->m_canvas->m_smask.m_rtt[plane_index].unbindTexture(); canvas->m_canvas->m_smask.m_rtt[plane_index].unbindTexture();
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);

View File

@@ -135,12 +135,13 @@ StrokeSample Stroke::randomize_sample(const glm::vec3& pos, float pressure, floa
float size_dyn = m_brush->m_tip_size_pressure ? pressure : 1.f; 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 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);
StrokeSample s; StrokeSample s;
s.origin = pos; s.origin = pos;
s.angle = -curve_angle + (m_brush->m_tip_angle + rnd_nor() * m_brush->m_jitter_angle) * (float)(M_PI * 2.0); s.angle = -curve_angle + (m_brush->m_tip_angle + rnd_nor() * m_brush->m_jitter_angle) * (float)(M_PI * 2.0);
s.pos = pos + (rnd_vec() * m_brush->m_jitter_spread * 100.f); s.pos = pos + (rnd_vec() * m_brush->m_jitter_spread * 100.f);
s.size = 800.f * m_brush->m_tip_size * (1.f - rnd_nor() * m_brush->m_jitter_scale) * size_dyn; s.size = 800.f * size * (1.f - rnd_nor() * m_brush->m_jitter_scale) * size_dyn;
s.flow = m_brush->m_tip_flow * (1.f - rnd_nor() * m_brush->m_jitter_flow) * flow_dyn; 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); 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.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);
@@ -215,7 +216,10 @@ void Stroke::add_point(glm::vec3 pos, float pressure)
//pressure = m_pressure_buff.average(); //pressure = m_pressure_buff.average();
if (m_brush->m_tip_size_pressure) if (m_brush->m_tip_size_pressure)
m_step = glm::max(m_brush->m_tip_spacing * m_brush->m_tip_size * pressure * 800.f, 1.f); {
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);
}
float dist = m_keypoints.empty() ? m_step : float dist = m_keypoints.empty() ? m_step :
m_keypoints.back().dist + glm::distance(m_keypoints.back().pos, pos); m_keypoints.back().dist + glm::distance(m_keypoints.back().pos, pos);
@@ -238,28 +242,31 @@ void Stroke::start(const std::shared_ptr<Brush>& brush)
m_hsv_jitter.clear(); m_hsv_jitter.clear();
m_last_kp = 0; m_last_kp = 0;
m_dist = 0.f; m_dist = 0.f;
m_brush = std::make_shared<Brush>(*brush); m_brush = brush;
m_brush->m_tip_size *= 1.f / glm::tan(glm::radians(m_camera.fov * 0.5f)); 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 * m_brush->m_tip_size * 800.f, 1.f); m_step = glm::max(m_brush->m_tip_spacing * size * 800.f, 1.f);
prng.seed(0); prng.seed(0);
} }
bool Brush::load_texture(const std::string & path) bool Brush::load_texture(const std::string& path, const std::string& thumb)
{ {
m_tip_texture = std::make_shared<Texture2D>(); m_tip_texture = std::make_shared<Texture2D>();
if (!m_tip_texture->load(path)) if (!m_tip_texture->load(path))
return false; return false;
m_tip_texture->create_mipmaps(); m_tip_texture->create_mipmaps();
m_tip_texture->auto_destroy = true; m_tip_texture->auto_destroy = true;
m_brush_path = path;
m_brush_thumb_path = thumb;
return true; return true;
} }
bool Brush::load_stencil(const std::string & path) bool Brush::load_stencil(const std::string& path)
{ {
m_stencil_texture = std::make_shared<Texture2D>(); m_stencil_texture = std::make_shared<Texture2D>();
if (!m_stencil_texture->load(path)) if (!m_stencil_texture->load(path))
return false; return false;
m_stencil_texture->create_mipmaps(); m_stencil_texture->create_mipmaps();
m_stencil_texture->auto_destroy = true; m_stencil_texture->auto_destroy = true;
m_stencil_path = path;
return true; return true;
} }

View File

@@ -8,8 +8,10 @@ class Brush
public: public:
Brush() = default; Brush() = default;
Brush(const Brush& brush) = default; Brush(const Brush& brush) = default;
int id = 0;
std::string m_name; std::string m_name;
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_tip_texture;
std::shared_ptr<Texture2D> m_stencil_texture; std::shared_ptr<Texture2D> m_stencil_texture;
//uint16_t m_tex_id = 0; //uint16_t m_tex_id = 0;
@@ -41,7 +43,7 @@ public:
float m_jitter_sat = 0; float m_jitter_sat = 0;
float m_jitter_val = 0; float m_jitter_val = 0;
int m_blend_mode = 0; int m_blend_mode = 0;
bool load_texture(const std::string& path); bool load_texture(const std::string& path, const std::string& thumb);
bool load_stencil(const std::string& path); bool load_stencil(const std::string& path);
}; };
@@ -94,6 +96,7 @@ public:
float m_curve = 0; float m_curve = 0;
float m_dist = 0; float m_dist = 0;
float m_step = 0; float m_step = 0;
float m_max_size = FLT_MAX;
Camera m_camera; Camera m_camera;
std::shared_ptr<Brush> m_brush; std::shared_ptr<Brush> m_brush;
cbuffer<float, 3> m_curve_angles; cbuffer<float, 3> m_curve_angles;

View File

@@ -304,7 +304,6 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
m_sampler.bind(0); m_sampler.bind(0);
m_sampler.bind(1); m_sampler.bind(1);
m_sampler.bind(2); m_sampler.bind(2);
auto& paper = *m_current_stroke->m_brush->m_stencil_texture;
ShaderManager::use(kShader::CompDraw); ShaderManager::use(kShader::CompDraw);
ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_int(kShaderUniform::Tex, 0);
//ShaderManager::u_int(kShaderUniform::TexA, 0); //ShaderManager::u_int(kShaderUniform::TexA, 0);
@@ -326,9 +325,13 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
glActiveTexture(GL_TEXTURE2); glActiveTexture(GL_TEXTURE2);
m_smask.m_rtt[plane_index].bindTexture(); m_smask.m_rtt[plane_index].bindTexture();
glActiveTexture(GL_TEXTURE3); glActiveTexture(GL_TEXTURE3);
paper.bind(); 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_node->m_face_plane.draw_fill(); m_node->m_face_plane.draw_fill();
paper.unbind(); if (m_current_stroke->m_brush->m_stencil_texture)
m_current_stroke->m_brush->m_stencil_texture->unbind();
glActiveTexture(GL_TEXTURE2); glActiveTexture(GL_TEXTURE2);
m_smask.m_rtt[plane_index].unbindTexture(); m_smask.m_rtt[plane_index].unbindTexture();
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
@@ -360,7 +363,6 @@ void Canvas::stroke_draw()
const auto& m_brush = m_current_stroke->m_brush; const auto& m_brush = m_current_stroke->m_brush;
auto samples = m_current_stroke->compute_samples(); auto samples = m_current_stroke->compute_samples();
auto& tex = *m_brush->m_tip_texture; auto& tex = *m_brush->m_tip_texture;
auto& stencil = *m_brush->m_stencil_texture;
auto ortho_proj = glm::ortho(0.f, (float)m_width, 0.f, (float)m_height, -1.f, 1.f); auto ortho_proj = glm::ortho(0.f, (float)m_width, 0.f, (float)m_height, -1.f, 1.f);
std::vector<vertex_t> B{ std::vector<vertex_t> B{
@@ -381,7 +383,11 @@ void Canvas::stroke_draw()
//m_sampler_linear.bind(5); //m_sampler_linear.bind(5);
glActiveTexture(GL_TEXTURE2); glActiveTexture(GL_TEXTURE2);
stencil.bind(); if (m_brush->m_stencil_texture)
m_brush->m_stencil_texture->bind();
else
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE3); glActiveTexture(GL_TEXTURE3);
m_mixer.bindTexture(); m_mixer.bindTexture();
@@ -458,7 +464,10 @@ void Canvas::stroke_draw()
//m_sampler_linear.bind(5); //m_sampler_linear.bind(5);
glActiveTexture(GL_TEXTURE2); glActiveTexture(GL_TEXTURE2);
stencil.bind(); if (m_brush->m_stencil_texture)
m_brush->m_stencil_texture->bind();
else
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE3); glActiveTexture(GL_TEXTURE3);
m_mixer.bindTexture(); m_mixer.bindTexture();
glDisable(GL_BLEND); glDisable(GL_BLEND);
@@ -633,7 +642,8 @@ void Canvas::stroke_draw()
glDisable(GL_BLEND); glDisable(GL_BLEND);
glActiveTexture(GL_TEXTURE2); glActiveTexture(GL_TEXTURE2);
stencil.unbind(); if (m_brush->m_stencil_texture)
m_brush->m_stencil_texture->unbind();
glActiveTexture(GL_TEXTURE3); glActiveTexture(GL_TEXTURE3);
m_mixer.unbindTexture(); m_mixer.unbindTexture();
@@ -846,8 +856,6 @@ void Canvas::stroke_commit()
} }
else else
{ {
auto& paper = *m_current_stroke->m_brush->m_stencil_texture;
ShaderManager::use(kShader::CompDraw); ShaderManager::use(kShader::CompDraw);
ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_int(kShaderUniform::Tex, 0);
ShaderManager::u_int(kShaderUniform::TexStroke, 1); ShaderManager::u_int(kShaderUniform::TexStroke, 1);
@@ -867,9 +875,13 @@ void Canvas::stroke_commit()
glActiveTexture(GL_TEXTURE2); glActiveTexture(GL_TEXTURE2);
m_smask.m_rtt[i].bindTexture(); m_smask.m_rtt[i].bindTexture();
glActiveTexture(GL_TEXTURE3); glActiveTexture(GL_TEXTURE3);
paper.bind(); 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_plane.draw_fill(); m_plane.draw_fill();
paper.unbind(); if (m_current_stroke->m_brush->m_stencil_texture)
m_current_stroke->m_brush->m_stencil_texture->unbind();
glActiveTexture(GL_TEXTURE2); glActiveTexture(GL_TEXTURE2);
m_smask.m_rtt[i].unbindTexture(); m_smask.m_rtt[i].unbindTexture();
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);

View File

@@ -177,7 +177,7 @@ void CanvasModePen::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
if (m_dragging && m_resizing) if (m_dragging && m_resizing)
{ {
auto diff = m_cur_pos - m_size_pos_start; auto diff = m_cur_pos - m_size_pos_start;
canvas->m_current_brush->m_tip_size = m_size_value_start + diff.x * 0.001f; canvas->m_current_brush->m_tip_size = glm::max(m_size_value_start + diff.x * 0.001f, 0.001f);
} }
m_cur_pos = loc; m_cur_pos = loc;
break; break;

View File

@@ -201,7 +201,6 @@ void NodeCanvas::draw()
else if(m_canvas->m_current_stroke && m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index) else if(m_canvas->m_current_stroke && m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index)
{ {
m_sampler.bind(0); m_sampler.bind(0);
auto& paper = *m_canvas->m_current_stroke->m_brush->m_stencil_texture;
ShaderManager::use(kShader::CompDraw); ShaderManager::use(kShader::CompDraw);
ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_int(kShaderUniform::Tex, 0);
ShaderManager::u_int(kShaderUniform::TexStroke, 1); ShaderManager::u_int(kShaderUniform::TexStroke, 1);
@@ -222,9 +221,13 @@ void NodeCanvas::draw()
glActiveTexture(GL_TEXTURE2); glActiveTexture(GL_TEXTURE2);
m_canvas->m_smask.m_rtt[plane_index].bindTexture(); m_canvas->m_smask.m_rtt[plane_index].bindTexture();
glActiveTexture(GL_TEXTURE3); glActiveTexture(GL_TEXTURE3);
paper.bind(); if (m_canvas->m_current_stroke->m_brush->m_stencil_texture)
m_canvas->m_current_stroke->m_brush->m_stencil_texture->bind();
else
glBindTexture(GL_TEXTURE_2D, 0);
m_face_plane.draw_fill(); m_face_plane.draw_fill();
paper.unbind(); if (m_canvas->m_current_stroke->m_brush->m_stencil_texture)
m_canvas->m_current_stroke->m_brush->m_stencil_texture->unbind();
glActiveTexture(GL_TEXTURE2); glActiveTexture(GL_TEXTURE2);
m_canvas->m_smask.m_rtt[plane_index].unbindTexture(); m_canvas->m_smask.m_rtt[plane_index].unbindTexture();
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);

View File

@@ -7,6 +7,8 @@
#ifdef __APPLE__ #ifdef __APPLE__
#include <Foundation/Foundation.h> #include <Foundation/Foundation.h>
#endif #endif
#include "canvas.h"
#include "app.h"
Node* NodeButtonBrush::clone_instantiate() const Node* NodeButtonBrush::clone_instantiate() const
{ {
@@ -186,7 +188,29 @@ Node* NodePanelBrushPreset::clone_instantiate() const
void NodePanelBrushPreset::init() void NodePanelBrushPreset::init()
{ {
init_template("tpl-panel-brush-preset"); init_template("tpl-panel-brush-preset");
m_container = find<NodeBorder>("brushes");
m_btn_add = find<NodeButtonCustom>("btn-add");
m_btn_add->on_click = [this] (Node*) {
NodeBrushPresetItem* brush = new NodeBrushPresetItem;
m_container->add_child(brush);
brush->init();
brush->create();
brush->loaded();
brush->thumb_path = Canvas::I->m_current_brush->m_brush_thumb_path;
brush->high_path = Canvas::I->m_current_brush->m_brush_path;
brush->m_brush = std::make_shared<Brush>(*Canvas::I->m_current_brush);
brush->m_brush->m_tip_size = .05f;
brush->m_preview->m_brush = brush->m_brush;
brush->m_preview->draw_stroke();
brush->m_thumb->set_image(brush->m_brush->m_brush_thumb_path);
m_brushes.push_back(brush);
brush->on_click = std::bind(&NodePanelBrushPreset::handle_click, this, std::placeholders::_1);
save();
};
restore();
/*
static auto icons = Asset::list_files("data/thumbs", true, ".*\\.png$"); static auto icons = Asset::list_files("data/thumbs", true, ".*\\.png$");
if ((m_container = find<NodeBorder>("brushes"))) if ((m_container = find<NodeBorder>("brushes")))
@@ -222,6 +246,7 @@ void NodePanelBrushPreset::init()
brush->on_click = std::bind(&NodePanelBrushPreset::handle_click, this, std::placeholders::_1); brush->on_click = std::bind(&NodePanelBrushPreset::handle_click, this, std::placeholders::_1);
} }
} }
*/
} }
void NodePanelBrushPreset::handle_click(Node* target) void NodePanelBrushPreset::handle_click(Node* target)
@@ -230,32 +255,132 @@ void NodePanelBrushPreset::handle_click(Node* target)
return; return;
if (m_current) if (m_current)
m_current->m_selected = false; m_current->m_selected = false;
m_current = (NodeButtonBrush*)target; m_current = (NodeBrushPresetItem*)target;
m_current->m_selected = true; m_current->m_selected = true;
if (on_brush_changed) if (on_brush_changed)
on_brush_changed(this, m_current->m_brushID); on_brush_changed(this, m_current->m_brush);
} }
std::shared_ptr<Brush> NodePanelBrushPreset::get_brush(int index) const bool NodePanelBrushPreset::save()
{ {
auto& b = m_brushes[index]->m_brush; auto path = App::I.data_path + "/presets.bin";
TextureManager::load(m_brushes[index]->high_path.c_str(), true); if (FILE* fp = fopen(path.c_str(), "wb"))
//b->m_tex_id = m_brushes[index]->high_id; {
return b; header_t h;
h.count = m_brushes.size();
fwrite(&h, sizeof(h), 1, fp);
for (const auto& b : m_brushes)
{
item_t i;
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_stencil_path_len = b->m_brush->m_stencil_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_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;
i.m_tip_noise = b->m_brush->m_tip_noise;
i.m_tip_hue = b->m_brush->m_tip_hue;
i.m_tip_sat = b->m_brush->m_tip_sat;
i.m_tip_val = b->m_brush->m_tip_val;
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;
i.m_jitter_flow = b->m_brush->m_jitter_flow;
i.m_jitter_hue = b->m_brush->m_jitter_hue;
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;
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_stencil_path.c_str(), 1, b->m_brush->m_stencil_path.size(), fp);
}
fclose(fp);
}
return false;
} }
uint16_t NodePanelBrushPreset::get_texture_id(int index) const bool NodePanelBrushPreset::restore()
{ {
TextureManager::load(m_brushes[index]->high_path.c_str(), true); auto path = App::I.data_path + "/presets.bin";
return m_brushes[index]->high_id; if (FILE* fp = fopen(path.c_str(), "rb"))
} {
header_t h;
fread(&h, sizeof(h), 1, fp);
for (int k = 0; k < h.count; k++)
{
item_t i;
fread(&i, sizeof(i), 1, fp);
auto b = std::make_shared<Brush>();
b->m_tip_color = i.m_tip_color;
b->m_tip_size = i.m_tip_size;
b->m_tip_spacing = i.m_tip_spacing;
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_mix = i.m_tip_mix;
b->m_tip_stencil = i.m_tip_stencil;
b->m_tip_wet = i.m_tip_wet;
b->m_tip_noise = i.m_tip_noise;
b->m_tip_hue = i.m_tip_hue;
b->m_tip_sat = i.m_tip_sat;
b->m_tip_val = i.m_tip_val;
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;
b->m_jitter_flow = i.m_jitter_flow;
b->m_jitter_hue = i.m_jitter_hue;
b->m_jitter_sat = i.m_jitter_sat;
b->m_jitter_val = i.m_jitter_val;
b->m_blend_mode = i.m_blend_mode;
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_stencil_path.resize(i.m_stencil_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_stencil_path.c_str(), 1, b->m_stencil_path.size(), fp);
std::string NodePanelBrushPreset::get_texture_path(int index) const b->load_texture(b->m_brush_path, b->m_brush_thumb_path);
{
return m_brushes[index]->high_path;
}
int NodePanelBrushPreset::get_brush_id(int index) const NodeBrushPresetItem* brush = new NodeBrushPresetItem;
{ m_container->add_child(brush);
return m_brushes[index]->m_brushID; brush->init();
brush->create();
brush->loaded();
brush->thumb_path = b->m_brush_thumb_path;
brush->high_path = b->m_brush_path;
brush->m_brush = b;
brush->m_brush->m_tip_size = .05f;
brush->m_preview->m_brush = b;
brush->m_preview->draw_stroke();
brush->m_thumb->set_image(brush->m_brush->m_brush_thumb_path);
m_brushes.push_back(brush);
brush->on_click = std::bind(&NodePanelBrushPreset::handle_click, this, std::placeholders::_1);
}
fclose(fp);
}
return false;
} }

View File

@@ -46,11 +46,9 @@ public:
class NodeBrushPresetItem : public NodeButtonCustom class NodeBrushPresetItem : public NodeButtonCustom
{ {
public: public:
int m_brushID;
std::shared_ptr<Brush> m_brush; std::shared_ptr<Brush> m_brush;
std::string high_path; std::string high_path;
std::string thumb_path; std::string thumb_path;
uint16_t high_id;
bool m_selected = false; bool m_selected = false;
NodeStrokePreview* m_preview; NodeStrokePreview* m_preview;
NodeImage* m_thumb; NodeImage* m_thumb;
@@ -62,16 +60,57 @@ public:
class NodePanelBrushPreset : public Node class NodePanelBrushPreset : public Node
{ {
std::vector<NodeBrushPresetItem*> m_brushes; std::vector<NodeBrushPresetItem*> m_brushes;
NodeButtonBrush* m_current = nullptr; NodeBrushPresetItem* m_current = nullptr;
Node* m_container; Node* m_container;
NodeButtonCustom* m_btn_add;
NodeButtonCustom* m_btn_save;
struct header_t {
char magic[4]{ 'P', 'P', 'P', 'R' };
uint16_t version = 0;
uint16_t count = 0;
};
struct item_t {
int m_name_len;
int m_brush_path_len;
int m_brush_thumb_path_len;
int m_stencil_path_len;
//std::shared_ptr<Texture2D> m_tip_texture;
//std::shared_ptr<Texture2D> m_stencil_texture;
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_mix = 0;
float m_tip_stencil = 0;
float m_tip_wet = 0;
float m_tip_noise = 0;
float m_tip_hue = 0;
float m_tip_sat = 0;
float m_tip_val = 0;
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;
float m_jitter_flow = 0;
float m_jitter_hue = 0;
float m_jitter_sat = 0;
float m_jitter_val = 0;
int m_blend_mode = 0;
};
public: public:
std::function<void(Node* target, int id)> on_brush_changed; std::function<void(Node* target, std::shared_ptr<Brush>& brush)> on_brush_changed;
virtual Node* clone_instantiate() const override; virtual Node* clone_instantiate() const override;
virtual void init() override; virtual void init() override;
void handle_click(Node* target); void handle_click(Node* target);
uint16_t get_texture_id(int index) const;
std::string get_texture_path(int index) const;
std::shared_ptr<Brush> get_brush(int index) const; std::shared_ptr<Brush> get_brush(int index) const;
int get_brush_id(int index) const; bool save();
bool restore();
}; };

View File

@@ -62,7 +62,7 @@ void NodePanelStroke::init_controls()
auto b = std::make_shared<Brush>(); auto b = std::make_shared<Brush>();
int br_idx = m_brush_popup->find_brush("Round-Hard"); int br_idx = m_brush_popup->find_brush("Round-Hard");
b->load_texture(m_brush_popup->get_texture_path(br_idx)); 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->load_stencil("data/paper.jpg");
b->m_tip_size = .1f; b->m_tip_size = .1f;
b->m_tip_flow = .5f; b->m_tip_flow = .5f;
@@ -83,7 +83,7 @@ void NodePanelStroke::init_controls()
m_brush_popup->on_brush_changed = [this](Node*, int index) { m_brush_popup->on_brush_changed = [this](Node*, int index) {
if (on_brush_changed) if (on_brush_changed)
on_brush_changed(this, m_brush_popup->get_texture_path(index)); on_brush_changed(this, m_brush_popup->get_texture_path(index), m_brush_popup->get_thumb_path(index));
m_brush_thumb->set_image(m_brush_popup->get_thumb_path(index)); m_brush_thumb->set_image(m_brush_popup->get_thumb_path(index));
m_brush_popup->mouse_release(); m_brush_popup->mouse_release();
m_brush_popup->parent->remove_child(m_brush_popup.get()); m_brush_popup->parent->remove_child(m_brush_popup.get());

View File

@@ -44,7 +44,7 @@ public:
std::shared_ptr<NodePanelBrush> m_brush_popup; std::shared_ptr<NodePanelBrush> m_brush_popup;
std::function<void(Node* target)> on_stroke_change; std::function<void(Node* target)> on_stroke_change;
std::function<void(Node* target, const std::string& path)> on_stencil_changed; std::function<void(Node* target, const std::string& path)> on_stencil_changed;
std::function<void(Node* target, const std::string& path)> on_brush_changed; std::function<void(Node* target, const std::string& path, const std::string& thumb)> on_brush_changed;
std::map<NodeSliderH*, std::function<float(float)>> m_curves; std::map<NodeSliderH*, std::function<float(float)>> m_curves;
virtual Node* clone_instantiate() const override; virtual Node* clone_instantiate() const override;

View File

@@ -68,6 +68,7 @@ void NodeStrokePreview::draw_stroke()
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);
const auto& b = m_brush; const auto& b = m_brush;
m_stroke.m_max_size = 0.1f;
m_stroke.m_camera.fov = Canvas::I->m_cam_fov; m_stroke.m_camera.fov = Canvas::I->m_cam_fov;
m_stroke.m_camera.rot = Canvas::I->m_cam_rot; m_stroke.m_camera.rot = Canvas::I->m_cam_rot;
m_stroke.reset(); m_stroke.reset();
@@ -80,9 +81,11 @@ void NodeStrokePreview::draw_stroke()
tex.bind(); tex.bind();
m_sampler_brush.bind(0); m_sampler_brush.bind(0);
auto& stencil = *b->m_stencil_texture;
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
stencil.bind(); if (b->m_stencil_texture)
b->m_stencil_texture->bind();
else
glBindTexture(GL_TEXTURE_2D, 0);
m_sampler.bind(1); m_sampler.bind(1);
if (true) if (true)
@@ -138,6 +141,9 @@ void NodeStrokePreview::draw()
void NodeStrokePreview::handle_resize(glm::vec2 old_size, glm::vec2 new_size) void NodeStrokePreview::handle_resize(glm::vec2 old_size, glm::vec2 new_size)
{ {
if (old_size == new_size)
return;
float pad = 30.f; float pad = 30.f;
new_size *= root()->m_zoom; new_size *= root()->m_zoom;
float w = new_size.x; float w = new_size.x;