#include "grid.h" namespace NB{ ConwayGridError::ConwayGridError(const std::string& msg) : std::runtime_error(msg) {} ConwayGrid::ConwayGrid( const Shader& shad, unsigned int m, unsigned int n, Vec2 bl, Vec2 tr ) : _buffer(shad, {{2, GL_FLOAT, false}, {3, GL_FLOAT, false}}, {{2, GL_FLOAT, false}, {1, GL_UNSIGNED_BYTE, false}} ), _m(m), _n(n), _bl(bl), _tr(tr) { if ( (_m < 2) || (_n < 2) ) { throw ConwayGridError("Grid size must be at least 2x2."); } std::vector vaps(2); unsigned int vertPosChunkDataSize = (_m+1)*(_n+1)*8; vaps[0].divisor = 1; vaps[0].stride = 2*GLSLTypeSize(GL_FLOAT); vaps[1].divisor = 1; vaps[1].offset = _m*_n*2*GLSLTypeSize(GL_FLOAT); vaps[1].stride = GLSLTypeSize(GL_UNSIGNED_BYTE); _buffer.changeInstanceLayout(0, vaps[0]); _buffer.changeInstanceLayout(1, vaps[1]); _cell_size.x = (_tr.x-_bl.x)/float(_m); _cell_size.y = (_tr.y-_bl.y)/float(_n); _cell_verts = { 0.0, 0.0, 1.0, 0.0, 0.0, _cell_size.x, 0.0, 0.0, 1.0, 0.0, 0.0, _cell_size.y, 0.0, 1.0, 0.0, _cell_size.x, _cell_size.y, 0.0, 0.0, 1.0 }; _cell_offsets = std::vector(_m*_n*2); _cells = CellGrid(_n, std::vector(_m, Cell::Dead)); for (int i = 0; i < _n; ++i) { for(int j = 0; j < _m; ++j) { _cell_offsets[(_m*i+j)*2 ] = _cell_size.x*j + _bl.x; _cell_offsets[(_m*i+j)*2 + 1] = _cell_size.y*i + _bl.y; } } _buffer.keepLocalElement(false); _buffer.keepLocalVertex(false); NB_GL_DEBUG(_buffer.generateEBO({0, 2, 3, 0, 3, 1})); NB_GL_DEBUG(_buffer.generateVBO(vectorToRaw(_cell_verts))); _buffer.generateIBO(_m*_n); RawVec cell_offs_raw = vectorToRaw(_cell_offsets); _buffer.loadIBO(cell_offs_raw); sendCells(); } ConwayGrid::CellGrid ConwayGrid::getCells() const { return _cells; } void ConwayGrid::setCells(const ConwayGrid::CellGrid& set_cells) { if (set_cells.size() != _n) { throw ConwayGridError("New cell grid with " + std::to_string(set_cells.size()) + " rows does not match ConwayGrid of " + std::to_string(_n) + " rows."); } for (const std::vector& row : set_cells) { if (row.size() != _m) { throw ConwayGridError("New cell grid with " + std::to_string(set_cells.size()) + " columns does not match ConwayGrid of " + std::to_string(_n) + " columns."); } } _cells = set_cells; } void ConwayGrid::sendCells() { unsigned int curr_byte = vectorToRaw(_cell_offsets).size(); for (int i = 0; i < _n; ++i) { _buffer.loadIBO(vectorToRaw(_cells[i]), curr_byte); curr_byte += _cells[i].size(); } } void ConwayGrid::calcNext() { decltype(_cells) prev = _cells; int numAlive = 0; for (int i = 0; i < _n; ++i) { for (int j = 0; j < _m; ++j) { numAlive = 0; if (j != 0) { numAlive += prev[i][j-1]; if (i != 0) { numAlive += prev[i-1][j-1]; } if (i != _n-1) { numAlive += prev[i+1][j-1]; } } if (j != _m-1) { numAlive += prev[i][j+1]; if (i != 0) { numAlive += prev[i-1][j+1]; } if (i != _n-1) { numAlive += prev[i+1][j+1]; } } if (i != 0) { numAlive += prev[i-1][j]; } if (i != _n-1) { numAlive += prev[i+1][j]; } if (_cells[i][j]) { if ((numAlive<2) || (numAlive>3)) { _cells[i][j] = Cell::Dead; } } else { if (numAlive==3) { _cells[i][j] = Cell::Alive; } } } } } void ConwayGrid::draw() { _buffer.draw(); } Cell& ConwayGrid::at(unsigned int x, unsigned int y) { if ((x<0) || (_n<=y) || (y<0) || (_m<=y)) { throw ConwayGridError("Indices of x=" + std::to_string(x) + " and y=" + std::to_string(y) + " are out of bounds."); } return _cells[y][x]; } void ConwayGrid::click(double x, double y) { x = x*2-1; y = y*-2+1; if (!(_bl.x x) { if (j) { j--; } break; } } for (; i<_n; ++i) { if (_cell_offsets[_m*i*2+1] > y) { if (i) { i--; } break; } } i = (i<_n) ? i : _n-1; j = (j<_m) ? j : _m-1; unsigned char prev = at(j, i); if (prev) { at(j,i)=Cell::Dead; } else { at(j, i)=Cell::Alive; } } }