@@ -2,7 +2,7 @@ cmake_minimum_required (VERSION 3.6) | |||
project ("voxeltronik") | |||
file (GLOB_RECURSE SOURCES "src/*.cpp" "src/*.c") | |||
include_directories("./include" "libcuckoo/libcuckoo") | |||
set(CMAKE_CXX_STANDARD 14) | |||
set(CMAKE_CXX_STANDARD 17) | |||
set(CMAKE_CXX_FLAGS "-O2") | |||
set(CMAKE_C_FLAGS "-fPIC") | |||
set(CMAKE_EXPORT_COMPILE_COMMANDS on) |
@@ -10,6 +10,8 @@ namespace vtk { | |||
class World; | |||
class HeightMap; | |||
typedef std::pair<short, unsigned short> LightIndexPair; | |||
class Chunk { | |||
friend class World; | |||
public: | |||
@@ -26,6 +28,7 @@ public: | |||
bool placeVoxel(const glm::ivec3& pos, const unsigned& type); | |||
bool isVoxelSolid(const int& x, const int& y, const int& z); //Is the voxel not a transparent type? | |||
bool isVoxelSolid(const glm::ivec3& pos); | |||
void setVoxelType(const glm::ivec3& pos, const unsigned& type); | |||
void setVoxelType(const int& x, const int& y, const int& z, const unsigned& type, const bool& update = false); | |||
@@ -33,9 +36,11 @@ public: | |||
unsigned getVoxelType(const glm::ivec3& pos); | |||
unsigned getVoxelType(const unsigned& x, const unsigned& y, const unsigned& z); | |||
void rebuildLighting(); | |||
glm::ivec3 getWorldCoords(const int& x, const int& y, const int& z); | |||
unsigned getLightLevel(const glm::ivec3& pos); | |||
unsigned short getLightPacked(const glm::ivec3& pos); | |||
void setLightPacked(const glm::ivec3& pos, const unsigned short& light); | |||
HeightMap* getHeightMap(); | |||
void setPos(const glm::ivec3& pos); | |||
@@ -44,6 +49,7 @@ public: | |||
protected: | |||
typedef std::tuple<short, Chunk*> LightIndexTup; | |||
void setQueuedForMeshRebuild(const bool& rebuild = true); | |||
bool isQueuedForMeshRebuild(); | |||
@@ -1,21 +1,3 @@ | |||
/* | |||
* ===================================================================================== | |||
* | |||
* Filename: voxelinfo.h | |||
* | |||
* Description: Stores information about voxel types, like texture coordinates. | |||
* | |||
* Version: 1.0 | |||
* Created: 04/06/2014 01:07:52 PM | |||
* Revision: none | |||
* Compiler: gcc | |||
* | |||
* Author: YOUR NAME (), | |||
* Organization: | |||
* | |||
* ===================================================================================== | |||
*/ | |||
#pragma once | |||
#include "voxelutils.h" | |||
@@ -55,6 +37,7 @@ struct VoxelData{ | |||
std::map<FaceDirection, unsigned> faceTextures; | |||
bool transparent; | |||
unsigned short emission; | |||
}; | |||
class World; | |||
@@ -76,6 +59,9 @@ public: | |||
std::pair<float, float> getTexCoordFromID(const unsigned& id, const Face3D& face, const Corner2D& corner); | |||
void setEmission(const unsigned& id, const unsigned short& emission); | |||
unsigned short getEmission(const unsigned& id); | |||
World* linkedWorld; | |||
protected: |
@@ -23,6 +23,10 @@ glm::ivec2 worldPosToChunkPos(const glm::ivec2& pos); | |||
//takes chunk and local positions, returns a world position | |||
glm::ivec3 chunkPosToWorldPos(const glm::ivec3& cPos, const glm::ivec3& lPos); | |||
//takes a chunk/local pos and returns a chunk,local pos pair (works for out of bounds coords) | |||
std::pair<glm::ivec3, glm::ivec3> worldPosToLocalPos(const glm::ivec3& pos); | |||
std::pair<glm::ivec3, glm::ivec3> localPosToLocalPos(const glm::ivec3& cPos, const glm::ivec3& lPos); | |||
/* | |||
//TODO: move this to cpp file | |||
constexpr glm::ivec3 FaceDirectionToVec(const FaceDirection& direction) { |
@@ -2,6 +2,7 @@ | |||
#include "world.h" | |||
#include <iostream> | |||
#include <queue> | |||
namespace vtk { | |||
@@ -17,7 +18,7 @@ Chunk::Chunk(World& world) : | |||
mData[i].store(0); | |||
} | |||
for (unsigned i = 0; i < mLighting.size(); ++i) { | |||
mLighting[i].store(0); | |||
mLighting[i].store(0xFFFF); | |||
} | |||
mLoaded.store(true); | |||
@@ -76,10 +77,12 @@ bool Chunk::placeVoxel(const glm::ivec3& pos, const unsigned& type) { | |||
mLinkedWorld.getHeightMap(glm::ivec2(mPos.x, mPos.z)) | |||
->blockHeight(glm::ivec3(pos.x, pos.y + mPos.y * 16, pos.z)); | |||
mLinkedWorld.queueChunkUpdate(mPos); | |||
mLinkedWorld.queueChunkUpdate(mPos, true); | |||
//update the neightboring chunks if voxel lies along border | |||
// TODO: make this a function in voxelutils(voxelmath?) | |||
glm::ivec3 neighborPos(0,0,0); | |||
if (pos.x == 0) neighborPos.x--; | |||
@@ -120,6 +123,10 @@ bool Chunk::isVoxelSolid(const int& x, const int& y, const int& z) { | |||
return !mLinkedWorld.voxelInfo.isTransparent(getVoxelType((unsigned)x, (unsigned)y, (unsigned)z)); | |||
} | |||
bool Chunk::isVoxelSolid(const glm::ivec3& pos) { | |||
return isVoxelSolid(pos.x, pos.y, pos.z); | |||
} | |||
void Chunk::setVoxelType(const glm::ivec3 &pos, const unsigned& type) { | |||
setVoxelType(pos.x, pos.y, pos.z, type); | |||
} | |||
@@ -148,6 +155,75 @@ unsigned Chunk::getVoxelType(const glm::ivec3& pos) { | |||
unsigned Chunk::getVoxelType(const unsigned& x, const unsigned& y, const unsigned& z) { | |||
return getVoxelType(glm::ivec3(x,y,z)); | |||
} | |||
void Chunk::rebuildLighting() { | |||
std::queue<LightIndexTup> sunBFSQueue; | |||
//FIRST PASS, block out all solid blocks | |||
for (short i = 0; i < 4096; ++i) { | |||
glm::ivec3 pos(i % 16, (i / 16) % 16,(i / 256)); // get current coord | |||
mLighting[i].store(0); | |||
auto lightVal = mLinkedWorld.voxelInfo.getEmission(getVoxelType(pos)); | |||
//set sunlighting if at the top of chunk and above the ground | |||
if(pos.y == 15 && | |||
mLinkedWorld.getHeightMap(glm::ivec2(mPos.x, mPos.z)) | |||
->getHeight(glm::ivec2(pos.x, pos.z)) <= | |||
pos.y + mPos.y * 16) | |||
{ | |||
lightVal = lightVal | 0xF; //max out the sun lighting | |||
} | |||
mLighting[i].store(lightVal); | |||
if ((lightVal & 0xF) != 0) { | |||
sunBFSQueue.push(std::make_tuple(i,this)); | |||
} | |||
} | |||
//iterate through sunlight | |||
while (!sunBFSQueue.empty()) { | |||
short index; | |||
Chunk* chunk; | |||
unsigned short light; | |||
std::tie(index, chunk) = sunBFSQueue.front(); | |||
light = light & 0xF; // so I don't have to remask every time | |||
glm::ivec3 pos( index % 16, | |||
(index / 16) % 16, | |||
index / 256); | |||
light = chunk->getLightPacked(pos) & 0xF; | |||
auto propogateSun = | |||
[&](glm::ivec3 nPos, Chunk* nChunk) | |||
{ | |||
bool straightDown = (pos.y > nPos.y && light == 0xF); | |||
auto checkPos = localPosToLocalPos(nChunk->getPos(), nPos); | |||
nChunk = mLinkedWorld.getChunk(checkPos.first); | |||
nPos = checkPos.second; | |||
auto newLight = chunk->getLightPacked(nPos) & 0xF; | |||
if (!chunk->isVoxelSolid(nPos)) { | |||
if (light >= newLight + 2) { | |||
if (straightDown) { | |||
chunk->setLightPacked(nPos, (newLight & 0xFFF0) | 0xF); | |||
} | |||
chunk->setLightPacked(nPos, (newLight & 0xFFF0) | light - 1); | |||
if (light - 1 > 1) { | |||
sunBFSQueue.push(std::make_tuple((short)(nPos.x + 16 * (nPos.y + 16 * nPos.z)), chunk)); | |||
} | |||
} | |||
} | |||
}; | |||
//visit neighbors | |||
propogateSun(glm::ivec3(pos.x-1, pos.y, pos.z), this); | |||
propogateSun(glm::ivec3(pos.x+1, pos.y, pos.z), this); | |||
propogateSun(glm::ivec3(pos.x, pos.y-1, pos.z), this); | |||
propogateSun(glm::ivec3(pos.x, pos.y+1, pos.z), this); | |||
propogateSun(glm::ivec3(pos.x, pos.y, pos.z-1), this); | |||
propogateSun(glm::ivec3(pos.x, pos.y, pos.z+1), this); | |||
sunBFSQueue.pop(); | |||
} | |||
} | |||
glm::ivec3 Chunk::getWorldCoords(const int& x, const int& y, const int& z) { | |||
return glm::ivec3(mPos.x * 16 + x, | |||
mPos.y * 16 + y, | |||
@@ -162,15 +238,25 @@ unsigned Chunk::getLightLevel(const glm::ivec3 &pos) { | |||
} | |||
unsigned short Chunk::getLightPacked(const glm::ivec3 &pos) { | |||
if (isVoxelSolid(pos.x, pos.y, pos.z)) { | |||
return 0x0000; | |||
} | |||
auto wPos = chunkPosToWorldPos(mPos, pos); | |||
if (mLinkedWorld.getHeight(glm::ivec2(wPos.x, wPos.z)) > wPos.y) { //voxel is below ground | |||
//std::cout << mLinkedWorld.getHeight(glm::ivec2(pos.x, pos.z)) << ", "; | |||
return 0x000A; | |||
//checking if pos is inside current chunk | |||
auto lPos = localPosToLocalPos(mPos, pos); //returns a chunk/local pos pair | |||
if (lPos.first != mPos) { //if it's not THIS chunk | |||
auto chunk = mLinkedWorld.getChunk(lPos.first); | |||
if (chunk) | |||
return chunk->getLightPacked(lPos.second); | |||
else | |||
return 0xFFFF; | |||
} | |||
return 0x000F; | |||
int index = pos.x + 16 * (pos.y + 16 * pos.z); | |||
return mLighting[index].load(); | |||
} | |||
void Chunk::setLightPacked(const glm::ivec3& pos, const unsigned short& light) { | |||
int index = pos.x + 16 * (pos.y + 16 * pos.z); | |||
mLighting[index].store(light); | |||
} | |||
HeightMap* Chunk::getHeightMap() { |
@@ -1,21 +1,3 @@ | |||
/* | |||
* ===================================================================================== | |||
* | |||
* Filename: voxelinfo.cpp | |||
* | |||
* Description: Voxelinfo source file | |||
* | |||
* Version: 1.0 | |||
* Created: 04/06/2014 01:30:10 PM | |||
* Revision: none | |||
* Compiler: gcc | |||
* | |||
* Author: YOUR NAME (), | |||
* Organization: | |||
* | |||
* ===================================================================================== | |||
*/ | |||
#include "voxelinfo.h" | |||
#include "world.h" | |||
@@ -141,5 +123,13 @@ bool VoxelInfo::isTransparent(const unsigned& id) { | |||
return voxelDataMap[id].transparent; | |||
} | |||
void VoxelInfo::setEmission(const unsigned int &id, const unsigned short &emission) { | |||
voxelDataMap[id].emission = emission; | |||
} | |||
unsigned short VoxelInfo::getEmission(const unsigned int &id) { | |||
return voxelDataMap[id].emission; | |||
} | |||
} | |||
@@ -18,4 +18,16 @@ glm::ivec2 worldPosToChunkPos(const glm::ivec2& pos) { | |||
glm::ivec3 chunkPosToWorldPos(const glm::ivec3& cPos, const glm::ivec3& lPos) { | |||
return glm::ivec3((cPos * 16) + lPos); | |||
} | |||
std::pair<glm::ivec3, glm::ivec3> worldPosToLocalPos(const glm::ivec3& pos) { | |||
auto cPos = worldPosToChunkPos(pos); | |||
auto lPos = pos - (16 * cPos); | |||
return std::make_pair(cPos, lPos); | |||
} | |||
std::pair<glm::ivec3, glm::ivec3> localPosToLocalPos(const glm::ivec3& cPos, const glm::ivec3& lPos) { | |||
glm::ivec3 wPos = chunkPosToWorldPos(cPos, lPos); // get world coords | |||
return worldPosToLocalPos(wPos); | |||
} | |||
} |
@@ -214,12 +214,9 @@ void World::update() { | |||
auto updatefunc = [&]() { | |||
glm::ivec3 pos; | |||
glm::ivec2 hm_pos; | |||
while (mHeightMapUpdateQueue.try_dequeue(hm_pos)) { | |||
auto heightMap = getHeightMap(hm_pos); | |||
heightMap->flushUpdates(); | |||
} | |||
while (mMeshUpdateQueueSoon.try_dequeue(pos)) { | |||
getChunk(pos)->rebuildLighting(); | |||
ChunkMesh* mesh; | |||
mChunkMeshes.find(pos, mesh); | |||
if (mesh) { | |||
@@ -229,6 +226,7 @@ void World::update() { | |||
} | |||
while (mMeshUpdateQueue.try_dequeue(pos)) { | |||
getChunk(pos)->rebuildLighting(); | |||
ChunkMesh* mesh; | |||
mChunkMeshes.find(pos, mesh); | |||
if (mesh) { |