157 lines
4.9 KiB
C++
157 lines
4.9 KiB
C++
#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<VertexAttributePointer> 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<float>(_m*_n*2);
|
|
_cells = CellGrid(_n, std::vector<Cell>(_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<Cell>& 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 && x<_tr.x) || !(_bl.y<y && y<_tr.y)) {
|
|
return;
|
|
}
|
|
int i=0, j=0;
|
|
for (; j < _m; ++j) {
|
|
if (_cell_offsets[j*2] > 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; }
|
|
}
|
|
|
|
} |