optimize stroke drawing

This commit is contained in:
2018-12-07 00:45:14 +01:00
parent 4980105d51
commit bbdad5a857
7 changed files with 131 additions and 69 deletions

View File

@@ -12,7 +12,7 @@
<AppxPackageIsForStore>True</AppxPackageIsForStore>
<AppxShowAllApps>False</AppxShowAllApps>
<AppxBuildConfigurationSelection>x64</AppxBuildConfigurationSelection>
<PackageOptionalProjectsInIdeBuilds>True</PackageOptionalProjectsInIdeBuilds>
<PackageOptionalProjectsInIdeBuilds>False</PackageOptionalProjectsInIdeBuilds>
<ShowAllFiles>false</ShowAllFiles>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

View File

@@ -984,6 +984,10 @@ Here's a list of what's available in this release.
<icon icon="bug" width="20"/>
<text id="menu-label" text="Induce crash" margin="0 0 0 5" font-face="arial" font-size="11"/>
</button-custom>
<button-custom id="about-perf" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
<icon icon="bug" width="20"/>
<text id="menu-label" text="Performance test" margin="0 0 0 5" font-face="arial" font-size="11"/>
</button-custom>
</popup-menu>
</layout>

View File

@@ -603,10 +603,42 @@ void App::init_menu_about()
}
if (auto b = popup->find<NodeButtonCustom>("about-crash"))
{
b->on_click = [this](Node*) {
LOG("crashing");
App::I.crash_test();
};
}
if (auto b = popup->find<NodeButtonCustom>("about-perf"))
{
b->on_click = [this](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);
for (int i = 0; i < 100; i++)
{
Canvas::I->stroke_update({ 100, 100, 0 }, 0.9f);
Canvas::I->stroke_update({ 200, 200, 0 }, 0.9f);
Canvas::I->stroke_update({ 200, 100, 0 }, 0.9f);
Canvas::I->stroke_update({ 100, 200, 0 }, 0.9f);
Canvas::I->stroke_update({ 300, 300, 0 }, 0.9f);
Canvas::I->stroke_update({ 200, 500, 0 }, 0.9f);
Canvas::I->stroke_update({ 500, 500, 0 }, 0.9f);
Canvas::I->stroke_update({ 400, 400, 0 }, 0.9f);
Canvas::I->stroke_update({ 0, 200, 0 }, 0.9f);
Canvas::I->stroke_update({ 200, 0, 0 }, 0.9f);
Canvas::I->stroke_draw();
}
Canvas::I->stroke_end();
auto diff = std::chrono::high_resolution_clock::now() - start;
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(diff).count();
LOG("%lld ms", ms);
static char str[256];
sprintf(str, "Time %lld ms", ms);
App::I.message_box("Performance test", str);
};
}
};
}
}

View File

