-
Pascal Engeler authoredPascal Engeler authored
slim_blockchain_handler.cpp 10.09 KiB
#include <slim_blockchain_handler.hpp>
#include <toolbox.hpp>
#include <message.hpp>
#include <enums.hpp>
#include <algorithm>
void SlimBlockchainHandler::update(Toolbox& tb) {
bool skip_events = false;
//can't be dragging if mstate changes
if (previous_mstate_ != tb.m_state) {
clear_blocks_();
skip_events = true;
}
//update tracked mstate
previous_mstate_ = tb.m_state;
/*Handle Messages*/
for (Message& m : tb.mailbox) {
if (m.target == MESSAGETARGET::BLOCKCHAIN && !skip_events) {
BLOCKCHAINMESSAGE message = std::get<BLOCKCHAINMESSAGE>(m.message);
switch (message) {
case BLOCKCHAINMESSAGE::CLEAR:
clear_blocks_();
m.handled = true;
skip_events = true;
break;
default:
break;
}
}
}
/*
//This is touchscreen-only
//Uncomment on a touchscreen
//Catch dangling Blocks, if no touches, then no dragging
if (!skip_events && dragpairs_.size() > 0 && tb.current_touchIDs.size() == 0 && tb.events.size() == 0) {
clear_blocks_();
skip_events = true;
#ifndef NDEBUG
std::cout << "Emergency Block-Release" << std::endl;
#endif
}
*/
if (tb.m_state == static_cast<int>(MSTATE::IMMEDIATE) && !skip_events) {
/*Handle Events*/
for (Pevent& pev : tb.events) {
/*Handle event differently depending on where it is*/
/*Event within wave window*/
if (in_wave_window_(tb, pev)) {
switch (pev.type) {
/*Finger down, place Block, add to dragpairs*/
case PEVENTTYPE::DOWN:
blockchain_.push_back(EfficientBlock(tb.block_width, tb.block_height, pev.itcoord_x - tb.block_width / 2, tb.texture_h - (pev.itcoord_y + tb.block_height / 2)));
dragpairs_.push_back({ &blockchain_.back(), pev.finger_id });
drawlist_dynamic_.push_back(blockchain_.back().xywh());
break;
/*Finger up, find and remove the associated Block and dragpair*/
case PEVENTTYPE::UP: {
auto released = std::find_if(dragpairs_.begin(), dragpairs_.end(), [=](auto dragpair) { return dragpair.second == pev.finger_id; });
if (released != dragpairs_.end()) {
released->first->request_removal();
eraselist_dynamic_.push_back(released->first->xywh());
}
dragpairs_.remove_if([=](auto dragpair) { return dragpair.second == pev.finger_id; });
break;
}
/*Finger moved, find and translate associated Block*/
case PEVENTTYPE::MOVE: {
auto moved = std::find_if(dragpairs_.begin(), dragpairs_.end(), [=](auto dragpair) { return dragpair.second == pev.finger_id; });
if (moved != dragpairs_.end()) {
eraselist_dynamic_.push_back(moved->first->xywh());
moved->first->translate(pev.itcoord_x - moved->first->width() / 2, tb.texture_h - (pev.itcoord_y + moved->first->height() / 2));
drawlist_dynamic_.push_back(moved->first->xywh());
}
break;
}
}
}
/*Event outside 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 Block exists, clear it*/
case PEVENTTYPE::UP:
case PEVENTTYPE::MOVE: {
auto released = std::find_if(dragpairs_.begin(), dragpairs_.end(), [=](auto dragpair) { return dragpair.second == pev.finger_id; });
if (released != dragpairs_.end()) {
released->first->request_removal();
eraselist_dynamic_.push_back(released->first->xywh());
}
dragpairs_.remove_if([=](auto dragpair) { return dragpair.second == pev.finger_id; });
break;
}
}
}
}
}
/*Update Blocks*/
/*TODO: Can reupload blocks depending on need, if necessary*/
update_blocks_(tb, false);
/*Toolbox developer region*/
tb.num_blocks = num_blocks();
}
size_t SlimBlockchainHandler::num_blocks() {
return blockchain_.size();
}
void SlimBlockchainHandler::clear_blocks_() {
for (EfficientBlock& b : blockchain_) {
eraselist_dynamic_.push_back(b.xywh());
b.request_removal();
}
dragpairs_.clear();
blockchain_.clear();
}
void SlimBlockchainHandler::update_blocks_(const Toolbox& tb, bool reload_all) {
find_dynamic_duplicates_();
if (drawlist_dynamic_.size() != 0 || drawlist_static_.size() != 0 || eraselist_dynamic_.size() != 0) {
glBindVertexArray(vao_);
glBindBuffer(GL_ARRAY_BUFFER, vbo_);
glViewport(0, 0, tb.texture_w, tb.texture_h);
glActiveTexture(GL_TEXTURE0);
shader_drawblocks_.use();
}
std::vector<float> vertices;
/*Erase dynamic blocks*/
if (eraselist_dynamic_.size() != 0) {
glBindFramebuffer(GL_FRAMEBUFFER, fbo_dynamic_);
glBindTexture(GL_TEXTURE_2D, tb.tex_damp_clean);
xywhs_to_vertices_(tb, eraselist_dynamic_duplicates_, eraselist_dynamic_, vertices);
if (vertices.size() != 0) {
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_DYNAMIC_DRAW);
/*Draw on damping*/
shader_drawblocks_.setFloat("color_multiplier", 1.f);
for (size_t i = 0; i < eraselist_dynamic_.size(); ++i) {
glDrawArrays(GL_TRIANGLES, 6 * i, 6);
}
}
eraselist_dynamic_.clear();
}
/*Draw static blocks*/
if (drawlist_static_.size() != 0) {
std::cout << "DRAWING STATIC" << std::endl;
glBindFramebuffer(GL_FRAMEBUFFER, fbo_static_);
glBindTexture(GL_TEXTURE_2D, tb.tex_wave_clean);
xywhs_to_vertices_(tb, std::vector<bool>(drawlist_static_.size(), false), drawlist_static_, vertices);
if (vertices.size() != 0) {
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_DYNAMIC_DRAW);
/*Draw on damping*/
shader_drawblocks_.setFloat("color_multiplier", 0.f);
for (size_t i = 0; i < drawlist_static_.size(); ++i) {
glDrawArrays(GL_TRIANGLES, 6 * i, 6);
}
/*Draw on wave*/
shader_drawblocks_.setFloat("color_multiplier", 1.f);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_wave_);
for (size_t i = 0; i < drawlist_static_.size(); ++i) {
glDrawArrays(GL_TRIANGLES, 6 * i, 6);
}
}
drawlist_static_.clear();
}
/*Draw dynamic blocks*/
if (drawlist_dynamic_.size() != 0) {
glBindFramebuffer(GL_FRAMEBUFFER, fbo_dynamic_);
glBindTexture(GL_TEXTURE_2D, tb.tex_wave_clean);
xywhs_to_vertices_(tb, drawlist_dynamic_duplicates_, drawlist_dynamic_, vertices);
if (vertices.size() != 0) {
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_DYNAMIC_DRAW);
/*Draw on damping*/
shader_drawblocks_.setFloat("color_multiplier", 0.f);
for (size_t i = 0; i < drawlist_dynamic_.size(); ++i) {
glDrawArrays(GL_TRIANGLES, 6 * i, 6);
}
/*Draw on wave*/
shader_drawblocks_.setFloat("color_multiplier", 1.f);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_wave_);
for (size_t i = 0; i < drawlist_dynamic_.size(); ++i) {
glDrawArrays(GL_TRIANGLES, 6 * i, 6);
}
}
drawlist_dynamic_.clear();
}
/*Drawing finished, reset OpenGL state*/
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
/*Clean up the blockchain*/
/* This doesn't work, because it invalidates all iterators/pointers, even in a list. See https://godbolt.org/z/GzxTExc44
blockchain_.erase(std::remove_if(blockchain_.begin(), blockchain_.end(), [](const Block& b) {return b.needs_removal(); }), blockchain_.end());
The following preserves iterator/pointer validity, which is what we need
*/
dragpairs_.remove_if([=](const std::pair<EfficientBlock*, SDL_FingerID>& dp) { return dp.first->needs_removal(); });
blockchain_.remove_if([=](const EfficientBlock& b) { return b.needs_removal(); });
}
bool SlimBlockchainHandler::in_wave_window_(const Toolbox& tb, const Pevent& pev) const {
return pev.fscoord_x < 1.f - tb.gui_pos;
}
void SlimBlockchainHandler::xywhs_to_vertices_(const Toolbox& tb, const std::vector<bool>& duplicates, const std::vector<glm::ivec4>& xywhs, std::vector<float>& vertices) const {
float texwidth = tb.texture_w;
float texheight = tb.texture_h;
vertices.clear();
vertices.reserve(24 * xywhs.size());
for (size_t i = 0; i < xywhs.size(); ++i) {
const glm::ivec4& xywh = xywhs[i];
if (duplicates[i]) {
continue;
}
float x = xywh.r >= 0 ? xywh.r : 0;
float y = xywh.g;
float w = xywh.r >= 0 ? xywh.b : xywh.b + xywh.r;
float h = xywh.a;
/*Lower Left Corner*/
vertices.push_back(2. * (x) / texwidth - 1.f); //x
vertices.push_back(2. * (y) / texheight - 1.f); //y
vertices.push_back((x) / texwidth); //u
vertices.push_back((y) / texheight); //v
/*Top Right Corner*/
vertices.push_back(2. * (x + w) / texwidth - 1.f); //x
vertices.push_back(2. * (y + h) / texheight - 1.f); //y
vertices.push_back((x + w) / texwidth); //u
vertices.push_back((y + h) / texheight); //v
/*Bottom Right Corner*/
vertices.push_back(2. * (x + w) / texwidth - 1.f); //x
vertices.push_back(2. * (y) / texheight - 1.f); //y
vertices.push_back((x + w) / texwidth); //u
vertices.push_back((y) / texheight); //v
/*Lower Left Corner*/
vertices.push_back(2. * (x) / texwidth - 1.f); //x
vertices.push_back(2. * (y) / texheight - 1.f); //y
vertices.push_back((x) / texwidth); //u
vertices.push_back((y) / texheight); //v
/*Top Right Corner*/
vertices.push_back(2. * (x + w) / texwidth - 1.f); //x
vertices.push_back(2. * (y + h) / texheight - 1.f); //y
vertices.push_back((x + w) / texwidth); //u
vertices.push_back((y + h) / texheight); //v
/*Top Left Corner*/
vertices.push_back(2. * (x) / texwidth - 1.f); //x
vertices.push_back(2. * (y + h) / texheight - 1.f); //y
vertices.push_back((x) / texwidth); //u
vertices.push_back((y + h) / texheight); //v
}
}
void SlimBlockchainHandler::find_dynamic_duplicates_() {
drawlist_dynamic_duplicates_ = std::vector<bool>(drawlist_dynamic_.size(), false);
eraselist_dynamic_duplicates_ = std::vector<bool>(eraselist_dynamic_.size(), false);
if (drawlist_dynamic_.size() == 0 || eraselist_dynamic_.size() == 0) {
return;
}
for (size_t i_draw = 0; i_draw < drawlist_dynamic_.size(); ++i_draw) {
const glm::ivec4 dr = drawlist_dynamic_[i_draw];
for (size_t i_erase = 0; i_erase < eraselist_dynamic_.size(); ++i_erase) {
if (eraselist_dynamic_duplicates_[i_erase] == true) {
continue;
}
const glm::ivec4 er = eraselist_dynamic_[i_erase];
if (dr.r == er.r && dr.g == er.g && dr.b == er.b && er.a == dr.a) {
drawlist_dynamic_duplicates_[i_draw] = true;
eraselist_dynamic_duplicates_[i_erase] = true;
break;
}
}
}
}