voxels renderer rebuilt, WorldFiles fix

This commit is contained in:
MihailRis 2023-11-02 13:23:52 +03:00 committed by GitHub
parent 0576316282
commit 754c5b80d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 1141 additions and 524 deletions

View File

@ -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){

View File

@ -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
View 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_

View File

@ -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];
}

View File

@ -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_ */

View File

@ -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];

View File

@ -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];

View 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;
}

View 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

View 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;
}

View 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_

View File

@ -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;

View File

@ -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);
}

View File

@ -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_ */

View File

@ -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();
}

View File

@ -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;

View File

@ -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_ */

View File

@ -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();
};

View File

@ -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);
};

View File

@ -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;

View File

@ -2,3 +2,6 @@
typedef unsigned int uint;
typedef unsigned char ubyte;
typedef uint8_t blockid_t;
typedef uint16_t light_t;

View File

@ -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;
}

View File

@ -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];

View File

@ -36,11 +36,3 @@ Chunk* Chunk::clone() const {
return other;
}
void Chunk::incref(){
references++;
}
void Chunk::decref(){
if (--references <= 0)
delete this;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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_ */

View 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)];
}
}
}
}
}
}
}

View 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_

View 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
View 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_

View File

@ -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
View 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_

View File

@ -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;
}

View File

@ -30,4 +30,6 @@ public:
static void toggleCursor();
};
#define _MOUSE_BUTTONS 1024
#endif /* WINDOW_EVENTS_H_ */

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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();