#include "pch.h" #include "log.h" #include "canvas.h" void ui::Canvas::clear() { m_fb.bindFramebuffer(); GLint vp[4]; GLfloat cc[4]; glGetIntegerv(GL_VIEWPORT, vp); glGetFloatv(GL_COLOR_CLEAR_VALUE, cc); glClearColor(1, 1, 1, 0); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, m_width, m_height); // glViewport(vp[0], vp[1], vp[2], vp[3]); glClearColor(cc[0], cc[1], cc[2], cc[3]); m_fb.unbindFramebuffer(); } void ui::Canvas::stroke_end() { m_current_stroke = nullptr; //stroke_commit(); m_show_tmp = false; } void ui::Canvas::stroke_draw() { if (!(m_current_stroke && m_current_stroke->has_sample())) return; m_fb.bindFramebuffer(); GLint vp[4]; GLfloat cc[4]; glGetIntegerv(GL_VIEWPORT, vp); glGetFloatv(GL_COLOR_CLEAR_VALUE, cc); glViewport(0, 0, m_width, m_height); auto proj = glm::ortho(0.f, (float)m_width, 0.f, (float)m_height, -1.f, 1.f); auto m_brush = m_current_stroke->m_brush; auto samples = m_current_stroke->compute_samples(); auto& tex = TextureManager::get(m_brush.m_tex_id); tex.bind(); m_sampler.bind(0); m_sampler_bg.bind(1); glActiveTexture(GL_TEXTURE1); m_tex.bind(); if (m_use_instanced) { glEnable(GL_BLEND); m_mesh.shader.use(); m_mesh.shader.u_vec4(kShaderUniform::Col, m_brush.m_tip_color); m_mesh.shader.u_int(kShaderUniform::Tex, 0); m_mesh.draw(samples, proj); } else { glDisable(GL_BLEND); ShaderManager::use(ui::kShader::Stroke); ShaderManager::u_vec4(kShaderUniform::Col, m_brush.m_tip_color); ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_int(kShaderUniform::TexBG, 1); ShaderManager::u_vec2(kShaderUniform::Resolution, { m_width, m_height }); for (const auto& s : samples) { auto mvp = proj * glm::translate(glm::vec3(s.pos, 0)) * glm::scale(glm::vec3(s.size, s.size, 1)) * glm::eulerAngleZ(s.angle); //ShaderManager::u_mat4(kShaderUniform::MVP, mvp); //ShaderManager::u_float(kShaderUniform::Alpha, s.flow); //m_plane.draw_fill(); glm::vec4 P[4] { mvp * glm::vec4(glm::vec2(-.5f, -.5f), 0, 1.f), // A - bottom-left mvp * glm::vec4(glm::vec2(-.5f, +.5f), 0, 1.f), // B - top-left mvp * glm::vec4(glm::vec2(+.5f, +.5f), 0, 1.f), // C - top-right mvp * glm::vec4(glm::vec2(+.5f, -.5f), 0, 1.f), // D - bottom-right }; //auto mvp_inv = glm::translate(glm::vec3(0, m_height, 0)) * glm::inverse(proj * glm::scale(glm::vec3(1, -1, 1))); auto mvp_inv = glm::inverse(proj); glm::vec4 P2[4]{ mvp_inv * P[0], mvp_inv * P[1], mvp_inv * P[2], mvp_inv * P[3], }; glm::vec2 bb_min(m_width, m_height); glm::vec2 bb_max(0, 0); for (int i = 0; i < 4; i++) { bb_min = glm::max({ 0, 0 }, glm::min(bb_min, P2[i].xy())); bb_max = glm::min({ m_width, m_height }, glm::max(bb_max, P2[i].xy())); } auto bb_sz = bb_max - bb_min; // TODO: use floor and ceil to round to pixel glm::vec2 pad(0); glm::ivec2 tex_pos = glm::clamp(glm::floor(bb_min) - pad , { 0, 0 }, { m_width, m_height }); glm::ivec2 tex_sz = glm::clamp(glm::floor(bb_sz ) + pad, { 0, 0 }, { m_width, m_height }); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, tex_pos.x, tex_pos.y, tex_pos.x, tex_pos.y, tex_sz.x, tex_sz.y); // glCopyTexSubImage2D(GL_TEXTURE_2D, 0, // 0, 0, // 0, 0, // m_width, m_height); //glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, // (int)floor(bb_min.x), (int)floor(bb_min.y), // (int)ceil(bb_sz.x), (int)ceil(bb_sz.y), 0); // auto tof = bb_min / glm::vec2(m_width, m_height); // auto tsz = bb_sz / glm::vec2(m_width, m_height); ShaderManager::u_mat4(kShaderUniform::MVP, mvp); // ShaderManager::u_vec2(kShaderUniform::Tof, tof); // ShaderManager::u_vec2(kShaderUniform::Tsz, tsz); ShaderManager::u_float(kShaderUniform::Alpha, s.flow); //m_plane.update_vertices(P); m_plane.draw_fill(); } } m_tex.unbind(); glActiveTexture(GL_TEXTURE0); m_sampler.unbind(); m_sampler_bg.unbind(); tex.unbind(); glDisable(GL_BLEND); m_fb.unbindFramebuffer(); // m_fb.bindFramebuffer(); // { // m_tmp.bindTexture(); // m_sampler.bind(0); // ShaderManager::use(ui::kShader::Texture); // ShaderManager::u_int(kShaderUniform::Tex, 0); // ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); // m_plane.draw_fill(); // m_sampler.unbind(); // m_tmp.unbindTexture(); // } // m_fb.unbindFramebuffer(); glViewport(vp[0], vp[1], vp[2], vp[3]); glClearColor(cc[0], cc[1], cc[2], cc[3]); } void ui::Canvas::stroke_commit() { m_fb.bindFramebuffer(); GLint vp[4]; GLfloat cc[4]; glGetIntegerv(GL_VIEWPORT, vp); glGetFloatv(GL_COLOR_CLEAR_VALUE, cc); glViewport(0, 0, m_width, m_height); GLboolean blend = glIsEnabled(GL_BLEND); if (!blend) glEnable(GL_BLEND); m_tmp.bindTexture(); m_sampler.bind(0); ShaderManager::use(ui::kShader::Texture); ShaderManager::u_int(kShaderUniform::Tex, 0); ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); m_plane.draw_fill(); m_sampler.unbind(); m_tmp.unbindTexture(); if (!blend) glDisable(GL_BLEND); glViewport(vp[0], vp[1], vp[2], vp[3]); glClearColor(cc[0], cc[1], cc[2], cc[3]); m_fb.unbindFramebuffer(); } void ui::Canvas::stroke_update(glm::vec2 point, float pressure) { m_current_stroke->add_point(point, pressure); } void ui::Canvas::stroke_start(glm::vec2 point, float pressure, const ui::Brush& brush) { m_strokes.emplace_back(); m_strokes.back().start(brush); m_strokes.back().add_point(point, pressure); m_current_stroke = &m_strokes.back(); m_tmp.bindFramebuffer(); m_tmp.clear({ 1, 1, 1, 0 }); m_tmp.unbindFramebuffer(); m_show_tmp = true; // m_fb.bindFramebuffer(); // m_tex.bind(); // glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height); // m_tex.unbind(); // m_fb.unbindFramebuffer(); } void ui::Canvas::layer_add(std::string name) { m_layers.emplace_back(); m_layers.back().create(m_width, m_height, name); } void ui::Canvas::resize(int width, int height) { m_width = width; m_height = height; m_tmp.create(width, height); m_fb.create(width, height); m_tex.create(width, height); } bool ui::Canvas::create(int width, int height) { m_width = width; m_height = height; m_tmp.create(width, height); m_fb.create(width, height); m_tex.create(width, height); m_sampler.create(); m_sampler_bg.create(); m_plane.create<1>(1, 1); m_mesh.create(); return true; }