voxels renderer rebuilt, WorldFiles fix
This commit is contained in:
parent
0576316282
commit
754c5b80d0
@ -18,8 +18,11 @@ Assets::~Assets() {
|
||||
}
|
||||
}
|
||||
|
||||
Texture* Assets::getTexture(std::string name){
|
||||
return textures[name];
|
||||
Texture* Assets::getTexture(std::string name) const {
|
||||
auto found = textures.find(name);
|
||||
if (found == textures.end())
|
||||
return nullptr;
|
||||
return found->second;
|
||||
}
|
||||
|
||||
void Assets::store(Texture* texture, std::string name){
|
||||
@ -27,8 +30,11 @@ void Assets::store(Texture* texture, std::string name){
|
||||
}
|
||||
|
||||
|
||||
Shader* Assets::getShader(std::string name){
|
||||
return shaders[name];
|
||||
Shader* Assets::getShader(std::string name) const{
|
||||
auto found = shaders.find(name);
|
||||
if (found == shaders.end())
|
||||
return nullptr;
|
||||
return found->second;
|
||||
}
|
||||
|
||||
void Assets::store(Shader* shader, std::string name){
|
||||
@ -36,8 +42,11 @@ void Assets::store(Shader* shader, std::string name){
|
||||
}
|
||||
|
||||
|
||||
Font* Assets::getFont(std::string name){
|
||||
return fonts[name];
|
||||
Font* Assets::getFont(std::string name) const {
|
||||
auto found = fonts.find(name);
|
||||
if (found == fonts.end())
|
||||
return nullptr;
|
||||
return found->second;
|
||||
}
|
||||
|
||||
void Assets::store(Font* font, std::string name){
|
||||
|
||||
@ -14,13 +14,13 @@ class Assets {
|
||||
std::unordered_map<std::string, Font*> fonts;
|
||||
public:
|
||||
~Assets();
|
||||
Texture* getTexture(std::string name);
|
||||
Texture* getTexture(std::string name) const;
|
||||
void store(Texture* texture, std::string name);
|
||||
|
||||
Shader* getShader(std::string name);
|
||||
Shader* getShader(std::string name) const;
|
||||
void store(Shader* shader, std::string name);
|
||||
|
||||
Font* getFont(std::string name);
|
||||
Font* getFont(std::string name) const;
|
||||
void store(Font* font, std::string name);
|
||||
};
|
||||
|
||||
|
||||
17
src/constants.h
Normal file
17
src/constants.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef SRC_CONSTANTS_H_
|
||||
#define SRC_CONSTANTS_H_
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
#define CHUNK_W 16
|
||||
#define CHUNK_H 256
|
||||
#define CHUNK_D 16
|
||||
#define CHUNK_VOL (CHUNK_W * CHUNK_H * CHUNK_D)
|
||||
|
||||
#define BLOCK_VOID (blockid_t)((2 << (sizeof(blockid_t)*8)) - 1)
|
||||
|
||||
inline uint vox_index(int x, int y, int z, int w, int d) {
|
||||
return (y * d + z) * w + x;
|
||||
}
|
||||
|
||||
#endif // SRC_CONSTANTS_H_
|
||||
@ -4,12 +4,10 @@
|
||||
#include "../window/Camera.h"
|
||||
#include "../objects/Player.h"
|
||||
#include "../physics/Hitbox.h"
|
||||
#include "../voxels/voxel.h"
|
||||
#include "../voxels/Chunk.h"
|
||||
|
||||
union {
|
||||
long _key;
|
||||
int _coords[2];
|
||||
} _tempcoords;
|
||||
#include "../typedefs.h"
|
||||
#include "../voxmaths.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
@ -22,21 +20,25 @@ union {
|
||||
#define SECTION_FLAGS 3
|
||||
#define PLAYER_FLAG_FLIGHT 0x1
|
||||
#define PLAYER_FLAG_NOCLIP 0x2
|
||||
#define CHUNK_DATA_LEN (CHUNK_VOL*sizeof(voxel))
|
||||
|
||||
unsigned long WorldFiles::totalCompressed = 0;
|
||||
using glm::ivec2;
|
||||
using glm::vec3;
|
||||
|
||||
int bytes2Int(const unsigned char* src, unsigned int offset){
|
||||
int64_t WorldFiles::totalCompressed = 0;
|
||||
|
||||
int bytes2Int(const ubyte* src, size_t offset){
|
||||
return (src[offset] << 24) | (src[offset+1] << 16) | (src[offset+2] << 8) | (src[offset+3]);
|
||||
}
|
||||
|
||||
void int2Bytes(int value, char* dest, unsigned int offset){
|
||||
void int2Bytes(int value, ubyte* dest, size_t offset){
|
||||
dest[offset] = (char) (value >> 24 & 255);
|
||||
dest[offset+1] = (char) (value >> 16 & 255);
|
||||
dest[offset+2] = (char) (value >> 8 & 255);
|
||||
dest[offset+3] = (char) (value >> 0 & 255);
|
||||
}
|
||||
|
||||
void floatToBytes(float fvalue, char* dest, unsigned int offset){
|
||||
void floatToBytes(float fvalue, ubyte* dest, size_t offset){
|
||||
uint32_t value = *((uint32_t*)&fvalue);
|
||||
dest[offset] = (char) (value >> 24 & 255);
|
||||
dest[offset+1] = (char) (value >> 16 & 255);
|
||||
@ -44,8 +46,7 @@ void floatToBytes(float fvalue, char* dest, unsigned int offset){
|
||||
dest[offset+3] = (char) (value >> 0 & 255);
|
||||
}
|
||||
|
||||
float bytes2Float(char* srcs, unsigned int offset){
|
||||
unsigned char* src = (unsigned char*) srcs;
|
||||
float bytes2Float(ubyte* src, uint offset){
|
||||
uint32_t value = ((src[offset] << 24) |
|
||||
(src[offset+1] << 16) |
|
||||
(src[offset+2] << 8) |
|
||||
@ -54,15 +55,14 @@ float bytes2Float(char* srcs, unsigned int offset){
|
||||
}
|
||||
|
||||
WorldFiles::WorldFiles(std::string directory, size_t mainBufferCapacity) : directory(directory){
|
||||
mainBufferIn = new char[CHUNK_VOL*2];
|
||||
mainBufferOut = new char[mainBufferCapacity];
|
||||
mainBufferIn = new ubyte[CHUNK_DATA_LEN];
|
||||
mainBufferOut = new ubyte[mainBufferCapacity];
|
||||
}
|
||||
|
||||
WorldFiles::~WorldFiles(){
|
||||
delete[] mainBufferIn;
|
||||
delete[] mainBufferOut;
|
||||
std::unordered_map<long, WorldRegion>::iterator it;
|
||||
for (it = regions.begin(); it != regions.end(); it++){
|
||||
for (auto it = regions.begin(); it != regions.end(); it++){
|
||||
WorldRegion region = it->second;
|
||||
if (region.chunksData == nullptr)
|
||||
continue;
|
||||
@ -74,31 +74,35 @@ WorldFiles::~WorldFiles(){
|
||||
regions.clear();
|
||||
}
|
||||
|
||||
void WorldFiles::put(const char* chunkData, int x, int y){
|
||||
void WorldFiles::put(const ubyte* chunkData, int x, int y){
|
||||
assert(chunkData != nullptr);
|
||||
|
||||
int regionX = x >> REGION_SIZE_BIT;
|
||||
int regionY = y >> REGION_SIZE_BIT;
|
||||
int regionX = floordiv(x, REGION_SIZE);
|
||||
int regionY = floordiv(y, REGION_SIZE);
|
||||
|
||||
int localX = x - (regionX << REGION_SIZE_BIT);
|
||||
int localY = y - (regionY << REGION_SIZE_BIT);
|
||||
int localX = x - (regionX * REGION_SIZE);
|
||||
int localY = y - (regionY * REGION_SIZE);
|
||||
|
||||
_tempcoords._coords[0] = regionX;
|
||||
_tempcoords._coords[1] = regionY;
|
||||
WorldRegion& region = regions[_tempcoords._key];
|
||||
ivec2 key(regionX, regionY);
|
||||
|
||||
auto found = regions.find(key);
|
||||
if (found == regions.end()) {
|
||||
ubyte** chunksData = new ubyte*[REGION_VOL];
|
||||
for (uint i = 0; i < REGION_VOL; i++) {
|
||||
chunksData[i] = nullptr;
|
||||
}
|
||||
regions[key] = { chunksData, true };
|
||||
}
|
||||
|
||||
WorldRegion& region = regions[key];
|
||||
region.unsaved = true;
|
||||
if (region.chunksData == nullptr){
|
||||
region.chunksData = new char*[REGION_VOL];
|
||||
for (unsigned int i = 0; i < REGION_VOL; i++)
|
||||
region.chunksData[i] = nullptr;
|
||||
}
|
||||
char* targetChunk = region.chunksData[localY * REGION_SIZE + localX];
|
||||
ubyte* targetChunk = region.chunksData[localY * REGION_SIZE + localX];
|
||||
if (targetChunk == nullptr){
|
||||
targetChunk = new char[CHUNK_VOL];
|
||||
targetChunk = new ubyte[CHUNK_DATA_LEN];
|
||||
region.chunksData[localY * REGION_SIZE + localX] = targetChunk;
|
||||
totalCompressed += CHUNK_VOL;
|
||||
totalCompressed += CHUNK_DATA_LEN;
|
||||
}
|
||||
for (unsigned int i = 0; i < CHUNK_VOL; i++)
|
||||
for (uint i = 0; i < CHUNK_DATA_LEN; i++)
|
||||
targetChunk[i] = chunkData[i];
|
||||
|
||||
}
|
||||
@ -111,44 +115,46 @@ std::string WorldFiles::getPlayerFile() {
|
||||
return directory + "/player.bin";
|
||||
}
|
||||
|
||||
bool WorldFiles::getChunk(int x, int y, char* out){
|
||||
bool WorldFiles::getChunk(int x, int y, ubyte* out){
|
||||
assert(out != nullptr);
|
||||
|
||||
int regionX = x >> REGION_SIZE_BIT;
|
||||
int regionY = y >> REGION_SIZE_BIT;
|
||||
int regionX = floordiv(x, REGION_SIZE);
|
||||
int regionY = floordiv(y, REGION_SIZE);
|
||||
|
||||
int localX = x - (regionX * REGION_SIZE);
|
||||
int localY = y - (regionY * REGION_SIZE);
|
||||
|
||||
int localX = x - (regionX << REGION_SIZE_BIT);
|
||||
int localY = y - (regionY << REGION_SIZE_BIT);
|
||||
int chunkIndex = localY * REGION_SIZE + localX;
|
||||
assert(chunkIndex >= 0 && chunkIndex < REGION_VOL);
|
||||
|
||||
_tempcoords._coords[0] = regionX;
|
||||
_tempcoords._coords[1] = regionY;
|
||||
ivec2 key(regionX, regionY);
|
||||
|
||||
WorldRegion& region = regions[_tempcoords._key];
|
||||
if (region.chunksData == nullptr)
|
||||
return readChunk(x,y,out);
|
||||
auto found = regions.find(key);
|
||||
if (found == regions.end()) {
|
||||
return readChunk(x, y, out);
|
||||
}
|
||||
|
||||
char* chunk = region.chunksData[chunkIndex];
|
||||
WorldRegion& region = found->second;
|
||||
ubyte* chunk = region.chunksData[chunkIndex];
|
||||
if (chunk == nullptr)
|
||||
return readChunk(x,y,out);
|
||||
for (unsigned int i = 0; i < CHUNK_VOL; i++)
|
||||
for (uint i = 0; i < CHUNK_DATA_LEN; i++)
|
||||
out[i] = chunk[i];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WorldFiles::readChunk(int x, int y, char* out){
|
||||
bool WorldFiles::readChunk(int x, int y, ubyte* out){
|
||||
assert(out != nullptr);
|
||||
|
||||
int regionX = x >> REGION_SIZE_BIT;
|
||||
int regionY = y >> REGION_SIZE_BIT;
|
||||
int regionX = floordiv(x, REGION_SIZE);
|
||||
int regionY = floordiv(y, REGION_SIZE);
|
||||
|
||||
int localX = x - (regionX * REGION_SIZE);
|
||||
int localY = y - (regionY * REGION_SIZE);
|
||||
|
||||
int localX = x - (regionX << REGION_SIZE_BIT);
|
||||
int localY = y - (regionY << REGION_SIZE_BIT);
|
||||
int chunkIndex = localY * REGION_SIZE + localX;
|
||||
|
||||
std::string filename = getRegionFile(regionX, regionY);
|
||||
|
||||
std::ifstream input(filename, std::ios::binary);
|
||||
if (!input.is_open()){
|
||||
return false;
|
||||
@ -166,35 +172,31 @@ bool WorldFiles::readChunk(int x, int y, char* out){
|
||||
}
|
||||
input.seekg(offset);
|
||||
input.read((char*)(&offset), 4);
|
||||
size_t compressedSize = bytes2Int((const unsigned char*)(&offset), 0);
|
||||
|
||||
input.read(mainBufferIn, compressedSize);
|
||||
size_t compressedSize = bytes2Int((const ubyte*)(&offset), 0);
|
||||
input.read((char*)mainBufferIn, compressedSize);
|
||||
input.close();
|
||||
|
||||
decompressRLE((unsigned char*)mainBufferIn, compressedSize, (unsigned char*)out, CHUNK_VOL);
|
||||
decompressRLE((ubyte*)mainBufferIn, compressedSize, (ubyte*)out, CHUNK_DATA_LEN);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WorldFiles::write(){
|
||||
std::unordered_map<long, WorldRegion>::iterator it;
|
||||
for (it = regions.begin(); it != regions.end(); it++){
|
||||
for (auto it = regions.begin(); it != regions.end(); it++){
|
||||
if (it->second.chunksData == nullptr || !it->second.unsaved)
|
||||
continue;
|
||||
|
||||
int x;
|
||||
int y;
|
||||
longToCoords(x,y, it->first);
|
||||
ivec2 key = it->first;
|
||||
|
||||
unsigned int size = writeRegion(mainBufferOut, x,y, it->second.chunksData);
|
||||
write_binary_file(getRegionFile(x,y), mainBufferOut, size);
|
||||
unsigned int size = writeRegion(mainBufferOut, key.x, key.y, it->second.chunksData);
|
||||
write_binary_file(getRegionFile(key.x, key.y), (const char*)mainBufferOut, size);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldFiles::writePlayer(Player* player){
|
||||
char dst[1+3*4 + 1+2*4 + 1+1];
|
||||
ubyte dst[1+3*4 + 1+2*4 + 1+1];
|
||||
|
||||
glm::vec3 position = player->hitbox->position;
|
||||
vec3 position = player->hitbox->position;
|
||||
|
||||
size_t offset = 0;
|
||||
dst[offset++] = SECTION_POSITION;
|
||||
@ -215,12 +217,12 @@ void WorldFiles::writePlayer(Player* player){
|
||||
|
||||
bool WorldFiles::readPlayer(Player* player) {
|
||||
size_t length = 0;
|
||||
char* data = read_binary_file(getPlayerFile(), length);
|
||||
ubyte* data = (ubyte*)read_binary_file(getPlayerFile(), length);
|
||||
if (data == nullptr){
|
||||
std::cerr << "could not to read player.bin (ignored)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
glm::vec3 position = player->hitbox->position;
|
||||
vec3 position = player->hitbox->position;
|
||||
size_t offset = 0;
|
||||
while (offset < length){
|
||||
char section = data[offset++];
|
||||
@ -248,21 +250,19 @@ bool WorldFiles::readPlayer(Player* player) {
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int WorldFiles::writeRegion(char* out, int x, int y, char** region){
|
||||
unsigned int offset = REGION_VOL * 4;
|
||||
for (unsigned int i = 0; i < offset; i++)
|
||||
uint WorldFiles::writeRegion(ubyte* out, int x, int y, ubyte** region){
|
||||
uint offset = REGION_VOL * 4;
|
||||
for (uint i = 0; i < offset; i++)
|
||||
out[i] = 0;
|
||||
|
||||
char* compressed = new char[CHUNK_VOL*2];
|
||||
ubyte* compressed = new ubyte[CHUNK_DATA_LEN];
|
||||
for (int i = 0; i < REGION_VOL; i++){
|
||||
char* chunk = region[i];
|
||||
ubyte* chunk = region[i];
|
||||
if (chunk == nullptr){
|
||||
chunk = new char[CHUNK_VOL];
|
||||
assert((((i % REGION_SIZE) + x * REGION_SIZE) >> REGION_SIZE_BIT) == x);
|
||||
assert((((i / REGION_SIZE) + y * REGION_SIZE) >> REGION_SIZE_BIT) == y);
|
||||
chunk = new ubyte[CHUNK_DATA_LEN];
|
||||
if (readChunk((i % REGION_SIZE) + x * REGION_SIZE, (i / REGION_SIZE) + y * REGION_SIZE, chunk)){
|
||||
region[i] = chunk;
|
||||
totalCompressed += CHUNK_VOL;
|
||||
totalCompressed += CHUNK_DATA_LEN;
|
||||
} else {
|
||||
delete[] chunk;
|
||||
chunk = nullptr;
|
||||
@ -274,21 +274,15 @@ unsigned int WorldFiles::writeRegion(char* out, int x, int y, char** region){
|
||||
} else {
|
||||
int2Bytes(offset, out, i*4);
|
||||
|
||||
unsigned int compressedSize = compressRLE((unsigned char*)chunk, CHUNK_VOL, (unsigned char*)compressed);
|
||||
uint compressedSize = compressRLE(chunk, CHUNK_DATA_LEN, compressed);
|
||||
|
||||
int2Bytes(compressedSize, out, offset);
|
||||
offset += 4;
|
||||
|
||||
for (unsigned int j = 0; j < compressedSize; j++)
|
||||
for (uint j = 0; j < compressedSize; j++)
|
||||
out[offset++] = compressed[j];
|
||||
}
|
||||
}
|
||||
delete[] compressed;
|
||||
return offset;
|
||||
}
|
||||
|
||||
void longToCoords(int& x, int& y, long key) {
|
||||
_tempcoords._key = key;
|
||||
x = _tempcoords._coords[0];
|
||||
y = _tempcoords._coords[1];
|
||||
}
|
||||
|
||||
@ -4,6 +4,13 @@
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include "glm/gtx/hash.hpp"
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
class Player;
|
||||
|
||||
#define REGION_SIZE_BIT 5
|
||||
@ -11,28 +18,27 @@ class Player;
|
||||
#define REGION_VOL ((REGION_SIZE) * (REGION_SIZE))
|
||||
|
||||
struct WorldRegion {
|
||||
char** chunksData;
|
||||
ubyte** chunksData;
|
||||
bool unsaved;
|
||||
};
|
||||
|
||||
class WorldFiles {
|
||||
public:
|
||||
static unsigned long totalCompressed;
|
||||
std::unordered_map<long, WorldRegion> regions;
|
||||
static int64_t totalCompressed;
|
||||
std::unordered_map<glm::ivec2, WorldRegion> regions;
|
||||
std::string directory;
|
||||
char* mainBufferIn;
|
||||
char* mainBufferOut;
|
||||
ubyte* mainBufferIn;
|
||||
ubyte* mainBufferOut;
|
||||
|
||||
WorldFiles(std::string directory, size_t mainBufferCapacity);
|
||||
~WorldFiles();
|
||||
|
||||
void put(const char* chunkData, int x, int y);
|
||||
void put(const ubyte* chunkData, int x, int y);
|
||||
|
||||
bool readPlayer(Player* player);
|
||||
bool readChunk(int x, int y, char* out);
|
||||
bool getChunk(int x, int y, char* out);
|
||||
void readRegion(char* fileContent);
|
||||
unsigned int writeRegion(char* out, int x, int y, char** region);
|
||||
bool readChunk(int x, int y, ubyte* out);
|
||||
bool getChunk(int x, int y, ubyte* out);
|
||||
uint writeRegion(ubyte* out, int x, int y, ubyte** region);
|
||||
void writePlayer(Player* player);
|
||||
void write();
|
||||
|
||||
@ -40,6 +46,4 @@ public:
|
||||
std::string getPlayerFile();
|
||||
};
|
||||
|
||||
extern void longToCoords(int& x, int& y, long key);
|
||||
|
||||
#endif /* FILES_WORLDFILES_H_ */
|
||||
|
||||
@ -8,8 +8,8 @@
|
||||
#define VERTEX_SIZE 8
|
||||
|
||||
Batch2D::Batch2D(size_t capacity) : capacity(capacity), offset(0), color(1.0f, 1.0f, 1.0f, 1.0f){
|
||||
const int attrs[] = {
|
||||
2, 2, 4, 0 //null terminator
|
||||
const vattr attrs[] = {
|
||||
{2}, {2}, {4}, {0}
|
||||
};
|
||||
|
||||
buffer = new float[capacity * VERTEX_SIZE];
|
||||
|
||||
@ -8,8 +8,8 @@
|
||||
#define VERTEX_SIZE 9
|
||||
|
||||
Batch3D::Batch3D(size_t capacity) : capacity(capacity), offset(0), color(1.0f, 1.0f, 1.0f, 0.0f){
|
||||
const int attrs[] = {
|
||||
3, 2, 4, 0 //null terminator
|
||||
const vattr attrs[] = {
|
||||
{3}, {2}, {4}, {0}
|
||||
};
|
||||
|
||||
buffer = new float[capacity * VERTEX_SIZE];
|
||||
|
||||
352
src/graphics/BlocksRenderer.cpp
Normal file
352
src/graphics/BlocksRenderer.cpp
Normal file
@ -0,0 +1,352 @@
|
||||
#include "BlocksRenderer.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "Mesh.h"
|
||||
#include "UVRegion.h"
|
||||
#include "../constants.h"
|
||||
#include "../voxels/Block.h"
|
||||
#include "../voxels/Chunk.h"
|
||||
#include "../voxels/VoxelsVolume.h"
|
||||
#include "../voxels/ChunksStorage.h"
|
||||
#include "../lighting/Lightmap.h"
|
||||
|
||||
using glm::ivec3;
|
||||
using glm::vec3;
|
||||
using glm::vec4;
|
||||
|
||||
#define VERTEX_SIZE 9
|
||||
|
||||
BlocksRenderer::BlocksRenderer(size_t capacity) : offset(0), capacity(capacity) {
|
||||
buffer = new float[capacity];
|
||||
voxelsBuffer = new VoxelsVolume(CHUNK_W + 2, CHUNK_H, CHUNK_D + 2);
|
||||
}
|
||||
|
||||
|
||||
BlocksRenderer::~BlocksRenderer() {
|
||||
delete voxelsBuffer;
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
void BlocksRenderer::vertex(vec3 coord,
|
||||
float u, float v,
|
||||
vec4 light) {
|
||||
buffer[offset++] = coord.x;
|
||||
buffer[offset++] = coord.y;
|
||||
buffer[offset++] = coord.z;
|
||||
|
||||
buffer[offset++] = u;
|
||||
buffer[offset++] = v;
|
||||
|
||||
buffer[offset++] = light.r;
|
||||
buffer[offset++] = light.g;
|
||||
buffer[offset++] = light.b;
|
||||
buffer[offset++] = light.a;
|
||||
}
|
||||
|
||||
void BlocksRenderer::face(vec3 coord, float w, float h,
|
||||
const vec3 axisX,
|
||||
const vec3 axisY,
|
||||
const UVRegion& region,
|
||||
const vec4 lights[4],
|
||||
const vec4 tint) {
|
||||
if (offset + VERTEX_SIZE * 6 > capacity) {
|
||||
overflow = true;
|
||||
return;
|
||||
}
|
||||
vertex(coord, region.u1, region.v1, lights[0] * tint);
|
||||
vertex(coord + axisX * w, region.u2, region.v1, lights[1] * tint);
|
||||
vertex(coord + axisX * w + axisY * h, region.u2, region.v2, lights[2] * tint);
|
||||
|
||||
vertex(coord, region.u1, region.v1, lights[0] * tint);
|
||||
vertex(coord + axisX * w + axisY * h, region.u2, region.v2, lights[2] * tint);
|
||||
vertex(coord + axisY * h, region.u1, region.v2, lights[3] * tint);
|
||||
}
|
||||
|
||||
void BlocksRenderer::face(vec3 coord, float w, float h,
|
||||
const vec3 axisX,
|
||||
const vec3 axisY,
|
||||
const UVRegion& region,
|
||||
const vec4 lights[4],
|
||||
const vec4 tint,
|
||||
bool rotated) {
|
||||
if (offset + VERTEX_SIZE * 6 > capacity) {
|
||||
overflow = true;
|
||||
return;
|
||||
}
|
||||
if (rotated) {
|
||||
vertex(coord, region.u2, region.v1, lights[0] * tint);
|
||||
vertex(coord + axisX * w, region.u2, region.v2, lights[1] * tint);
|
||||
vertex(coord + axisX * w + axisY * h, region.u1, region.v2, lights[2] * tint);
|
||||
|
||||
vertex(coord, region.u2, region.v1, lights[0] * tint);
|
||||
vertex(coord + axisX * w + axisY * h, region.u1, region.v2, lights[2] * tint);
|
||||
vertex(coord + axisY * h, region.u1, region.v1, lights[3] * tint);
|
||||
}
|
||||
else {
|
||||
vertex(coord, region.u1, region.v1, lights[0] * tint);
|
||||
vertex(coord + axisX * w, region.u2, region.v1, lights[1] * tint);
|
||||
vertex(coord + axisX * w + axisY * h, region.u2, region.v2, lights[2] * tint);
|
||||
|
||||
vertex(coord, region.u1, region.v1, lights[0] * tint);
|
||||
vertex(coord + axisX * w + axisY * h, region.u2, region.v2, lights[2] * tint);
|
||||
vertex(coord + axisY * h, region.u1, region.v2, lights[3] * tint);
|
||||
}
|
||||
}
|
||||
|
||||
void BlocksRenderer::cube(vec3 coord, vec3 size, const UVRegion texfaces[6]) {
|
||||
vec4 lights[]{ vec4(),vec4(),vec4(),vec4() };
|
||||
|
||||
face(coord, size.x, size.y, vec3(1, 0, 0), vec3(0, 1, 0), texfaces[0], lights);
|
||||
face(coord + vec3(size.x, 0, -size.z), size.x, size.y, vec3(-1, 0, 0), vec3(0, 1, 0), texfaces[1], lights);
|
||||
|
||||
face(coord + vec3(0, size.y, 0), size.x, size.z, vec3(1, 0, 0), vec3(0, 0, -1), texfaces[2], lights);
|
||||
face(coord + vec3(0, 0, -size.z), size.x, size.z, vec3(1, 0, 0), vec3(0, 0, 1), texfaces[3], lights);
|
||||
|
||||
face(coord + vec3(0, 0, -size.z), size.z, size.y, vec3(0, 0, 1), vec3(0, 1, 0), texfaces[4], lights);
|
||||
face(coord + vec3(size.x, 0, 0), size.z, size.y, vec3(0, 0, -1), vec3(0, 1, 0), texfaces[5], lights);
|
||||
}
|
||||
|
||||
constexpr vec4 do_tint(float value) {
|
||||
return vec4(value, value, value, 1.0f);
|
||||
}
|
||||
|
||||
void BlocksRenderer::blockCube(int x, int y, int z, vec3 size, const UVRegion texfaces[6], ubyte group) {
|
||||
vec4 lights[]{ vec4(1.0f), vec4(1.0f), vec4(1.0f), vec4(1.0f) };
|
||||
if (isOpen(x, y, z + 1, group)) {
|
||||
face(vec3(x, y, z), size.x, size.y, vec3(1, 0, 0), vec3(0, 1, 0), texfaces[5], lights, do_tint(0.9f));
|
||||
}
|
||||
if (isOpen(x, y, z - 1, group)) {
|
||||
face(vec3(x + size.x, y, z - size.z), size.x, size.y, vec3(-1, 0, 0), vec3(0, 1, 0), texfaces[4], lights, vec4(1.0f));
|
||||
}
|
||||
|
||||
if (isOpen(x, y + 1, z, group)) {
|
||||
face(vec3(x, y + size.y, z), size.x, size.z, vec3(1, 0, 0), vec3(0, 0, -1), texfaces[3], lights);
|
||||
}
|
||||
|
||||
if (isOpen(x, y - 1, z, group)) {
|
||||
face(vec3(x, y, z - size.z), size.x, size.z, vec3(1, 0, 0), vec3(0, 0, 1), texfaces[2], lights, vec4(1.0f));
|
||||
}
|
||||
|
||||
if (isOpen(x - 1, y, z, group)) {
|
||||
face(vec3(x, y, z - size.z), size.z, size.y, vec3(0, 0, 1), vec3(0, 1, 0), texfaces[0], lights, vec4(1.0f));
|
||||
}
|
||||
if (isOpen(x + 1, y, z, group)) {
|
||||
face(vec3(x + size.x, y, z), size.z, size.y, vec3(0, 0, -1), vec3(0, 1, 0), texfaces[1], lights, vec4(1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
void BlocksRenderer::blockXSprite(int x, int y, int z, vec3 size, const UVRegion texface1, const UVRegion texface2, float spread) {
|
||||
vec4 lights[]{
|
||||
pickSoftLight(x, y, z, {1, 0, 0}, {0, 1, 0}),
|
||||
pickSoftLight(x + 1, y, z, {1, 0, 0}, {0, 1, 0}),
|
||||
pickSoftLight(x + 1, y + 1, z, {1, 0, 0}, {0, 1, 0}),
|
||||
pickSoftLight(x, y + 1, z, {1, 0, 0}, {0, 1, 0}) };
|
||||
|
||||
int rand = ((x * z + y) ^ (z * y - x)) * (z + y);
|
||||
|
||||
float xs = ((float)(char)rand / 512) * spread;
|
||||
float zs = ((float)(char)(rand >> 8) / 512) * spread;
|
||||
|
||||
const float w = size.x/1.41f;
|
||||
face(vec3(x + xs + (1.0 - w) * 0.5f, y,
|
||||
z + zs - 1 + (1.0 - w) * 0.5f), w, size.y,
|
||||
vec3(1.0f, 0, 1.0f), vec3(0, 1, 0), texface1, lights, do_tint(0.9f));
|
||||
face(vec3(x + xs - (1.0 - w) * 0.5f + 1, y,
|
||||
z + zs - (1.0 - w) * 0.5f), w, size.y,
|
||||
vec3(-1.0f, 0, -1.0f), vec3(0, 1, 0), texface1, lights, do_tint(0.9f));
|
||||
|
||||
face(vec3(x + xs + (1.0 - w) * 0.5f, y,
|
||||
z + zs - (1.0 - w) * 0.5f), w, size.y,
|
||||
vec3(1.0f, 0, -1.0f), vec3(0, 1, 0), texface2, lights, do_tint(0.9f));
|
||||
face(vec3(x + xs - (1.0 - w) * 0.5f + 1, y,
|
||||
z + zs + (1.0 - w) * 0.5f - 1), w, size.y,
|
||||
vec3(-1.0f, 0, 1.0f), vec3(0, 1, 0), texface2, lights, do_tint(0.9f));
|
||||
}
|
||||
|
||||
void BlocksRenderer::blockCubeShaded(int x, int y, int z, vec3 size, const UVRegion texfaces_[6], const Block* block, ubyte states) {
|
||||
ubyte group = block->drawGroup;
|
||||
UVRegion texfaces[6];
|
||||
int rot = 0;
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
texfaces[i] = texfaces_[i];
|
||||
}
|
||||
|
||||
if (block->rotatable) {
|
||||
if (states == 0x31) {
|
||||
rot = 1;
|
||||
texfaces[0] = texfaces_[2];
|
||||
texfaces[1] = texfaces_[3];
|
||||
texfaces[2] = texfaces_[0];
|
||||
texfaces[3] = texfaces_[1];
|
||||
}
|
||||
else if (states == 0x32) {
|
||||
rot = 2;
|
||||
}
|
||||
else if (states == 0x33) {
|
||||
rot = 3;
|
||||
texfaces[2] = texfaces_[4];
|
||||
texfaces[3] = texfaces_[5];
|
||||
texfaces[4] = texfaces_[2];
|
||||
texfaces[5] = texfaces_[3];
|
||||
}
|
||||
}
|
||||
if (isOpen(x, y, z + 1, group)) {
|
||||
vec4 lights[]{
|
||||
pickSoftLight(x, y, z + 1, {1, 0, 0}, {0, 1, 0}),
|
||||
pickSoftLight(x + 1, y, z + 1, {1, 0, 0}, {0, 1, 0}),
|
||||
pickSoftLight(x + 1, y + 1, z + 1, {1, 0, 0}, {0, 1, 0}),
|
||||
pickSoftLight(x, y + 1, z + 1, {1, 0, 0}, {0, 1, 0}) };
|
||||
face(vec3(x, y, z), size.x, size.y, vec3(1, 0, 0), vec3(0, 1, 0), texfaces[5], lights, do_tint(0.9f), rot == 1);
|
||||
}
|
||||
if (isOpen(x, y, z - 1, group)) {
|
||||
vec4 lights[]{
|
||||
pickSoftLight(x, y, z - 1, {-1, 0, 0}, {0, 1, 0}),
|
||||
pickSoftLight(x - 1, y, z - 1, {-1, 0, 0}, {0, 1, 0}),
|
||||
pickSoftLight(x - 1, y + 1, z - 1, {-1, 0, 0}, {0, 1, 0}),
|
||||
pickSoftLight(x, y + 1, z - 1, {-1, 0, 0}, {0, 1, 0}) };
|
||||
face(vec3(x + size.x, y, z - size.z), size.x, size.y, vec3(-1, 0, 0), vec3(0, 1, 0), texfaces[4], lights, do_tint(0.75f), rot == 1);
|
||||
}
|
||||
|
||||
if (isOpen(x, y + 1, z, group)) {
|
||||
vec4 lights[]{
|
||||
pickSoftLight(x, y + 1, z + 1, {1, 0, 0}, {0, 0, 1}),
|
||||
pickSoftLight(x + 1, y + 1, z + 1, {1, 0, 0}, {0, 0, 1}),
|
||||
pickSoftLight(x + 1, y + 1, z, {1, 0, 0}, {0, 0, 1}),
|
||||
pickSoftLight(x, y + 1, z, {1, 0, 0}, {0, 0, 1}) };
|
||||
|
||||
face(vec3(x, y + size.y, z), size.x, size.z, vec3(1, 0, 0), vec3(0, 0, -1), texfaces[3], lights, vec4(1.0f), rot == 1);
|
||||
}
|
||||
|
||||
if (isOpen(x, y - 1, z, group)) {
|
||||
vec4 lights[]{
|
||||
pickSoftLight(x, y - 1, z - 1, {1, 0, 0}, {0, 0, -1}),
|
||||
pickSoftLight(x + 1, y - 1, z - 1, {1, 0, 0}, {0, 0,-1}),
|
||||
pickSoftLight(x + 1, y - 1, z, {1, 0, 0}, {0, 0, -1}),
|
||||
pickSoftLight(x, y - 1, z, {1, 0, 0}, {0, 0, -1}) };
|
||||
face(vec3(x, y, z - size.z), size.x, size.z, vec3(1, 0, 0), vec3(0, 0, 1), texfaces[2], lights, do_tint(0.6f), rot == 1);
|
||||
}
|
||||
|
||||
if (isOpen(x - 1, y, z, group)) {
|
||||
vec4 lights[]{
|
||||
pickSoftLight(x - 1, y, z - 1, {0, 0, -1}, {0, 1, 0}),
|
||||
pickSoftLight(x - 1, y, z, {0, 0, -1}, {0, 1, 0}),
|
||||
pickSoftLight(x - 1, y + 1, z, {0, 0, -1}, {0, 1, 0}),
|
||||
pickSoftLight(x - 1, y + 1, z - 1, {0, 0, -1}, {0, 1, 0}) };
|
||||
face(vec3(x, y, z - size.z), size.z, size.y, vec3(0, 0, 1), vec3(0, 1, 0), texfaces[0], lights, do_tint(0.7f), rot == 3);
|
||||
}
|
||||
if (isOpen(x + 1, y, z, group)) {
|
||||
vec4 lights[]{
|
||||
pickSoftLight(x + 1, y, z, {0, 0, -1}, {0, 1, 0}),
|
||||
pickSoftLight(x + 1, y, z - 1, {0, 0, -1}, {0, 1, 0}),
|
||||
pickSoftLight(x + 1, y + 1, z - 1, {0, 0, -1}, {0, 1, 0}),
|
||||
pickSoftLight(x + 1, y + 1, z, {0, 0, -1}, {0, 1, 0}) };
|
||||
face(vec3(x + size.x, y, z), size.z, size.y, vec3(0, 0, -1), vec3(0, 1, 0), texfaces[1], lights, do_tint(0.8f), rot == 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Does block allow to see other blocks sides (is it transparent)
|
||||
bool BlocksRenderer::isOpen(int x, int y, int z, ubyte group) const {
|
||||
blockid_t id = voxelsBuffer->pickBlockId(chunk->x * CHUNK_W + x, y, chunk->z * CHUNK_D + z);
|
||||
if (id == BLOCK_VOID)
|
||||
return false;
|
||||
const Block& block = *Block::blocks[id];
|
||||
if (block.drawGroup != group) {
|
||||
return true;
|
||||
}
|
||||
return !id;
|
||||
}
|
||||
|
||||
bool BlocksRenderer::isOpenForLight(int x, int y, int z) const {
|
||||
blockid_t id = voxelsBuffer->pickBlockId(chunk->x * CHUNK_W + x, y, chunk->z * CHUNK_D + z);
|
||||
if (id == BLOCK_VOID)
|
||||
return false;
|
||||
const Block& block = *Block::blocks[id];
|
||||
if (block.lightPassing) {
|
||||
return true;
|
||||
}
|
||||
return !id;
|
||||
}
|
||||
|
||||
vec4 BlocksRenderer::pickLight(int x, int y, int z) const {
|
||||
if (isOpenForLight(x, y, z)) {
|
||||
light_t light = voxelsBuffer->pickLight(chunk->x * CHUNK_W + x, y, chunk->z * CHUNK_D + z);
|
||||
return vec4(Lightmap::extract(light, 0) / 15.0f,
|
||||
Lightmap::extract(light, 1) / 15.0f,
|
||||
Lightmap::extract(light, 2) / 15.0f,
|
||||
Lightmap::extract(light, 3) / 15.0f);
|
||||
}
|
||||
else {
|
||||
return vec4(0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
vec4 BlocksRenderer::pickSoftLight(int x, int y, int z, ivec3 right, ivec3 up) const {
|
||||
return (pickLight(x - right.x - up.x, y - right.y - up.y, z - right.z - up.z) +
|
||||
pickLight(x - up.x, y - up.y, z - up.z) +
|
||||
pickLight(x, y, z) +
|
||||
pickLight(x - right.x, y - right.y, z - right.z)) * 0.25f;
|
||||
}
|
||||
|
||||
// Get texture atlas UV region for block face
|
||||
inline UVRegion uvfor(const Block& def, uint face, int atlas_size) {
|
||||
float uvsize = 1.0f / (float)atlas_size;
|
||||
const uint id = def.textureFaces[face];
|
||||
float u = (id % atlas_size) * uvsize;
|
||||
float v = 1.0f - (id / atlas_size + 1) * uvsize;
|
||||
return UVRegion(u, v, u + uvsize, v + uvsize);
|
||||
}
|
||||
|
||||
void BlocksRenderer::render(const voxel* voxels, int atlas_size) {
|
||||
for (ubyte group = 0; group < 8; group++) {
|
||||
for (uint y = 0; y < CHUNK_H; y++) {
|
||||
for (uint z = 0; z < CHUNK_D; z++) {
|
||||
for (uint x = 0; x < CHUNK_W; x++) {
|
||||
const voxel& vox = voxels[((y * CHUNK_D) + z) * CHUNK_W + x];
|
||||
blockid_t id = vox.id;
|
||||
const Block& def = *Block::blocks[id];
|
||||
if (!id || def.drawGroup != group)
|
||||
continue;
|
||||
const UVRegion texfaces[6]{ uvfor(def, 0, atlas_size), uvfor(def, 1, atlas_size),
|
||||
uvfor(def, 2, atlas_size), uvfor(def, 3, atlas_size),
|
||||
uvfor(def, 4, atlas_size), uvfor(def, 5, atlas_size) };
|
||||
switch (def.model) {
|
||||
case BLOCK_MODEL_CUBE:
|
||||
if (*((light_t*)&def.emission)) {
|
||||
blockCube(x, y, z, vec3(1, 1, 1), texfaces, def.drawGroup);
|
||||
}
|
||||
else {
|
||||
blockCubeShaded(x, y, z, vec3(1, 1, 1), texfaces, &def, vox.states);
|
||||
}
|
||||
break;
|
||||
case BLOCK_MODEL_X_SPRITE: {
|
||||
blockXSprite(x, y, z, vec3(1, 1, 1), texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (overflow)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mesh* BlocksRenderer::render(const Chunk* chunk, int atlas_size, const ChunksStorage* chunks) {
|
||||
this->chunk = chunk;
|
||||
voxelsBuffer->setPosition(chunk->x * CHUNK_W - 1, 0, chunk->z * CHUNK_D - 1);
|
||||
chunks->getVoxels(voxelsBuffer);
|
||||
overflow = false;
|
||||
offset = 0;
|
||||
const voxel* voxels = chunk->voxels;
|
||||
render(voxels, atlas_size);
|
||||
|
||||
const vattr attrs[]{ {3}, {2}, {4}, {0} };
|
||||
Mesh* mesh = new Mesh(buffer, offset / VERTEX_SIZE, attrs);
|
||||
return mesh;
|
||||
}
|
||||
|
||||
VoxelsVolume* BlocksRenderer::getVoxelsBuffer() const {
|
||||
return voxelsBuffer;
|
||||
}
|
||||
71
src/graphics/BlocksRenderer.h
Normal file
71
src/graphics/BlocksRenderer.h
Normal file
@ -0,0 +1,71 @@
|
||||
#ifndef GRAPHICS_BLOCKS_RENDERER_H
|
||||
#define GRAPHICS_BLOCKS_RENDERER_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include "UVRegion.h"
|
||||
#include "../typedefs.h"
|
||||
#include "../voxels/voxel.h"
|
||||
|
||||
class Mesh;
|
||||
class Block;
|
||||
class Chunk;
|
||||
class Chunks;
|
||||
class VoxelsVolume;
|
||||
class ChunksStorage;
|
||||
|
||||
class BlocksRenderer {
|
||||
float* buffer;
|
||||
size_t offset;
|
||||
size_t capacity;
|
||||
|
||||
bool overflow = false;
|
||||
|
||||
const Chunk* chunk = nullptr;
|
||||
VoxelsVolume* voxelsBuffer;
|
||||
|
||||
void vertex(glm::vec3 coord, float u, float v, glm::vec4 light);
|
||||
|
||||
void face(glm::vec3 coord, float w, float h,
|
||||
const glm::vec3 axisX,
|
||||
const glm::vec3 axisY,
|
||||
const UVRegion& region,
|
||||
const glm::vec4 lights[4],
|
||||
const glm::vec4 tint);
|
||||
|
||||
void face(glm::vec3 coord, float w, float h,
|
||||
const glm::vec3 axisX,
|
||||
const glm::vec3 axisY,
|
||||
const UVRegion& region,
|
||||
const glm::vec4 lights[4],
|
||||
const glm::vec4 tint,
|
||||
bool rotated);
|
||||
|
||||
void face(glm::vec3 coord, float w, float h,
|
||||
const glm::vec3 axisX,
|
||||
const glm::vec3 axisY,
|
||||
const UVRegion& region,
|
||||
const glm::vec4 lights[4]) {
|
||||
face(coord, w, h, axisX, axisY, region, lights, glm::vec4(1.0f));
|
||||
}
|
||||
|
||||
void cube(glm::vec3 coord, glm::vec3 size, const UVRegion faces[6]);
|
||||
void blockCube(int x, int y, int z, glm::vec3 size, const UVRegion faces[6], ubyte group);
|
||||
void blockCubeShaded(int x, int y, int z, glm::vec3 size, const UVRegion faces[6], const Block* block, ubyte states);
|
||||
void blockXSprite(int x, int y, int z, glm::vec3 size, const UVRegion face1, const UVRegion face2, float spread);
|
||||
|
||||
bool isOpenForLight(int x, int y, int z) const;
|
||||
bool isOpen(int x, int y, int z, ubyte group) const;
|
||||
|
||||
glm::vec4 pickLight(int x, int y, int z) const;
|
||||
glm::vec4 pickSoftLight(int x, int y, int z, glm::ivec3 right, glm::ivec3 up) const;
|
||||
void render(const voxel* voxels, int atlas_size);
|
||||
public:
|
||||
BlocksRenderer(size_t capacity);
|
||||
virtual ~BlocksRenderer();
|
||||
|
||||
Mesh* render(const Chunk* chunk, int atlas_size, const ChunksStorage* chunks);
|
||||
VoxelsVolume* getVoxelsBuffer() const;
|
||||
};
|
||||
|
||||
#endif // GRAPHICS_BLOCKS_RENDERER_H
|
||||
52
src/graphics/ChunksRenderer.cpp
Normal file
52
src/graphics/ChunksRenderer.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
#include "ChunksRenderer.h"
|
||||
|
||||
#include "Mesh.h"
|
||||
#include "BlocksRenderer.h"
|
||||
#include "../voxels/Chunk.h"
|
||||
#include "../world/Level.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/ext.hpp>
|
||||
|
||||
using glm::ivec2;
|
||||
using std::shared_ptr;
|
||||
|
||||
ChunksRenderer::ChunksRenderer(Level* level) : level(level) {
|
||||
const int MAX_FULL_CUBES = 3000;
|
||||
renderer = new BlocksRenderer(9 * 6 * 6 * MAX_FULL_CUBES);
|
||||
}
|
||||
|
||||
ChunksRenderer::~ChunksRenderer() {
|
||||
delete renderer;
|
||||
}
|
||||
|
||||
shared_ptr<Mesh> ChunksRenderer::render(Chunk* chunk) {
|
||||
chunk->setModified(false);
|
||||
Mesh* mesh = renderer->render(chunk, 16, level->chunksStorage);
|
||||
auto sptr = shared_ptr<Mesh>(mesh);
|
||||
meshes[ivec2(chunk->x, chunk->z)] = sptr;
|
||||
return sptr;
|
||||
}
|
||||
|
||||
void ChunksRenderer::unload(Chunk* chunk) {
|
||||
auto found = meshes.find(ivec2(chunk->x, chunk->z));
|
||||
if (found != meshes.end()) {
|
||||
meshes.erase(found);
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<Mesh> ChunksRenderer::getOrRender(Chunk* chunk) {
|
||||
auto found = meshes.find(ivec2(chunk->x, chunk->z));
|
||||
if (found != meshes.end() && !chunk->isModified()){
|
||||
return found->second;
|
||||
}
|
||||
return render(chunk);
|
||||
}
|
||||
|
||||
shared_ptr<Mesh> ChunksRenderer::get(Chunk* chunk) {
|
||||
auto found = meshes.find(ivec2(chunk->x, chunk->z));
|
||||
if (found != meshes.end()) {
|
||||
return found->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
31
src/graphics/ChunksRenderer.h
Normal file
31
src/graphics/ChunksRenderer.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef SRC_GRAPHICS_CHUNKSRENDERER_H_
|
||||
#define SRC_GRAPHICS_CHUNKSRENDERER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <glm/glm.hpp>
|
||||
#include "../voxels/Block.h"
|
||||
#include "../voxels/ChunksStorage.h"
|
||||
|
||||
class Mesh;
|
||||
class Chunk;
|
||||
class Level;
|
||||
class BlocksRenderer;
|
||||
|
||||
class ChunksRenderer {
|
||||
BlocksRenderer* renderer;
|
||||
Level* level;
|
||||
std::unordered_map<glm::ivec2, std::shared_ptr<Mesh>> meshes;
|
||||
public:
|
||||
ChunksRenderer(Level* level);
|
||||
virtual ~ChunksRenderer();
|
||||
|
||||
std::shared_ptr<Mesh> render(Chunk* chunk);
|
||||
void unload(Chunk* chunk);
|
||||
|
||||
std::shared_ptr<Mesh> getOrRender(Chunk* chunk);
|
||||
std::shared_ptr<Mesh> get(Chunk* chunk);
|
||||
|
||||
};
|
||||
|
||||
#endif // SRC_GRAPHICS_CHUNKSRENDERER_H_
|
||||
@ -13,7 +13,7 @@
|
||||
#define LB_VERTEX_SIZE (3+4)
|
||||
|
||||
LineBatch::LineBatch(size_t capacity) : capacity(capacity) {
|
||||
int attrs[] = {3,4, 0};
|
||||
const vattr attrs[] = { {3},{4}, {0} };
|
||||
buffer = new float[capacity * LB_VERTEX_SIZE * 2];
|
||||
mesh = new Mesh(buffer, 0, attrs);
|
||||
index = 0;
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
#include "Mesh.h"
|
||||
#include <GL/glew.h>
|
||||
|
||||
Mesh::Mesh(const float* buffer, size_t vertices, const int* attrs) : vertices(vertices){
|
||||
int Mesh::meshesCount = 0;
|
||||
|
||||
Mesh::Mesh(const float* buffer, size_t vertices, const vattr* attrs) : vertices(vertices){
|
||||
meshesCount++;
|
||||
vertexSize = 0;
|
||||
for (int i = 0; attrs[i]; i++){
|
||||
vertexSize += attrs[i];
|
||||
for (int i = 0; attrs[i].size; i++){
|
||||
vertexSize += attrs[i].size;
|
||||
}
|
||||
|
||||
glGenVertexArrays(1, &vao);
|
||||
@ -21,8 +24,8 @@ Mesh::Mesh(const float* buffer, size_t vertices, const int* attrs) : vertices(ve
|
||||
|
||||
// attributes
|
||||
int offset = 0;
|
||||
for (int i = 0; attrs[i]; i++){
|
||||
int size = attrs[i];
|
||||
for (int i = 0; attrs[i].size; i++){
|
||||
int size = attrs[i].size;
|
||||
glVertexAttribPointer(i, size, GL_FLOAT, GL_FALSE, vertexSize * sizeof(float), (GLvoid*)(offset * sizeof(float)));
|
||||
glEnableVertexAttribArray(i);
|
||||
offset += size;
|
||||
@ -32,6 +35,7 @@ Mesh::Mesh(const float* buffer, size_t vertices, const int* attrs) : vertices(ve
|
||||
}
|
||||
|
||||
Mesh::~Mesh(){
|
||||
meshesCount--;
|
||||
glDeleteVertexArrays(1, &vao);
|
||||
glDeleteBuffers(1, &vbo);
|
||||
}
|
||||
@ -48,3 +52,7 @@ void Mesh::draw(unsigned int primitive){
|
||||
glDrawArrays(primitive, 0, vertices);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
void Mesh::draw() {
|
||||
draw(GL_TRIANGLES);
|
||||
}
|
||||
@ -2,6 +2,11 @@
|
||||
#define GRAPHICS_MESH_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "../typedefs.h"
|
||||
|
||||
struct vattr {
|
||||
ubyte size;
|
||||
};
|
||||
|
||||
class Mesh {
|
||||
unsigned int vao;
|
||||
@ -9,11 +14,14 @@ class Mesh {
|
||||
size_t vertices;
|
||||
size_t vertexSize;
|
||||
public:
|
||||
Mesh(const float* buffer, size_t vertices, const int* attrs);
|
||||
Mesh(const float* buffer, size_t vertices, const vattr* attrs);
|
||||
~Mesh();
|
||||
|
||||
void reload(const float* buffer, size_t vertices);
|
||||
void draw(unsigned int primitive);
|
||||
void draw();
|
||||
|
||||
static int meshesCount;
|
||||
};
|
||||
|
||||
#endif /* GRAPHICS_MESH_H_ */
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#include "hud_render.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
@ -20,19 +21,6 @@
|
||||
|
||||
|
||||
HudRenderer::HudRenderer() {
|
||||
// float vertices[] = {
|
||||
// // x y
|
||||
// -0.01f,-0.01f,
|
||||
// 0.01f, 0.01f,
|
||||
|
||||
// -0.01f, 0.01f,
|
||||
// 0.01f,-0.01f,
|
||||
// };
|
||||
// int attrs[] = {
|
||||
// 2, 0 //null terminator
|
||||
// };
|
||||
// crosshair = new Mesh(vertices, 4, attrs);
|
||||
|
||||
batch = new Batch2D(1024);
|
||||
uicamera = new Camera(glm::vec3(), Window::height / 1.0f);
|
||||
uicamera->perspective = false;
|
||||
@ -63,6 +51,11 @@ void HudRenderer::drawDebug(Level* level, Assets* assets, int fps, bool occlusio
|
||||
font->draw(batch, L"fps:", 16, 42, STYLE_OUTLINE);
|
||||
font->draw(batch, std::to_wstring(fps), 44, 42, STYLE_OUTLINE);
|
||||
font->draw(batch, L"occlusion: "+std::to_wstring(occlusion), 16, 54, STYLE_OUTLINE);
|
||||
|
||||
std::wstringstream stream;
|
||||
stream << std::hex << player->selectedVoxel.states;
|
||||
font->draw(batch, L"block-selected: "+std::to_wstring(player->selectedVoxel.id)+L" "+stream.str(), 16, 78, STYLE_OUTLINE);
|
||||
font->draw(batch, L"meshes: " + std::to_wstring(Mesh::meshesCount), 16, 102, STYLE_OUTLINE);
|
||||
// batch->render();
|
||||
}
|
||||
|
||||
|
||||
@ -6,8 +6,11 @@
|
||||
#include "../voxels/voxel.h"
|
||||
#include "../voxels/Block.h"
|
||||
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
using std::shared_ptr;
|
||||
|
||||
Lighting::Lighting(Chunks* chunks){
|
||||
this->chunks = chunks;
|
||||
solverR = new LightSolver(chunks, 0);
|
||||
@ -25,7 +28,7 @@ Lighting::~Lighting(){
|
||||
|
||||
void Lighting::clear(){
|
||||
for (unsigned int index = 0; index < chunks->volume; index++){
|
||||
Chunk* chunk = chunks->chunks[index];
|
||||
shared_ptr<Chunk> chunk = chunks->chunks[index];
|
||||
if (chunk == nullptr)
|
||||
continue;
|
||||
Lightmap* lightmap = chunk->lightmap;
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
#ifndef LIGHTING_LIGHTMAP_H_
|
||||
#define LIGHTING_LIGHTMAP_H_
|
||||
|
||||
#include "../constants.h"
|
||||
#include "../voxels/Chunk.h"
|
||||
|
||||
// Lichtkarte
|
||||
class Lightmap {
|
||||
public:
|
||||
unsigned short* map;
|
||||
light_t* map;
|
||||
int highestPoint = 0;
|
||||
Lightmap();
|
||||
~Lightmap();
|
||||
@ -60,6 +62,18 @@ public:
|
||||
const int index = y*CHUNK_D*CHUNK_W+z*CHUNK_W+x;
|
||||
map[index] = (map[index] & (0xFFFF & (~(0xF << (channel*4))))) | (value << (channel << 2));
|
||||
}
|
||||
|
||||
inline const light_t* getLights() const {
|
||||
return map;
|
||||
}
|
||||
|
||||
inline light_t* getLightsWriteable() {
|
||||
return map;
|
||||
}
|
||||
|
||||
static inline light_t extract(light_t light, ubyte channel) {
|
||||
return (light >> (channel << 2)) & 0xF;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* LIGHTING_LIGHTMAP_H_ */
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "../voxels/voxel.h"
|
||||
|
||||
class Camera;
|
||||
class Hitbox;
|
||||
class PhysicsSolver;
|
||||
@ -21,6 +23,7 @@ public:
|
||||
float cameraShaking = 0.0f;
|
||||
float cameraShakingTimer = 0.0f;
|
||||
glm::vec3 interpVel {0.0f, 0.0f, 0.0f};
|
||||
voxel selectedVoxel {0, 0};
|
||||
Player(glm::vec3 position, float speed, Camera* camera);
|
||||
~Player();
|
||||
};
|
||||
|
||||
@ -5,15 +5,13 @@
|
||||
#include <glm/ext.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
using namespace glm;
|
||||
|
||||
class Hitbox;
|
||||
class Chunks;
|
||||
|
||||
class PhysicsSolver {
|
||||
vec3 gravity;
|
||||
glm::vec3 gravity;
|
||||
public:
|
||||
PhysicsSolver(vec3 gravity);
|
||||
PhysicsSolver(glm::vec3 gravity);
|
||||
void step(Chunks* chunks,
|
||||
Hitbox* hitbox,
|
||||
float delta,
|
||||
@ -21,7 +19,7 @@ public:
|
||||
bool shifting,
|
||||
float gravityScale,
|
||||
bool collisions);
|
||||
void colisionCalc(Chunks* chunks, Hitbox* hitbox, vec3* vel, vec3* pos, vec3 half);
|
||||
void colisionCalc(Chunks* chunks, Hitbox* hitbox, glm::vec3* vel, glm::vec3* pos, glm::vec3 half);
|
||||
bool isBlockInside(int x, int y, int z, Hitbox* hitbox);
|
||||
};
|
||||
|
||||
|
||||
@ -183,6 +183,7 @@ void PlayerController::update_interaction(){
|
||||
vec3 iend;
|
||||
voxel* vox = chunks->rayCast(camera->position, camera->front, 10.0f, end, norm, iend);
|
||||
if (vox != nullptr){
|
||||
player->selectedVoxel = *vox;
|
||||
selectedBlockId = vox->id;
|
||||
selectedBlockPosition = iend;
|
||||
int x = (int)iend.x;
|
||||
|
||||
@ -2,3 +2,6 @@
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned char ubyte;
|
||||
|
||||
typedef uint8_t blockid_t;
|
||||
typedef uint16_t light_t;
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <ctime>
|
||||
#include <exception>
|
||||
@ -17,8 +18,6 @@
|
||||
#include <glm/ext.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
using namespace glm;
|
||||
|
||||
#include "window/Window.h"
|
||||
#include "window/Events.h"
|
||||
#include "window/Camera.h"
|
||||
@ -26,7 +25,7 @@ using namespace glm;
|
||||
#include "voxels/Chunk.h"
|
||||
#include "voxels/Chunks.h"
|
||||
#include "voxels/ChunksController.h"
|
||||
#include "voxels/ChunksLoader.h"
|
||||
#include "voxels/ChunksStorage.h"
|
||||
#include "objects/Player.h"
|
||||
#include "world/Level.h"
|
||||
#include "world/World.h"
|
||||
@ -36,14 +35,19 @@ using namespace glm;
|
||||
#include "world_render.h"
|
||||
#include "hud_render.h"
|
||||
|
||||
using std::shared_ptr;
|
||||
|
||||
|
||||
class initialize_error : public std::runtime_error {
|
||||
public:
|
||||
initialize_error(const std::string& message) : std::runtime_error(message) {}
|
||||
};
|
||||
|
||||
|
||||
struct EngineSettings {
|
||||
int displayWidth;
|
||||
int displayHeight;
|
||||
int displaySamples;
|
||||
const char* title;
|
||||
};
|
||||
|
||||
@ -66,8 +70,7 @@ public:
|
||||
};
|
||||
|
||||
Engine::Engine(const EngineSettings& settings) {
|
||||
Window::initialize(settings.displayWidth, settings.displayHeight, settings.title);
|
||||
Events::initialize();
|
||||
Window::initialize(settings.displayWidth, settings.displayHeight, settings.title, settings.displaySamples);
|
||||
|
||||
assets = new Assets();
|
||||
std::cout << "-- loading assets" << std::endl;
|
||||
@ -78,7 +81,7 @@ Engine::Engine(const EngineSettings& settings) {
|
||||
if (!loader.loadNext()) {
|
||||
delete assets;
|
||||
Window::terminate();
|
||||
throw std::runtime_error("could not to initialize assets");
|
||||
throw initialize_error("could not to initialize assets");
|
||||
}
|
||||
}
|
||||
std::cout << "-- loading world" << std::endl;
|
||||
@ -115,7 +118,7 @@ void Engine::updateHotkeys() {
|
||||
}
|
||||
if (Events::jpressed(GLFW_KEY_F5)) {
|
||||
for (unsigned i = 0; i < level->chunks->volume; i++) {
|
||||
Chunk* chunk = level->chunks->chunks[i];
|
||||
shared_ptr<Chunk> chunk = level->chunks->chunks[i];
|
||||
if (chunk != nullptr && chunk->isReady()) {
|
||||
chunk->setModified(true);
|
||||
}
|
||||
@ -137,15 +140,7 @@ void Engine::mainloop() {
|
||||
updateHotkeys();
|
||||
|
||||
level->update(delta, Events::_cursor_locked);
|
||||
int freeLoaders = level->chunksController->countFreeLoaders();
|
||||
for (int i = 0; i < freeLoaders; i++)
|
||||
level->chunksController->_buildMeshes();
|
||||
freeLoaders = level->chunksController->countFreeLoaders();
|
||||
for (int i = 0; i < freeLoaders; i++)
|
||||
level->chunksController->calculateLights();
|
||||
freeLoaders = level->chunksController->countFreeLoaders();
|
||||
for (int i = 0; i < freeLoaders; i++)
|
||||
level->chunksController->loadVisible(world->wfile);
|
||||
level->chunksController->loadVisible(world->wfile);
|
||||
|
||||
worldRenderer.draw(camera, occlusion);
|
||||
hud.draw(level, assets);
|
||||
@ -176,15 +171,13 @@ Engine::~Engine() {
|
||||
|
||||
int main() {
|
||||
setup_definitions();
|
||||
|
||||
try {
|
||||
Engine engine(EngineSettings{ 1280, 720, "VoxelEngine-Cpp v13" });
|
||||
Engine engine(EngineSettings{ 1280, 720, 1, "VoxelEngine-Cpp v13" });
|
||||
engine.mainloop();
|
||||
}
|
||||
catch (const initialize_error& err) {
|
||||
std::cerr << "could not to initialize engine" << std::endl;
|
||||
std::cerr << err.what() << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -4,6 +4,13 @@
|
||||
#define BLOCK_MODEL_CUBE 1
|
||||
#define BLOCK_MODEL_X_SPRITE 2
|
||||
|
||||
#define FACE_MX 0
|
||||
#define FACE_PX 1
|
||||
#define FACE_MY 2
|
||||
#define FACE_PY 3
|
||||
#define FACE_MZ 4
|
||||
#define FACE_PZ 5
|
||||
|
||||
class Block {
|
||||
public:
|
||||
static Block* blocks[256];
|
||||
|
||||
@ -36,11 +36,3 @@ Chunk* Chunk::clone() const {
|
||||
return other;
|
||||
}
|
||||
|
||||
void Chunk::incref(){
|
||||
references++;
|
||||
}
|
||||
|
||||
void Chunk::decref(){
|
||||
if (--references <= 0)
|
||||
delete this;
|
||||
}
|
||||
|
||||
@ -2,11 +2,7 @@
|
||||
#define VOXELS_CHUNK_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define CHUNK_W 16
|
||||
#define CHUNK_H 256
|
||||
#define CHUNK_D 16
|
||||
#define CHUNK_VOL (CHUNK_W * CHUNK_H * CHUNK_D * 2)
|
||||
#include "../constants.h"
|
||||
|
||||
#define CHUNK_MODIFIED 0x1
|
||||
#define CHUNK_READY 0x2
|
||||
@ -14,7 +10,7 @@
|
||||
#define CHUNK_LIGHTED 0x8
|
||||
#define CHUNK_UNSAVED 0x10
|
||||
|
||||
class voxel;
|
||||
struct voxel;
|
||||
class Lightmap;
|
||||
|
||||
struct RenderData {
|
||||
@ -33,7 +29,6 @@ public:
|
||||
Lightmap* lightmap;
|
||||
int flags = 0;
|
||||
int surrounding = 0;
|
||||
int references = 1;
|
||||
RenderData renderData;
|
||||
|
||||
Chunk(int x, int z);
|
||||
@ -42,8 +37,6 @@ public:
|
||||
bool isEmpty();
|
||||
|
||||
Chunk* clone() const;
|
||||
void incref();
|
||||
void decref();
|
||||
|
||||
// flags getters/setters below
|
||||
|
||||
|
||||
@ -7,29 +7,28 @@
|
||||
#include "../files/WorldFiles.h"
|
||||
|
||||
#include "../graphics/Mesh.h"
|
||||
#include "../voxmaths.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
using glm::vec3;
|
||||
using std::shared_ptr;
|
||||
|
||||
Chunks::Chunks(int w, int d, int ox, int oz) : w(w), d(d), ox(ox), oz(oz){
|
||||
volume = w*d;
|
||||
chunks = new Chunk*[volume];
|
||||
chunksSecond = new Chunk*[volume];
|
||||
|
||||
meshes = new Mesh*[volume];
|
||||
meshesSecond = new Mesh*[volume];
|
||||
chunks = new shared_ptr<Chunk>[volume];
|
||||
chunksSecond = new shared_ptr<Chunk>[volume];
|
||||
|
||||
for (size_t i = 0; i < volume; i++){
|
||||
chunks[i] = nullptr;
|
||||
meshes[i] = nullptr;
|
||||
}
|
||||
chunksCount = 0;
|
||||
}
|
||||
|
||||
Chunks::~Chunks(){
|
||||
for (size_t i = 0; i < volume; i++){
|
||||
if (chunks[i])
|
||||
chunks[i]->decref();
|
||||
chunks[i] = nullptr;
|
||||
}
|
||||
delete[] chunks;
|
||||
}
|
||||
@ -45,7 +44,7 @@ voxel* Chunks::get(int x, int y, int z){
|
||||
if (z < 0) cz--;
|
||||
if (cx < 0 || cy < 0 || cz < 0 || cx >= w || cy >= 1 || cz >= d)
|
||||
return nullptr;
|
||||
Chunk* chunk = chunks[(cy * d + cz) * w + cx];
|
||||
shared_ptr<Chunk> chunk = chunks[(cy * d + cz) * w + cx];
|
||||
if (chunk == nullptr)
|
||||
return nullptr;
|
||||
int lx = x - cx * CHUNK_W;
|
||||
@ -61,18 +60,15 @@ bool Chunks::isObstacle(int x, int y, int z){
|
||||
return Block::blocks[v->id]->obstacle;
|
||||
}
|
||||
|
||||
unsigned char Chunks::getLight(int x, int y, int z, int channel){
|
||||
ubyte Chunks::getLight(int x, int y, int z, int channel){
|
||||
x -= ox * CHUNK_W;
|
||||
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--;
|
||||
int cx = floordiv(x, CHUNK_W);
|
||||
int cy = floordiv(y, CHUNK_H);
|
||||
int cz = floordiv(z, CHUNK_D);
|
||||
if (cx < 0 || cy < 0 || cz < 0 || cx >= w || cy >= 1 || cz >= d)
|
||||
return 0;
|
||||
Chunk* chunk = chunks[(cy * d + cz) * w + cx];
|
||||
shared_ptr<Chunk> chunk = chunks[(cy * d + cz) * w + cx];
|
||||
if (chunk == nullptr)
|
||||
return 0;
|
||||
int lx = x - cx * CHUNK_W;
|
||||
@ -81,18 +77,15 @@ 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){
|
||||
light_t Chunks::getLight(int x, int y, int z){
|
||||
x -= ox * CHUNK_W;
|
||||
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--;
|
||||
int cx = floordiv(x, CHUNK_W);
|
||||
int cy = floordiv(y, CHUNK_H);
|
||||
int cz = floordiv(z, CHUNK_D);
|
||||
if (cx < 0 || cy < 0 || cz < 0 || cx >= w || cy >= 1 || cz >= d)
|
||||
return 0;
|
||||
Chunk* chunk = chunks[(cy * d + cz) * w + cx];
|
||||
shared_ptr<Chunk> chunk = chunks[(cy * d + cz) * w + cx];
|
||||
if (chunk == nullptr)
|
||||
return 0;
|
||||
int lx = x - cx * CHUNK_W;
|
||||
@ -112,7 +105,7 @@ Chunk* Chunks::getChunkByVoxel(int x, int y, int z){
|
||||
if (z < 0) cz--;
|
||||
if (cx < 0 || cy < 0 || cz < 0 || cx >= w || cy >= 1 || cz >= d)
|
||||
return nullptr;
|
||||
return chunks[(cy * d + cz) * w + cx];
|
||||
return chunks[(cy * d + cz) * w + cx].get();
|
||||
}
|
||||
|
||||
Chunk* Chunks::getChunk(int x, int z){
|
||||
@ -120,7 +113,7 @@ Chunk* Chunks::getChunk(int x, int z){
|
||||
z -= oz;
|
||||
if (x < 0 || z < 0 || x >= w || z >= d)
|
||||
return nullptr;
|
||||
return chunks[z * w + x];
|
||||
return chunks[z * w + x].get();
|
||||
}
|
||||
|
||||
void Chunks::set(int x, int y, int z, int id, uint8_t states){
|
||||
@ -134,7 +127,7 @@ void Chunks::set(int x, int y, int z, int id, uint8_t states){
|
||||
if (z < 0) cz--;
|
||||
if (cx < 0 || cz < 0 || cx >= w || cz >= d)
|
||||
return;
|
||||
Chunk* chunk = chunks[cz * w + cx];
|
||||
Chunk* chunk = chunks[cz * w + cx].get();
|
||||
if (chunk == nullptr)
|
||||
return;
|
||||
int lx = x - cx * CHUNK_W;
|
||||
@ -169,7 +162,7 @@ voxel* Chunks::rayCast(vec3 a, vec3 dir, float maxDist, vec3& end, vec3& norm, v
|
||||
float stepy = (dy > 0.0f) ? 1.0f : -1.0f;
|
||||
float stepz = (dz > 0.0f) ? 1.0f : -1.0f;
|
||||
|
||||
float infinity = std::numeric_limits<float>::infinity();
|
||||
constexpr float infinity = std::numeric_limits<float>::infinity();
|
||||
|
||||
float txDelta = (dx == 0.0f) ? infinity : abs(1.0f / dx);
|
||||
float tyDelta = (dy == 0.0f) ? infinity : abs(1.0f / dy);
|
||||
@ -256,35 +249,26 @@ void Chunks::setCenter(WorldFiles* worldFiles, int x, int z) {
|
||||
void Chunks::translate(WorldFiles* worldFiles, int dx, int dz){
|
||||
for (unsigned int i = 0; i < volume; i++){
|
||||
chunksSecond[i] = nullptr;
|
||||
meshesSecond[i] = nullptr;
|
||||
}
|
||||
for (int z = 0; z < d; z++){
|
||||
for (int x = 0; x < w; x++){
|
||||
Chunk* chunk = chunks[z * w + x];
|
||||
shared_ptr<Chunk> chunk = chunks[z * w + x];
|
||||
int nx = x - dx;
|
||||
int nz = z - dz;
|
||||
if (chunk == nullptr)
|
||||
continue;
|
||||
Mesh* mesh = meshes[z * w + x];
|
||||
if (nx < 0 || nz < 0 || nx >= w || nz >= d){
|
||||
worldFiles->put((const char*)chunk->voxels, chunk->x, chunk->z);
|
||||
chunk->decref();
|
||||
delete mesh;
|
||||
worldFiles->put((const ubyte*)chunk->voxels, chunk->x, chunk->z);
|
||||
chunksCount--;
|
||||
continue;
|
||||
}
|
||||
meshesSecond[nz * w + nx] = mesh;
|
||||
chunksSecond[nz * w + nx] = chunk;
|
||||
}
|
||||
}
|
||||
Chunk** ctemp = chunks;
|
||||
shared_ptr<Chunk>* ctemp = chunks;
|
||||
chunks = chunksSecond;
|
||||
chunksSecond = ctemp;
|
||||
|
||||
Mesh** mtemp = meshes;
|
||||
meshes = meshesSecond;
|
||||
meshesSecond = mtemp;
|
||||
|
||||
ox += dx;
|
||||
oz += dz;
|
||||
}
|
||||
@ -294,7 +278,7 @@ void Chunks::_setOffset(int x, int z){
|
||||
oz = z;
|
||||
}
|
||||
|
||||
bool Chunks::putChunk(Chunk* chunk) {
|
||||
bool Chunks::putChunk(shared_ptr<Chunk> chunk) {
|
||||
int x = chunk->x;
|
||||
int z = chunk->z;
|
||||
x -= ox;
|
||||
@ -306,14 +290,9 @@ bool Chunks::putChunk(Chunk* chunk) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void Chunks::clear(bool freeMemory){
|
||||
void Chunks::clear(){
|
||||
for (size_t i = 0; i < volume; i++){
|
||||
if (freeMemory){
|
||||
chunks[i]->decref();
|
||||
delete meshes[i];
|
||||
}
|
||||
chunks[i] = nullptr;
|
||||
meshes[i] = nullptr;
|
||||
}
|
||||
chunksCount = 0;
|
||||
}
|
||||
|
||||
@ -2,11 +2,10 @@
|
||||
#define VOXELS_CHUNKS_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <memory>
|
||||
#include <glm/glm.hpp>
|
||||
#include "../typedefs.h"
|
||||
|
||||
using namespace glm;
|
||||
|
||||
class Mesh;
|
||||
class VoxelRenderer;
|
||||
|
||||
class Chunk;
|
||||
@ -15,10 +14,8 @@ class WorldFiles;
|
||||
|
||||
class Chunks {
|
||||
public:
|
||||
Chunk** chunks;
|
||||
Chunk** chunksSecond;
|
||||
Mesh** meshes;
|
||||
Mesh** meshesSecond;
|
||||
std::shared_ptr<Chunk>* chunks;
|
||||
std::shared_ptr<Chunk>* chunksSecond;
|
||||
size_t volume;
|
||||
size_t chunksCount;
|
||||
int w,d;
|
||||
@ -27,15 +24,15 @@ public:
|
||||
Chunks(int w, int d, int ox, int oz);
|
||||
~Chunks();
|
||||
|
||||
bool putChunk(Chunk* chunk);
|
||||
bool putChunk(std::shared_ptr<Chunk> chunk);
|
||||
|
||||
Chunk* getChunk(int x, 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);
|
||||
light_t getLight(int x, int y, int z);
|
||||
ubyte getLight(int x, int y, int z, int channel);
|
||||
void set(int x, int y, int z, int id, uint8_t states);
|
||||
voxel* rayCast(vec3 start, vec3 dir, float maxLength, vec3& end, vec3& norm, vec3& iend);
|
||||
voxel* rayCast(glm::vec3 start, glm::vec3 dir, float maxLength, glm::vec3& end, glm::vec3& norm, glm::vec3& iend);
|
||||
|
||||
bool isObstacle(int x, int y, int z);
|
||||
|
||||
@ -45,7 +42,7 @@ public:
|
||||
void setCenter(WorldFiles* worldFiles, int x, int z);
|
||||
void translate(WorldFiles* worldFiles, int x, int z);
|
||||
|
||||
void clear(bool freeMemory);
|
||||
void clear();
|
||||
};
|
||||
|
||||
#endif /* VOXELS_CHUNKS_H_ */
|
||||
|
||||
@ -1,14 +1,17 @@
|
||||
#include "ChunksController.h"
|
||||
#include "Block.h"
|
||||
#include "Chunk.h"
|
||||
#include "Chunks.h"
|
||||
#include "ChunksStorage.h"
|
||||
#include "WorldGenerator.h"
|
||||
#include "../graphics/Mesh.h"
|
||||
#include "../graphics/VoxelRenderer.h"
|
||||
#include "../lighting/Lighting.h"
|
||||
#include "../files/WorldFiles.h"
|
||||
#include "ChunksLoader.h"
|
||||
#include "../world/Level.h"
|
||||
#include "../world/World.h"
|
||||
#include <iostream>
|
||||
#include <limits.h>
|
||||
#include <memory>
|
||||
|
||||
#if defined(_WIN32) && defined(__MINGW32__)
|
||||
#define _WIN32_WINNT 0x0501
|
||||
@ -19,31 +22,13 @@
|
||||
|
||||
#define MIN_SURROUNDING 9
|
||||
|
||||
using std::shared_ptr;
|
||||
|
||||
ChunksController::ChunksController(World* world, Chunks* chunks, Lighting* lighting) : chunks(chunks), lighting(lighting){
|
||||
loadersCount = std::thread::hardware_concurrency() * 2 - 1;
|
||||
if (loadersCount <= 0)
|
||||
loadersCount = 1;
|
||||
loaders = new ChunksLoader*[loadersCount];
|
||||
for (int i = 0; i < loadersCount; i++){
|
||||
loaders[i] = new ChunksLoader(world);
|
||||
}
|
||||
std::cout << "created " << loadersCount << " loaders" << std::endl;
|
||||
|
||||
ChunksController::ChunksController(Level* level, Chunks* chunks, Lighting* lighting) : level(level), chunks(chunks), lighting(lighting){
|
||||
}
|
||||
|
||||
ChunksController::~ChunksController(){
|
||||
for (int i = 0; i < loadersCount; i++)
|
||||
delete loaders[i];
|
||||
delete[] loaders;
|
||||
}
|
||||
|
||||
int ChunksController::countFreeLoaders(){
|
||||
int count = 0;
|
||||
for (int i = 0; i < loadersCount; i++){
|
||||
if (!loaders[i]->isBusy())
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
bool ChunksController::loadVisible(WorldFiles* worldFiles){
|
||||
@ -57,16 +42,22 @@ bool ChunksController::loadVisible(WorldFiles* worldFiles){
|
||||
for (int z = 2; z < d-2; z++){
|
||||
for (int x = 2; x < w-2; x++){
|
||||
int index = z * w + x;
|
||||
Chunk* chunk = chunks->chunks[index];
|
||||
shared_ptr<Chunk> chunk = chunks->chunks[index];
|
||||
if (chunk != nullptr){
|
||||
int surrounding = 0;
|
||||
for (int oz = -1; oz <= 1; oz++){
|
||||
for (int ox = -1; ox <= 1; ox++){
|
||||
Chunk* other = chunks->getChunk(chunk->x+ox, chunk->z+oz);
|
||||
if (other != nullptr && other->isReady()) surrounding++;
|
||||
if (other != nullptr) surrounding++;
|
||||
}
|
||||
}
|
||||
chunk->surrounding = surrounding;
|
||||
if (surrounding == MIN_SURROUNDING && !chunk->isLighted()) {
|
||||
lighting->buildSkyLight(chunk->x, chunk->z);
|
||||
lighting->onChunkLoaded(chunk->x, chunk->z);
|
||||
chunk->setLighted(true);
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
int lx = x - w / 2;
|
||||
@ -81,200 +72,29 @@ bool ChunksController::loadVisible(WorldFiles* worldFiles){
|
||||
}
|
||||
|
||||
int index = nearZ * w + nearX;
|
||||
Chunk* chunk = chunks->chunks[index];
|
||||
if (chunk != nullptr)
|
||||
shared_ptr<Chunk> chunk = chunks->chunks[index];
|
||||
if (chunk != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ChunksLoader* freeLoader = getFreeLoader();
|
||||
if (freeLoader == nullptr)
|
||||
return false;
|
||||
|
||||
chunk = new Chunk(nearX+ox, nearZ+oz);
|
||||
if (worldFiles->getChunk(chunk->x, chunk->z, (char*)chunk->voxels))
|
||||
chunk = shared_ptr<Chunk>(new Chunk(nearX+ox, nearZ+oz));
|
||||
level->chunksStorage->store(chunk);
|
||||
if (worldFiles->getChunk(chunk->x, chunk->z, (ubyte*)chunk->voxels))
|
||||
chunk->setLoaded(true);
|
||||
|
||||
chunks->putChunk(chunk);
|
||||
|
||||
Chunk* closes[9];
|
||||
for (int i = 0; i < 9; i++)
|
||||
closes[i] = nullptr;
|
||||
for (size_t j = 0; j < chunks->volume; j++){
|
||||
Chunk* other = chunks->chunks[j];
|
||||
if (other == nullptr)
|
||||
continue;
|
||||
if (!other->isReady())
|
||||
continue;
|
||||
|
||||
int ox = other->x - chunk->x;
|
||||
int oz = other->z - chunk->z;
|
||||
|
||||
if (abs(ox) > 1 || abs(oz) > 1)
|
||||
continue;
|
||||
|
||||
ox += 1;
|
||||
oz += 1;
|
||||
closes[oz * 3 + ox] = other;
|
||||
if (!chunk->isLoaded()) {
|
||||
WorldGenerator::generate(chunk->voxels, chunk->x, chunk->z, level->world->seed);
|
||||
chunk->setUnsaved(true);
|
||||
}
|
||||
freeLoader->load(chunk, (Chunk**)closes);
|
||||
|
||||
for (size_t i = 0; i < CHUNK_VOL; i++) {
|
||||
if (Block::blocks[chunk->voxels[i].id] == nullptr) {
|
||||
std::cout << "corruped block detected at " << i << " of chunk " << chunk->x << "x" << chunk->z << std::endl;
|
||||
chunk->voxels[i].id = 11;
|
||||
}
|
||||
}
|
||||
lighting->prebuildSkyLight(chunk->x, chunk->z);
|
||||
return true;
|
||||
}
|
||||
|
||||
ChunksLoader* ChunksController::getFreeLoader() {
|
||||
ChunksLoader* freeLoader = nullptr;
|
||||
for (int i = 0; i < loadersCount; i++){
|
||||
ChunksLoader* loader = loaders[i];
|
||||
if (loader->isBusy()){
|
||||
continue;
|
||||
}
|
||||
freeLoader = loader;
|
||||
break;
|
||||
}
|
||||
return freeLoader;
|
||||
}
|
||||
|
||||
void ChunksController::calculateLights() {
|
||||
ChunksLoader* freeLoader = getFreeLoader();
|
||||
if (freeLoader == nullptr)
|
||||
return;
|
||||
const int w = chunks->w;
|
||||
const int d = chunks->d;
|
||||
int nearX = 0;
|
||||
int nearZ = 0;
|
||||
int minDistance = INT_MAX;
|
||||
for (int z = 1; z < d-1; z++){
|
||||
for (int x = 1; x < w-1; x++){
|
||||
int index = z * w + x;
|
||||
Chunk* chunk = chunks->chunks[index];
|
||||
if (chunk == nullptr)
|
||||
continue;
|
||||
if (chunk->isLighted() || chunk->surrounding < MIN_SURROUNDING){
|
||||
continue;
|
||||
}
|
||||
int lx = x - w / 2;
|
||||
int lz = z - d / 2;
|
||||
int distance = (lx * lx + lz * lz);
|
||||
if (distance < minDistance){
|
||||
minDistance = distance;
|
||||
nearX = x;
|
||||
nearZ = z;
|
||||
}
|
||||
}
|
||||
}
|
||||
int index = nearZ * w + nearX;
|
||||
Chunk* chunk = chunks->chunks[index];
|
||||
if (chunk == nullptr)
|
||||
return;
|
||||
Chunk* closes[9];
|
||||
for (int i = 0; i < 9; i++)
|
||||
closes[i] = nullptr;
|
||||
for (size_t j = 0; j < chunks->volume; j++){
|
||||
Chunk* other = chunks->chunks[j];
|
||||
if (other == nullptr)
|
||||
continue;
|
||||
|
||||
int ox = other->x - chunk->x;
|
||||
int oz = other->z - chunk->z;
|
||||
|
||||
if (abs(ox) > 1|| abs(oz) > 1)
|
||||
continue;
|
||||
|
||||
ox += 1;
|
||||
oz += 1;
|
||||
closes[oz * 3 + ox] = other;
|
||||
}
|
||||
freeLoader->lights(chunk, (Chunk**)closes);
|
||||
}
|
||||
|
||||
bool ChunksController::_buildMeshes() {
|
||||
const int w = chunks->w;
|
||||
const int d = chunks->d;
|
||||
|
||||
for (int z = 1; z < d-1; z++){
|
||||
for (int x = 1; x < w-1; x++){
|
||||
int index = z * w + x;
|
||||
Chunk* chunk = chunks->chunks[index];
|
||||
if (chunk == nullptr)
|
||||
continue;
|
||||
if (chunk->renderData.vertices > (void*)1){
|
||||
const int chunk_attrs[] = {3,2,4, 0};
|
||||
Mesh* mesh = new Mesh(chunk->renderData.vertices, chunk->renderData.size / CHUNK_VERTEX_SIZE, chunk_attrs);
|
||||
if (chunks->meshes[index])
|
||||
delete chunks->meshes[index];
|
||||
chunks->meshes[index] = mesh;
|
||||
delete[] chunk->renderData.vertices;
|
||||
chunk->renderData.vertices = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
ChunksLoader* freeLoader = getFreeLoader();
|
||||
if (freeLoader == nullptr)
|
||||
return false;
|
||||
|
||||
int nearX = 0;
|
||||
int nearZ = 0;
|
||||
int minDistance = INT_MAX;
|
||||
for (int z = 1; z < d-1; z++){
|
||||
for (int x = 1; x < w-1; x++){
|
||||
int index = z * w + x;
|
||||
Chunk* chunk = chunks->chunks[index];
|
||||
if (chunk == nullptr)
|
||||
continue;
|
||||
Mesh* mesh = chunks->meshes[index];
|
||||
if (mesh != nullptr && !chunk->isModified())
|
||||
continue;
|
||||
if (!chunk->isReady() || !chunk->isLighted() || chunk->surrounding < MIN_SURROUNDING){
|
||||
continue;
|
||||
}
|
||||
int lx = x - w / 2;
|
||||
int lz = z - d / 2;
|
||||
int distance = (lx * lx + lz * lz);
|
||||
if (distance < minDistance){
|
||||
minDistance = distance;
|
||||
nearX = x;
|
||||
nearZ = z;
|
||||
}
|
||||
}
|
||||
}
|
||||
int index = nearZ * w + nearX;
|
||||
Chunk* chunk = chunks->chunks[index];
|
||||
if (chunk == nullptr){
|
||||
return false;
|
||||
}
|
||||
Mesh* mesh = chunks->meshes[index];
|
||||
if (mesh == nullptr || chunk->isModified()){
|
||||
if (chunk->renderData.vertices != nullptr) {
|
||||
return false;
|
||||
}
|
||||
Chunk* closes[9];
|
||||
if (chunk->isEmpty()){
|
||||
chunks->meshes[index] = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 9; i++)
|
||||
closes[i] = nullptr;
|
||||
for (size_t j = 0; j < chunks->volume; j++){
|
||||
Chunk* other = chunks->chunks[j];
|
||||
if (other == nullptr)
|
||||
continue;
|
||||
|
||||
int ox = other->x - chunk->x;
|
||||
int oz = other->z - chunk->z;
|
||||
|
||||
if (abs(ox) > 1 || abs(oz) > 1)
|
||||
continue;
|
||||
|
||||
ox += 1;
|
||||
oz += 1;
|
||||
if ((!other->isReady() || !other->isLighted()) && other != chunk)
|
||||
return false;
|
||||
closes[oz * 3 + ox] = other;
|
||||
}
|
||||
chunk->setModified(false);
|
||||
chunk->renderData.vertices = (float*)1;
|
||||
freeLoader->render(chunk, (Chunk**)closes);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
#ifndef VOXELS_CHUNKSCONTROLLER_H_
|
||||
#define VOXELS_CHUNKSCONTROLLER_H_
|
||||
|
||||
class World;
|
||||
class Level;
|
||||
class Chunks;
|
||||
class Lighting;
|
||||
class WorldFiles;
|
||||
@ -10,19 +10,14 @@ class ChunksLoader;
|
||||
|
||||
class ChunksController {
|
||||
private:
|
||||
Level* level;
|
||||
Chunks* chunks;
|
||||
Lighting* lighting;
|
||||
ChunksLoader** loaders;
|
||||
int loadersCount;
|
||||
public:
|
||||
ChunksController(World* world, Chunks* chunks, Lighting* lighting);
|
||||
ChunksController(Level* level, Chunks* chunks, Lighting* lighting);
|
||||
~ChunksController();
|
||||
|
||||
ChunksLoader* getFreeLoader();
|
||||
int countFreeLoaders();
|
||||
bool loadVisible(WorldFiles* worldFiles);
|
||||
void calculateLights();
|
||||
bool _buildMeshes();
|
||||
};
|
||||
|
||||
#endif /* VOXELS_CHUNKSCONTROLLER_H_ */
|
||||
|
||||
93
src/voxels/ChunksStorage.cpp
Normal file
93
src/voxels/ChunksStorage.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
#include "ChunksStorage.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "VoxelsVolume.h"
|
||||
#include "Chunk.h"
|
||||
#include "../voxmaths.h"
|
||||
#include "../lighting/Lightmap.h"
|
||||
|
||||
|
||||
using glm::ivec2;
|
||||
using std::shared_ptr;
|
||||
|
||||
ChunksStorage::ChunksStorage() {
|
||||
}
|
||||
|
||||
ChunksStorage::~ChunksStorage() {
|
||||
}
|
||||
|
||||
void ChunksStorage::store(shared_ptr<Chunk> chunk) {
|
||||
chunksMap[ivec2(chunk->x, chunk->z)] = chunk;
|
||||
}
|
||||
|
||||
shared_ptr<Chunk> ChunksStorage::get(int x, int z) const {
|
||||
auto found = chunksMap.find(ivec2(x, z));
|
||||
if (found == chunksMap.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return found->second;
|
||||
}
|
||||
|
||||
// some magic code
|
||||
void ChunksStorage::getVoxels(VoxelsVolume* volume) const {
|
||||
voxel* voxels = volume->getVoxels();
|
||||
light_t* lights = volume->getLights();
|
||||
int x = volume->getX();
|
||||
int y = volume->getY();
|
||||
int z = volume->getZ();
|
||||
|
||||
int w = volume->getW();
|
||||
int h = volume->getH();
|
||||
int d = volume->getD();
|
||||
|
||||
int scx = floordiv(x, CHUNK_W);
|
||||
int scz = floordiv(z, CHUNK_D);
|
||||
|
||||
int ecx = floordiv(x + w, CHUNK_W);
|
||||
int ecz = floordiv(z + d, CHUNK_D);
|
||||
|
||||
int cw = ecx - scx + 1;
|
||||
int ch = ecz - scz + 1;
|
||||
|
||||
// cw*ch chunks will be scanned
|
||||
for (int cz = scz; cz < scz + ch; cz++) {
|
||||
for (int cx = scx; cx < scx + cw; cx++) {
|
||||
auto found = chunksMap.find(ivec2(cx, cz));
|
||||
if (found == chunksMap.end()) {
|
||||
// no chunk loaded -> filling with BLOCK_VOID
|
||||
for (int ly = y; ly < y + h; ly++) {
|
||||
for (int lz = max(z, cz * CHUNK_D);
|
||||
lz < min(z + d, (cz + 1) * CHUNK_D);
|
||||
lz++) {
|
||||
for (int lx = max(x, cx * CHUNK_W);
|
||||
lx < min(x + w, (cx + 1) * CHUNK_W);
|
||||
lx++) {
|
||||
voxels[vox_index(lx - x, ly - y, lz - z, w, d)].id = BLOCK_VOID;
|
||||
lights[vox_index(lx - x, ly - y, lz - z, w, d)] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const std::shared_ptr<Chunk>& chunk = found->second;
|
||||
const voxel* cvoxels = chunk->voxels;
|
||||
const light_t* clights = chunk->lightmap->getLights();
|
||||
for (int ly = y; ly < y + h; ly++) {
|
||||
for (int lz = max(z, cz * CHUNK_D);
|
||||
lz < min(z + d, (cz + 1) * CHUNK_D);
|
||||
lz++) {
|
||||
for (int lx = max(x, cx * CHUNK_W);
|
||||
lx < min(x + w, (cx + 1) * CHUNK_W);
|
||||
lx++) {
|
||||
voxels[vox_index(lx - x, ly - y, lz - z, w, d)] =
|
||||
cvoxels[vox_index(lx - cx * CHUNK_W, ly, lz - cz * CHUNK_D, CHUNK_W, CHUNK_D)];
|
||||
lights[vox_index(lx - x, ly - y, lz - z, w, d)] =
|
||||
clights[vox_index(lx - cx * CHUNK_W, ly, lz - cz * CHUNK_D, CHUNK_W, CHUNK_D)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
src/voxels/ChunksStorage.h
Normal file
29
src/voxels/ChunksStorage.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef VOXELS_CHUNKSSTORAGE_H_
|
||||
#define VOXELS_CHUNKSSTORAGE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include "voxel.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include "glm/gtx/hash.hpp"
|
||||
|
||||
class Chunk;
|
||||
class VoxelsVolume;
|
||||
|
||||
class ChunksStorage {
|
||||
std::unordered_map<glm::ivec2, std::shared_ptr<Chunk>> chunksMap;
|
||||
public:
|
||||
ChunksStorage();
|
||||
virtual ~ChunksStorage();
|
||||
|
||||
std::shared_ptr<Chunk> get(int x, int y) const;
|
||||
void store(std::shared_ptr<Chunk> chunk);
|
||||
void getVoxels(VoxelsVolume* volume) const;
|
||||
|
||||
light_t getLight(int x, int y, int z, ubyte channel) const;
|
||||
};
|
||||
|
||||
|
||||
#endif // VOXELS_CHUNKSSTORAGE_H_
|
||||
30
src/voxels/VoxelsVolume.cpp
Normal file
30
src/voxels/VoxelsVolume.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
#include "VoxelsVolume.h"
|
||||
|
||||
VoxelsVolume::VoxelsVolume(int x, int y, int z, int w, int h, int d)
|
||||
: x(x), y(y), z(z), w(w), h(h), d(d) {
|
||||
voxels = new voxel[w * h * d];
|
||||
for (int i = 0; i < w * h * d; i++) {
|
||||
voxels[i].id = BLOCK_VOID;
|
||||
}
|
||||
lights = new light_t[w * h * d];
|
||||
}
|
||||
|
||||
VoxelsVolume::VoxelsVolume(int w, int h, int d)
|
||||
: x(0), y(0), z(0), w(w), h(h), d(d) {
|
||||
voxels = new voxel[w * h * d];
|
||||
for (int i = 0; i < w * h * d; i++) {
|
||||
voxels[i].id = BLOCK_VOID;
|
||||
}
|
||||
lights = new light_t[w * h * d];
|
||||
}
|
||||
|
||||
VoxelsVolume::~VoxelsVolume() {
|
||||
delete[] lights;
|
||||
delete[] voxels;
|
||||
}
|
||||
|
||||
void VoxelsVolume::setPosition(int x, int y, int z) {
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
this->z = z;
|
||||
}
|
||||
67
src/voxels/VoxelsVolume.h
Normal file
67
src/voxels/VoxelsVolume.h
Normal file
@ -0,0 +1,67 @@
|
||||
#ifndef VOXELS_VOXELSVOLUME_H_
|
||||
#define VOXELS_VOXELSVOLUME_H_
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../constants.h"
|
||||
#include "voxel.h"
|
||||
|
||||
class VoxelsVolume {
|
||||
int x, y, z;
|
||||
int w, h, d;
|
||||
voxel* voxels;
|
||||
light_t* lights;
|
||||
public:
|
||||
VoxelsVolume(int w, int h, int d);
|
||||
VoxelsVolume(int x, int y, int z, int w, int h, int d);
|
||||
virtual ~VoxelsVolume();
|
||||
|
||||
void setPosition(int x, int y, int z);
|
||||
|
||||
int getX() const {
|
||||
return x;
|
||||
}
|
||||
|
||||
int getY() const {
|
||||
return y;
|
||||
}
|
||||
|
||||
int getZ() const {
|
||||
return z;
|
||||
}
|
||||
|
||||
int getW() const {
|
||||
return w;
|
||||
}
|
||||
|
||||
int getH() const {
|
||||
return h;
|
||||
}
|
||||
|
||||
int getD() const {
|
||||
return d;
|
||||
}
|
||||
|
||||
voxel* getVoxels() const {
|
||||
return voxels;
|
||||
}
|
||||
|
||||
light_t* getLights() const {
|
||||
return lights;
|
||||
}
|
||||
|
||||
inline blockid_t pickBlockId(int bx, int by, int bz) const {
|
||||
if (bx < x || by < y || bz < z || bx >= x + w || by >= y + h || bz >= z + d) {
|
||||
return BLOCK_VOID;
|
||||
}
|
||||
return voxels[vox_index(bx - x, by - y, bz - z, w, d)].id;
|
||||
}
|
||||
|
||||
inline light_t pickLight(int bx, int by, int bz) const {
|
||||
if (bx < x || by < y || bz < z || bx >= x + w || by >= y + h || bz >= z + d) {
|
||||
return 0;
|
||||
}
|
||||
return lights[vox_index(bx - x, by - y, bz - z, w, d)];
|
||||
}
|
||||
};
|
||||
|
||||
#endif // VOXELS_VOXELSVOLUME_H_
|
||||
@ -1,10 +1,10 @@
|
||||
#ifndef VOXELS_VOXEL_H_
|
||||
#define VOXELS_VOXEL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../typedefs.h"
|
||||
|
||||
struct voxel {
|
||||
uint8_t id;
|
||||
blockid_t id;
|
||||
uint8_t states;
|
||||
};
|
||||
|
||||
|
||||
43
src/voxmaths.h
Normal file
43
src/voxmaths.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef SRC_VOXNATHS_H_
|
||||
#define SRC_VOXNATHS_H_
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
inline int floordiv(int a, int b) {
|
||||
if (a < 0 && a % b) {
|
||||
return (a / b) - 1;
|
||||
}
|
||||
return a / b;
|
||||
}
|
||||
|
||||
inline int ceildiv(int a, int b) {
|
||||
if (a > 0 && a % b) {
|
||||
return a / b + 1;
|
||||
}
|
||||
return a / b;
|
||||
}
|
||||
|
||||
inline int max(int a, int b) {
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
|
||||
inline int min(int a, int b) {
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
static unsigned int g_seed;
|
||||
|
||||
inline void fast_srand(int seed) {
|
||||
g_seed = seed;
|
||||
}
|
||||
|
||||
inline int fast_rand(void) {
|
||||
g_seed = (214013 * g_seed + 2531011);
|
||||
return (g_seed >> 16) & 0x7FFF;
|
||||
}
|
||||
|
||||
inline light_t light_pack(ubyte r, ubyte g, ubyte b, ubyte s) {
|
||||
return r | (g << 4) | (b << 8) | (s << 12);
|
||||
}
|
||||
|
||||
#endif // SRC_VOXNATHS_H_
|
||||
@ -13,60 +13,15 @@ float Events::y = 0.0f;
|
||||
bool Events::_cursor_locked = false;
|
||||
bool Events::_cursor_started = false;
|
||||
|
||||
#define _MOUSE_BUTTONS 1024
|
||||
|
||||
void cursor_position_callback(GLFWwindow*, double xpos, double ypos){
|
||||
if (Events::_cursor_started){
|
||||
Events::deltaX += xpos-Events::x;
|
||||
Events::deltaY += ypos-Events::y;
|
||||
}
|
||||
else {
|
||||
Events::_cursor_started = true;
|
||||
}
|
||||
Events::x = xpos;
|
||||
Events::y = ypos;
|
||||
}
|
||||
|
||||
void mouse_button_callback(GLFWwindow*, int button, int action, int){
|
||||
if (action == GLFW_PRESS){
|
||||
Events::_keys[_MOUSE_BUTTONS+button] = true;
|
||||
Events::_frames[_MOUSE_BUTTONS+button] = Events::_current;
|
||||
}
|
||||
else if (action == GLFW_RELEASE){
|
||||
Events::_keys[_MOUSE_BUTTONS+button] = false;
|
||||
Events::_frames[_MOUSE_BUTTONS+button] = Events::_current;
|
||||
}
|
||||
}
|
||||
|
||||
void key_callback(GLFWwindow*, int key, int /*scancode*/, int action, int /*mode*/) {
|
||||
if (action == GLFW_PRESS){
|
||||
Events::_keys[key] = true;
|
||||
Events::_frames[key] = Events::_current;
|
||||
}
|
||||
else if (action == GLFW_RELEASE){
|
||||
Events::_keys[key] = false;
|
||||
Events::_frames[key] = Events::_current;
|
||||
}
|
||||
}
|
||||
|
||||
void window_size_callback(GLFWwindow*, int width, int height){
|
||||
glViewport(0,0, width, height);
|
||||
Window::width = width;
|
||||
Window::height = height;
|
||||
}
|
||||
|
||||
int Events::initialize(){
|
||||
GLFWwindow* window = Window::window;
|
||||
_keys = new bool[1032];
|
||||
_frames = new uint[1032];
|
||||
|
||||
memset(_keys, false, 1032*sizeof(bool));
|
||||
memset(_frames, 0, 1032*sizeof(uint));
|
||||
|
||||
glfwSetKeyCallback(window, key_callback);
|
||||
glfwSetMouseButtonCallback(window, mouse_button_callback);
|
||||
glfwSetCursorPosCallback(window, cursor_position_callback);
|
||||
glfwSetWindowSizeCallback(window, window_size_callback);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -30,4 +30,6 @@ public:
|
||||
static void toggleCursor();
|
||||
};
|
||||
|
||||
#define _MOUSE_BUTTONS 1024
|
||||
|
||||
#endif /* WINDOW_EVENTS_H_ */
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#include <iostream>
|
||||
#include "Window.h"
|
||||
#include "Events.h"
|
||||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
@ -7,13 +8,53 @@ GLFWwindow* Window::window = nullptr;
|
||||
uint Window::width = 0;
|
||||
uint Window::height = 0;
|
||||
|
||||
int Window::initialize(uint width, uint height, const char* title){
|
||||
void cursor_position_callback(GLFWwindow*, double xpos, double ypos) {
|
||||
if (Events::_cursor_started) {
|
||||
Events::deltaX += xpos - Events::x;
|
||||
Events::deltaY += ypos - Events::y;
|
||||
}
|
||||
else {
|
||||
Events::_cursor_started = true;
|
||||
}
|
||||
Events::x = xpos;
|
||||
Events::y = ypos;
|
||||
}
|
||||
|
||||
void mouse_button_callback(GLFWwindow*, int button, int action, int) {
|
||||
if (action == GLFW_PRESS) {
|
||||
Events::_keys[_MOUSE_BUTTONS + button] = true;
|
||||
Events::_frames[_MOUSE_BUTTONS + button] = Events::_current;
|
||||
}
|
||||
else if (action == GLFW_RELEASE) {
|
||||
Events::_keys[_MOUSE_BUTTONS + button] = false;
|
||||
Events::_frames[_MOUSE_BUTTONS + button] = Events::_current;
|
||||
}
|
||||
}
|
||||
|
||||
void key_callback(GLFWwindow*, int key, int /*scancode*/, int action, int /*mode*/) {
|
||||
if (action == GLFW_PRESS) {
|
||||
Events::_keys[key] = true;
|
||||
Events::_frames[key] = Events::_current;
|
||||
}
|
||||
else if (action == GLFW_RELEASE) {
|
||||
Events::_keys[key] = false;
|
||||
Events::_frames[key] = Events::_current;
|
||||
}
|
||||
}
|
||||
|
||||
void window_size_callback(GLFWwindow*, int width, int height) {
|
||||
glViewport(0, 0, width, height);
|
||||
Window::width = width;
|
||||
Window::height = height;
|
||||
}
|
||||
|
||||
int Window::initialize(uint width, uint height, const char* title, int samples){
|
||||
glfwInit();
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
|
||||
glfwWindowHint(GLFW_SAMPLES, 16);
|
||||
glfwWindowHint(GLFW_SAMPLES, samples);
|
||||
|
||||
window = glfwCreateWindow(width, height, title, nullptr, nullptr);
|
||||
if (window == nullptr){
|
||||
@ -35,11 +76,16 @@ int Window::initialize(uint width, uint height, const char* title){
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_BLEND);
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
// glDisable(GL_MULTISAMPLE);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
Window::width = width;
|
||||
Window::height = height;
|
||||
|
||||
Events::initialize();
|
||||
glfwSetKeyCallback(window, key_callback);
|
||||
glfwSetMouseButtonCallback(window, mouse_button_callback);
|
||||
glfwSetCursorPosCallback(window, cursor_position_callback);
|
||||
glfwSetWindowSizeCallback(window, window_size_callback);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -6,11 +6,11 @@
|
||||
class GLFWwindow;
|
||||
|
||||
class Window {
|
||||
static GLFWwindow* window;
|
||||
public:
|
||||
static uint width;
|
||||
static uint height;
|
||||
static GLFWwindow* window; // не лучшее решение делать window публичным
|
||||
static int initialize(uint width, uint height, const char* title);
|
||||
static int initialize(uint width, uint height, const char* title, int samples);
|
||||
static void terminate();
|
||||
|
||||
static void viewport(int x, int y, int width, int height);
|
||||
|
||||
@ -3,18 +3,20 @@
|
||||
#include "../lighting/Lighting.h"
|
||||
#include "../voxels/Chunks.h"
|
||||
#include "../voxels/ChunksController.h"
|
||||
#include "../voxels/ChunksStorage.h"
|
||||
#include "../player_control.h"
|
||||
#include "../physics/Hitbox.h"
|
||||
#include "../physics/PhysicsSolver.h"
|
||||
#include "../objects/Player.h"
|
||||
|
||||
Level::Level(World* world, Player* player, Chunks* chunks, PhysicsSolver* physics) :
|
||||
Level::Level(World* world, Player* player, Chunks* chunks, ChunksStorage* chunksStorage, PhysicsSolver* physics) :
|
||||
world(world),
|
||||
player(player),
|
||||
chunks(chunks),
|
||||
chunksStorage(chunksStorage),
|
||||
physics(physics) {
|
||||
lighting = new Lighting(chunks);
|
||||
chunksController = new ChunksController(world, chunks, lighting);
|
||||
chunksController = new ChunksController(this, chunks, lighting);
|
||||
playerController = new PlayerController(this);
|
||||
}
|
||||
|
||||
@ -24,6 +26,7 @@ Level::~Level(){
|
||||
delete player;
|
||||
delete lighting;
|
||||
delete chunksController;
|
||||
delete chunksStorage;
|
||||
delete playerController;
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ class Chunks;
|
||||
class Lighting;
|
||||
class PhysicsSolver;
|
||||
class ChunksController;
|
||||
class ChunksStorage;
|
||||
class PlayerController;
|
||||
|
||||
class Level {
|
||||
@ -14,11 +15,12 @@ public:
|
||||
World* world;
|
||||
Player* player;
|
||||
Chunks* chunks;
|
||||
ChunksStorage* chunksStorage;
|
||||
PhysicsSolver* physics;
|
||||
Lighting* lighting;
|
||||
ChunksController* chunksController;
|
||||
PlayerController* playerController;
|
||||
Level(World* world, Player* player, Chunks* chunks, PhysicsSolver* physics);
|
||||
Level(World* world, Player* player, Chunks* chunks, ChunksStorage* chunksStorage, PhysicsSolver* physics);
|
||||
~Level();
|
||||
|
||||
void update(float delta, bool interactions);
|
||||
|
||||
@ -1,13 +1,18 @@
|
||||
#include "World.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "Level.h"
|
||||
#include "../files/WorldFiles.h"
|
||||
#include "../voxels/Chunk.h"
|
||||
#include "../voxels/Chunks.h"
|
||||
#include "Level.h"
|
||||
#include "../voxels/ChunksStorage.h"
|
||||
#include "../objects/Player.h"
|
||||
#include "../physics/PhysicsSolver.h"
|
||||
#include "../window/Camera.h"
|
||||
|
||||
using std::shared_ptr;
|
||||
|
||||
World::World(std::string name, std::string directory, int seed) : name(name), seed(seed) {
|
||||
wfile = new WorldFiles(directory, REGION_VOL * (CHUNK_VOL * 2 + 8));
|
||||
}
|
||||
@ -20,10 +25,10 @@ void World::write(Level* level) {
|
||||
Chunks* chunks = level->chunks;
|
||||
|
||||
for (unsigned int i = 0; i < chunks->volume; i++) {
|
||||
Chunk* chunk = chunks->chunks[i];
|
||||
shared_ptr<Chunk> chunk = chunks->chunks[i];
|
||||
if (chunk == nullptr || !chunk->isUnsaved())
|
||||
continue;
|
||||
wfile->put((const char*)chunk->voxels, chunk->x, chunk->z);
|
||||
wfile->put((const ubyte*)chunk->voxels, chunk->x, chunk->z);
|
||||
}
|
||||
|
||||
wfile->write();
|
||||
@ -31,7 +36,8 @@ void World::write(Level* level) {
|
||||
}
|
||||
|
||||
Level* World::loadLevel(Player* player) {
|
||||
Level* level = new Level(this, player, new Chunks(56, 56, 0, 0), new PhysicsSolver(vec3(0, -19.6f, 0)));
|
||||
ChunksStorage* storage = new ChunksStorage();
|
||||
Level* level = new Level(this, player, new Chunks(16, 16, 0, 0), storage, new PhysicsSolver(vec3(0, -19.6f, 0)));
|
||||
wfile->readPlayer(player);
|
||||
|
||||
Camera* camera = player->camera;
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
#include "world_render.h"
|
||||
|
||||
#include <iostream>
|
||||
#include "graphics/VoxelRenderer.h"
|
||||
#include <GL/glew.h>
|
||||
#include <memory>
|
||||
|
||||
#include "graphics/ChunksRenderer.h"
|
||||
#include "window/Window.h"
|
||||
#include "window/Camera.h"
|
||||
#include "graphics/Mesh.h"
|
||||
@ -20,13 +21,15 @@
|
||||
#include "Assets.h"
|
||||
#include "player_control.h"
|
||||
|
||||
using std::shared_ptr;
|
||||
|
||||
float _camera_cx;
|
||||
float _camera_cz;
|
||||
|
||||
WorldRenderer::WorldRenderer(Level* level, Assets* assets) : assets(assets), level(level) {
|
||||
lineBatch = new LineBatch(4096);
|
||||
batch3d = new Batch3D(1024);
|
||||
renderer = new VoxelRenderer();
|
||||
renderer = new ChunksRenderer(level);
|
||||
}
|
||||
|
||||
WorldRenderer::~WorldRenderer() {
|
||||
@ -38,15 +41,17 @@ WorldRenderer::~WorldRenderer() {
|
||||
Chunks* _chunks = nullptr;
|
||||
|
||||
bool chunks_distance_compare(size_t i, size_t j) {
|
||||
Chunk* a = _chunks->chunks[i];
|
||||
Chunk* b = _chunks->chunks[j];
|
||||
shared_ptr<Chunk> a = _chunks->chunks[i];
|
||||
shared_ptr<Chunk> b = _chunks->chunks[j];
|
||||
return ((a->x + 0.5f - _camera_cx)*(a->x + 0.5f - _camera_cx) + (a->z + 0.5f - _camera_cz)*(a->z + 0.5f - _camera_cz) >
|
||||
(b->x + 0.5f - _camera_cx)*(b->x + 0.5f - _camera_cx) + (b->z + 0.5f - _camera_cz)*(b->z + 0.5f - _camera_cz));
|
||||
}
|
||||
|
||||
bool WorldRenderer::drawChunk(size_t index, Camera* camera, Shader* shader, bool occlusion){
|
||||
Chunk* chunk = level->chunks->chunks[index];
|
||||
Mesh* mesh = level->chunks->meshes[index];
|
||||
shared_ptr<Chunk> chunk = level->chunks->chunks[index];
|
||||
if (!chunk->isLighted())
|
||||
return false;
|
||||
shared_ptr<Mesh> mesh = renderer->getOrRender(chunk.get());
|
||||
if (mesh == nullptr)
|
||||
return false;
|
||||
|
||||
@ -64,7 +69,7 @@ bool WorldRenderer::drawChunk(size_t index, Camera* camera, Shader* shader, bool
|
||||
}
|
||||
}
|
||||
}
|
||||
mat4 model = glm::translate(mat4(1.0f), vec3(chunk->x*CHUNK_W+0.5f, 0.5f, chunk->z*CHUNK_D+0.5f));
|
||||
mat4 model = glm::translate(mat4(1.0f), vec3(chunk->x*CHUNK_W, 0.0f, chunk->z*CHUNK_D+1));
|
||||
shader->uniformMatrix("u_model", model);
|
||||
glDisable(GL_MULTISAMPLE);
|
||||
mesh->draw(GL_TRIANGLES);
|
||||
@ -109,11 +114,10 @@ void WorldRenderer::draw(Camera* camera, bool occlusion){
|
||||
std::vector<size_t> indices;
|
||||
|
||||
for (size_t i = 0; i < chunks->volume; i++){
|
||||
Chunk* chunk = chunks->chunks[i];
|
||||
shared_ptr<Chunk> chunk = chunks->chunks[i];
|
||||
if (chunk == nullptr)
|
||||
continue;
|
||||
if (chunks->meshes[i] != nullptr)
|
||||
indices.push_back(i);
|
||||
indices.push_back(i);
|
||||
}
|
||||
|
||||
float px = camera->position.x / (float)CHUNK_W;
|
||||
|
||||
@ -16,7 +16,7 @@ class Camera;
|
||||
class Assets;
|
||||
class LineBatch;
|
||||
class Batch3D;
|
||||
class VoxelRenderer;
|
||||
class ChunksRenderer;
|
||||
class Shader;
|
||||
class Texture;
|
||||
class Framebuffer;
|
||||
@ -28,8 +28,8 @@ class WorldRenderer {
|
||||
Level* level;
|
||||
bool drawChunk(size_t index, Camera* camera, Shader* shader, bool occlusion);
|
||||
public:
|
||||
VoxelRenderer *renderer;
|
||||
LineBatch *lineBatch;
|
||||
ChunksRenderer* renderer;
|
||||
LineBatch* lineBatch;
|
||||
|
||||
WorldRenderer(Level* level, Assets* assets);
|
||||
~WorldRenderer();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user