265 lines
9.0 KiB
C++
265 lines
9.0 KiB
C++
#include "Chunk.hpp"
|
|
#include "Platform.hpp"
|
|
#include "GlobalProperties.hpp"
|
|
#include "Blocks.hpp"
|
|
#include "Game.hpp"
|
|
#include "ChunkChangeHelper.hpp"
|
|
#include <cstring>
|
|
#include <cstddef>
|
|
#include <glm/glm.hpp>
|
|
#include <glm/gtc/type_ptr.hpp>
|
|
|
|
#define CXY (CX*CY)
|
|
#define I(x,y,z) (x+y*CX+z*CXY)
|
|
|
|
namespace Diggler {
|
|
|
|
const Program *Chunk::RenderProgram = nullptr;
|
|
Texture *Chunk::TextureAtlas = nullptr;
|
|
Blocks *Chunk::BlkInf = nullptr;
|
|
GLint Chunk::RenderProgram_attrib_texcoord = -1;
|
|
GLint Chunk::RenderProgram_attrib_coord = -1;
|
|
GLint Chunk::RenderProgram_attrib_color = -1;
|
|
GLint Chunk::RenderProgram_uni_mvp = -1;
|
|
|
|
constexpr float Chunk::CullSphereRadius;
|
|
constexpr float Chunk::MidX, Chunk::MidY, Chunk::MidZ;
|
|
|
|
Chunk::Chunk(bool buffer, int scx, int scy, int scz, Game *G) : blk2(nullptr),
|
|
scx(scx), scy(scy), scz(scz), G(G), vbo(nullptr), lavaCount(0) {
|
|
changed = true;
|
|
blk = new BlockType[CX*CY*CZ];
|
|
for (int i=0; i < CX*CY*CZ; ++i)
|
|
blk[i] = BlockType::Air;
|
|
|
|
if (!buffer && GlobalProperties::IsClient) {
|
|
vbo = new VBO;
|
|
ibo = new VBO;
|
|
if (RenderProgram == nullptr) {
|
|
RenderProgram = G->PM->getProgram(PM_3D | PM_TEXTURED | PM_COLORED | PM_FOG);
|
|
RenderProgram_attrib_coord = RenderProgram->att("coord");
|
|
RenderProgram_attrib_color = RenderProgram->att("color");
|
|
RenderProgram_attrib_texcoord = RenderProgram->att("texcoord");
|
|
RenderProgram_uni_mvp = RenderProgram->uni("mvp");
|
|
|
|
BlkInf = new Blocks();
|
|
|
|
TextureAtlas = BlkInf->getAtlas();
|
|
}
|
|
}
|
|
if (GlobalProperties::IsServer) {
|
|
blk2 = new BlockType[CX*CY*CZ];
|
|
}
|
|
}
|
|
|
|
Chunk::~Chunk() {
|
|
delete blk;
|
|
delete[] blk2;
|
|
delete vbo; delete ibo;
|
|
}
|
|
|
|
BlockType Chunk::get(int x, int y, int z) {
|
|
if ((x < 0 || y < 0 || z < 0 || x >= CX || y >= CY || z >= CZ) && G) {
|
|
return G->SC->get(scx * CX + x, scy * CY + y, scz * CZ + z);
|
|
}
|
|
return blk[I(x,y,z)];
|
|
}
|
|
|
|
void Chunk::set2(int x, int y, int z, BlockType type) {
|
|
if ((x < 0 || y < 0 || z < 0 || x >= CX || y >= CY || z >= CZ) && G)
|
|
return G->SC->set2(scx * CX + x, scy * CY + y, scz * CZ + z, type);
|
|
register BlockType *b = &(blk2[I(x,y,z)]);
|
|
if (*b == BlockType::Lava)
|
|
lavaCount--;
|
|
if (type == BlockType::Lava)
|
|
lavaCount++;
|
|
*b = type;
|
|
if (G && G->CCH)
|
|
G->CCH->add(scx * CX + x, scy * CY + y, scz * CZ + z, type);
|
|
}
|
|
|
|
void Chunk::set(int x, int y, int z, BlockType type) {
|
|
mut.lock();
|
|
if ((x < 0 || y < 0 || z < 0 || x >= CX || y >= CY || z >= CZ) && G)
|
|
return G->SC->set(scx * CX + x, scy * CY + y, scz * CZ + z, type);
|
|
register BlockType *b = &(blk[I(x,y,z)]);
|
|
if (*b == BlockType::Lava)
|
|
lavaCount--;
|
|
if (type == BlockType::Lava)
|
|
lavaCount++;
|
|
*b = type;
|
|
changed = true;
|
|
mut.unlock();
|
|
}
|
|
|
|
void Chunk::updateServerPrepare() {
|
|
memcpy(blk2, blk, CX*CY*CZ*sizeof(BlockType));
|
|
}
|
|
|
|
void Chunk::updateServer() {
|
|
if (lavaCount == 0)
|
|
return;
|
|
mut.lock();
|
|
for (int x=0; x < CX; x++)
|
|
for (int y=0; y < CY; y++)
|
|
for (int z=0; z < CZ; z++) {
|
|
if (blk[I(x,y,z)] == BlockType::Lava) {
|
|
BlockType under = get(x, y-1, z);
|
|
if (under == BlockType::Air) {
|
|
set2(x, y-1, z, BlockType::Lava);
|
|
} else if (under != BlockType::Lava) {
|
|
if (get(x+1, y, z) == BlockType::Air)
|
|
set2(x+1, y, z, BlockType::Lava);
|
|
if (get(x-1, y, z) == BlockType::Air)
|
|
set2(x-1, y, z, BlockType::Lava);
|
|
if (get(x, y, z+1) == BlockType::Air)
|
|
set2(x, y, z+1, BlockType::Lava);
|
|
if (get(x, y, z-1) == BlockType::Air)
|
|
set2(x, y, z-1, BlockType::Lava);
|
|
}
|
|
}
|
|
}
|
|
mut.unlock();
|
|
}
|
|
|
|
void Chunk::updateServerSwap() {
|
|
std::swap(blk, blk2);
|
|
}
|
|
|
|
void Chunk::updateClient() {
|
|
mut.lock();
|
|
GLCoord vertex[CX * CY * CZ * 6 /* faces */ * 6 /* vertices */ / 2 /* face removing (HSR) makes a lower vert max */];
|
|
GLushort index[CX * CY * CZ * 6 /* faces */ * 4 /* indexes */ / 2 /* HSR */];
|
|
int v = 0, i = 0;
|
|
|
|
BlockType bt;
|
|
const AtlasCreator::Coord *tc;
|
|
for(uint8 x = 0; x < CX; x++) {
|
|
for(uint8 y = 0; y < CY; y++) {
|
|
for(uint8 z = 0; z < CZ; z++) {
|
|
bt = blk[I(x,y,z)];
|
|
|
|
// Empty block?
|
|
if (!bt)
|
|
continue;
|
|
|
|
// View from negative x
|
|
if (Blocks::isFaceRemoved(bt, get(x - 1, y, z))) {
|
|
index[i++] = v; index[i++] = v+1; index[i++] = v+2;
|
|
index[i++] = v+3; index[i++] = v+2; index[i++] = v+1;
|
|
tc = BlkInf->gTC(bt, FaceDirection::XDec);
|
|
vertex[v++] = {x, y, z, tc->x, tc->v, .6f, .6f, .6f};
|
|
vertex[v++] = {x, y, z + 1, tc->u, tc->v, .6f, .6f, .6f};
|
|
vertex[v++] = {x, y + 1, z, tc->x, tc->y, .6f, .6f, .6f};
|
|
vertex[v++] = {x, y + 1, z + 1, tc->u, tc->y, .6f, .6f, .6f};
|
|
}
|
|
|
|
// View from positive x
|
|
if (Blocks::isFaceRemoved(bt, get(x + 1, y, z))) {
|
|
index[i++] = v; index[i++] = v+1; index[i++] = v+2;
|
|
index[i++] = v+3; index[i++] = v+2; index[i++] = v+1;
|
|
tc = BlkInf->gTC(bt, FaceDirection::XInc);
|
|
vertex[v++] = {x + 1, y, z, tc->u, tc->v, .6f, .6f, .6f};
|
|
vertex[v++] = {x + 1, y + 1, z, tc->u, tc->y, .6f, .6f, .6f};
|
|
vertex[v++] = {x + 1, y, z + 1, tc->x, tc->v, .6f, .6f, .6f};
|
|
vertex[v++] = {x + 1, y + 1, z + 1, tc->x, tc->y, .6f, .6f, .6f};
|
|
}
|
|
|
|
// Negative Y
|
|
if (Blocks::isFaceRemoved(bt, get(x, y - 1, z))) {
|
|
index[i++] = v; index[i++] = v+1; index[i++] = v+2;
|
|
index[i++] = v+3; index[i++] = v+2; index[i++] = v+1;
|
|
float shade = (blk[I(x,y,z)] == BlockType::Shock) ? 1.5f : .2f;;
|
|
tc = BlkInf->gTC(bt, FaceDirection::YDec);
|
|
vertex[v++] = {x, y, z, tc->x, tc->v, shade, shade, shade};
|
|
vertex[v++] = {x + 1, y, z, tc->u, tc->v, shade, shade, shade};
|
|
vertex[v++] = {x, y, z + 1, tc->x, tc->y, shade, shade, shade};
|
|
vertex[v++] = {x + 1, y, z + 1, tc->u, tc->y, shade, shade, shade};
|
|
}
|
|
|
|
// Positive Y
|
|
if (Blocks::isFaceRemoved(bt, get(x, y + 1, z))) {
|
|
index[i++] = v; index[i++] = v+1; index[i++] = v+2;
|
|
index[i++] = v+3; index[i++] = v+2; index[i++] = v+1;
|
|
tc = BlkInf->gTC(bt, FaceDirection::YInc);
|
|
vertex[v++] = {x, y + 1, z, tc->u, tc->v, .8f, .8f, .8f};
|
|
vertex[v++] = {x, y + 1, z + 1, tc->u, tc->y, .8f, .8f, .8f};
|
|
vertex[v++] = {x + 1, y + 1, z, tc->x, tc->v, .8f, .8f, .8f};
|
|
vertex[v++] = {x + 1, y + 1, z + 1, tc->x, tc->y, .8f, .8f, .8f};
|
|
}
|
|
|
|
// Negative Z
|
|
if (Blocks::isFaceRemoved(bt, get(x, y, z - 1))) {
|
|
index[i++] = v; index[i++] = v+1; index[i++] = v+2;
|
|
index[i++] = v+3; index[i++] = v+2; index[i++] = v+1;
|
|
tc = BlkInf->gTC(bt, FaceDirection::ZDec);
|
|
vertex[v++] = {x, y, z, tc->u, tc->v, .4f, .4f, .4f};
|
|
vertex[v++] = {x, y + 1, z, tc->u, tc->y, .4f, .4f, .4f};
|
|
vertex[v++] = {x + 1, y, z, tc->x, tc->v, .4f, .4f, .4f};
|
|
vertex[v++] = {x + 1, y + 1, z, tc->x, tc->y, .4f, .4f, .4f};
|
|
}
|
|
|
|
// Positive Z
|
|
if (Blocks::isFaceRemoved(bt, get(x, y, z + 1))) {
|
|
index[i++] = v; index[i++] = v+1; index[i++] = v+2;
|
|
index[i++] = v+3; index[i++] = v+2; index[i++] = v+1;
|
|
tc = BlkInf->gTC(bt, FaceDirection::ZInc);
|
|
vertex[v++] = {x, y, z + 1, tc->x, tc->v, .4f, .4f, .4f};
|
|
vertex[v++] = {x + 1, y, z + 1, tc->u, tc->v, .4f, .4f, .4f};
|
|
vertex[v++] = {x, y + 1, z + 1, tc->x, tc->y, .4f, .4f, .4f};
|
|
vertex[v++] = {x + 1, y + 1, z + 1, tc->u, tc->y, .4f, .4f, .4f};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
vertices = v;
|
|
vbo->setData(vertex, v);
|
|
indices = i;
|
|
ibo->setData(index, i);
|
|
changed = false;
|
|
mut.unlock();
|
|
}
|
|
|
|
void Chunk::render(const glm::mat4 &transform) {
|
|
if (changed)
|
|
updateClient();
|
|
if (!indices)
|
|
return;
|
|
|
|
RenderProgram->bind();
|
|
|
|
glEnableVertexAttribArray(RenderProgram_attrib_coord);
|
|
glEnableVertexAttribArray(RenderProgram_attrib_texcoord);
|
|
glEnableVertexAttribArray(RenderProgram_attrib_color);
|
|
glUniformMatrix4fv(RenderProgram_uni_mvp, 1, GL_FALSE, glm::value_ptr(transform));
|
|
|
|
TextureAtlas->bind();
|
|
vbo->bind();
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo->id);
|
|
glVertexAttribPointer(RenderProgram_attrib_coord, 3, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(GLCoord), 0);
|
|
glVertexAttribPointer(RenderProgram_attrib_texcoord, 2, GL_UNSIGNED_SHORT, GL_TRUE, sizeof(GLCoord), (GLvoid*)offsetof(GLCoord, tx));
|
|
glVertexAttribPointer(RenderProgram_attrib_color, 3, GL_FLOAT, GL_FALSE, sizeof(GLCoord), (GLvoid*)offsetof(GLCoord, r));
|
|
glDrawElements(GL_TRIANGLES, indices, GL_UNSIGNED_SHORT, nullptr);
|
|
|
|
glDisableVertexAttribArray(RenderProgram_attrib_color);
|
|
glDisableVertexAttribArray(RenderProgram_attrib_texcoord);
|
|
glDisableVertexAttribArray(RenderProgram_attrib_coord);
|
|
}
|
|
|
|
void Chunk::renderBatched(const glm::mat4& transform) {
|
|
if (changed)
|
|
updateClient();
|
|
if (!indices)
|
|
return;
|
|
|
|
glUniformMatrix4fv(RenderProgram_uni_mvp, 1, GL_FALSE, glm::value_ptr(transform));
|
|
vbo->bind();
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo->id);
|
|
glVertexAttribPointer(RenderProgram_attrib_coord, 3, GL_BYTE, GL_FALSE, sizeof(GLCoord), 0);
|
|
glVertexAttribPointer(RenderProgram_attrib_texcoord, 2, GL_UNSIGNED_SHORT, GL_TRUE, sizeof(GLCoord), (GLvoid*)offsetof(GLCoord, tx));
|
|
glVertexAttribPointer(RenderProgram_attrib_color, 3, GL_FLOAT, GL_FALSE, sizeof(GLCoord), (GLvoid*)offsetof(GLCoord, r));
|
|
glDrawElements(GL_TRIANGLES, indices, GL_UNSIGNED_SHORT, nullptr);
|
|
}
|
|
|
|
} |