mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
Tools/mmaps_generator: Replace do while (false) loops with unique_ptr using custom deleter
This commit is contained in:
@@ -188,7 +188,7 @@ namespace MMAP
|
||||
fwrite(mesh->meshes, sizeof(int), mesh->nmeshes*4, file);
|
||||
}
|
||||
|
||||
void IntermediateValues::generateObjFile(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData)
|
||||
void IntermediateValues::generateObjFile(uint32 mapID, uint32 tileX, uint32 tileY, MeshData const& meshData)
|
||||
{
|
||||
std::string objFileName;
|
||||
objFileName = Trinity::StringFormat("meshes/map{:04}{:02}{:02}.obj", mapID, tileY, tileX);
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace MMAP
|
||||
void debugWrite(FILE* file, rcPolyMesh const* mesh);
|
||||
void debugWrite(FILE* file, rcPolyMeshDetail const* mesh);
|
||||
|
||||
void generateObjFile(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData);
|
||||
void generateObjFile(uint32 mapID, uint32 tileX, uint32 tileY, MeshData const& meshData);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -571,136 +571,135 @@ namespace MMAP
|
||||
bool TerrainBuilder::loadVMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, VMAP::VMapManager* vmapManager)
|
||||
{
|
||||
VMAP::LoadResult result = vmapManager->loadMap("vmaps", mapID, tileX, tileY);
|
||||
if (result != VMAP::LoadResult::Success)
|
||||
return false;
|
||||
|
||||
auto vmapTile = Trinity::make_unique_ptr_with_deleter(vmapManager, [=](VMAP::VMapManager* mgr)
|
||||
{
|
||||
mgr->unloadMap(mapID, tileX, tileY);
|
||||
});
|
||||
|
||||
std::span<VMAP::ModelInstance const> models = vmapManager->getModelsOnMap(mapID);
|
||||
if (models.empty())
|
||||
return false;
|
||||
|
||||
bool retval = false;
|
||||
|
||||
do
|
||||
for (VMAP::ModelInstance const& instance : models)
|
||||
{
|
||||
if (result != VMAP::LoadResult::Success)
|
||||
break;
|
||||
// model instances exist in tree even though there are instances of that model in this tile
|
||||
VMAP::WorldModel const* worldModel = instance.getWorldModel();
|
||||
if (!worldModel)
|
||||
continue;
|
||||
|
||||
std::span<VMAP::ModelInstance const> models = vmapManager->getModelsOnMap(mapID);
|
||||
if (models.empty())
|
||||
break;
|
||||
// now we have a model to add to the meshdata
|
||||
retval = true;
|
||||
|
||||
for (VMAP::ModelInstance const& instance : models)
|
||||
std::vector<VMAP::GroupModel> const& groupModels = worldModel->getGroupModels();
|
||||
|
||||
// all M2s need to have triangle indices reversed
|
||||
bool isM2 = worldModel->IsM2();
|
||||
|
||||
// transform data
|
||||
float scale = instance.iScale;
|
||||
G3D::Matrix3 rotation = instance.GetInvRot();
|
||||
G3D::Vector3 position = instance.iPos;
|
||||
position.x -= 32 * GRID_SIZE;
|
||||
position.y -= 32 * GRID_SIZE;
|
||||
|
||||
for (std::vector<VMAP::GroupModel>::const_iterator it = groupModels.begin(); it != groupModels.end(); ++it)
|
||||
{
|
||||
// model instances exist in tree even though there are instances of that model in this tile
|
||||
VMAP::WorldModel const* worldModel = instance.getWorldModel();
|
||||
if (!worldModel)
|
||||
continue;
|
||||
std::vector<G3D::Vector3> const& tempVertices = it->GetVertices();
|
||||
std::vector<G3D::Vector3> transformedVertices;
|
||||
std::vector<VMAP::MeshTriangle> const& tempTriangles = it->GetTriangles();
|
||||
VMAP::WmoLiquid const* liquid = it->GetLiquid();
|
||||
|
||||
// now we have a model to add to the meshdata
|
||||
retval = true;
|
||||
// first handle collision mesh
|
||||
transform(tempVertices, transformedVertices, scale, rotation, position);
|
||||
|
||||
std::vector<VMAP::GroupModel> const& groupModels = worldModel->getGroupModels();
|
||||
int offset = meshData.solidVerts.size() / 3;
|
||||
|
||||
// all M2s need to have triangle indices reversed
|
||||
bool isM2 = worldModel->IsM2();
|
||||
copyVertices(transformedVertices, meshData.solidVerts);
|
||||
copyIndices(tempTriangles, meshData.solidTris, offset, isM2);
|
||||
|
||||
// transform data
|
||||
float scale = instance.iScale;
|
||||
G3D::Matrix3 rotation = instance.GetInvRot();
|
||||
G3D::Vector3 position = instance.iPos;
|
||||
position.x -= 32 * GRID_SIZE;
|
||||
position.y -= 32 * GRID_SIZE;
|
||||
|
||||
for (std::vector<VMAP::GroupModel>::const_iterator it = groupModels.begin(); it != groupModels.end(); ++it)
|
||||
// now handle liquid data
|
||||
if (liquid && liquid->GetFlagsStorage())
|
||||
{
|
||||
std::vector<G3D::Vector3> const& tempVertices = it->GetVertices();
|
||||
std::vector<G3D::Vector3> transformedVertices;
|
||||
std::vector<VMAP::MeshTriangle> const& tempTriangles = it->GetTriangles();
|
||||
VMAP::WmoLiquid const* liquid = it->GetLiquid();
|
||||
std::vector<G3D::Vector3> liqVerts;
|
||||
std::vector<int> liqTris;
|
||||
uint32 tilesX, tilesY, vertsX, vertsY;
|
||||
G3D::Vector3 corner;
|
||||
liquid->getPosInfo(tilesX, tilesY, corner);
|
||||
vertsX = tilesX + 1;
|
||||
vertsY = tilesY + 1;
|
||||
uint8 const* flags = liquid->GetFlagsStorage();
|
||||
float const* data = liquid->GetHeightStorage();
|
||||
uint8 type = NAV_AREA_EMPTY;
|
||||
|
||||
// first handle collision mesh
|
||||
transform(tempVertices, transformedVertices, scale, rotation, position);
|
||||
// convert liquid type to NavTerrain
|
||||
EnumFlag<map_liquidHeaderTypeFlags> liquidFlags = map_liquidHeaderTypeFlags(vmapManager->GetLiquidFlagsPtr(liquid->GetType()));
|
||||
if (liquidFlags.HasFlag(map_liquidHeaderTypeFlags::Water | map_liquidHeaderTypeFlags::Ocean))
|
||||
type = NAV_AREA_WATER;
|
||||
else if (liquidFlags.HasFlag(map_liquidHeaderTypeFlags::Magma | map_liquidHeaderTypeFlags::Slime))
|
||||
type = NAV_AREA_MAGMA_SLIME;
|
||||
|
||||
int offset = meshData.solidVerts.size() / 3;
|
||||
// indexing is weird...
|
||||
// after a lot of trial and error, this is what works:
|
||||
// vertex = y*vertsX+x
|
||||
// tile = x*tilesY+y
|
||||
// flag = y*tilesY+x
|
||||
|
||||
copyVertices(transformedVertices, meshData.solidVerts);
|
||||
copyIndices(tempTriangles, meshData.solidTris, offset, isM2);
|
||||
|
||||
// now handle liquid data
|
||||
if (liquid && liquid->GetFlagsStorage())
|
||||
G3D::Vector3 vert;
|
||||
for (uint32 x = 0; x < vertsX; ++x)
|
||||
{
|
||||
std::vector<G3D::Vector3> liqVerts;
|
||||
std::vector<int> liqTris;
|
||||
uint32 tilesX, tilesY, vertsX, vertsY;
|
||||
G3D::Vector3 corner;
|
||||
liquid->getPosInfo(tilesX, tilesY, corner);
|
||||
vertsX = tilesX + 1;
|
||||
vertsY = tilesY + 1;
|
||||
uint8 const* flags = liquid->GetFlagsStorage();
|
||||
float const* data = liquid->GetHeightStorage();
|
||||
uint8 type = NAV_AREA_EMPTY;
|
||||
|
||||
// convert liquid type to NavTerrain
|
||||
EnumFlag<map_liquidHeaderTypeFlags> liquidFlags = map_liquidHeaderTypeFlags(vmapManager->GetLiquidFlagsPtr(liquid->GetType()));
|
||||
if (liquidFlags.HasFlag(map_liquidHeaderTypeFlags::Water | map_liquidHeaderTypeFlags::Ocean))
|
||||
type = NAV_AREA_WATER;
|
||||
else if (liquidFlags.HasFlag(map_liquidHeaderTypeFlags::Magma | map_liquidHeaderTypeFlags::Slime))
|
||||
type = NAV_AREA_MAGMA_SLIME;
|
||||
|
||||
// indexing is weird...
|
||||
// after a lot of trial and error, this is what works:
|
||||
// vertex = y*vertsX+x
|
||||
// tile = x*tilesY+y
|
||||
// flag = y*tilesY+x
|
||||
|
||||
G3D::Vector3 vert;
|
||||
for (uint32 x = 0; x < vertsX; ++x)
|
||||
for (uint32 y = 0; y < vertsY; ++y)
|
||||
{
|
||||
for (uint32 y = 0; y < vertsY; ++y)
|
||||
vert = G3D::Vector3(corner.x + x * GRID_PART_SIZE, corner.y + y * GRID_PART_SIZE, data[y * vertsX + x]);
|
||||
vert = vert * rotation * scale + position;
|
||||
vert.x *= -1.f;
|
||||
vert.y *= -1.f;
|
||||
liqVerts.push_back(vert);
|
||||
}
|
||||
}
|
||||
|
||||
int idx1, idx2, idx3, idx4;
|
||||
uint32 square;
|
||||
for (uint32 x = 0; x < tilesX; ++x)
|
||||
{
|
||||
for (uint32 y = 0; y < tilesY; ++y)
|
||||
{
|
||||
if ((flags[x + y * tilesX] & 0x0f) != 0x0f)
|
||||
{
|
||||
vert = G3D::Vector3(corner.x + x * GRID_PART_SIZE, corner.y + y * GRID_PART_SIZE, data[y * vertsX + x]);
|
||||
vert = vert * rotation * scale + position;
|
||||
vert.x *= -1.f;
|
||||
vert.y *= -1.f;
|
||||
liqVerts.push_back(vert);
|
||||
square = x * tilesY + y;
|
||||
idx1 = square + x;
|
||||
idx2 = square + 1 + x;
|
||||
idx3 = square + tilesY + 1 + 1 + x;
|
||||
idx4 = square + tilesY + 1 + x;
|
||||
|
||||
// top triangle
|
||||
liqTris.push_back(idx3);
|
||||
liqTris.push_back(idx2);
|
||||
liqTris.push_back(idx1);
|
||||
// bottom triangle
|
||||
liqTris.push_back(idx4);
|
||||
liqTris.push_back(idx3);
|
||||
liqTris.push_back(idx1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int idx1, idx2, idx3, idx4;
|
||||
uint32 square;
|
||||
for (uint32 x = 0; x < tilesX; ++x)
|
||||
{
|
||||
for (uint32 y = 0; y < tilesY; ++y)
|
||||
{
|
||||
if ((flags[x + y * tilesX] & 0x0f) != 0x0f)
|
||||
{
|
||||
square = x * tilesY + y;
|
||||
idx1 = square + x;
|
||||
idx2 = square + 1 + x;
|
||||
idx3 = square + tilesY + 1 + 1 + x;
|
||||
idx4 = square + tilesY + 1 + x;
|
||||
uint32 liqOffset = meshData.liquidVerts.size() / 3;
|
||||
for (uint32 i = 0; i < liqVerts.size(); ++i)
|
||||
meshData.liquidVerts.append(liqVerts[i].y, liqVerts[i].z, liqVerts[i].x);
|
||||
|
||||
// top triangle
|
||||
liqTris.push_back(idx3);
|
||||
liqTris.push_back(idx2);
|
||||
liqTris.push_back(idx1);
|
||||
// bottom triangle
|
||||
liqTris.push_back(idx4);
|
||||
liqTris.push_back(idx3);
|
||||
liqTris.push_back(idx1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 liqOffset = meshData.liquidVerts.size() / 3;
|
||||
for (uint32 i = 0; i < liqVerts.size(); ++i)
|
||||
meshData.liquidVerts.append(liqVerts[i].y, liqVerts[i].z, liqVerts[i].x);
|
||||
|
||||
for (uint32 i = 0; i < liqTris.size() / 3; ++i)
|
||||
{
|
||||
meshData.liquidTris.append(liqTris[i * 3 + 1] + liqOffset, liqTris[i * 3 + 2] + liqOffset, liqTris[i * 3] + liqOffset);
|
||||
meshData.liquidType.append(type);
|
||||
}
|
||||
for (uint32 i = 0; i < liqTris.size() / 3; ++i)
|
||||
{
|
||||
meshData.liquidTris.append(liqTris[i * 3 + 1] + liqOffset, liqTris[i * 3 + 2] + liqOffset, liqTris[i * 3] + liqOffset);
|
||||
meshData.liquidType.append(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (false);
|
||||
|
||||
vmapManager->unloadMap(mapID, tileX, tileY);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -371,98 +371,100 @@ namespace MMAP
|
||||
unsigned char* navData = nullptr;
|
||||
int navDataSize = 0;
|
||||
|
||||
do
|
||||
{
|
||||
// these values are checked within dtCreateNavMeshData - handle them here
|
||||
// so we have a clear error message
|
||||
if (params.nvp > DT_VERTS_PER_POLYGON)
|
||||
{
|
||||
TC_LOG_ERROR("maps.mmapgen", "{} Invalid verts-per-polygon value!", tileString);
|
||||
break;
|
||||
}
|
||||
if (params.vertCount >= 0xffff)
|
||||
{
|
||||
TC_LOG_ERROR("maps.mmapgen", "{} Too many vertices!", tileString);
|
||||
break;
|
||||
}
|
||||
if (!params.vertCount || !params.verts)
|
||||
{
|
||||
// occurs mostly when adjacent tiles have models
|
||||
// loaded but those models don't span into this tile
|
||||
|
||||
// message is an annoyance
|
||||
//TC_LOG_ERROR("maps.mmapgen", "{} No vertices to build tile!", tileString);
|
||||
break;
|
||||
}
|
||||
if (!params.polyCount || !params.polys)
|
||||
{
|
||||
// we have flat tiles with no actual geometry - don't build those, its useless
|
||||
// keep in mind that we do output those into debug info
|
||||
TC_LOG_ERROR("maps.mmapgen", "{} No polygons to build on tile!", tileString);
|
||||
break;
|
||||
}
|
||||
if (!params.detailMeshes || !params.detailVerts || !params.detailTris)
|
||||
{
|
||||
TC_LOG_ERROR("maps.mmapgen", "{} No detail mesh to build tile!", tileString);
|
||||
break;
|
||||
}
|
||||
|
||||
TC_LOG_DEBUG("maps.mmapgen", "{} Building navmesh tile...", tileString);
|
||||
if (!dtCreateNavMeshData(¶ms, &navData, &navDataSize))
|
||||
{
|
||||
TC_LOG_ERROR("maps.mmapgen", "{} Failed building navmesh tile!", tileString);
|
||||
break;
|
||||
}
|
||||
|
||||
dtTileRef tileRef = 0;
|
||||
TC_LOG_DEBUG("maps.mmapgen", "{} Adding tile to navmesh...", tileString);
|
||||
// DT_TILE_FREE_DATA tells detour to unallocate memory when the tile
|
||||
// is removed via removeTile()
|
||||
dtStatus dtResult = navMesh->addTile(navData, navDataSize, DT_TILE_FREE_DATA, 0, &tileRef);
|
||||
if (!tileRef || !dtStatusSucceed(dtResult))
|
||||
{
|
||||
TC_LOG_ERROR("maps.mmapgen", "{} Failed adding tile to navmesh!", tileString);
|
||||
break;
|
||||
}
|
||||
|
||||
// file output
|
||||
std::string fileName = Trinity::StringFormat("mmaps/{:04}{:02}{:02}.mmtile", mapID, tileY, tileX);
|
||||
auto file = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(fileName.c_str(), "wb"));
|
||||
if (!file)
|
||||
{
|
||||
TC_LOG_ERROR("maps.mmapgen", "{}: [Map {:04}] Failed to open {} for writing!", strerror(errno), mapID, fileName);
|
||||
navMesh->removeTile(tileRef, nullptr, nullptr);
|
||||
break;
|
||||
}
|
||||
|
||||
TC_LOG_DEBUG("maps.mmapgen", "{} Writing to file...", tileString);
|
||||
|
||||
// write header
|
||||
MmapTileHeader header;
|
||||
header.usesLiquids = m_terrainBuilder.usesLiquids();
|
||||
header.size = uint32(navDataSize);
|
||||
fwrite(&header, sizeof(MmapTileHeader), 1, file.get());
|
||||
|
||||
// write data
|
||||
fwrite(navData, sizeof(unsigned char), navDataSize, file.get());
|
||||
|
||||
// now that tile is written to disk, we can unload it
|
||||
navMesh->removeTile(tileRef, nullptr, nullptr);
|
||||
} while (false);
|
||||
|
||||
if (m_debugOutput)
|
||||
auto debugOutputWriter = Trinity::make_unique_ptr_with_deleter(m_debugOutput ? &iv : nullptr, [=, borderSize = static_cast<unsigned short>(config.borderSize), &meshData](IntermediateValues* intermediate)
|
||||
{
|
||||
// restore padding so that the debug visualization is correct
|
||||
for (int i = 0; i < iv.polyMesh->nverts; ++i)
|
||||
for (std::ptrdiff_t i = 0; i < intermediate->polyMesh->nverts; ++i)
|
||||
{
|
||||
unsigned short* v = &iv.polyMesh->verts[i * 3];
|
||||
v[0] += (unsigned short)config.borderSize;
|
||||
v[2] += (unsigned short)config.borderSize;
|
||||
unsigned short* v = &intermediate->polyMesh->verts[i * 3];
|
||||
v[0] += borderSize;
|
||||
v[2] += borderSize;
|
||||
}
|
||||
|
||||
iv.generateObjFile(mapID, tileX, tileY, meshData);
|
||||
iv.writeIV(mapID, tileX, tileY);
|
||||
intermediate->generateObjFile(mapID, tileX, tileY, meshData);
|
||||
intermediate->writeIV(mapID, tileX, tileY);
|
||||
});
|
||||
|
||||
// these values are checked within dtCreateNavMeshData - handle them here
|
||||
// so we have a clear error message
|
||||
if (params.nvp > DT_VERTS_PER_POLYGON)
|
||||
{
|
||||
TC_LOG_ERROR("maps.mmapgen", "{} Invalid verts-per-polygon value!", tileString);
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.vertCount >= 0xffff)
|
||||
{
|
||||
TC_LOG_ERROR("maps.mmapgen", "{} Too many vertices!", tileString);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!params.vertCount || !params.verts)
|
||||
{
|
||||
// occurs mostly when adjacent tiles have models
|
||||
// loaded but those models don't span into this tile
|
||||
|
||||
// message is an annoyance
|
||||
//TC_LOG_ERROR("maps.mmapgen", "{} No vertices to build tile!", tileString);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!params.polyCount || !params.polys)
|
||||
{
|
||||
// we have flat tiles with no actual geometry - don't build those, its useless
|
||||
// keep in mind that we do output those into debug info
|
||||
TC_LOG_ERROR("maps.mmapgen", "{} No polygons to build on tile!", tileString);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!params.detailMeshes || !params.detailVerts || !params.detailTris)
|
||||
{
|
||||
TC_LOG_ERROR("maps.mmapgen", "{} No detail mesh to build tile!", tileString);
|
||||
return;
|
||||
}
|
||||
|
||||
TC_LOG_DEBUG("maps.mmapgen", "{} Building navmesh tile...", tileString);
|
||||
if (!dtCreateNavMeshData(¶ms, &navData, &navDataSize))
|
||||
{
|
||||
TC_LOG_ERROR("maps.mmapgen", "{} Failed building navmesh tile!", tileString);
|
||||
return;
|
||||
}
|
||||
|
||||
dtTileRef tileRef = 0;
|
||||
TC_LOG_DEBUG("maps.mmapgen", "{} Adding tile to navmesh...", tileString);
|
||||
// DT_TILE_FREE_DATA tells detour to unallocate memory when the tile
|
||||
// is removed via removeTile()
|
||||
dtStatus dtResult = navMesh->addTile(navData, navDataSize, DT_TILE_FREE_DATA, 0, &tileRef);
|
||||
if (!tileRef || !dtStatusSucceed(dtResult))
|
||||
{
|
||||
TC_LOG_ERROR("maps.mmapgen", "{} Failed adding tile to navmesh!", tileString);
|
||||
return;
|
||||
}
|
||||
|
||||
auto navMeshTile = Trinity::make_unique_ptr_with_deleter(&tileRef, [navMesh](dtTileRef const* ref)
|
||||
{
|
||||
navMesh->removeTile(*ref, nullptr, nullptr);
|
||||
});
|
||||
|
||||
// file output
|
||||
std::string fileName = Trinity::StringFormat("mmaps/{:04}{:02}{:02}.mmtile", mapID, tileY, tileX);
|
||||
auto file = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(fileName.c_str(), "wb"));
|
||||
if (!file)
|
||||
{
|
||||
TC_LOG_ERROR("maps.mmapgen", "{}: [Map {:04}] Failed to open {} for writing!", strerror(errno), mapID, fileName);
|
||||
return;
|
||||
}
|
||||
|
||||
TC_LOG_DEBUG("maps.mmapgen", "{} Writing to file...", tileString);
|
||||
|
||||
// write header
|
||||
MmapTileHeader header;
|
||||
header.usesLiquids = m_terrainBuilder.usesLiquids();
|
||||
header.size = uint32(navDataSize);
|
||||
fwrite(&header, sizeof(MmapTileHeader), 1, file.get());
|
||||
|
||||
// write data
|
||||
fwrite(navData, sizeof(unsigned char), navDataSize, file.get());
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
Reference in New Issue
Block a user