void Chunk::fillTiles(const ChunkData &packet) { unsigned int index = 0; unsigned int chunkLength = Chunk::height * Chunk::width; const google::protobuf::RepeatedField<uint32> &fgTile = packet.fgtilecode(); const google::protobuf::RepeatedField<uint32> &bgTile = packet.bgtilecode(); const google::protobuf::RepeatedField<uint32> &fgNumber = packet.fgnumber(); const google::protobuf::RepeatedField<uint32> &bgNumber = packet.bgnumber(); unsigned int fgCounter = 0; unsigned int bgCounter = 0; uint32 fgTileCounter = 0; uint32 bgTileCounter = 0; std::cout << "Filling chunk at pos " << _pos.x << " " << _pos.y << std::endl; for (index = 0; index < chunkLength; ++index) { if (fgTileCounter >= fgNumber.Get(fgCounter)) { fgTileCounter = 0; ++fgCounter; } if (bgTileCounter >= bgNumber.Get(bgCounter)) { bgTileCounter = 0; ++bgCounter; } _bgTiles[index] = tile(static_cast<TileType>(bgTile.Get(bgCounter))); _tiles[index] = tile(static_cast<TileType>(fgTile.Get(fgCounter))); ++fgTileCounter; ++bgTileCounter; } _generated = true; }
void Renderer::draw() { //int dw = al_get_display_width(dpy_); //int dh = al_get_display_height(dpy_); ALLEGRO_TRANSFORM trans; al_identity_transform(&trans); al_compose_transform(&trans, &camera_transform_); al_rotate_transform_3d(&trans, 1.0, 0.0, 0.0, rx_look); setupProjection(&trans); al_identity_transform(&trans); al_use_transform(&trans); getWorldPos(camera_pos_); al_copy_transform(&cur3d_transform_, al_get_current_transform()); glEnable(GL_DEPTH_TEST); // Accept fragment if it closer to the camera than the former one glDepthFunc(GL_LEQUAL); glEnable(GL_CULL_FACE); glFrontFace(GL_CCW); glEnable(GL_ALPHA_TEST); if(!setShader(SHADER_DEFAULT)) { NBT_Debug("failed to set default shader"); } glBindVertexArray(vao_); resManager_->setAtlasUniforms(); for(auto &it: chunkData_) { ChunkData *cd = it.second; ALLEGRO_TRANSFORM ctrans; al_identity_transform(&ctrans); al_translate_transform_3d(&ctrans, cd->x()*15.0, 0.0, cd->z()*15.0); al_use_transform(&ctrans); cd->draw(&ctrans); } glBindVertexArray(0); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); //drawSelection(); resManager_->unsetAtlasUniforms(); }
/** * @brief Loads the next chunk. * * If the current chunk was the last chunk in the array a new chunk is created. * Otherwise the old chunk is reset and loaded as current chunk. * * Always the position of the nested chunk vector is stored. */ inline void nextChunk() { curChunk->store(); curChunkIndex += 1; if(chunks.size() == curChunkIndex) { curChunk = new ChunkData(chunkSize); chunks.push_back(curChunk); positions.push_back(nested.getPosition()); } else { curChunk = chunks[curChunkIndex]; curChunk->reset(); positions[curChunkIndex] = nested.getPosition(); } }
/** * @brief Resets the chunk vector to the given position. * * This method will call reset on all chunks which are behind the * given position. * * It calls also reset on the nested chunk vector. * * @param pos The position to reset to. */ void reset(const Position& pos) { assert(pos.chunk < chunks.size()); assert(pos.data < chunkSize); for(size_t i = curChunkIndex; i > pos.chunk; --i) { chunks[i]->reset(); } curChunk = chunks[pos.chunk]; curChunk->load(); curChunk->setUsedSize(pos.data); curChunkIndex = pos.chunk; nested.reset(pos.inner); }
/** * @brief Release all the memory, that the chunk vector has acquired. * * Reverts the chunk vector into its initial state after the construction. * Only the memory of one chunk stays allocated. */ void resetHard() { for(size_t i = 1; i < chunks.size(); ++i) { delete chunks[i]; } chunks.resize(1); positions.resize(1); curChunk = chunks[0]; curChunk->load(); curChunk->setUsedSize(0); curChunkIndex = 0; nested->resetHard(); }
/** * @brief Checks if the current chunk has enough items left. * * If the chunk has not enough items left, the next chunk is * loaded. * * @param items The maximum number of items to store. */ inline void reserveItems(const size_t items) { assert(items <= chunkSize); if(chunkSize < curChunk->getUsedSize() + items) { nextChunk(); } }
/** * @brief Checks if the current chunk has enough items left. * * If the chunk has not enough items left, the next chunk is * loaded. * * @param items The maximum number of items to store. */ CODI_INLINE void reserveItems(const size_t items) { codiAssert(items <= chunkSize); if(chunkSize < curChunk->getUsedSize() + items) { nextChunk(); } }
/** * @brief Get the total number of data items used. * @return The number of data items used in all chunks. */ inline size_t getDataSize() { size_t size = curChunk->getUsedSize(); if(getNumChunks() != 0) { size += (getNumChunks() - 1) * chunkSize; } return size; }
ChunkData* Region::getChunkData(Int2 pos) { if(mChunks.find(pos)==mChunks.end()) { int offset = getOffset(pos); //cout << offset << endl; if(offset==-1) { mChunks[pos] = new ChunkData(pos); cout << "Missing Chunk " << pos.first <<" " << pos.second << endl; return mChunks[pos]; } mRegionFile.seekg(offset,mRegionFile.beg); int length = NBT::ReadSwap<int32_t>(mRegionFile); uint8_t format = NBT::Read<uint8_t>(mRegionFile); NBT::TagCompound* tag = NBT::ReadNBTFromZlibStream(mRegionFile); ChunkData* chunk = new ChunkData(pos); chunk->loadFromNBT(tag); mChunks[pos] = chunk; delete tag; } return mChunks[pos]; }
bool ChunkMesh::isAirNearBlockFace(const ChunkData & chunkData, int blockX, int blockY, int blockZ, BlockFace face) { switch(face) { case BlockFace::North: return blockZ == 0 || chunkData.getBlock(blockX, blockY, blockZ - 1) == 0; case BlockFace::South: return blockZ == chunkData.getZSize() - 1 || chunkData.getBlock(blockX, blockY, blockZ + 1) == 0; case BlockFace::West: return blockX == 0 || chunkData.getBlock(blockX - 1, blockY, blockZ) == 0; case BlockFace::East: return blockX == chunkData.getXSize() - 1 || chunkData.getBlock(blockX + 1, blockY, blockZ) == 0; case BlockFace::Bottom: return blockY == 0 || chunkData.getBlock(blockX, blockY - 1, blockZ) == 0; case BlockFace::Top: return blockY == chunkData.getYSize() - 1 || chunkData.getBlock(blockX, blockY + 1, blockZ) == 0; default: return false; } }
CODI_INLINE void setDataAndMove(const Data& ... data) { // this method should only be called if reserveItems has been called curChunk->setDataAndMove(data...); }
ChunkMesh ChunkMesh::createFromChunkData(const ChunkData & chunkData) { ChunkMesh mesh; mesh.m_isValid = true; unsigned int indicesOffset = 0; for(int y = 0; y < chunkData.getYSize(); ++y) { for(int z = 0; z < chunkData.getZSize(); ++z) { for(int x = 0; x < chunkData.getXSize(); ++x) { const int blockCode = chunkData.getBlock(x, y, z); if(blockCode != 0) { if(isAirNearBlockFace(chunkData, x, y, z, BlockFace::North)) { mesh.m_vertices.insert( mesh.m_vertices.end(), { 1.0f + x, 0.0f + y, 0.0f + z, 0.0f, 0.0f, 0.0f + x, 0.0f + y, 0.0f + z, 0.0f, 1.0f, 0.0f + x, 1.0f + y, 0.0f + z, 1.0f, 1.0f, 1.0f + x, 1.0f + y, 0.0f + z, 1.0f, 0.0f } ); mesh.m_indices.insert( mesh.m_indices.end(), { 0 + indicesOffset, 1 + indicesOffset, 2 + indicesOffset, 0 + indicesOffset, 2 + indicesOffset, 3 + indicesOffset } ); indicesOffset += 4; } if(isAirNearBlockFace(chunkData, x, y, z, BlockFace::South)) { mesh.m_vertices.insert( mesh.m_vertices.end(), { 0.0f + x, 0.0f + y, 1.0f + z, 0.0f, 0.0f, 0.0f + x, 1.0f + y, 1.0f + z, 0.0f, 1.0f, 1.0f + x, 1.0f + y, 1.0f + z, 1.0f, 1.0f, 1.0f + x, 0.0f + y, 1.0f + z, 1.0f, 0.0f } ); mesh.m_indices.insert( mesh.m_indices.end(), { 0 + indicesOffset, 1 + indicesOffset, 2 + indicesOffset, 0 + indicesOffset, 2 + indicesOffset, 3 + indicesOffset } ); indicesOffset += 4; } if(isAirNearBlockFace(chunkData, x, y, z, BlockFace::West)) { mesh.m_vertices.insert( mesh.m_vertices.end(), { 0.0f + x, 0.0f + y, 0.0f + z, 0.0f, 0.0f, 0.0f + x, 1.0f + y, 0.0f + z, 0.0f, 1.0f, 0.0f + x, 1.0f + y, 1.0f + z, 1.0f, 1.0f, 0.0f + x, 0.0f + y, 1.0f + z, 1.0f, 0.0f } ); mesh.m_indices.insert( mesh.m_indices.end(), { 0 + indicesOffset, 1 + indicesOffset, 2 + indicesOffset, 0 + indicesOffset, 2 + indicesOffset, 3 + indicesOffset } ); indicesOffset += 4; } if(isAirNearBlockFace(chunkData, x, y, z, BlockFace::East)) { mesh.m_vertices.insert( mesh.m_vertices.end(), { 1.0f + x, 0.0f + y, 1.0f + z, 0.0f, 0.0f, 1.0f + x, 1.0f + y, 1.0f + z, 0.0f, 1.0f, 1.0f + x, 1.0f + y, 0.0f + z, 1.0f, 1.0f, 1.0f + x, 0.0f + y, 0.0f + z, 1.0f, 0.0f } ); mesh.m_indices.insert( mesh.m_indices.end(), { 0 + indicesOffset, 1 + indicesOffset, 2 + indicesOffset, 0 + indicesOffset, 2 + indicesOffset, 3 + indicesOffset } ); indicesOffset += 4; } if(isAirNearBlockFace(chunkData, x, y, z, BlockFace::Bottom)) { mesh.m_vertices.insert( mesh.m_vertices.end(), { 0.0f + x, 0.0f + y, 0.0f + z, 0.0f, 0.0f, 0.0f + x, 0.0f + y, 1.0f + z, 0.0f, 1.0f, 1.0f + x, 0.0f + y, 1.0f + z, 1.0f, 1.0f, 1.0f + x, 0.0f + y, 0.0f + z, 1.0f, 0.0f } ); mesh.m_indices.insert( mesh.m_indices.end(), { 0 + indicesOffset, 1 + indicesOffset, 2 + indicesOffset, 0 + indicesOffset, 2 + indicesOffset, 3 + indicesOffset } ); indicesOffset += 4; } if(isAirNearBlockFace(chunkData, x, y, z, BlockFace::Top)) { mesh.m_vertices.insert( mesh.m_vertices.end(), { 0.0f + x, 1.0f + y, 1.0f + z, 0.0f, 0.0f, 0.0f + x, 1.0f + y, 0.0f + z, 0.0f, 1.0f, 1.0f + x, 1.0f + y, 0.0f + z, 1.0f, 1.0f, 1.0f + x, 1.0f + y, 1.0f + z, 1.0f, 0.0f } ); mesh.m_indices.insert( mesh.m_indices.end(), { 0 + indicesOffset, 1 + indicesOffset, 2 + indicesOffset, 0 + indicesOffset, 2 + indicesOffset, 3 + indicesOffset } ); indicesOffset += 4; } } } } } return mesh; }
/** * @brief Get the position of the chunk vector and the nested vectors. * @return The position of the chunk vector. */ inline Position getPosition() { return Position(curChunkIndex, curChunk->getUsedSize(), nested.getPosition()); }
/** * @brief The position inside the data of the current chunk. * @return The current position in the current chunk. */ inline size_t getChunkPosition() { return curChunk->getUsedSize(); }
ChunkData *ChunkData::Create(Chunk *chunk, ResourceManager *resourceManager) { const uint32_t DATA_VTX_COUNT = MAX_VERTS / MAX_SLICES; CustomVertex *data = (CustomVertex*)malloc(sizeof(CustomVertex) * DATA_VTX_COUNT); if(!data) return nullptr; memset(data, 0, DATA_VTX_COUNT * sizeof(CustomVertex)); uint32_t total_size = 0; // TODO: maybe allow putting more than one section per slice if we end up with more than 16 sections. // currently minecraft only uses 16 sections per chunk. //assert(num_sections <= MAX_SLICES); int32_t x_off = chunk->x() * 16; int32_t z_off = chunk->z() * 16; ChunkData *cdata = new ChunkData(chunk->x(), chunk->z()); CustomVertex *dptr = data; // reset dptr, reuse data memory. for(uint32_t i = 0; i < chunk->sectionCount(); i++) { ChunkSection *section = chunk->getSection(i); if(!section) continue; //NBT_Debug("new section[%i]: %p", i, section); int32_t y = section->y() * 16; //int32_t y = section_y * 16; #ifdef VIEWER_USE_MORE_VBOS dptr = data; total_size = 0; #endif for(int dy = 0; dy < 16; dy++) { for(int dz = 0; dz < 16; dz++) { for(int dx = 0; dx < 16; dx++) { BlockAddress baddr; if(!chunk->getBlockAddress(x_off + dx, y + dy, z_off + dz, &baddr)) { NBT_Debug("failed to find block %i, %i, %i", x_off + dx, y + dy, z_off + dz); assert(nullptr); continue; } //NBT_Debug("block %i,%i,%i: %s", x_off+dx, y+dy, z_off+dz, baddr.toString().c_str()); BlockInfo bi; chunk->getBlockInfo(baddr, &bi); //NBT_Debug("blockInfo: %i:%i:%s", bi.id, bi.data, bi.state_name); Resource::ID rid = resourceManager->getModelVariant(bi); if(rid == Resource::INVALID_ID) { //NBT_Debug("failed to get model %i:%i:%s", bi.id, bi.data, bi.state_name); continue; } //if(bi.id != BLOCK_AIR && bi.id != BLOCK_BARRIER) // NBT_Debug("block:%i:%i %s", bi.id, bi.data, bi.state_name); ResourceModelVariant *var = resourceManager->getModelVariantResource(rid); uint32_t vertex_count = var->getVertexCount(); CustomVertex *verticies = var->getVertexData(); for(uint32_t i = 0; i < vertex_count; i++) { CustomVertex &v = verticies[i], &cv = dptr[i]; float xoff = cdata->x() + dx, yoff = y + dy, zoff = cdata->z() + dz; cv.pos = { v.pos.f1 + xoff, v.pos.f2 + yoff, v.pos.f3 + zoff }; //cv.txcoord = { (v.txcoord.f1 * tx_xfact + tx_x), 1-(v.txcoord.f2 * tx_yfact + tx_y) }; cv.txcoord = { v.txcoord.f1 , 1-v.txcoord.f2 }; // { 0.25 + 0.25 * v.txcoord.f1, 0.25 + 0.25 * v.txcoord.f2 }; //NBT_Debug("tex: %f, %f", cv.txcoord.f1, cv.txcoord.f2); cv.tx_page = v.tx_page; cv.color = v.color; } dptr += vertex_count; total_size += vertex_count; } } } #ifdef VIEWER_USE_MORE_VBOS if(total_size > 0) if(!cdata->fillSlice(section->y(), data, total_size)) NBT_Warn("failed to fill slice %i???", y); #endif } #ifndef VIEWER_USE_MORE_VBOS if(total_size) if(!cdata->fillSlice(0, data, total_size)) NBT_Warn("failed to fill chunk data"); #endif free(data); return cdata; }
CODI_INLINE void getDataPointer(Pointers* &... pointers) { curChunk->dataPointer(curChunk->usedSize, pointers...); }
/** * @brief The position inside the data of the current chunk. * @return The current position in the current chunk. */ CODI_INLINE size_t getChunkPosition() const { return curChunk->getUsedSize(); }
/** * @brief Get the position of the chunk vector and the nested vectors. * @return The position of the chunk vector. */ CODI_INLINE Position getPosition() const { return Position(curChunkIndex, curChunk->getUsedSize(), nested->getPosition()); }
std::string World::serialize(const Vector2i &chunkId) { ProtocolMessage msg; ChunkData *chunkData = new ChunkData; VectorInt *vecInt; std::string serialized; Chunk *chunk; unsigned int fgcont = 0; unsigned int bgcont = 0; TileType fgtile; TileType bgtile; TileType oldfgtile; TileType oldbgtile; if ((chunk = getChunk(chunkId)) != nullptr) { for (unsigned int y = 0; y < Chunk::height; ++y) { for (unsigned int x = 0; x < Chunk::width; ++x) { fgtile = chunk->getTile(x, y); bgtile = chunk->getBgTile(x, y); if (x == 0 && y == 0) { oldfgtile = fgtile; oldbgtile = bgtile; } else { if (fgtile != oldfgtile) { chunkData->add_fgnumber(fgcont); chunkData->add_fgtilecode(static_cast<unsigned int>(oldfgtile)); fgcont = 0; oldfgtile = fgtile; } if (bgtile != oldbgtile) { chunkData->add_bgnumber(bgcont); chunkData->add_bgtilecode(static_cast<unsigned int>(oldbgtile)); bgcont = 0; oldbgtile = bgtile; } } ++fgcont; ++bgcont; } } } chunkData->add_bgnumber(bgcont); chunkData->add_bgtilecode(static_cast<unsigned int>(oldbgtile)); chunkData->add_fgnumber(fgcont); chunkData->add_fgtilecode(static_cast<unsigned int>(oldfgtile)); vecInt = new VectorInt; vecInt->set_x(chunkId.x); vecInt->set_y(chunkId.y); chunkData->set_allocated_id(vecInt); msg.set_content(ProtocolMessage::CHUNK); msg.set_allocated_chunkdata(chunkData); msg.SerializeToString(&serialized); return serialized; }
/** * @brief Sets the data and increases the used chunk data by one. * * This method should only be called if 'reserveItems' was called * beforehand with enough items to accommodate to all calls to this * method. * * @param data The data set to the current position in the chunk. */ inline void setDataAndMove(const typename ChunkData::DataValues& data) { // this method should only be called if reserveItems has been called curChunk->setDataAndMove(data); }