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] *