2022-09-25 23:05:56 +00:00
|
|
|
#include "chunk.hpp"
|
2022-09-27 17:35:49 +00:00
|
|
|
|
2022-09-25 23:05:56 +00:00
|
|
|
namespace app {
|
|
|
|
|
2022-09-27 17:35:49 +00:00
|
|
|
//
|
|
|
|
// CHUNK CONSTRUCTORS AND DECONSTUCTORS
|
|
|
|
//
|
2022-09-25 23:05:56 +00:00
|
|
|
|
2022-09-26 17:24:16 +00:00
|
|
|
Chunk::Chunk(int32_t gridX, int32_t gridZ, uint32_t world_seed)
|
2022-09-25 23:05:56 +00:00
|
|
|
: world_seed{world_seed},
|
|
|
|
chunk_seed{(world_seed * gridX) + (world_seed * gridZ) / 2},
|
|
|
|
gridX{gridX},
|
|
|
|
gridZ{gridZ} {
|
2022-09-27 17:35:49 +00:00
|
|
|
chunkMesh = nullptr;
|
2022-09-25 23:05:56 +00:00
|
|
|
generate();
|
|
|
|
}
|
|
|
|
|
2022-09-27 17:35:49 +00:00
|
|
|
Chunk::~Chunk() {
|
|
|
|
if(worker.joinable())
|
|
|
|
worker.join();
|
2022-09-28 01:40:20 +00:00
|
|
|
xe::Model::deleteModel(chunkMesh);
|
2022-09-28 14:51:15 +00:00
|
|
|
vertexData.data.clear();
|
|
|
|
cubes.clear();
|
2022-09-27 17:35:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
2022-09-27 21:03:43 +00:00
|
|
|
// CHUNK CREATION, DELETION, AND RETREVAL
|
2022-09-27 17:35:49 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
static std::map<std::pair<int32_t, int32_t>, Chunk*> chunks{};
|
|
|
|
|
2022-09-26 17:24:16 +00:00
|
|
|
Chunk* Chunk::newChunk(int32_t gridX, int32_t gridZ, uint32_t world_seed) {
|
2022-09-26 15:03:27 +00:00
|
|
|
Chunk* chunk = new Chunk(gridX, gridZ, world_seed);
|
|
|
|
chunks[{gridX, gridZ}] = std::move(chunk);
|
|
|
|
return chunks[{gridX, gridZ}];
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
|
|
|
|
2022-09-26 17:24:16 +00:00
|
|
|
Chunk* Chunk::getChunk(int32_t gridX, int32_t gridZ) {
|
2022-09-26 15:03:27 +00:00
|
|
|
if(chunks.count({gridX, gridZ})) {
|
|
|
|
return chunks[{gridX, gridZ}];
|
|
|
|
} else {
|
2022-09-27 21:03:43 +00:00
|
|
|
return nullptr;
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-27 21:03:43 +00:00
|
|
|
void Chunk::deleteChunk(int32_t gridX, int32_t gridZ) {
|
|
|
|
Chunk* chunk = getChunk(gridX, gridZ);
|
|
|
|
if(chunk == nullptr) return; // Chunk does not exist or is already deleted
|
|
|
|
delete chunk;
|
|
|
|
chunks.erase({gridX, gridZ});
|
|
|
|
}
|
|
|
|
|
2022-09-27 17:35:49 +00:00
|
|
|
//
|
|
|
|
// CHUNK TEXTURE AND BLOCK LOADING
|
|
|
|
//
|
2022-09-25 23:05:56 +00:00
|
|
|
|
2022-09-27 00:57:53 +00:00
|
|
|
static std::map<uint8_t, Block> blocks{};
|
|
|
|
static std::map<std::string, uint32_t> texturesIds{};
|
|
|
|
static std::vector<xe::Image*> textures{};
|
|
|
|
|
|
|
|
void loadTexture(const std::string& filePath) {
|
2022-09-28 13:38:25 +00:00
|
|
|
xe::Image* image = xe::Image::createImage(filePath, false);
|
2022-09-27 00:57:53 +00:00
|
|
|
texturesIds[filePath] = static_cast<uint32_t>(textures.size());
|
|
|
|
textures.push_back(image);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t getTexture(const std::string& filePath) {
|
|
|
|
return texturesIds[filePath];
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<xe::Image*>& Chunk::getTextures() {
|
|
|
|
return textures;
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
|
|
|
|
2022-09-27 00:57:53 +00:00
|
|
|
void Chunk::load() {
|
|
|
|
loadTexture(DIRT_TEXTURE);
|
|
|
|
loadTexture(GRASS_TEXTURE);
|
|
|
|
loadTexture(GRASS_TOP_TEXTURE);
|
|
|
|
blocks[DIRT] = {{getTexture(DIRT_TEXTURE), getTexture(DIRT_TEXTURE), getTexture(DIRT_TEXTURE), getTexture(DIRT_TEXTURE), getTexture(DIRT_TEXTURE), getTexture(DIRT_TEXTURE)}};
|
|
|
|
blocks[GRASS] = {{getTexture(GRASS_TEXTURE), getTexture(GRASS_TEXTURE), getTexture(GRASS_TOP_TEXTURE), getTexture(DIRT_TEXTURE), getTexture(GRASS_TEXTURE), getTexture(GRASS_TEXTURE)}};
|
|
|
|
}
|
|
|
|
|
|
|
|
void Chunk::unload() {
|
|
|
|
for(const auto &image: textures) {
|
2022-09-28 13:38:25 +00:00
|
|
|
xe::Image::deleteImage(image);
|
2022-09-27 00:57:53 +00:00
|
|
|
}
|
2022-09-26 15:03:27 +00:00
|
|
|
for(const auto &[key, chunk]: chunks) {
|
|
|
|
delete chunk;
|
|
|
|
}
|
|
|
|
chunks.clear();
|
2022-09-27 00:57:53 +00:00
|
|
|
textures.clear();
|
|
|
|
}
|
|
|
|
|
2022-09-27 17:35:49 +00:00
|
|
|
//
|
|
|
|
// CHUNK MESH CREATION FOR BOTH SYNC AND ASYNC
|
|
|
|
//
|
2022-09-26 15:03:27 +00:00
|
|
|
|
2022-09-27 17:35:49 +00:00
|
|
|
void Chunk::createMeshAsync(Chunk* c) {
|
2022-09-27 21:03:43 +00:00
|
|
|
if(c == nullptr) return;
|
2022-09-27 17:35:49 +00:00
|
|
|
if(c->working) return;
|
2022-09-27 21:03:43 +00:00
|
|
|
if(c->worker.joinable())
|
|
|
|
c->worker.join();
|
2022-09-27 17:35:49 +00:00
|
|
|
c->worker = std::thread(createMesh, c);
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
|
|
|
|
2022-09-27 17:35:49 +00:00
|
|
|
void Chunk::createMesh(Chunk* c) {
|
2022-09-27 21:03:43 +00:00
|
|
|
if(c == nullptr) return;
|
2022-09-27 17:35:49 +00:00
|
|
|
c->vertexData.data.clear();
|
2022-09-26 17:24:16 +00:00
|
|
|
for(int32_t x=0;x<16;x++) {
|
|
|
|
for(int32_t y=0; y<256; y++) {
|
|
|
|
for(int32_t z=0; z<16; z++) {
|
2022-09-27 17:35:49 +00:00
|
|
|
uint8_t block = c->getBlock(x,y,z);
|
2022-09-25 23:05:56 +00:00
|
|
|
if(block == AIR) continue;
|
2022-09-27 17:35:49 +00:00
|
|
|
if(c->getBlock(x+1,y,z) == AIR) {
|
|
|
|
c->addVerticies(c, 0, x, y, z, block);
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
2022-09-27 17:35:49 +00:00
|
|
|
if(c->getBlock(x-1,y,z) == AIR) {
|
|
|
|
c->addVerticies(c, 1, x, y, z, block);
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
2022-09-27 17:35:49 +00:00
|
|
|
if(c->getBlock(x,y+1,z) == AIR) {
|
|
|
|
c->addVerticies(c, 2, x, y, z, block);
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
2022-09-27 17:35:49 +00:00
|
|
|
if(c->getBlock(x,y-1,z) == AIR) {
|
|
|
|
c->addVerticies(c, 3, x, y, z, block);
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
2022-09-27 17:35:49 +00:00
|
|
|
if(c->getBlock(x,y,z+1) == AIR) {
|
|
|
|
c->addVerticies(c, 4, x, y, z, block);
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
2022-09-27 17:35:49 +00:00
|
|
|
if(c->getBlock(x,y,z-1) == AIR) {
|
|
|
|
c->addVerticies(c, 5, x, y, z, block);
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-09-27 17:35:49 +00:00
|
|
|
c->working = false;
|
|
|
|
c->reloadRequired = true;
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
|
|
|
|
2022-09-27 17:35:49 +00:00
|
|
|
void Chunk::addVerticies(Chunk* c, uint8_t side, int32_t x, int32_t y, int32_t z, uint8_t block) {
|
2022-09-25 23:05:56 +00:00
|
|
|
for(int i = 0; i < 6; i ++) {
|
2022-09-27 17:35:49 +00:00
|
|
|
c->vertexData.write<float>(px[side * 6 + i][0] + x);
|
|
|
|
c->vertexData.write<float>(px[side * 6 + i][1] + y);
|
|
|
|
c->vertexData.write<float>(px[side * 6 + i][2] + z);
|
|
|
|
c->vertexData.write<float>(nm[side][0]);
|
|
|
|
c->vertexData.write<float>(nm[side][1]);
|
|
|
|
c->vertexData.write<float>(nm[side][2]);
|
|
|
|
c->vertexData.write<float>(uv[i][0]);
|
|
|
|
c->vertexData.write<float>(uv[i][1]);
|
|
|
|
c->vertexData.write<uint32_t>(static_cast<uint32_t>(blocks[block].textures[side]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// CHUNK GETTERS AND SETTORS
|
|
|
|
//
|
|
|
|
|
|
|
|
xe::Model* Chunk::getMesh() {
|
|
|
|
if(reloadRequired) {
|
2022-09-28 01:40:20 +00:00
|
|
|
if(chunkMesh != nullptr) {
|
|
|
|
xe::Model::deleteModel(chunkMesh);
|
|
|
|
chunkMesh = nullptr;
|
|
|
|
}
|
2022-09-27 17:35:49 +00:00
|
|
|
if(worker.joinable())
|
|
|
|
worker.join();
|
|
|
|
xe::Model::Builder builder{};
|
|
|
|
builder.vertexData = vertexData;
|
|
|
|
builder.vertexSize = 36;
|
2022-09-28 13:38:25 +00:00
|
|
|
chunkMesh = xe::Model::createModel(builder);
|
2022-09-27 17:35:49 +00:00
|
|
|
reloadRequired = false;
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
2022-09-27 17:35:49 +00:00
|
|
|
return chunkMesh;
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
|
|
|
|
2022-09-27 17:35:49 +00:00
|
|
|
uint8_t Chunk::getBlock(int32_t x, int32_t y, int32_t z) {
|
|
|
|
if(y > 256) return AIR;
|
|
|
|
if(y < 0) return INVALID;
|
|
|
|
int chunkX = gridX;
|
|
|
|
int chunkZ = gridZ;
|
|
|
|
if(x < 0) {
|
|
|
|
chunkX--;
|
|
|
|
} else if(x > 15) {
|
|
|
|
chunkX++;
|
|
|
|
}
|
|
|
|
if(z < 0) {
|
|
|
|
chunkZ--;
|
|
|
|
} else if(z > 15) {
|
|
|
|
chunkZ++;
|
|
|
|
}
|
|
|
|
x = (x+16)%16;
|
|
|
|
z = (z+16)%16;
|
|
|
|
if(chunkX == gridX && chunkZ == gridZ) {
|
|
|
|
int index = x + (z * 16) + (y * 256);
|
|
|
|
return cubes[index];
|
|
|
|
} else {
|
|
|
|
Chunk* chunk = getChunk(chunkX, chunkZ);
|
|
|
|
if(chunk == NULL) {
|
|
|
|
return INVALID;
|
|
|
|
} else {
|
|
|
|
int index = x + (z * 16) + (y * 256);
|
|
|
|
return chunk->cubes[index];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Chunk::setBlock(int32_t x, int32_t y, int32_t z, uint8_t block) {
|
|
|
|
int index = x + (z * 16) + (y * 256);
|
|
|
|
cubes[index] = block;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// CHUNK GENERATION
|
|
|
|
//
|
|
|
|
|
2022-09-25 23:05:56 +00:00
|
|
|
void Chunk::generate() {
|
2022-09-27 00:57:53 +00:00
|
|
|
cubes.resize(16*16*256);
|
2022-09-25 23:05:56 +00:00
|
|
|
|
2022-09-26 15:03:27 +00:00
|
|
|
const PerlinNoise perlin{world_seed};
|
2022-09-25 23:05:56 +00:00
|
|
|
|
|
|
|
for(int x = 0; x < 16; x++) {
|
|
|
|
for(int z = 0; z < 16; z++) {
|
2022-09-28 14:51:15 +00:00
|
|
|
int height = perlin.octave2D_01((( x + gridX * 16) * 0.01), ((z + gridZ * 16) * 0.01), 4) * 20;
|
2022-09-25 23:05:56 +00:00
|
|
|
for(int y = 0; y < 256; y++) {
|
2022-09-27 00:57:53 +00:00
|
|
|
if(y == height){
|
|
|
|
setBlock(x, y, z, GRASS);
|
|
|
|
} else if(y < height)
|
2022-09-25 23:05:56 +00:00
|
|
|
setBlock(x, y, z, DIRT);
|
|
|
|
else
|
|
|
|
setBlock(x, y, z, AIR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|