@@ -343,6 +343,47 @@ void Canvas::stroke_draw()
auto& stencil = TextureManager::get(const_hash("data/paper.jpg"));
auto ortho_proj = glm::ortho(0.f, (float)m_width, 0.f, (float)m_height, -1.f, 1.f);
std::vector<vertex_t> B{
vertex_t{ {0, 0, 1, 1}, {0, 0}, {0, 0} },
vertex_t{ {0, 0, 1, 1}, {0, 1}, {0, 1} },
vertex_t{ {0, 0, 1, 1}, {1, 1}, {1, 1} },
vertex_t{ {0, 0, 1, 1}, {1, 0}, {1, 0} },
};
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);
stencil.bind();
glActiveTexture(GL_TEXTURE3);
m_mixer.bindTexture();
glDisable(GL_BLEND);
ShaderManager::use(kShader::Stroke);
ShaderManager::u_int(kShaderUniform::Tex, 0); // brush
#ifndef __IOS__
ShaderManager::u_int(kShaderUniform::TexBG, 1); // bg
#endif
ShaderManager::u_int(kShaderUniform::TexStencil, 2); // stencil
ShaderManager::u_int(kShaderUniform::TexMix, 3); // mixer
//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);
auto unp_vp = zw(m_box);
auto unp_inv = glm::inverse(m_proj * m_mv);
for (const auto& s : samples)
{
if (m_mixer_idle)
@@ -352,30 +393,13 @@ void Canvas::stroke_draw()
}
static glm::vec2 UV2[4];
{
glm::vec2 dx(m_mixer_sample.size * 0.5f, 0), dy(0, m_mixer_sample.size * 0.5f);
glm::vec2 off[4] = {
-dx - dy, // A - bottom-left
-dx + dy, // B - top-left
+dx + dy, // C - top-right
+dx - dy, // D - bottom-right
};
auto sz = glm::vec2(m_mixer.getWidth(), m_mixer.getHeight()) * m_mixer_scale;
glm::vec2 bb_min(sz);
glm::vec2 bb_max(0, 0);
for (int j = 0; j < 4; j++)
{
auto p = (xy(m_mixer_sample.pos) + off[j] * glm::orientate2(-s.angle) + glm::vec2(0, 1)) / zoom;
UV2[j] = p / sz;
bb_min = glm::max({ 0, 0 }, glm::min(bb_min, p));
bb_max = glm::min(sz, glm::max(bb_max, p));
}
auto bb_sz = bb_max - bb_min;
if (m_brush.m_tip_mix > 0.f)
stroke_draw_mix(bb_min, bb_sz);
}
glm::vec2 dx_mix(m_mixer_sample.size * 0.5f, 0), dy_mix(0, m_mixer_sample.size * 0.5f);
glm::vec2 off_mix[4] = {
-dx_mix - dy_mix, // A - bottom-left
-dx_mix + dy_mix, // B - top-left
+dx_mix + dy_mix, // C - top-right
+dx_mix - dy_mix, // D - bottom-right
};
// P is the initial square centered at the cursor location
glm::vec2 dx(s.size * 0.5f, 0), dy(0, s.size * 0.5f);
glm::vec2 off[4] = {
@@ -384,48 +408,23 @@ void Canvas::stroke_draw()
+dx + dy, // C - top-right
+dx - dy, // D - bottom-right
};
std::vector<vertex_t> B{
vertex_t{ {0, 0, 1, 1}, {0, 0}, {0, 0} },
vertex_t{ {0, 0, 1, 1}, {0, 1}, {0, 1} },
vertex_t{ {0, 0, 1, 1}, {1, 1}, {1, 1} },
vertex_t{ {0, 0, 1, 1}, {1, 0}, {1, 0} },
};
auto sz = glm::vec2(m_mixer.getWidth(), m_mixer.getHeight()) * m_mixer_scale;
glm::vec2 bb_min(sz);
glm::vec2 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)) / zoom;
UV2[j] = p / sz;
bb_min = glm::max({ 0, 0 }, glm::min(bb_min, p));
bb_max = glm::min(sz, glm::max(bb_max, p));
B[j].pos = glm::vec4(xy(s.pos) + off[j] * glm::orientate2(-s.angle), 1, 1);
B[j].uvs2 = UV2[j];
}
auto bb_sz = bb_max - bb_min;
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);
stencil.bind();
glActiveTexture(GL_TEXTURE3);
m_mixer.bindTexture();
glDisable(GL_BLEND);
ShaderManager::use(kShader::Stroke);
ShaderManager::u_int(kShaderUniform::Tex, 0); // brush
#ifndef __IOS__
ShaderManager::u_int(kShaderUniform::TexBG, 1); // bg
#endif
ShaderManager::u_int(kShaderUniform::TexStencil, 2); // stencil
ShaderManager::u_int(kShaderUniform::TexMix, 3); // mixer
//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);
if (m_brush.m_tip_mix > 0.f)
stroke_draw_mix(bb_min, bb_sz);
for (int i = 0; i < 6; i++)
{
@@ -439,17 +438,21 @@ void Canvas::stroke_draw()
int intersected = 0;
int inside = 0;
// face is the 2d shape of the cube plane i projected onto the window space
auto face = face_to_shape2D(i);
// intersect P with the current face to clip diverging points from the plane
auto P = poly_intersect(B, face);
auto P = poly_intersect(B, m_plane_shape[i]);
for (int j = 0; j < P.size(); j++)
{
glm::vec3 ray_origin, ray_dir;
if (s.pos.z == 0)
{
point_unproject(P[j].pos, { 0, 0, zw(m_box) }, m_mv, m_proj, ray_origin, ray_dir);
//point_unproject(P[j].pos, { 0, 0, zw(m_box) }, m_mv, m_proj, ray_origin, ray_dir);
auto clip_space = glm::vec2(P[j].pos.x, unp_vp.y - P[j].pos.y - 1.f) / unp_vp * 2.f - 1.f;
auto wp0 = unp_inv * glm::vec4(clip_space, 0, 1);
auto wp1 = unp_inv * glm::vec4(clip_space, .5, 1);
ray_origin = xyz(wp0 / wp0.w);
ray_dir = glm::normalize(xyz(wp1 / wp1.w) - ray_origin);
}
else
{
@@ -526,13 +529,31 @@ void Canvas::stroke_draw()
glm::max(zw(m_dirty_box[i]), (glm::vec2)(tex_pos + tex_sz))
);
ShaderManager::use(kShader::Stroke);
//ShaderManager::use(kShader::Stroke);
ShaderManager::u_mat4(kShaderUniform::MVP, ortho_proj);
ShaderManager::u_vec4(kShaderUniform::Col, glm::vec4(s.col, m_brush.m_tip_color.a));
ShaderManager::u_float(kShaderUniform::Alpha, s.flow);
P = triangulate_simple(P);
m_brush_shape.update_vertices(P.data(), P.size());
if (P.size() == 4)
{
static vertex_t rect[6];
rect[0] = P[0];
rect[1] = P[1];
rect[2] = P[2];
rect[3] = P[0];
rect[4] = P[2];
rect[5] = P[3];
m_brush_shape.update_vertices(rect, 6);
}
else if (P.size() == 3)
{
m_brush_shape.update_vertices(P.data(), P.size());
}
else
{
P = triangulate_simple(P);
m_brush_shape.update_vertices(P.data(), P.size());
}
m_brush_shape.draw_fill();
/*

View File

@@ -131,6 +131,7 @@ public:
bool m_show_tmp = false;
std::vector<Layer> m_layers;
std::vector<int> m_order;
std::vector<glm::vec2> m_plane_shape[6]; // screen space projection of the plane
glm::mat4 m_plane_unproject[6] = SIXPLETTE(glm::mat4(1));
glm::vec3 m_plane_dir[6] = SIXPLETTE(glm::vec3(0));
glm::vec4 m_dirty_box[6] = SIXPLETTE(glm::vec4(0));

View File

@@ -464,7 +464,7 @@ int main(int argc, char** argv)
auto x = unsigned{};
auto y = unsigned{};
GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &x, &y);
App::I.zoom = (float)x / 96.f;
App::I.zoom *= (float)x / 96.f;
AdjustWindowRect(&clientRect, WS_OVERLAPPEDWINDOW, false);
hWnd = CreateWindow(wc.lpszClassName, L"PanoPainter", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,

View File

@@ -103,6 +103,10 @@ void NodeCanvas::draw()
glm::mat4 plane_camera = glm::lookAt(m_canvas->m_plane_origin[plane_index], m_canvas->m_plane_normal[plane_index], m_canvas->m_plane_tangent[plane_index]);
m_canvas->m_plane_unproject[plane_index] = glm::inverse(m_canvas->m_proj * m_canvas->m_mv * m_canvas->m_plane_transform[plane_index]);
m_canvas->m_plane_dir[plane_index] = -(m_canvas->m_plane_transform[plane_index] * glm::vec4(m_canvas->m_plane_origin[plane_index], 1));
// face is the 2d shape of the cube plane i projected onto the window space
m_canvas->m_plane_shape[plane_index] = m_canvas->face_to_shape2D(plane_index);
auto plane_mvp = proj * camera *
glm::scale(glm::vec3(m_canvas->m_order.size() + 500)) *
m_canvas->m_plane_transform[plane_index] *