ChunkManager::ChunkManager(Renderer* pRenderer) { m_pRenderer = pRenderer; m_pPlayer = NULL; // Chunk material m_chunkMaterialID = -1; m_pRenderer->CreateMaterial(Colour(1.0f, 1.0f, 1.0f, 1.0f), Colour(1.0f, 1.0f, 1.0f, 1.0f), Colour(1.0f, 1.0f, 1.0f, 1.0f), Colour(0.0f, 0.0f, 0.0f, 1.0f), 64, &m_chunkMaterialID); // Loader radius m_loaderRadius = 64.0f; // Update lock m_stepLockEnabled = false; m_updateStepLock = true; // Rendering modes m_wireframeRender = false; m_faceMerging = true; // Create initial chunk CreateNewChunk(0, 0, 0); // Threading m_updateThreadActive = true; m_pUpdatingChunksThread = new thread(_UpdatingChunksThread, this); }
MemoryHeapManager::MemoryHeapManager(void* pAddress, size_t i_size) : _pMemoryAddress(pAddress), _size(i_size) { //if there is no memory for the Chunk structure, just return. if (!_pMemoryAddress || i_size<sizeof(MemoryChunkHeader)) { return; } //create a chunk of header structure by alignment new; _pHead = CreateNewChunk(_pMemoryAddress, i_size); }
void* MemoryHeapManager::Alloc(size_t i_size) { MessagedAssert(_pMemoryAddress != nullptr, "_pMemoryAddress cannot be nullptr!"); void* pResult = nullptr; //calculate the realsize of memory alloc for the user. //becuase every time the memory address should be align 4, so we should calculate spaces beased on this size. size_t sizeOfMemory = (size_t)ceil((float)i_size / (float)NewAlignment::NEW_ALIGN_4) * NewAlignment::NEW_ALIGN_4;//ceil means round up value //std::unique_lock<std::mutex> lk(_heapMutex); MemoryChunkHeader* pChunk = GetFirstSuitbaleChunk(sizeOfMemory); if (pChunk == nullptr) { MessagedAssert(pChunk != nullptr, "No enough Memory!"); return nullptr; } pResult = pChunk->GetAddress(); //calculate how many memory left in the chunk size_t leftMemSize = pChunk->GetSize() - sizeOfMemory; pChunk->SetUsed(true); //if there is no enough space left for generating the next chunk, just return the result chunk for user if (leftMemSize <= sizeof(MemoryChunkHeader)) { return pResult; } //Before create a new Chunk, we should resize the size of the current Chunk pChunk->ReSize(sizeOfMemory); //else we need to create a new Chunk and link it with others void* pNewStartAddress = static_cast<char*>(pResult) + sizeOfMemory; MemoryChunkHeader* pNextChunk = CreateNewChunk(pNewStartAddress, leftMemSize); SetMem((uint8_t*)pNextChunk->GetAddress(), (size_t)pNextChunk->GetSize(), 0); pNextChunk->SetUsed(false); //link the new chunk with others pNextChunk->SetPrevPtr(pChunk); MemoryChunkHeader* pPreviousNext = pChunk->GetNextPtr(); pChunk->SetNextPtr(pNextChunk); pNextChunk->SetNextPtr(pPreviousNext); //return the address for user return pResult; }
// Initial chunk creation void ChunkManager::InitializeChunkCreation() { // Create initial chunk CreateNewChunk(0, 0, 0); }
void ChunkManager::UpdatingChunksThread() { while (m_updateThreadActive) { while (m_pPlayer == NULL) { #ifdef _WIN32 Sleep(100); #else usleep(100000); #endif } while (m_stepLockEnabled == true && m_updateStepLock == true) { #ifdef _WIN32 Sleep(100); #else usleep(100000); #endif } ChunkList updateChunkList; ChunkCoordKeysList addChunkList; ChunkList rebuildChunkList; ChunkList unloadChunkList; m_ChunkMapMutexLock.lock(); typedef map<ChunkCoordKeys, Chunk*>::iterator it_type; for (it_type iterator = m_chunksMap.begin(); iterator != m_chunksMap.end(); iterator++) { Chunk* pChunk = iterator->second; updateChunkList.push_back(pChunk); } m_ChunkMapMutexLock.unlock(); // Updating chunks int numAddedChunks = 0; int MAX_NUM_CHUNKS_ADD = 10; sort(updateChunkList.begin(), updateChunkList.end(), Chunk::ClosestToCamera); for (unsigned int i = 0; i < (int)updateChunkList.size(); i++) { Chunk* pChunk = updateChunkList[i]; if (pChunk != NULL) { pChunk->Update(0.01f); int gridX = pChunk->GetGridX(); int gridY = pChunk->GetGridY(); int gridZ = pChunk->GetGridZ(); float xPos = gridX * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; float yPos = gridY * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; float zPos = gridZ * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; vec3 chunkCenter = vec3(xPos, yPos, zPos) + vec3(Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE, Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE, Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE); vec3 distanceVec = chunkCenter - m_pPlayer->GetCenter(); float lengthValue = length(distanceVec); if (lengthValue > m_loaderRadius) { unloadChunkList.push_back(pChunk); } else { if (numAddedChunks < MAX_NUM_CHUNKS_ADD) { // Check neighbours if (pChunk->GetNumNeighbours() < 6 && (pChunk->IsEmpty() == false) || (gridY == 0)) { if (pChunk->GetxMinus() == NULL) { ChunkCoordKeys coordKey; coordKey.x = gridX - 1; coordKey.y = gridY; coordKey.z = gridZ; float xPos = coordKey.x * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; float yPos = coordKey.y * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; float zPos = coordKey.z * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; vec3 chunkCenter = vec3(xPos, yPos, zPos) + vec3(Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE, Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE, Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE); vec3 distanceVec = chunkCenter - m_pPlayer->GetCenter(); float lengthValue = length(distanceVec); if (lengthValue <= m_loaderRadius) { addChunkList.push_back(coordKey); numAddedChunks++; } } if (pChunk->GetxPlus() == NULL) { ChunkCoordKeys coordKey; coordKey.x = gridX + 1; coordKey.y = gridY; coordKey.z = gridZ; float xPos = coordKey.x * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; float yPos = coordKey.y * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; float zPos = coordKey.z * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; vec3 chunkCenter = vec3(xPos, yPos, zPos) + vec3(Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE, Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE, Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE); vec3 distanceVec = chunkCenter - m_pPlayer->GetCenter(); float lengthValue = length(distanceVec); if (lengthValue <= m_loaderRadius) { addChunkList.push_back(coordKey); numAddedChunks++; } } if (pChunk->GetyMinus() == NULL) { ChunkCoordKeys coordKey; coordKey.x = gridX; coordKey.y = gridY - 1; coordKey.z = gridZ; float xPos = coordKey.x * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; float yPos = coordKey.y * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; float zPos = coordKey.z * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; vec3 chunkCenter = vec3(xPos, yPos, zPos) + vec3(Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE, Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE, Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE); vec3 distanceVec = chunkCenter - m_pPlayer->GetCenter(); float lengthValue = length(distanceVec); if (lengthValue <= m_loaderRadius) { addChunkList.push_back(coordKey); numAddedChunks++; } } if (pChunk->GetyPlus() == NULL) { ChunkCoordKeys coordKey; coordKey.x = gridX; coordKey.y = gridY + 1; coordKey.z = gridZ; float xPos = coordKey.x * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; float yPos = coordKey.y * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; float zPos = coordKey.z * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; vec3 chunkCenter = vec3(xPos, yPos, zPos) + vec3(Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE, Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE, Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE); vec3 distanceVec = chunkCenter - m_pPlayer->GetCenter(); float lengthValue = length(distanceVec); if (lengthValue <= m_loaderRadius) { addChunkList.push_back(coordKey); numAddedChunks++; } } if (pChunk->GetzMinus() == NULL) { ChunkCoordKeys coordKey; coordKey.x = gridX; coordKey.y = gridY; coordKey.z = gridZ - 1; float xPos = coordKey.x * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; float yPos = coordKey.y * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; float zPos = coordKey.z * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; vec3 chunkCenter = vec3(xPos, yPos, zPos) + vec3(Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE, Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE, Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE); vec3 distanceVec = chunkCenter - m_pPlayer->GetCenter(); float lengthValue = length(distanceVec); if (lengthValue <= m_loaderRadius) { addChunkList.push_back(coordKey); numAddedChunks++; } } if (pChunk->GetzPlus() == NULL) { ChunkCoordKeys coordKey; coordKey.x = gridX; coordKey.y = gridY; coordKey.z = gridZ + 1; float xPos = coordKey.x * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; float yPos = coordKey.y * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; float zPos = coordKey.z * Chunk::CHUNK_SIZE * Chunk::BLOCK_RENDER_SIZE*2.0f; vec3 chunkCenter = vec3(xPos, yPos, zPos) + vec3(Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE, Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE, Chunk::CHUNK_SIZE*Chunk::BLOCK_RENDER_SIZE); vec3 distanceVec = chunkCenter - m_pPlayer->GetCenter(); float lengthValue = length(distanceVec); if (lengthValue <= m_loaderRadius) { addChunkList.push_back(coordKey); numAddedChunks++; } } } } } } } updateChunkList.clear(); // Adding chunks for (unsigned int i = 0; i < (int)addChunkList.size(); i++) { ChunkCoordKeys coordKey = addChunkList[i]; Chunk* pChunk = GetChunk(coordKey.x, coordKey.y, coordKey.z); if (pChunk == NULL) { CreateNewChunk(coordKey.x, coordKey.y, coordKey.z); } else { UpdateChunkNeighbours(pChunk, coordKey.x, coordKey.y, coordKey.z); } } addChunkList.clear(); // Unloading chunks for (unsigned int i = 0; i < (int)unloadChunkList.size(); i++) { Chunk* pChunk = unloadChunkList[i]; UnloadChunk(pChunk); } unloadChunkList.clear(); // Check for rebuild chunks m_ChunkMapMutexLock.lock(); for (it_type iterator = m_chunksMap.begin(); iterator != m_chunksMap.end(); iterator++) { Chunk* pChunk = iterator->second; if (pChunk != NULL) { if (pChunk->NeedsRebuild()) { rebuildChunkList.push_back(pChunk); } } } m_ChunkMapMutexLock.unlock(); // Rebuilding chunks int numRebuildChunks = 0; int MAX_NUM_CHUNKS_REBUILD = 30; for (unsigned int i = 0; i < (int)rebuildChunkList.size() && numRebuildChunks < MAX_NUM_CHUNKS_REBUILD; i++) { Chunk* pChunk = rebuildChunkList[i]; pChunk->SwitchToCachedMesh(); pChunk->RebuildMesh(); pChunk->CompleteMesh(); pChunk->UndoCachedMesh(); numRebuildChunks++; } rebuildChunkList.clear(); if (m_stepLockEnabled == true && m_updateStepLock == false) { m_updateStepLock = true; } #ifdef _WIN32 Sleep(10); #else usleep(10000); #endif } m_updateThreadFinished = true; }
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; }