+bool Chunk::Obstructed(int idx) const {
+ Chunk::Pos pos(ToPos(idx));
+
+ Chunk::Pos left_pos(pos + Chunk::Pos(-1, 0, 0));
+ const Block *left_block = nullptr;
+ if (InBounds(left_pos)) {
+ left_block = &BlockAt(left_pos);
+ } else if (HasNeighbor(Block::FACE_LEFT)) {
+ left_pos += Chunk::Pos(Width(), 0, 0);
+ left_block = &GetNeighbor(Block::FACE_LEFT).BlockAt(left_pos);
+ } else {
+ return false;
+ }
+ if (!Type(*left_block).FaceFilled(*left_block, Block::FACE_RIGHT)) {
+ return false;
+ }
+
+ Chunk::Pos right_pos(pos + Chunk::Pos(1, 0, 0));
+ const Block *right_block = nullptr;
+ if (InBounds(right_pos)) {
+ right_block = &BlockAt(right_pos);
+ } else if (HasNeighbor(Block::FACE_RIGHT)) {
+ right_pos += Chunk::Pos(-Width(), 0, 0);
+ right_block = &GetNeighbor(Block::FACE_RIGHT).BlockAt(right_pos);
+ } else {
+ return false;
+ }
+ if (!Type(*right_block).FaceFilled(*right_block, Block::FACE_LEFT)) {
+ return false;
+ }
+
+ Chunk::Pos down_pos(pos + Chunk::Pos(0, -1, 0));
+ const Block *down_block = nullptr;
+ if (InBounds(down_pos)) {
+ down_block = &BlockAt(down_pos);
+ } else if (HasNeighbor(Block::FACE_DOWN)) {
+ down_pos += Chunk::Pos(0, Height(), 0);
+ down_block = &GetNeighbor(Block::FACE_DOWN).BlockAt(down_pos);
+ } else {
+ return false;
+ }
+ if (!Type(*down_block).FaceFilled(*down_block, Block::FACE_UP)) {
+ return false;
+ }
+
+ Chunk::Pos up_pos(pos + Chunk::Pos(0, 1, 0));
+ const Block *up_block = nullptr;
+ if (InBounds(up_pos)) {
+ up_block = &BlockAt(up_pos);
+ } else if (HasNeighbor(Block::FACE_UP)) {
+ up_pos += Chunk::Pos(0, -Height(), 0);
+ up_block = &GetNeighbor(Block::FACE_UP).BlockAt(up_pos);
+ } else {
+ return false;
+ }
+ if (!Type(*up_block).FaceFilled(*up_block, Block::FACE_DOWN)) {
+ return false;
+ }
+
+ Chunk::Pos back_pos(pos + Chunk::Pos(0, 0, -1));
+ const Block *back_block = nullptr;
+ if (InBounds(back_pos)) {
+ back_block = &BlockAt(back_pos);
+ } else if (HasNeighbor(Block::FACE_BACK)) {
+ back_pos += Chunk::Pos(0, 0, Depth());
+ back_block = &GetNeighbor(Block::FACE_BACK).BlockAt(back_pos);
+ } else {
+ return false;
+ }
+ if (!Type(*back_block).FaceFilled(*back_block, Block::FACE_FRONT)) {
+ return false;
+ }
+
+ Chunk::Pos front_pos(pos + Chunk::Pos(0, 0, 1));
+ const Block *front_block = nullptr;
+ if (InBounds(front_pos)) {
+ front_block = &BlockAt(front_pos);
+ } else if (HasNeighbor(Block::FACE_FRONT)) {
+ front_pos += Chunk::Pos(0, 0, -Depth());
+ front_block = &GetNeighbor(Block::FACE_FRONT).BlockAt(front_pos);
+ } else {
+ return false;
+ }
+ if (!Type(*front_block).FaceFilled(*front_block, Block::FACE_BACK)) {
+ return false;
+ }
+
+ return true;
+}
+
+glm::mat4 Chunk::ToTransform(int idx) const {
+ return glm::translate(glm::mat4(1.0f), ToCoords(idx)) * blocks[idx].Transform();
+}
+