A lot of changes in almost all files

This commit is contained in:
MihailRis
2022-02-28 02:30:15 +03:00
committed by GitHub
parent cd3e737385
commit bc9d29cf68
28 changed files with 3485 additions and 476 deletions
+1
View File
@@ -11,6 +11,7 @@ public:
unsigned char emission[3];
unsigned char drawGroup = 0;
bool lightPassing = false;
bool skyLightPassing = false;
bool obstacle = true;
Block(unsigned int id, int texture);
+8
View File
@@ -27,3 +27,11 @@ bool Chunk::isEmpty(){
}
return true;
}
Chunk* Chunk::clone() const {
Chunk* other = new Chunk(x,y,z);
for (int i = 0; i < CHUNK_VOL; i++)
other->voxels[i] = voxels[i];
other->lightmap->set(lightmap);
return other;
}
+5
View File
@@ -15,10 +15,15 @@ public:
voxel* voxels;
Lightmap* lightmap;
bool modified = true;
bool ready = false;
bool accepted = false;
bool generated = false;
Chunk(int x, int y, int z);
~Chunk();
bool isEmpty();
Chunk* clone() const;
};
#endif /* VOXELS_CHUNK_H_ */
+51 -117
View File
@@ -6,14 +6,8 @@
#include "../lighting/Lightmap.h"
#include "../files/WorldFiles.h"
#include "../lighting/Lighting.h"
#include "../graphics/VoxelRenderer.h"
#include "../graphics/Mesh.h"
#include <glm/glm.hpp>
using namespace glm;
#include <math.h>
#include <limits.h>
@@ -38,77 +32,6 @@ Chunks::~Chunks(){
delete[] chunks;
}
bool Chunks::_buildMeshes(VoxelRenderer* renderer) {
int nearX = 0;
int nearY = 0;
int nearZ = 0;
int minDistance = 1000000000;
for (unsigned int y = 0; y < h; y++){
for (unsigned int z = 1; z < d-1; z++){
for (unsigned int x = 1; x < w-1; x++){
int index = (y * d + z) * w + x;
Chunk* chunk = chunks[index];
if (chunk == nullptr)
continue;
Mesh* mesh = meshes[index];
if (mesh != nullptr && !chunk->modified)
continue;
int lx = x - w / 2;
int ly = y - h / 2;
int lz = z - d / 2;
int distance = (lx * lx + ly * ly + lz * lz);
if (distance < minDistance){
minDistance = distance;
nearX = x;
nearY = y;
nearZ = z;
}
}
}
}
int index = (nearY * d + nearZ) * w + nearX;
Chunk* closes[27];
Chunk* chunk = chunks[index];
if (chunk == nullptr)
return false;
Mesh* mesh = meshes[index];
if (mesh == nullptr || chunk->modified){
if (mesh != nullptr)
delete mesh;
if (chunk->isEmpty()){
meshes[index] = nullptr;
return false;
}
chunk->modified = false;
for (int i = 0; i < 27; i++)
closes[i] = nullptr;
for (size_t j = 0; j < volume; j++){
Chunk* other = chunks[j];
if (other == nullptr)
continue;
int ox = other->x - chunk->x;
int oy = other->y - chunk->y;
int oz = other->z - chunk->z;
if (abs(ox) > 1 || abs(oy) > 1 || abs(oz) > 1)
continue;
ox += 1;
oy += 1;
oz += 1;
closes[(oy * 3 + oz) * 3 + ox] = other;
}
mesh = renderer->render(chunk, (const Chunk**)closes);
meshes[index] = mesh;
return true;
}
return false;
}
voxel* Chunks::get(int x, int y, int z){
x -= ox * CHUNK_W;
y -= oy * CHUNK_H;
@@ -158,6 +81,27 @@ unsigned char Chunks::getLight(int x, int y, int z, int channel){
return chunk->lightmap->get(lx,ly,lz, channel);
}
unsigned short Chunks::getLight(int x, int y, int z){
x -= ox * CHUNK_W;
y -= oy * CHUNK_H;
z -= oz * CHUNK_D;
int cx = x / CHUNK_W;
int cy = y / CHUNK_H;
int cz = z / CHUNK_D;
if (x < 0) cx--;
if (y < 0) cy--;
if (z < 0) cz--;
if (cx < 0 || cy < 0 || cz < 0 || cx >= w || cy >= h || cz >= d)
return 0;
Chunk* chunk = chunks[(cy * d + cz) * w + cx];
if (chunk == nullptr)
return 0;
int lx = x - cx * CHUNK_W;
int ly = y - cy * CHUNK_H;
int lz = z - cz * CHUNK_D;
return chunk->lightmap->get(lx,ly,lz);
}
Chunk* Chunks::getChunkByVoxel(int x, int y, int z){
x -= ox * CHUNK_W;
y -= oy * CHUNK_H;
@@ -317,46 +261,6 @@ void Chunks::setCenter(WorldFiles* worldFiles, int x, int y, int z) {
translate(worldFiles, cx,cy,cz);
}
bool Chunks::loadVisible(WorldFiles* worldFiles){
int nearX = 0;
int nearY = 0;
int nearZ = 0;
int minDistance = (w/2)*(w/2);
for (unsigned int y = 0; y < h; y++){
for (unsigned int z = 1; z < d-1; z++){
for (unsigned int x = 1; x < w-1; x++){
int index = (y * d + z) * w + x;
Chunk* chunk = chunks[index];
if (chunk != nullptr)
continue;
int lx = x - w / 2;
int ly = y - h / 2;
int lz = z - d / 2;
int distance = (lx * lx + ly * ly + lz * lz);
if (distance < minDistance){
minDistance = distance;
nearX = x;
nearY = y;
nearZ = z;
}
}
}
}
int index = (nearY * d + nearZ) * w + nearX;
Chunk* chunk = chunks[index];
if (chunk != nullptr)
return false;
chunk = new Chunk(nearX+ox,nearY+oy,nearZ+oz);
if (!worldFiles->getChunk(chunk->x, chunk->z, (char*)chunk->voxels)){
WorldGenerator::generate(chunk->voxels, chunk->x, chunk->y, chunk->z);
}
chunks[index] = chunk;
Lighting::onChunkLoaded(ox+nearX, oy+nearY, oz+nearZ);
return true;
}
void Chunks::translate(WorldFiles* worldFiles, int dx, int dy, int dz){
for (unsigned int i = 0; i < volume; i++){
chunksSecond[i] = nullptr;
@@ -395,3 +299,33 @@ void Chunks::translate(WorldFiles* worldFiles, int dx, int dy, int dz){
oy += dy;
oz += dz;
}
void Chunks::_setOffset(int x, int y, int z){
ox = x;
oy = y;
oz = z;
}
bool Chunks::putChunk(Chunk* chunk) {
int x = chunk->x;
int y = chunk->y;
int z = chunk->z;
x -= ox;
y -= oy;
z -= oz;
if (x < 0 || y < 0 || z < 0 || x >= w || y >= h || z >= d)
return false;
chunks[(y * d + z) * w + x] = chunk;
return true;
}
void Chunks::clear(bool freeMemory){
for (size_t i = 0; i < volume; i++){
if (freeMemory){
delete chunks[i];
delete meshes[i];
}
chunks[i] = nullptr;
meshes[i] = nullptr;
}
}
+7 -2
View File
@@ -26,20 +26,25 @@ public:
Chunks(int w, int h, int d, int ox, int oy, int oz);
~Chunks();
bool putChunk(Chunk* chunk);
Chunk* getChunk(int x, int y, int z);
Chunk* getChunkByVoxel(int x, int y, int z);
voxel* get(int x, int y, int z);
unsigned short getLight(int x, int y, int z);
unsigned char getLight(int x, int y, int z, int channel);
void set(int x, int y, int z, int id);
voxel* rayCast(vec3 start, vec3 dir, float maxLength, vec3& end, vec3& norm, vec3& iend);
bool isObstacle(int x, int y, int z);
// does not move chunks inside
void _setOffset(int x, int y, int z);
void setCenter(WorldFiles* worldFiles, int x, int y, int z);
void translate(WorldFiles* worldFiles, int x, int y, int z);
bool loadVisible(WorldFiles* worldFiles);
bool _buildMeshes(VoxelRenderer* renderer);
void clear(bool freeMemory);
};
#endif /* VOXELS_CHUNKS_H_ */
+209
View File
@@ -0,0 +1,209 @@
#include "ChunksController.h"
#include "Chunk.h"
#include "Chunks.h"
#include "WorldGenerator.h"
#include "../graphics/Mesh.h"
#include "../graphics/VoxelRenderer.h"
#include "../lighting/Lighting.h"
#include "../files/WorldFiles.h"
#include "ChunksLoader.h"
#include <iostream>
#define LOADERS_COUNT 3
ChunksController::ChunksController(Chunks* chunks, Lighting* lighting) : chunks(chunks), lighting(lighting){
loaders = new ChunksLoader*[LOADERS_COUNT];
for (int i = 0; i < LOADERS_COUNT; i++){
loaders[i] = new ChunksLoader();
}
}
ChunksController::~ChunksController(){
for (int i = 0; i < LOADERS_COUNT; i++)
delete loaders[i];
delete[] loaders;
}
bool ChunksController::loadVisible(WorldFiles* worldFiles){
const int w = chunks->w;
const int h = chunks->h;
const int d = chunks->d;
const int ox = chunks->ox;
const int oy = chunks->oy;
const int oz = chunks->oz;
int nearX = 0;
int nearY = 0;
int nearZ = 0;
int minDistance = (w/2)*(w/2);
for (int y = 0; y < h; y++){
for (int z = 2; z < d-2; z++){
for (int x = 2; x < w-2; x++){
int index = (y * d + z) * w + x;
Chunk* chunk = chunks->chunks[index];
if (chunk != nullptr)
continue;
int lx = x - w / 2;
int ly = y - h / 2;
int lz = z - d / 2;
int distance = (lx * lx + ly * ly + lz * lz);
if (distance < minDistance){
minDistance = distance;
nearX = x;
nearY = y;
nearZ = z;
}
}
}
}
int index = (nearY * d + nearZ) * w + nearX;
Chunk* chunk = chunks->chunks[index];
if (chunk != nullptr)
return false;
ChunksLoader* freeLoader = nullptr;
for (int i = 0; i < LOADERS_COUNT; i++){
ChunksLoader* loader = loaders[i];
if (loader->isBusy())
continue;
freeLoader = loader;
break;
}
if (freeLoader == nullptr)
return false;
chunk = new Chunk(nearX+ox,nearY+oy,nearZ+oz);
if (worldFiles->getChunk(chunk->x, chunk->z, (char*)chunk->voxels))
chunk->generated = true;
chunks->chunks[index] = chunk;
Chunk* closes[27];
for (int i = 0; i < 27; i++)
closes[i] = nullptr;
for (size_t j = 0; j < chunks->volume; j++){
Chunk* other = chunks->chunks[j];
if (other == nullptr)
continue;
if (!other->ready)
continue;
int ox = other->x - chunk->x;
int oy = other->y - chunk->y;
int oz = other->z - chunk->z;
if (abs(ox) > 1 || abs(oy) > 1 || abs(oz) > 1)
continue;
ox += 1;
oy += 1;
oz += 1;
closes[(oy * 3 + oz) * 3 + ox] = other;
}
freeLoader->perform(chunk, (const Chunk**)closes);
return true;
}
bool ChunksController::_buildMeshes(VoxelRenderer* renderer, int tick) {
const int w = chunks->w;
const int h = chunks->h;
const int d = chunks->d;
int nearX = 0;
int nearY = 0;
int nearZ = 0;
int minDistance = 1000000000;
for (int y = 0; y < h; y++){
for (int z = 1; z < d-1; z++){
for (int x = 1; x < w-1; x++){
int index = (y * d + z) * w + x;
Chunk* chunk = chunks->chunks[index];
if (chunk == nullptr)
continue;
Mesh* mesh = chunks->meshes[index];
if (mesh != nullptr && !chunk->modified)
continue;
if (!chunk->ready){
continue;
}
int lx = x - w / 2;
int ly = y - h / 2;
int lz = z - d / 2;
int distance = (lx * lx + ly * ly + lz * lz);
if (distance < minDistance){
minDistance = distance;
nearX = x;
nearY = y;
nearZ = z;
}
}
}
}
int index = (nearY * d + nearZ) * w + nearX;
Chunk* chunk = chunks->chunks[index];
if (chunk == nullptr){
for (int y = 0; y < h; y++){
for (int z = 1; z < d-1; z++){
for (int x = 1; x < w-1; x++){
int index = (y * d + z) * w + x;
chunk = chunks->chunks[index];
if (chunk != nullptr && chunk->ready && !chunk->accepted){
int lx = x - w / 2;
int ly = y - h / 2;
int lz = z - d / 2;
int distance = (lx * lx + ly * ly + lz * lz);
lighting->onChunkLoaded(chunk->x, chunk->y, chunk->z, false);
for (int i = 0; i < chunks->volume; i++){
Chunk* other = chunks->chunks[i];
if (other)
other->modified = true;
}
chunk->accepted = true;
std::cout << "1: built mesh for " << chunk << std::endl;
return true;
}
}
}
}
return false;
}
Mesh* mesh = chunks->meshes[index];
if (mesh == nullptr || chunk->modified){
Chunk* closes[27];
if (mesh != nullptr)
delete mesh;
if (chunk->isEmpty()){
chunks->meshes[index] = nullptr;
return false;
}
chunk->modified = false;
for (int i = 0; i < 27; i++)
closes[i] = nullptr;
for (size_t j = 0; j < chunks->volume; j++){
Chunk* other = chunks->chunks[j];
if (other == nullptr)
continue;
if (!other->ready)
continue;
int ox = other->x - chunk->x;
int oy = other->y - chunk->y;
int oz = other->z - chunk->z;
if (abs(ox) > 1 || abs(oy) > 1 || abs(oz) > 1)
continue;
ox += 1;
oy += 1;
oz += 1;
closes[(oy * 3 + oz) * 3 + ox] = other;
}
mesh = renderer->render(chunk, (const Chunk**)closes);
chunks->meshes[index] = mesh;
//std::cout << "2: built mesh for " << chunk << std::endl;
return true;
}
return false;
}
+23
View File
@@ -0,0 +1,23 @@
#ifndef VOXELS_CHUNKSCONTROLLER_H_
#define VOXELS_CHUNKSCONTROLLER_H_
class Chunks;
class Lighting;
class WorldFiles;
class VoxelRenderer;
class ChunksLoader;
class ChunksController {
private:
Chunks* chunks;
Lighting* lighting;
ChunksLoader** loaders;
public:
ChunksController(Chunks* chunks, Lighting* lighting);
~ChunksController();
bool loadVisible(WorldFiles* worldFiles);
bool _buildMeshes(VoxelRenderer* renderer, int tick);
};
#endif /* VOXELS_CHUNKSCONTROLLER_H_ */
+64
View File
@@ -0,0 +1,64 @@
#include "ChunksLoader.h"
#include <chrono>
#include "Chunk.h"
#include "Chunks.h"
#include "WorldGenerator.h"
#include "../lighting/Lighting.h"
#include <iostream>
void ChunksLoader::_thread(){
Chunks chunks(3,3,3, -1,-1,-1);
Lighting lighting(&chunks);
while (working){
if (current == nullptr){
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
Chunk* chunk = current;
//std::cout << "LOADER: received chunk " << chunk->x << " " << chunk->y << " " << chunk->z << std::endl;
chunks._setOffset(chunk->x-1, chunk->y-1, chunk->z-1);
if (!chunk->generated){
WorldGenerator::generate(chunk->voxels, chunk->x, chunk->y, chunk->z);
//std::cout << "LOADER: generated chunk" << std::endl;
}
/*for (int i = 0; i < 27; i++){
Chunk* other = closes[i];
if (other == nullptr)
continue;
chunks.putChunk(other);
}*/
chunks.putChunk(chunk);
lighting.onChunkLoaded(chunk->x, chunk->y, chunk->z, true);
chunks.clear(false);
for (int i = 0; i < 27; i++){
Chunk* other = closes[i];
delete other;
}
chunk->ready = true;
current = nullptr;
//std::cout << "LOADER: success" << std::endl;
}
}
void ChunksLoader::perform(Chunk* chunk, const Chunk** cs){
if (isBusy()){
std::cerr << "performing while busy" << std::endl;
return;
}
if (closes == nullptr){
closes = new Chunk*[27];
}
for (int i = 0; i < 27; i++){
const Chunk* other = cs[i];
if (other == nullptr)
closes[i] = nullptr;
else
closes[i] = other->clone();
}
current = chunk;
}
+36
View File
@@ -0,0 +1,36 @@
#ifndef VOXELS_CHUNKSLOADER_H_
#define VOXELS_CHUNKSLOADER_H_
#include <thread>
#include <atomic>
class Chunk;
class ChunksLoader final {
private:
std::thread loaderThread;
void _thread();
std::atomic<Chunk*> current {nullptr};
std::atomic<Chunk**> closes {nullptr};
std::atomic<bool> working {true};
public:
ChunksLoader() : loaderThread{} {
loaderThread = std::thread{&ChunksLoader::_thread, this};
}
~ChunksLoader(){
working = false;
loaderThread.join();
}
bool isBusy(){
return current != nullptr;
}
void perform(Chunk* chunk, const Chunk** closes);
void stop(){
working = false;
}
};
#endif /* VOXELS_CHUNKSLOADER_H_ */
+113 -13
View File
@@ -5,29 +5,129 @@
#include <math.h>
#include <glm/glm.hpp>
#include <glm/gtc/noise.hpp>
#define FNL_IMPL
#include "../maths/FastNoiseLite.h"
#include <time.h>
class PseudoRandom {
unsigned seed;
public:
PseudoRandom(){
seed = (unsigned)time(0);
}
int rand(){
seed = (8253729 * seed + 2396403);
return seed % 32768;
}
void setSeed(int number){
seed = (unsigned)number+8253729;
rand();
}
};
float calc_height(fnl_state *noise, int real_x, int real_z){
const float s = 0.2f;
float height = fnlGetNoise3D(noise, real_x*0.0125f*s*32,real_z*0.0125f*s*32, 0.0f);
height += fnlGetNoise3D(noise, real_x*0.025f*s*32,real_z*0.025f*s*32, 0.0f)*0.5f;
height += fnlGetNoise3D(noise, real_x*0.05f*s*32,real_z*0.05f*s*32, 0.0f)*0.25f;
height += fnlGetNoise3D(noise, real_x*0.1f*s*32,real_z*0.1f*s*32, 0.0f)*0.225f;
height += fnlGetNoise3D(noise, real_x*0.2f*s*32,real_z*0.2f*s*32, 0.0f)*0.125f;
height += fnlGetNoise3D(noise, real_x*0.4f*s*32,real_z*0.4f*s*32, 0.0f)*0.125f*0.5F;
height = height * 0.5f + 0.5f;
height *= height;
height *= (140.0f)*0.12f/s;
height += (42)*0.12f/s;
return height;
}
float calc_height_faster(fnl_state *noise, int real_x, int real_z){
const float s = 0.2f;
float height = fnlGetNoise3D(noise, real_x*0.0125f*s*32,real_z*0.0125f*s*32, 0.0f);
height += fnlGetNoise3D(noise, real_x*0.025f*s*32,real_z*0.025f*s*32, 0.0f)*0.5f;
height += fnlGetNoise3D(noise, real_x*0.05f*s*32,real_z*0.05f*s*32, 0.0f)*0.25f;
height += fnlGetNoise3D(noise, real_x*0.1f*s*32,real_z*0.1f*s*32, 0.0f)*0.225f;
height += fnlGetNoise3D(noise, real_x*0.2f*s*32,real_z*0.2f*s*32, 0.0f)*0.125f;
//height += fnlGetNoise3D(noise, real_x*0.4f*s*32,real_z*0.4f*s*32, 0.0f)*0.125f*0.5F;
height = height * 0.5f + 0.5f;
height *= height;
height *= (140.0f)*0.12f/s;
height += (42)*0.12f/s;
return height;
}
#include <iostream>
int generate_tree(fnl_state *noise, PseudoRandom* random, const float* heights, int real_x, int real_y, int real_z, int tileSize){
const int tileX = floor((double)real_x/(double)tileSize);
const int tileY = floor((double)real_z/(double)tileSize);
random->setSeed(tileX*4325261+tileY*12160951+tileSize*9431111);
bool gentree = fnlGetNoise3D(noise, tileX*3.0f+633, 0.0, tileY*3.0f) > -0.1f && (random->rand() % 10) < 7;
if (!gentree)
return 0;
const int randomX = (random->rand() % (tileSize/2)) - tileSize/4;
const int randomZ = (random->rand() % (tileSize/2)) - tileSize/4;
int centerX = tileX * tileSize + tileSize/2 + randomX;
int centerY = tileY * tileSize + tileSize/2 + randomZ;
int height = (int)calc_height_faster(noise, centerX, centerY);
if (height < 55)
return 0;
int lx = real_x - centerX;
int radius = random->rand() % 4 + 3;
int ly = real_y - height - 3 * radius;
int lz = real_z - centerY;
if (lx == 0 && lz == 0 && real_y - height < 4*radius)
return 6;
if (lx*lx+ly*ly/2+lz*lz < radius*radius)
return 7;
return 0;
}
void WorldGenerator::generate(voxel* voxels, int cx, int cy, int cz){
const float s = 0.25f;
fnl_state noise = fnlCreateState();
noise.noise_type = FNL_NOISE_OPENSIMPLEX2;
PseudoRandom random;
float heights[CHUNK_VOL];
for (int z = 0; z < CHUNK_D; z++){
for (int x = 0; x < CHUNK_W; x++){
int real_x = x + cx * CHUNK_W;
int real_z = z + cz * CHUNK_D;
float height = glm::perlin(glm::vec3(real_x*0.0125f*s,real_z*0.0125f*s, 0.0f));
height += glm::perlin(glm::vec3(real_x*0.025f*s,real_z*0.025f*s, 0.0f))*0.5f;
height += glm::perlin(glm::vec3(real_x*0.05f*s,real_z*0.05f*s, 0.0f))*0.25f;
height += glm::perlin(glm::vec3(real_x*0.1f*s,real_z*0.1f*s, 0.0f))*0.225f;
height += glm::perlin(glm::vec3(real_x*0.2f*s,real_z*0.2f*s, 0.0f))*0.125f;
height = height * 0.5f + 0.5f;
height *= height;
height *= 140.0f;
height += 48;
float height = calc_height(&noise, real_x, real_z);
heights[z*CHUNK_W+x] = height;
}
}
for (int z = 0; z < CHUNK_D; z++){
for (int x = 0; x < CHUNK_W; x++){
int real_x = x + cx * CHUNK_W;
int real_z = z + cz * CHUNK_D;
float height = heights[z*CHUNK_W+x];
for (int y = 0; y < CHUNK_H; y++){
int real_y = y + cy * CHUNK_H;
int id = 0;
int id = real_y < 55 ? 9 : 0;
if (real_y == (int)height)
id = 2;
else if (real_y < height)
id = 1;
else if (real_y < height){
if (real_y < height-6)
id = 8;
else
id = 1;
} else {
int tree = generate_tree(&noise, &random, heights, real_x, real_y, real_z, 16);
if (tree)
id = tree;
else if ((tree = generate_tree(&noise, &random, heights, real_x, real_y, real_z, 19))){
id = tree;
}else if ((tree = generate_tree(&noise, &random, heights, real_x, real_y, real_z, 23))){
id = tree;
}
}
if (real_y <= 2)
id = 2;
voxels[(y * CHUNK_D + z) * CHUNK_W + x].id = id;