void ChunkManager::Update() { ChunkList unloadList; m_chunkMapMutex.lock(); std::map<ChunkCoordKey, Chunk*>::iterator it; for (it = m_chunkMap.begin(); it != m_chunkMap.end(); ++it) { Chunk* chunk = it->second; if (chunk->IsUnloading()) { unloadList.push_back(chunk); } else if (chunk->IsRebuildComplete()) { chunk->CompleteMesh(); } } m_chunkMapMutex.unlock(); int numUnloadChunks = 0; const static int MAX_NUM_CHUNKS_UNLOAD = 1; for (unsigned int i = 0; i < unloadList.size() && numUnloadChunks < MAX_NUM_CHUNKS_UNLOAD; ++i) { Chunk* chunk = unloadList[i]; UnloadChunk(chunk); } }
void ChunkManager::UpdateChunksThread() { while (m_updateThreadActive) { while (m_stepLockEnabled && m_updateStepLock) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } ChunkList updateList; ChunkList rebuildList; ChunkCoordKeyList addKeyList; // STEP 1: PUT ALL CREATED CHUNKS IN `UPDATE LIST` m_chunkMapMutex.lock(); std::map<ChunkCoordKey, Chunk*>::iterator it; for (it = m_chunkMap.begin(); it != m_chunkMap.end(); ++it) { Chunk* chunk = it->second; if (!chunk->IsUnloading()) { updateList.push_back(chunk); } } m_chunkMapMutex.unlock(); // STEP 2: FIND CHUNKS TO ADD (OR UNLOAD IF THEY'RE TOO FAR) int numAddedChunks = 0; const int MAX_NUM_CHUNKS_ADD = 10; std::sort(updateList.begin(), updateList.end(), Chunk::ClosestToCamera); for (unsigned int i = 0; i < updateList.size(); ++i) { Chunk* chunk = updateList[i]; if (chunk) { glm::vec3 chunkCenter = chunk->GetCenter(); glm::vec3 cameraPos = m_renderer->GetCamera().GetPosition(); float cameraDistance = glm::length(chunkCenter - cameraPos); if (cameraDistance > m_loadRadius) { chunk->SetUnloading(); } else if (numAddedChunks < MAX_NUM_CHUNKS_ADD) { ChunkCoordKeyList missing = chunk->GetMissingNeighbors(); if (!chunk->IsEmpty()) { for (ChunkCoordKey key : missing) { if (std::find(addKeyList.begin(), addKeyList.end(), key) == addKeyList.end()) { // Here we are calculating the distance of each // neighbor chunk to decide if we should add it glm::vec3 chunkCenter = Chunk::GetWorldCenter(key.x, key.y, key.z); float cameraDistance = glm::length(chunkCenter - cameraPos); if (cameraDistance <= m_loadRadius && key.y == 0) { addKeyList.push_back(key); ++numAddedChunks; } } } } } } } updateList.clear(); // STEP 3: ADD CHUNKS for (unsigned int i = 0; i < addKeyList.size(); ++i) { ChunkCoordKey key = addKeyList[i]; CreateNewChunk(key.x, key.y, key.z); } addKeyList.clear(); // STEP 4: CHECK FOR REBUILD CHUNKS m_chunkMapMutex.lock(); for (it = m_chunkMap.begin(); it != m_chunkMap.end(); ++it) { Chunk* chunk = it->second; if (!chunk->IsUnloading() && chunk->NeedsRebuild()) { rebuildList.push_back(chunk); } } m_chunkMapMutex.unlock(); // STEP 5: REBUILD CHUNKS int numRebuildChunks = 0; const int MAX_NUM_CHUNKS_REBUILD = 30; for (unsigned int i = 0; i < rebuildList.size() && numRebuildChunks < MAX_NUM_CHUNKS_REBUILD; ++i) { Chunk* chunk = rebuildList[i]; chunk->RebuildMesh(); ++numRebuildChunks; } rebuildList.clear(); if (m_stepLockEnabled && !m_updateStepLock) { m_updateStepLock = true; } std::this_thread::sleep_for(std::chrono::milliseconds(10)); } m_updateThreadFinished = true; }