You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

world.cpp 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. #include "world.h"
  2. #include "chunk.h"
  3. #include "threadpool.h"
  4. #include <cmath>
  5. #include <iostream>
  6. #include <thread>
  7. #include <GL/glew.h>
  8. #include <GL/gl.h>
  9. #define GLM_FORCE_RADIANS
  10. #include <glm/glm.hpp>
  11. #include <glm/gtc/type_ptr.hpp>
  12. #include <glm/gtc/matrix_transform.hpp>
  13. namespace vtk {
  14. World::World() {
  15. chunkSize = 16;
  16. voxelSize = 1.0f;
  17. voxelInfo.linkedWorld = this;
  18. voxelMath.linkedWorld = this;
  19. rebuildThreadActive = false;
  20. mLoadThreadActive = false;
  21. }
  22. bool World::isVoxelSolid(const int& x, const int& y, const int& z) {
  23. auto chunkPos = glm::ivec3(floor((float)x / (float)chunkSize),
  24. floor((float)y / (float)chunkSize),
  25. floor((float)z / (float)chunkSize));
  26. auto chunk = getChunk(chunkPos);
  27. if (!chunk) //block is in nonexistant chunk
  28. return true;
  29. int relPosX = x - chunkPos.x * chunkSize;
  30. int relPosY = y - chunkPos.y * chunkSize;
  31. int relPosZ = z - chunkPos.z * chunkSize;
  32. if (!chunk->isLoaded()) return true;
  33. return chunk->isVoxelSolid(relPosX, relPosY, relPosZ);
  34. }
  35. bool World::setVoxelType(const int& x, const int& y, const int& z, const unsigned& type, const bool& updateChunk) {
  36. auto chunkPos = glm::ivec3(floor((float)x / (float)chunkSize), floor((float)y / (float)chunkSize), floor((float)z / (float)chunkSize));
  37. auto chunk = getChunk(chunkPos);
  38. if (!chunk) return false;
  39. int relPosX = x - chunkPos.x * chunkSize;
  40. int relPosY = y - chunkPos.y * chunkSize;
  41. int relPosZ = z - chunkPos.z * chunkSize;
  42. chunk->setVoxelType(relPosX, relPosY, relPosZ, type, updateChunk);
  43. return true;
  44. }
  45. unsigned World::getVoxelType(const glm::ivec3& pos) {
  46. auto chunkPos = glm::ivec3(floor((float)pos.x / (float)chunkSize),
  47. floor((float)pos.y / (float)chunkSize),
  48. floor((float)pos.z / (float)chunkSize));
  49. Chunk* chunk = getChunk(chunkPos);
  50. if (!chunk) return 0;
  51. int relPosX = pos.x - chunkPos.x * chunkSize;
  52. int relPosY = pos.y - chunkPos.y * chunkSize;
  53. int relPosZ = pos.z - chunkPos.z * chunkSize;
  54. return chunk->getVoxelType((unsigned)relPosX, (unsigned)relPosY, (unsigned)relPosZ);
  55. }
  56. Chunk* World::makeChunk(const int& x, const int& y, const int& z, bool insertAfter) {
  57. auto pos = glm::ivec3(x, y, z);
  58. Chunk* chunk;
  59. if (mChunks.find(pos, chunk)) { //chunk already exists
  60. return chunk;
  61. }
  62. chunk = new Chunk(*this);
  63. chunk->setPos(pos);
  64. if (insertAfter) insertChunk(chunk);
  65. return chunk;
  66. }
  67. bool World::generateChunk(const int& x, const int& y, const int& z) {
  68. auto chunkMade = makeChunk(x,y,z, false);
  69. if (chunkMade != nullptr) {
  70. terrain.generateChunk(chunkMade);
  71. //queue this chunk for geometry update
  72. queueChunkUpdate(x,y,z);
  73. //queue the neighboring 6 chunks. the queue functions throws them out
  74. // if they don't exist
  75. queueChunkUpdate(x+1,y,z);
  76. queueChunkUpdate(x-1,y,z);
  77. queueChunkUpdate(x,y+1,z);
  78. queueChunkUpdate(x,y-1,z);
  79. queueChunkUpdate(x,y,z+1);
  80. queueChunkUpdate(x,y,z-1);
  81. }
  82. insertChunk(chunkMade);
  83. return chunkMade;
  84. }
  85. bool World::insertChunk(Chunk* chunk) {
  86. mChunks.insert(chunk->getPos(), chunk);
  87. mChunkMeshes.emplace(chunk->getPos(), ChunkMesh(*this, chunk->getPos()));
  88. return true;
  89. }
  90. Chunk* World::getChunk(const glm::ivec3& pos) {
  91. Chunk* chunk;
  92. if (mChunks.find(pos, chunk) && chunk->isLoaded()) return chunk;
  93. else return nullptr;
  94. }
  95. void World::queueChunkUpdate(const int& x, const int& y, const int& z, const bool& back) {
  96. queueChunkUpdate(glm::ivec3(x,y,z));
  97. }
  98. void World::queueChunkUpdate(const glm::ivec3& pos, const bool& back) {
  99. if (!getChunk(pos)) return; //chunk doesn't exist
  100. for (auto& i : mChunkUpdateQueue) {
  101. if (i == pos) return; //chunk is already in queue, we don't need to update multiple times
  102. }
  103. if (back) {
  104. mChunkUpdateQueue.push_back(pos);
  105. } else {
  106. mChunkUpdateQueue.push_front(pos);
  107. }
  108. }
  109. void World::queueChunkLoad(const glm::ivec3 &pos) {
  110. if (getChunk(pos)) return; //chunk already exists
  111. for (auto& i : mChunkLoadQueue) {
  112. if (i == pos) return;
  113. }
  114. makeChunk(pos.x, pos.y, pos.z);
  115. mChunkLoadQueue.push_back(pos);
  116. }
  117. void World::draw() {
  118. for (auto& i : mChunkMeshes) {
  119. glm::mat4 modelMat = glm::translate(glm::mat4(), glm::vec3((float)i.first.x * 16,
  120. (float)i.first.y * 16,
  121. (float)i.first.z * 16
  122. ));
  123. glUniformMatrix4fv(modelMatUni, 1, GL_FALSE, glm::value_ptr(modelMat));
  124. i.second.draw();
  125. }
  126. }
  127. void World::update() {
  128. if (!rebuildThreadActive && !mChunkUpdateQueue.empty( )) {
  129. auto updatefunc = [&]() {
  130. while (!mChunkUpdateQueue.empty()) {
  131. auto& pos = mChunkUpdateQueue.back();
  132. auto& mesh = mChunkMeshes.find(pos)->second;
  133. mChunkUpdateQueue.pop_back();
  134. if (!mesh.rebuildChunkGeometry())
  135. queueChunkUpdate(pos);
  136. }
  137. rebuildThreadActive = false;
  138. };
  139. rebuildThreadActive = true;
  140. ThreadPool::getInstance().addJob(updatefunc);
  141. }
  142. if (!mLoadThreadActive && !mChunkLoadQueue.empty()) {
  143. auto loadFunc = [&]() {
  144. while (!mChunkLoadQueue.empty()) {
  145. auto& pos = mChunkLoadQueue.back();
  146. generateChunk(pos.x, pos.y, pos.z);
  147. mChunkLoadQueue.pop_back();
  148. }
  149. mLoadThreadActive = false;
  150. };
  151. mLoadThreadActive = true;
  152. ThreadPool::getInstance().addJob(loadFunc);
  153. }
  154. }
  155. void World::forceGlobalGeometryUpdate() {
  156. int chunkCount = 1;
  157. chunkCount = 1;
  158. for (auto& i : mChunkMeshes) {
  159. std::cout << "\rUpdating chunk geometry, but better (" << chunkCount << "/" << mChunkMeshes.size() << ")" << std::flush;
  160. i.second.rebuildChunkGeometry();
  161. i.second.updateGeometry();
  162. ++chunkCount;
  163. }
  164. }
  165. void World::queueChunkLoadsAroundPoint(const glm::vec3 &point, const int &chunkRadius) {
  166. glm::ivec3 chunkPoint = point / 16.0f;
  167. for (int z = -chunkRadius; z <= chunkRadius; ++z) {
  168. for (int x = -chunkRadius; x <= chunkRadius; ++x) {
  169. if (z*z + x*x <= chunkRadius * chunkRadius) {
  170. for (int y = 0; y < 8; ++y) {
  171. queueChunkLoad(glm::ivec3(x + chunkPoint.x, y, z + chunkPoint.z));
  172. }
  173. }
  174. }
  175. }
  176. }
  177. }