Converted World's use of glm::vec3* to glm::vec3 to allow proper checks.

master
aurailus 2018-12-19 21:15:05 -08:00
parent a62cadb408
commit 5f6c663003
11 changed files with 162 additions and 80 deletions

View File

@ -66,6 +66,6 @@ add_executable(zeus
zeus/lua_api/LuaParser.h
zeus/lua_api/LRegisterBlock.cpp
zeus/lua_api/LRegisterBlock.h
)
zeus/engine/iVec3.h)
target_link_libraries(zeus ${OPENGL_gl_LIBRARY} glfw libGLEW.so pthread lua dl)

View File

@ -22,7 +22,7 @@ int main(int argc, char* argv[]) {
game->initialize(renderer);
boot.elapsed();
boot.printElapsedSeconds();
//Game Loop
while (!renderer->getWindow()->getShouldClose()) {
@ -43,7 +43,9 @@ int main(int argc, char* argv[]) {
game->draw();
renderer->end();
// t.elapsedMs(); //Print frame time
if (t.elapsedNs() / (double)1000000 >= 20) {
t.printElapsedMs(); //Print frame time
}
}
return 0;

View File

@ -89,4 +89,8 @@ void Camera::update() {
up = glm::normalize(glm::cross(right, front));
}
glm::vec3 *Camera::getPosition() {
return &position;
}
Camera::~Camera() = default;

View File

@ -18,10 +18,11 @@ public:
void keyControl(bool* keys, GLfloat delta);
void mouseControl(double deltaX, double deltaY);
glm::vec3* getPosition();
glm::mat4 calculateViewMatrix();
~Camera();
private:
glm::vec3 position;

View File

@ -9,26 +9,21 @@ Timer::Timer(const char* name) {
start = std::chrono::high_resolution_clock::now();
}
void Timer::elapsedNs() {
auto finish = std::chrono::high_resolution_clock::now();
long elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(finish - start).count();
printf("%s took %ld ns.\n", this->name, elapsed);
}
void Timer::elapsedMs() {
auto finish = std::chrono::high_resolution_clock::now();
double elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(finish - start).count() / (double)1000000;
printf("%s took %.2f ms.\n", this->name, elapsed);
}
void Timer::elapsed() {
long Timer::elapsedNs() {
auto finish = std::chrono::high_resolution_clock::now();
long elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(finish - start).count();
return elapsed;
};
double elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(finish - start).count() / (double)1000000 / (double)1000;
printf("%s took %.2f secs.\n", this->name, elapsed);
void Timer::printElapsedNs() {
printf("%s took %ld ns.\n", this->name, elapsedNs());
}
void Timer::printElapsedMs() {
printf("%s took %.2f ms.\n", this->name, elapsedNs() / (double)1000000);
}
void Timer::printElapsedSeconds() {
printf("%s took %.2f secs.\n", this->name, elapsedNs() / (double)1000000 / (double)1000);
}

View File

@ -12,9 +12,11 @@ class Timer {
public:
explicit Timer(const char* name);
void elapsedNs();
void elapsedMs();
void elapsed(); //Seconds
long elapsedNs();
void printElapsedNs();
void printElapsedMs();
void printElapsedSeconds(); //Seconds
private:
const char* name;
std::chrono::high_resolution_clock::time_point start;

53
zeus/engine/iVec3.h Normal file
View File

@ -0,0 +1,53 @@
//
// Created by aurailus on 19/12/18.
//
#ifndef ZEUS_IVEC3_H
#define ZEUS_IVEC3_H
struct iVec3 {
int x, y, z;
iVec3() {
x = 0;
y = 0;
z = 0;
}
iVec3(int x, int y, int z) {
this->x = x;
this->y = y;
this->z = z;
}
// iVec3(int n) {
// this->x = n;
// this->y = n;
// this->z = n;
// }
};
#endif //ZEUS_IVEC3_H
namespace std {
template<> struct hash<iVec3> {
std::size_t operator()(const iVec3 &k) const {
return (k.x * 97 + k.y) * 89 + k.z;
}
};
template<> struct less<iVec3> {
bool operator()(const iVec3 &a, const iVec3 &b) const {
if (a.x < b.x) return true;
if (a.y < b.y) return true;
if (a.z < b.z) return true;
return false;
}
};
template<> struct equal_to<iVec3> {
bool operator()(const iVec3 &a, const iVec3 &b) const {
return (a.x == b.x && a.y == b.y && a.z == b.z);
}
};
}

View File

@ -59,7 +59,7 @@ void MeshGenerator::build(BlockChunk* chunk, BlockAtlas* atlas,
vertices.shrink_to_fit();
indices.shrink_to_fit();
// t.elapsedMs();
// t.printElapsedMs();
}
void MeshGenerator::addFaces(glm::vec3 &offset, vector<float>* vertices, vector<unsigned int>* indices, vector<MeshPart*>* meshParts) {

View File

@ -26,16 +26,14 @@ void GameInstance::initialize(Renderer* renderer) {
//The world requires the blockAtlas for meshing and handling inputs.
world = new World(blockAtlas);
int SIZE = 16;
for (int i = -SIZE; i < SIZE; i++) {
for (int j = -4; j < 4; j++) {
for (int k = -SIZE; k < SIZE; k++) {
world->genChunk(new glm::vec3(i, j, k));
}
}
}
// genChunks(world);
// int SIZE = 8;
// for (int i = -SIZE; i < SIZE; i++) {
// for (int j = -4; j < 4; j++) {
// for (int k = -SIZE; k < SIZE; k++) {
// world->genChunk(glm::vec3(i, j, k));
// }
// }
// }
}
void GameInstance::update(GLfloat deltaTime) {
@ -46,6 +44,21 @@ void GameInstance::update(GLfloat deltaTime) {
camera->mouseControl(window->getDeltaX(), window->getDeltaY());
world->update();
glm::vec3 chunk = *camera->getPosition();
chunk.x = round(chunk.x / 16);
chunk.y = round(chunk.y / 16);
chunk.z = round(chunk.z / 16);
int SIZE = 32;
for (int i = -SIZE; i < SIZE; i++) {
for (int j = -4; j < 4; j++) {
for (int k = -SIZE; k < SIZE; k++) {
glm::vec3 adjustedPos(i + chunk.x, j + chunk.y, k + chunk.z);
world->genChunk(adjustedPos);
}
}
}
}
void GameInstance::draw() {

View File

@ -14,12 +14,14 @@ World::World(BlockAtlas *atlas) {
blockAtlas = atlas;
}
void World::genChunk(glm::vec3* pos) {
chunkGenQueue.insert(pos);
void World::genChunk(glm::vec3 pos) {
if (!blockChunks.count(pos)) {
chunkGenQueue.insert(pos);
}
}
void World::newChunk(glm::vec3* pos, BlockChunk *c) {
blockChunks.insert(std::pair<glm::vec3*, BlockChunk*>(pos, c));
void World::newChunk(glm::vec3 pos, BlockChunk *c) {
blockChunks.insert(std::pair<glm::vec3, BlockChunk*>(pos, c));
meshGenQueue.insert(pos);
}
@ -34,9 +36,9 @@ void chunkGenThread(World::ChunkThreadData *t) {
for (int ind = 0; ind < 4096; ind++) {
ArrayTrans3D::indAssignVec(ind, &innerPos);
pos.x = innerPos.x + t->pos->x * CHUNK_SIZE;
pos.y = innerPos.y + t->pos->y * CHUNK_SIZE;
pos.z = innerPos.z + t->pos->z * CHUNK_SIZE;
pos.x = innerPos.x + t->pos.x * CHUNK_SIZE;
pos.y = innerPos.y + t->pos.y * CHUNK_SIZE;
pos.z = innerPos.z + t->pos.z * CHUNK_SIZE;
double val = p.noise(pos.x / (double) 32, pos.z / (double) 32, 0) * 16 - pos.y;
@ -53,23 +55,19 @@ void meshGenThread(World::MeshThreadData *t) {
t->done = true;
}
void World::update() {
int done = 0;
//Generate block chunks
void World::handleChunkGenQueue() {
//Finish Block Gen threads
for (auto iter = chunkGenThreads.begin(); iter != chunkGenThreads.end(); ) {
ChunkThreadData* threadData = (*iter);
//If the threadData is done, create a BlockChunk and delete the threadData.
if (threadData->done) {
done++;
// blockChunks.insert(std::pair<glm::vec3*, BlockChunk*>(threadData->pos, threadData->chunk));
newChunk(threadData->pos, threadData->chunk);
delete threadData;
iter = chunkGenThreads.erase(iter);
}
//Otherwise ignore it and move to the next BlockChunk
//Otherwise ignore it and move to the next BlockChunk
else {
iter++;
}
@ -80,7 +78,7 @@ void World::update() {
//Get and remove the first position from the vector.
auto it = chunkGenQueue.begin();
chunkGenQueue.erase(chunkGenQueue.begin());
glm::vec3* pos = (*it);
glm::vec3 pos = (*it);
//Create a thread for it and add the threadData to the chunkGenThreads vector
auto t = new ChunkThreadData(pos, blockAtlas);
@ -89,12 +87,15 @@ void World::update() {
t->thread = thread;
chunkGenThreads.push_back(t);
}
}
void World::handleMeshGenQueue() {
//Run through all of the active generation threads, and finish and remove the ones that are ready to be finished.
//Then, spin up new threads when there is space in the meshGenThreads array and there are chunks waiting to be meshed.
//Create MeshChunks for the finished threads.
Timer applyGlobal("Applying Meshes");
for (auto iter = meshGenThreads.begin(); iter != meshGenThreads.end(); ) {
MeshThreadData* threadData = (*iter);
@ -104,22 +105,24 @@ void World::update() {
auto meshChunk = new MeshChunk();
meshChunk->build(threadData->vertices, threadData->indices);
meshChunk->setPosition(*(threadData->pos) * glm::vec3(CHUNK_SIZE));
meshChunks.insert(std::pair<glm::vec3*, MeshChunk*>(threadData->pos, meshChunk));
glm::vec3 pos = glm::vec3(threadData->pos.x * CHUNK_SIZE, threadData->pos.y * CHUNK_SIZE, threadData->pos.z * CHUNK_SIZE);
meshChunk->setPosition(pos);
// apply.elapsedMs();
meshChunks.insert(std::pair<glm::vec3, MeshChunk*>(threadData->pos, meshChunk));
// apply.printElapsedMs();
delete threadData;
iter = meshGenThreads.erase(iter);
}
//Otherwise ignore it and move to the next MeshChunk
//Otherwise ignore it and move to the next MeshChunk
else {
iter++;
}
}
// applyGlobal.elapsedMs();
// applyGlobal.printElapsedMs();
//Begin processing queued chunks if there are chunks to be processed and there's room for more threads.
while (!meshGenQueue.empty() && meshGenThreads.size() < MAX_MESH_GEN_THREADS) {
@ -127,7 +130,7 @@ void World::update() {
//Get and remove the first position from the vector.
auto it = meshGenQueue.begin();
meshGenQueue.erase(meshGenQueue.begin());
glm::vec3* pos = (*it);
glm::vec3 pos = (*it);
//Create a thread for it and add the threadData to the meshGenThreads vector
auto t = new MeshThreadData(pos, blockChunks.at(pos), blockAtlas);
@ -138,11 +141,16 @@ void World::update() {
}
}
std::map<glm::vec3*, MeshChunk*>* World::getMeshChunks() {
void World::update() {
handleChunkGenQueue();
handleMeshGenQueue();
}
std::unordered_map<glm::vec3, MeshChunk*, World::vec3cmp>* World::getMeshChunks() {
return &meshChunks;
}
World::MeshThreadData::MeshThreadData(glm::vec3 *pos, BlockChunk *chunk, BlockAtlas *atlas) {
World::MeshThreadData::MeshThreadData(glm::vec3 pos, BlockChunk *chunk, BlockAtlas *atlas) {
this->pos = pos;
this->chunk = chunk;
this->atlas = atlas;
@ -152,15 +160,13 @@ World::MeshThreadData::MeshThreadData(glm::vec3 *pos, BlockChunk *chunk, BlockAt
}
World::MeshThreadData::~MeshThreadData() {
//Not delete this->pos because it is used in the MeshChunk and BlockChunk vectors.
//delete pos
delete vertices;
delete indices;
//Delete the thread, when the deconstructor is called, the thread is done.
delete thread;
}
World::ChunkThreadData::ChunkThreadData(glm::vec3 *pos, BlockAtlas *atlas) {
World::ChunkThreadData::ChunkThreadData(glm::vec3 pos, BlockAtlas *atlas) {
this->pos = pos;
this->atlas = atlas;
this->done = false;

View File

@ -5,12 +5,12 @@
#ifndef GLPROJECT_WORLD_H
#define GLPROJECT_WORLD_H
#include <map>
#include <unordered_set>
#include <iostream>
#include <gtc/type_ptr.hpp>
#include <vec3.hpp>
#include <thread>
#include <bits/unordered_map.h>
#include "BlockChunk.h"
#include "MeshChunk.h"
@ -18,24 +18,30 @@
class World {
public:
struct vec3cmp {
size_t operator()(const glm::vec3& k)const {
return std::hash<float>()(k.x) ^ std::hash<float>()(k.y) ^ std::hash<float>()(k.z);
}
};
World();
explicit World(BlockAtlas* atlas);
void genChunk(glm::vec3* pos);
void newChunk(glm::vec3* pos, BlockChunk* c);
void genChunk(glm::vec3 pos);
void newChunk(glm::vec3 pos, BlockChunk* c);
void update();
std::map<glm::vec3*, MeshChunk*>* getMeshChunks();
std::unordered_map<glm::vec3, MeshChunk*, vec3cmp>* getMeshChunks();
~World() = default;
struct MeshThreadData {
MeshThreadData(glm::vec3* pos, BlockChunk* chunk, BlockAtlas* atlas);
MeshThreadData(glm::vec3 pos, BlockChunk* chunk, BlockAtlas* atlas);
std::thread* thread;
glm::vec3* pos;
glm::vec3 pos;
BlockChunk* chunk;
BlockAtlas* atlas;
@ -48,11 +54,11 @@ public:
};
struct ChunkThreadData {
ChunkThreadData(glm::vec3* pos, BlockAtlas* atlas);
ChunkThreadData(glm::vec3 pos, BlockAtlas* atlas);
std::thread* thread;
glm::vec3* pos;
glm::vec3 pos;
BlockAtlas* atlas;
bool done;
@ -62,22 +68,22 @@ public:
~ChunkThreadData();
};
private:
//Note to self:
//The same glm::vec3 pointer is used for the blockChunk and meshChunk maps. If discarding a block/meshChunk, keep
//this in mind. If this needs to be changed later change the 'update' method.
std::map<glm::vec3*, BlockChunk*> blockChunks;
std::map<glm::vec3*, MeshChunk*> meshChunks;
std::unordered_map<glm::vec3, BlockChunk*, vec3cmp> blockChunks;
std::unordered_map<glm::vec3, MeshChunk*, vec3cmp> meshChunks;
void handleChunkGenQueue();
void handleMeshGenQueue();
//TODO: Replace this BiQueueThreadArray model with a BiQueueThreadPool model (it's in the name)
//Chunk Gen BiQueue Variables
const int MAX_CHUNK_GEN_THREADS = 16;
std::unordered_set<glm::vec3*> chunkGenQueue;
const int MAX_CHUNK_GEN_THREADS = 32;
std::unordered_set<glm::vec3, vec3cmp> chunkGenQueue;
std::vector<ChunkThreadData*> chunkGenThreads;
//Mesh Gen BiQueue Variables
const int MAX_MESH_GEN_THREADS = 64;
std::unordered_set<glm::vec3*> meshGenQueue;
const int MAX_MESH_GEN_THREADS = 32;
std::unordered_set<glm::vec3, vec3cmp> meshGenQueue;
std::vector<MeshThreadData*> meshGenThreads;
BlockAtlas* blockAtlas;