GraphicsTest/grid.cpp
2024-11-17 23:23:25 -06:00

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; }
}
}