Browse Source

heightmaps fully working

testing
totallyfake 1 year ago
parent
commit
160495389e

+ 4
- 1
include/heightmap.h View File

@@ -5,6 +5,7 @@
#include <utility>

#include "concurrentqueue.h"
#include "util/mobileatomic.h"

namespace vtk {

@@ -17,13 +18,15 @@ public:

int getHeight(const glm::ivec2& pos);
bool pushUpdate(const glm::ivec3& pos, const bool& destroyed);
void blockHeight(const glm::ivec3& pos);
void unblockHeight(const glm::ivec3& pos);
void flushUpdates(); // called from worker thread
protected:
void setHeight(const::glm::ivec3& pos);
World& mWorld;
glm::ivec2 mPos;
std::array<int, (16*16)> mHeights; //stores 16*16 heightmap
std::array<util::MobileAtomic<int>, (16*16)> mHeights; //stores 16*16 heightmap
moodycamel::ConcurrentQueue<std::pair<glm::ivec3, bool>> mUpdateQueue;
};


+ 5
- 0
include/mathplus.h View File

@@ -20,6 +20,11 @@

namespace mp {

inline constexpr int floor_div3(int a, int b) {
int d = a / b;
return d * b == a ? d : d - ((a < 0) ^ (b < 0));
}

//Convert value to one within min/max. Useful for angles n' shit
template <typename T>
T normalize(const T& value, const T& min, const T& max) {

+ 34
- 0
include/util/mobileatomic.h View File

@@ -0,0 +1,34 @@
#pragma once

#include <cstdint>
#include <atomic>

namespace util {

template<typename T>
struct MobileAtomic
{
std::atomic<T> atomic;

MobileAtomic() : atomic(T()) {}

explicit MobileAtomic ( T const& v ) : atomic ( v ) {}
explicit MobileAtomic ( std::atomic<T> const& a ) : atomic ( a.load() ) {}
inline T load(const std::memory_order& order = std::memory_order_seq_cst) {
return atomic.load(order);
}

inline void store(const T& desired, const std::memory_order& order = std::memory_order_seq_cst) {
atomic.store(desired, order);
}

MobileAtomic ( MobileAtomic const&other ) : atomic( other.atomic.load() ) {}

MobileAtomic& operator=( MobileAtomic const &other )
{
atomic.store( other.atomic.load() );
return *this;
}
};

}

+ 2
- 0
include/voxelmath.h View File

@@ -36,6 +36,8 @@ public:

iPos getChunkContaining(const int& x, const int& y, const int& z);



World* linkedWorld;

protected:

+ 3
- 0
include/voxelutils.h View File

@@ -17,6 +17,9 @@ enum class FaceDirection : unsigned int {

typedef std::tuple<unsigned, unsigned, unsigned> uPos; //used for voxel positions

glm::ivec3 worldPosToChunkPos(const glm::ivec3& pos);
glm::ivec2 worldPosToChunkPos(const glm::ivec2& pos);

/*
//TODO: move this to cpp file
constexpr glm::ivec3 FaceDirectionToVec(const FaceDirection& direction) {

+ 3
- 0
include/world.h View File

@@ -37,6 +37,9 @@ public:

HeightMap* getHeightMap(const glm::ivec2& pos);

//get max height of world at pos(x,z)
int getHeight(const glm::ivec2& pos);

void queueChunkUpdate(const int& x, const int& y, const int& z, const bool& highpriority = false);
void queueChunkUpdate(const glm::ivec3& pos, const bool& highpriority = false);


+ 5
- 1
src/chunk.cpp View File

@@ -92,7 +92,11 @@ unsigned Chunk::getLightPacked(const glm::ivec3 &pos) {
if (isVoxelSolid(pos.x, pos.y, pos.z)) {
return 0x00000000;
}
return 0xFFFFFFFF;
if (getHeightMap()->getHeight(glm::ivec2(pos.x, pos.z)) > pos.y + (mPos.y * 16)) { //voxel is below ground
//std::cout << mLinkedWorld.getHeight(glm::ivec2(pos.x, pos.z)) << ", ";
return 0x000000AA;
}
return 0x000000FF;
}

HeightMap* Chunk::getHeightMap() {

+ 7
- 2
src/game.cpp View File

@@ -40,8 +40,8 @@ void Game::init() {
SDL_Init(SDL_INIT_VIDEO);

SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

SDL_GL_SetSwapInterval(conf->getValue<int>("graphics.vsync", 0));
@@ -63,6 +63,11 @@ void Game::init() {
glCullFace(GL_BACK);
glFrontFace(GL_CW);

//needed for inverted depth buffer for long distance rendering
glDepthFunc(GL_GREATER);
glClearDepth(0.0f);
glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);

running = false;
gls::setTracking(true); // track OpenGL state changes
}

+ 14
- 1
src/graphics/camera.cpp View File

@@ -47,7 +47,20 @@ glm::mat4 Camera::getViewMatrix() {
}

glm::mat4 Camera::getProjectionMatrix() {
return glm::infinitePerspective(mFOV, mAspectRatio, 0.1f);
const float zNear = 0.001f;
const float viewAngleVertical = 90.0f;
const float f = 1.0f / tan(viewAngleVertical / 2.0f); // 1.0 / tan(X) == cotangent(X)
const float aspect = mAspectRatio;

//infinite Perspective matrix reversed
glm::mat4 projectionMatrix = {
f/aspect, 0.0f, 0.0f, 0.0f,
0.0f, f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, -1.0f,
0.0f, 0.0f, zNear, 0.0f
};
return projectionMatrix;
//return glm::perspective(mFOV, mAspectRatio, -100000.0f, -0.01f);
}

glm::mat4 Camera::getAngleMatrix() {

+ 24
- 7
src/heightmap.cpp View File

@@ -7,8 +7,9 @@ HeightMap::HeightMap(const glm::ivec2& pos, World& world) :
mPos(pos),
mWorld(world)
{
//initialize all heights to 0
for (int i = 0; i < mHeights.size(); ++i) {
mHeights[i] = 0x7FFFFFFF;
mHeights[i].store(0x80000000);
}
}

@@ -18,27 +19,43 @@ glm::ivec2 HeightMap::getPos() {

int HeightMap::getHeight(const glm::ivec2 &pos) {
int index = pos.x + (16 * pos.y);
return mHeights[index];
return mHeights[index].load();
}

bool HeightMap::pushUpdate(const glm::ivec3 &pos, const bool &destroyed) {
return mUpdateQueue.try_enqueue(std::make_pair(pos, destroyed));
}

void HeightMap::blockHeight(const glm::ivec3& pos) {
if (getHeight(glm::ivec2(pos.x, pos.z)) < pos.y) {
setHeight(pos);
}
}

void HeightMap::unblockHeight(const glm::ivec3& pos) {
int height = getHeight(glm::ivec2(pos.x, pos.z));
if (height <= pos.y) {
glm::ivec3 searchPos(pos.x + (mPos.x * 16), pos.y, pos.z + (mPos.y * 16));
while (!mWorld.isVoxelSolid(searchPos.x, searchPos.y, searchPos.z)) {
--searchPos.y;
}
setHeight(glm::ivec3(pos.x, searchPos.y, pos.z));
}
}

void HeightMap::flushUpdates() {
std::pair<glm::ivec3, bool> updateItem;
while (mUpdateQueue.try_dequeue(updateItem)) {
glm::ivec3& pos = updateItem.first;
int index = pos.x + (16 * pos.y);
int height = getHeight(glm::ivec2(pos.x, pos.z));
if (updateItem.second) { // if destroyed
if(height <= pos.y) { // if voxel is at the top of the heightmap
if(height == pos.y) { // if voxel is at the top of the heightmap
// search downward until the next solid voxel is reached
glm::ivec3 searchPos(pos.x + (mPos.x * 16), pos.y, pos.z + (mPos.y * 16));
while(mWorld.isVoxelSolid(searchPos.x, searchPos.y, searchPos.z)) {
while(!mWorld.isVoxelSolid(searchPos.x, searchPos.y, searchPos.z)) {
--searchPos.y;
}
setHeight(searchPos);
setHeight(glm::ivec3(pos.x, searchPos.y, pos.z));
}
} else { // if placed
if (height < pos.y)
@@ -48,7 +65,7 @@ void HeightMap::flushUpdates() {
}

void HeightMap::setHeight(const glm::ivec3& pos) {
mHeights[pos.x + (16 * pos.z)] = pos.y;
mHeights[pos.x + (16 * pos.z)].store(pos.y);
}

}

+ 3
- 0
src/main.cpp View File

@@ -13,6 +13,9 @@

int main (int argc, char *argv[])
{
glm::ivec3 test(-14, -18, -18);
std::cout << glm::ivec3(test / 16).x << std::endl;
vtk::LoggerSetup lSetup;
lSetup.setup();
spdlog::get("general")->info("Starting Voxeltronik Engine...");

+ 1
- 0
src/scenes/testscene.cpp View File

@@ -165,6 +165,7 @@ void TestScene::update(const float& dTime) {
world.voxelMath.rayCast(hitPos, hitNormal, success, camera.getPosition(), camera.getAngleVector(), 10);
if (success) {
std::cout << "Hit voxel at: " << hitPos.x << ", " << hitPos.y << ", " << hitPos.z << std::endl;
std::cout << "Height @ " << world.getHeight(glm::ivec2(hitPos.x + hitNormal.x, hitPos.z + hitNormal.z)) << std::endl;
if (handler.isActionDown("Place Voxel")) {
world.setVoxelType((int)(hitPos.x + hitNormal.x), (int)(hitPos.y + hitNormal.y), (int)(hitPos.z + hitNormal.z), voxelType, true);
} else {

+ 1
- 3
src/terraingen.cpp View File

@@ -57,10 +57,8 @@ void TerrainGen::generateChunk(Chunk* chunk) {
} else {// block above is air
chunk->setVoxelType(i,j,k,1);
}
chunk->getHeightMap()->pushUpdate(glm::ivec3(i,(chunkPos.y * 16) + j, k),false);
chunk->getHeightMap()->blockHeight(glm::ivec3(i,(chunkPos.y * 16) + j, k));
} else {
chunk->getHeightMap()->pushUpdate(glm::ivec3(i,(chunkPos.y * 16) + j, k), true);
chunk->setVoxelType(i,j,k,0);
}
}
}

+ 0
- 0
src/util/mobileatomic.cpp View File


+ 16
- 0
src/voxelutils.cpp View File

@@ -0,0 +1,16 @@
#include "voxelutils.h"
#include "mathplus.h"

namespace vtk {

glm::ivec3 worldPosToChunkPos(const glm::ivec3& pos) {
return glm::ivec3(mp::floor_div3(pos.x, 16),
mp::floor_div3(pos.y, 16),
mp::floor_div3(pos.z, 16));
}

glm::ivec2 worldPosToChunkPos(const glm::ivec2& pos) {
return glm::ivec2(mp::floor_div3(pos.x, 16),
mp::floor_div3(pos.y, 16));
}
}

+ 12
- 4
src/world.cpp View File

@@ -42,9 +42,7 @@ bool World::isVoxelSolid(const int& x, const int& y, const int& z) {
}

bool World::setVoxelType(const int& x, const int& y, const int& z, const unsigned& type, const bool& updateChunk) {
auto chunkPos = glm::ivec3(floor((float)x / (float)chunkSize),
floor((float)y / (float)chunkSize),
floor((float)z / (float)chunkSize));
auto chunkPos = worldPosToChunkPos(glm::ivec3(x,y,z));

auto chunk = getChunk(chunkPos);
if (!chunk) return false;
@@ -54,6 +52,10 @@ bool World::setVoxelType(const int& x, const int& y, const int& z, const unsigne
int relPosZ = z - chunkPos.z * chunkSize;

chunk->setVoxelType(relPosX, relPosY, relPosZ, type, updateChunk);
if (type != 0)
getHeightMap(glm::ivec2(chunkPos.x, chunkPos.z))->blockHeight(glm::ivec3(relPosX, y, relPosZ));
else
getHeightMap(glm::ivec2(chunkPos.x, chunkPos.z))->unblockHeight(glm::ivec3(relPosX, y, relPosZ));
return true;
}

@@ -88,7 +90,7 @@ Chunk* World::makeChunk(const int& x, const int& y, const int& z, bool insertAft
}

bool World::generateChunk(const int& x, const int& y, const int& z) {
auto chunkMade = makeChunk(x,y,z, false);
auto chunkMade = makeChunk(x,y,z);
if (chunkMade != nullptr) {
terrain.generateChunk(chunkMade);
//queue this chunk for geometry update
@@ -134,6 +136,12 @@ HeightMap* World::getHeightMap(const glm::ivec2& pos) {
return heightMap;
}

int World::getHeight(const glm::ivec2& pos) {
glm::ivec2 cPos = worldPosToChunkPos(pos);
return getHeightMap(cPos)->getHeight(pos - (cPos * 16));
std::cout << cPos.x << ", " << cPos.y << std::endl;
}

void World::queueChunkUpdate(const int& x, const int& y, const int& z, const bool& highpriority) {
queueChunkUpdate(glm::ivec3(x,y,z));
}

Loading…
Cancel
Save