diff --git a/PanoPainterPackage/PanoPainterPackage.wapproj.user b/PanoPainterPackage/PanoPainterPackage.wapproj.user
index 7bc18ae..aa7eaa8 100644
--- a/PanoPainterPackage/PanoPainterPackage.wapproj.user
+++ b/PanoPainterPackage/PanoPainterPackage.wapproj.user
@@ -12,7 +12,7 @@
True
False
x64
- True
+ False
false
diff --git a/data/layout.xml b/data/layout.xml
index b99cb67..be43d13 100644
--- a/data/layout.xml
+++ b/data/layout.xml
@@ -984,6 +984,10 @@ Here's a list of what's available in this release.
+
+
+
+
diff --git a/src/app_layout.cpp b/src/app_layout.cpp
index 4d245a4..285daab 100644
--- a/src/app_layout.cpp
+++ b/src/app_layout.cpp
@@ -603,10 +603,42 @@ void App::init_menu_about()
}
if (auto b = popup->find("about-crash"))
+ {
b->on_click = [this](Node*) {
LOG("crashing");
App::I.crash_test();
};
+ }
+
+ if (auto b = popup->find("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(diff).count();
+ LOG("%lld ms", ms);
+ static char str[256];
+ sprintf(str, "Time %lld ms", ms);
+ App::I.message_box("Performance test", str);
+ };
+ }
};
}
}
diff --git a/src/canvas.cpp b/src/canvas.cpp
index ce4398a..b4dc960 100644
--- a/src/canvas.cpp
+++ b/src/canvas.cpp
@@ -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 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 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();
/*
diff --git a/src/canvas.h b/src/canvas.h
index 5041e64..42034c3 100644
--- a/src/canvas.h
+++ b/src/canvas.h
@@ -131,6 +131,7 @@ public:
bool m_show_tmp = false;
std::vector m_layers;
std::vector m_order;
+ std::vector 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));
diff --git a/src/main.cpp b/src/main.cpp
index d238889..b0b890f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -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,
diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp
index 9c9ba91..06ba559 100644
--- a/src/node_canvas.cpp
+++ b/src/node_canvas.cpp
@@ -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] *