#include <drawing_handler.hpp> DrawingHandler::DrawingHandler(Toolbox& tb) : shader_draw_((tb.shader_path + "draw.vert").c_str(), (tb.shader_path + "draw.frag").c_str()), vao_(0), vbo_(0), fbo_(0) { /*Shader*/ shader_draw_.use(); shader_draw_.setInt("source_texture", 0); /*vao, vbo*/ glGenVertexArrays(1, &vao_); glGenBuffers(1, &vbo_); glBindVertexArray(vao_); glBindBuffer(GL_ARRAY_BUFFER, vbo_); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); glBindVertexArray(0); /*fbo*/ glGenFramebuffers(1, &fbo_); glBindFramebuffer(GL_FRAMEBUFFER, fbo_); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tb.tex_damp_static, 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { std::cout << "ERROR: DRAWINGMANAGER: FRAMEBUFFER NOT COMPLETE" << std::endl; } /*wave fbo*/ glGenFramebuffers(1, &fbo_wave_); glBindFramebuffer(GL_FRAMEBUFFER, fbo_wave_); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tb.tex_wave_1, 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { std::cout << "ERROR: DRAWINGMANAGER: WAVE FRAMEBUFFER NOT COMPLETE" << std::endl; } glBindFramebuffer(GL_FRAMEBUFFER, 0); } DrawingHandler::~DrawingHandler() { shader_draw_.clean_up(); glDeleteVertexArrays(1, &vao_); glDeleteBuffers(1, &vbo_); glDeleteFramebuffers(1, &fbo_); } void DrawingHandler::update(Toolbox& tb) { if (previous_mstate_ != tb.m_state) { drawpairs_.clear(); } previous_mstate_ = tb.m_state; /*Handle Messages*/ for (Message& m : tb.mailbox) { if (m.target == MESSAGETARGET::DRAWER) { DRAWERMESSAGE message = std::get<DRAWERMESSAGE>(m.message); switch (message) { case DRAWERMESSAGE::CLEAR: drawpairs_.clear(); m.handled = true; break; default: break; } } } /* //This is touchscreen-only //Uncomment on a touchscreen //Catch dangling Drawers, no touches means no drawers if (drawpairs_.size() > 0 && tb.current_touchIDs.size() == 0 && tb.events.size() == 0) { drawpairs_.clear(); #ifndef NDEBUG std::cout << "Emergency Drawer-Release" << std::endl; #endif } */ /*We can return here if MSTATE is not interesting*/ if (tb.m_state != static_cast<int>(MSTATE::DRAW) && tb.m_state != static_cast<int>(MSTATE::ERASE)) { return; } /*Handle Events*/ /*Bind*/ shader_draw_.use(); glBindFramebuffer(GL_FRAMEBUFFER, fbo_); glBindVertexArray(vao_); glBindBuffer(GL_ARRAY_BUFFER, vbo_); glViewport(0, 0, tb.texture_w, tb.texture_h); for (Pevent& pev : tb.events) { /*Event is in wave window*/ if (in_wave_window_(tb, pev)) { if (pev.type == PEVENTTYPE::DOWN) { if (tb.m_state == static_cast<int>(MSTATE::DRAW)) { /*Start drawing with new Drawer here*/ std::array<float, 2> coords = drawerCoordinates_(pev, tb); Drawer d(tb); d.start_drawing(coords[0], coords[1]); drawpairs_.push_back({ d, pev.finger_id }); } else if (tb.m_state == static_cast<int>(MSTATE::ERASE)) { /*Start erasing with new Eraser here*/ std::array<float, 2> coords = drawerCoordinates_(pev, tb); Drawer d(tb); d.start_drawing(coords[0], coords[1]); drawpairs_.push_back({ d, pev.finger_id }); } } else if (pev.type == PEVENTTYPE::UP) { if (tb.m_state == static_cast<int>(MSTATE::DRAW)) { /*Stop drawing with correct Drawer and delete it here*/ for (auto it = drawpairs_.begin(); it != drawpairs_.end(); ++it) { if (it->second == pev.finger_id) { drawpairs_.erase(it); break; //only one drawer per finger exists } } } else if (tb.m_state == static_cast<int>(MSTATE::ERASE)) { /*Stop erasing with correct Drawer and delete it here*/ for (auto it = drawpairs_.begin(); it != drawpairs_.end(); ++it) { if (it->second == pev.finger_id) { drawpairs_.erase(it); break; //only one drawer per finger exists } } } } else if (pev.type == PEVENTTYPE::MOVE) { if (tb.m_state == static_cast<int>(MSTATE::DRAW)) { /*Draw with correct Drawer here*/ for (std::pair<Drawer, SDL_FingerID>& dp : drawpairs_) { if (dp.second == pev.finger_id) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tb.tex_const_zero); std::array<float, 2> coords = drawerCoordinates_(pev, tb); bool actually_drawn = dp.first.draw(coords[0], coords[1], tb, true); //draw on damping if (actually_drawn) { glBindFramebuffer(GL_FRAMEBUFFER, fbo_wave_); glBindTexture(GL_TEXTURE_2D, tb.tex_wave_clean); dp.first.redraw(tb); //redraw on wave glBindFramebuffer(GL_FRAMEBUFFER, fbo_); } break; //only one drawer per finger exists } } } else if (tb.m_state == static_cast<int>(MSTATE::ERASE)) { /*Erase with correct Eraser here*/ for (std::pair<Drawer, SDL_FingerID>& dp : drawpairs_) { if (dp.second == pev.finger_id) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tb.tex_damp_clean); std::array<float, 2> coords = drawerCoordinates_(pev, tb); dp.first.draw(coords[0], coords[1], tb, false); //erase break; //only one drawer per finger exists } } } } } /*Event not in wave window*/ else { switch (pev.type) { /*Finger down outside wave area, don't care*/ case PEVENTTYPE::DOWN: break; /*Finger up or moved outside wave area, if associated Drawer exists, clear it*/ case PEVENTTYPE::UP: [[fallthrough]]; case PEVENTTYPE::MOVE: { for (auto it = drawpairs_.begin(); it != drawpairs_.end(); ++it) { if (it->second == pev.finger_id) { drawpairs_.erase(it); break; //only one drawer per finger exists } } break; } } } } /*Unbind*/ glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); /*Push info to toolbox developer region*/ tb.num_drawers = num_drawers(); } size_t DrawingHandler::num_drawers() { return drawpairs_.size(); } void DrawingHandler::draw_(Toolbox& tb) { /*This probably doesn't do anything for now*/ return; } bool DrawingHandler::in_wave_window_(const Toolbox& tb, const Pevent& pev) const { return pev.fscoord_x < 1.f - tb.gui_pos; } std::array<float, 2> DrawingHandler::drawerCoordinates_(const Pevent& pev, const Toolbox& tb) { return { static_cast<float>(pev.itcoord_x) / static_cast<float>(tb.texture_w) * 2.f - 1.f, //x - (static_cast<float>(pev.itcoord_y) / static_cast<float>(tb.texture_h) * 2.f - 1.f) }; //y }