Tools/mmaps_generator: Replace G3D::Array with std::vector

This commit is contained in:
Shauren
2025-10-26 00:51:01 +02:00
parent 07ada79e89
commit bc342f2a90
5 changed files with 228 additions and 265 deletions

View File

@@ -200,24 +200,24 @@ namespace MMAP
return;
}
G3D::Array<float> allVerts;
G3D::Array<int> allTris;
std::vector<float> allVerts;
std::vector<int> allTris;
allTris.append(meshData.liquidTris);
allVerts.append(meshData.liquidVerts);
allTris.insert(allTris.end(), meshData.liquidTris.begin(), meshData.liquidTris.end());
allVerts.insert(allVerts.end(), meshData.liquidVerts.begin(), meshData.liquidVerts.end());
TerrainBuilder::copyIndices(meshData.solidTris, allTris, allVerts.size() / 3);
allVerts.append(meshData.solidVerts);
allVerts.insert(allVerts.end(), meshData.solidVerts.begin(), meshData.solidVerts.end());
float* verts = allVerts.getCArray();
float* verts = allVerts.data();
int vertCount = allVerts.size() / 3;
int* tris = allTris.getCArray();
int* tris = allTris.data();
int triCount = allTris.size() / 3;
for (int i = 0; i < allVerts.size() / 3; i++)
fprintf(objFile.get(), "v %f %f %f\n", verts[i*3], verts[i*3 + 1], verts[i*3 + 2]);
for (std::size_t i = 0; i < allVerts.size() / 3; i++)
fprintf(objFile.get(), "v %f %f %f\n", verts[i * 3], verts[i * 3 + 1], verts[i * 3 + 2]);
for (int i = 0; i < allTris.size() / 3; i++)
fprintf(objFile.get(), "f %i %i %i\n", tris[i*3] + 1, tris[i*3 + 1] + 1, tris[i*3 + 2] + 1);
for (std::size_t i = 0; i < allTris.size() / 3; i++)
fprintf(objFile.get(), "f %i %i %i\n", tris[i * 3] + 1, tris[i * 3 + 1] + 1, tris[i * 3 + 2] + 1);
TC_LOG_INFO("maps.mmapgen.debug", "[Map {:04}] [{:02},{:02}]: Writing debug output object file...", mapID, tileY, tileX);

View File

@@ -310,26 +310,20 @@ namespace MMAP
if (fread(&indicesCount, sizeof(uint32), 1, file.get()) != 1)
return;
std::unique_ptr<float[]> verts = std::make_unique<float[]>(verticesCount);
if (fread(verts.get(), sizeof(float), verticesCount, file.get()) != verticesCount)
return;
std::unique_ptr<int[]> inds = std::make_unique<int[]>(indicesCount);
if (fread(inds.get(), sizeof(int), indicesCount, file.get()) != indicesCount)
return;
MeshData data;
for (uint32 i = 0; i < verticesCount; ++i)
data.solidVerts.append(verts[i]);
data.solidVerts.resize(verticesCount);
if (fread(data.solidVerts.data(), sizeof(float), verticesCount, file.get()) != verticesCount)
return;
for (uint32 i = 0; i < indicesCount; ++i)
data.solidTris.append(inds[i]);
data.solidTris.resize(indicesCount);
if (fread(data.solidTris.data(), sizeof(int), indicesCount, file.get()) != indicesCount)
return;
TerrainBuilder::cleanVertices(data.solidVerts, data.solidTris);
// get bounds of current tile
float bmin[3], bmax[3];
TileBuilder::getTileBounds(tileX, tileY, data.solidVerts.getCArray(), data.solidVerts.size() / 3, bmin, bmax);
TileBuilder::getTileBounds(tileX, tileY, data.solidVerts.data(), data.solidVerts.size() / 3, bmin, bmax);
// build navmesh tile
MapTileBuilder tileBuilder(this, m_maxWalkableAngle, m_maxWalkableAngleNotSteep,

View File

@@ -25,7 +25,7 @@
#include "StringFormat.h"
#include "Util.h"
#include "VMapManager.h"
#include <map>
#include <unordered_map>
namespace MMAP
{
@@ -123,8 +123,8 @@ namespace MMAP
uint8 holes[16][16][8] = { };
uint16 liquid_entry[16][16] = { };
map_liquidHeaderTypeFlags liquid_flags[16][16] = { };
G3D::Array<int> ltriangles;
G3D::Array<int> ttriangles;
std::vector<int> ltriangles;
std::vector<int> ttriangles;
// terrain data
if (haveTerrain)
@@ -188,38 +188,35 @@ namespace MMAP
}
int count = meshData.solidVerts.size() / 3;
meshData.solidVerts.resize(meshData.solidVerts.size() + (V9_SIZE_SQ + V8_SIZE_SQ) * 3);
float* solidVerts = meshData.solidVerts.data() + count * 3;
float xoffset = (float(tileX)-32)*GRID_SIZE;
float yoffset = (float(tileY)-32)*GRID_SIZE;
float coord[3];
for (int i = 0; i < V9_SIZE_SQ; ++i)
{
getHeightCoord(i, GRID_V9, xoffset, yoffset, coord, V9);
meshData.solidVerts.append(coord[0]);
meshData.solidVerts.append(coord[2]);
meshData.solidVerts.append(coord[1]);
getHeightCoord(i, GRID_V9, xoffset, yoffset, solidVerts, V9);
solidVerts += 3;
}
for (int i = 0; i < V8_SIZE_SQ; ++i)
{
getHeightCoord(i, GRID_V8, xoffset, yoffset, coord, V8);
meshData.solidVerts.append(coord[0]);
meshData.solidVerts.append(coord[2]);
meshData.solidVerts.append(coord[1]);
getHeightCoord(i, GRID_V8, xoffset, yoffset, solidVerts, V8);
solidVerts += 3;
}
int indices[] = { 0, 0, 0 };
int loopStart = 0, loopEnd = 0, loopInc = 0;
getLoopVars(portion, loopStart, loopEnd, loopInc);
for (int i = loopStart; i < loopEnd; i+=loopInc)
for (int j = TOP; j <= BOTTOM; j+=1)
{
getHeightTriangle(i, Spot(j), indices);
ttriangles.append(indices[2] + count);
ttriangles.append(indices[1] + count);
ttriangles.append(indices[0] + count);
}
{
std::size_t trianglesOffset = ttriangles.size();
ttriangles.resize(ttriangles.size() + 12);
getHeightTriangle(i, TOP, ttriangles.data() + trianglesOffset + 0, count);
getHeightTriangle(i, RIGHT, ttriangles.data() + trianglesOffset + 3, count);
getHeightTriangle(i, LEFT, ttriangles.data() + trianglesOffset + 6, count);
getHeightTriangle(i, BOTTOM, ttriangles.data() + trianglesOffset + 9, count);
}
}
// liquid data
@@ -257,10 +254,11 @@ namespace MMAP
}
int count = meshData.liquidVerts.size() / 3;
meshData.liquidVerts.resize(meshData.liquidVerts.size() + V9_SIZE_SQ * 3);
float* liquidVerts = meshData.liquidVerts.data();
float xoffset = (float(tileX)-32)*GRID_SIZE;
float yoffset = (float(tileY)-32)*GRID_SIZE;
float coord[3];
int row, col;
// generate coordinates
@@ -276,14 +274,13 @@ namespace MMAP
col < lheader.offsetX || col >= lheader.offsetX + lheader.width)
{
// dummy vert using invalid height
meshData.liquidVerts.append((xoffset+col*GRID_PART_SIZE)*-1, INVALID_MAP_LIQ_HEIGHT, (yoffset+row*GRID_PART_SIZE)*-1);
liquidVerts[(count + i) * 3 + 0] = (xoffset + col * GRID_PART_SIZE) * -1;
liquidVerts[(count + i) * 3 + 1] = INVALID_MAP_LIQ_HEIGHT;
liquidVerts[(count + i) * 3 + 2] = (yoffset + row * GRID_PART_SIZE) * -1;
continue;
}
getLiquidCoord(i, j, xoffset, yoffset, coord, liquid_map.get());
meshData.liquidVerts.append(coord[0]);
meshData.liquidVerts.append(coord[2]);
meshData.liquidVerts.append(coord[1]);
getLiquidCoord(i, j, xoffset, yoffset, &liquidVerts[(count + i) * 3], liquid_map.get());
j++;
}
}
@@ -293,24 +290,22 @@ namespace MMAP
{
row = i / V9_SIZE;
col = i % V9_SIZE;
meshData.liquidVerts.append((xoffset+col*GRID_PART_SIZE)*-1, lheader.liquidLevel, (yoffset+row*GRID_PART_SIZE)*-1);
liquidVerts[(count + i) * 3 + 0] = (xoffset + col * GRID_PART_SIZE) * -1;
liquidVerts[(count + i) * 3 + 1] = lheader.liquidLevel;
liquidVerts[(count + i) * 3 + 2] = (yoffset + row * GRID_PART_SIZE) * -1;
}
}
int indices[] = { 0, 0, 0 };
int loopStart = 0, loopEnd = 0, loopInc = 0, triInc = BOTTOM-TOP;
int loopStart = 0, loopEnd = 0, loopInc = 0;
getLoopVars(portion, loopStart, loopEnd, loopInc);
// generate triangles
for (int i = loopStart; i < loopEnd; i += loopInc)
{
for (int j = TOP; j <= BOTTOM; j += triInc)
{
getHeightTriangle(i, Spot(j), indices, true);
ltriangles.append(indices[2] + count);
ltriangles.append(indices[1] + count);
ltriangles.append(indices[0] + count);
}
std::size_t trianglesOffset = ltriangles.size();
ltriangles.resize(ltriangles.size() + 6);
getHeightTriangle(i, TOP, ltriangles.data() + trianglesOffset + 0, count, true);
getHeightTriangle(i, BOTTOM, ltriangles.data() + trianglesOffset + 3, count, true);
}
}
@@ -319,11 +314,11 @@ namespace MMAP
int loopStart = 0, loopEnd = 0, loopInc = 0, tTriCount = 4;
bool useTerrain, useLiquid;
float* lverts = meshData.liquidVerts.getCArray();
int* ltris = ltriangles.getCArray();
float* lverts = meshData.liquidVerts.data();
int* ltris = ltriangles.data();
float* tverts = meshData.solidVerts.getCArray();
int* ttris = ttriangles.getCArray();
float* tverts = meshData.solidVerts.data();
int* ttris = ttriangles.data();
if ((ltriangles.size() + ttriangles.size()) == 0)
return false;
@@ -331,7 +326,7 @@ namespace MMAP
// make a copy of liquid vertices
// used to pad right-bottom frame due to lost vertex data at extraction
std::unique_ptr<float[]> lverts_copy;
if (meshData.liquidVerts.size())
if (!meshData.liquidVerts.empty())
{
lverts_copy = std::make_unique<float[]>(meshData.liquidVerts.size());
memcpy(lverts_copy.get(), lverts, sizeof(float)* meshData.liquidVerts.size());
@@ -349,7 +344,7 @@ namespace MMAP
uint8 navLiquidType = NAV_AREA_EMPTY;
// if there is no liquid, don't use liquid
if (!meshData.liquidVerts.size() || !ltriangles.size())
if (meshData.liquidVerts.empty() || ltriangles.empty())
useLiquid = false;
else
{
@@ -369,7 +364,7 @@ namespace MMAP
}
// if there is no terrain, don't use terrain
if (!ttriangles.size())
if (ttriangles.empty())
useTerrain = false;
// while extracting ADT data we are losing right-bottom vertices
@@ -448,14 +443,12 @@ namespace MMAP
// store the result
if (useLiquid)
{
meshData.liquidType.append(navLiquidType);
for (int k = 0; k < 3; ++k)
meshData.liquidTris.append(ltris[k]);
meshData.liquidTris.insert(meshData.liquidTris.end(), &ltris[0], &ltris[3]);
meshData.liquidType.push_back(navLiquidType);
}
if (useTerrain)
for (int k = 0; k < 3*tTriCount/2; ++k)
meshData.solidTris.append(ttris[k]);
meshData.solidTris.insert(meshData.solidTris.end(), &ttris[0], &ttris[3 * tTriCount / 2]);
// advance to next set of triangles
ltris += 3;
@@ -463,88 +456,88 @@ namespace MMAP
}
}
return meshData.solidTris.size() || meshData.liquidTris.size();
return !meshData.solidTris.empty() || !meshData.liquidTris.empty();
}
/**************************************************************************/
void TerrainBuilder::getHeightCoord(int index, Grid grid, float xOffset, float yOffset, float* coord, float* v)
inline void TerrainBuilder::getHeightCoord(int index, Grid grid, float xOffset, float yOffset, float* coord, float* v)
{
// wow coords: x, y, height
// coord is mirroed about the horizontal axes
switch (grid)
{
case GRID_V9:
coord[0] = (xOffset + index%(V9_SIZE)*GRID_PART_SIZE) * -1.f;
coord[1] = (yOffset + (int)(index/(V9_SIZE))*GRID_PART_SIZE) * -1.f;
coord[2] = v[index];
coord[0] = (xOffset + (int)(index % V9_SIZE) * GRID_PART_SIZE) * -1.f;
coord[1] = v[index];
coord[2] = (yOffset + (int)(index / (V9_SIZE)) * GRID_PART_SIZE) * -1.f;
break;
case GRID_V8:
coord[0] = (xOffset + index%(V8_SIZE)*GRID_PART_SIZE + GRID_PART_SIZE/2.f) * -1.f;
coord[1] = (yOffset + (int)(index/(V8_SIZE))*GRID_PART_SIZE + GRID_PART_SIZE/2.f) * -1.f;
coord[2] = v[index];
coord[0] = (xOffset + (int)(index % V8_SIZE) * GRID_PART_SIZE + GRID_PART_SIZE / 2.f) * -1.f;
coord[1] = v[index];
coord[2] = (yOffset + (int)(index / (V8_SIZE)) * GRID_PART_SIZE + GRID_PART_SIZE / 2.f) * -1.f;
break;
}
}
/**************************************************************************/
void TerrainBuilder::getHeightTriangle(int square, Spot triangle, int* indices, bool liquid/* = false*/)
inline void TerrainBuilder::getHeightTriangle(int square, Spot triangle, int* indices, int offset, bool liquid/* = false*/)
{
int rowOffset = square/V8_SIZE;
if (!liquid)
switch (triangle)
{
case TOP:
indices[0] = square+rowOffset; // 0-----1 .... 128
indices[1] = square+1+rowOffset; // |\ T /|
indices[2] = (V9_SIZE_SQ)+square; // | \ / |
break; // |L 0 R| .. 127
case LEFT: // | / \ |
indices[0] = square+rowOffset; // |/ B \|
indices[1] = (V9_SIZE_SQ)+square; // 129---130 ... 386
indices[2] = square+V9_SIZE+rowOffset; // |\ /|
break; // | \ / |
case RIGHT: // | 128 | .. 255
indices[0] = square+1+rowOffset; // | / \ |
indices[1] = square+V9_SIZE+1+rowOffset; // |/ \|
indices[2] = (V9_SIZE_SQ)+square; // 258---259 ... 515
indices[0] = V9_SIZE_SQ + square + offset; // 0-----1 .... 128
indices[1] = square + 1 + rowOffset + offset; // |\ T /|
indices[2] = square + rowOffset + offset; // | \ / |
break; // |L 0 R| .. 127
case LEFT: // | / \ |
indices[0] = square + V9_SIZE + rowOffset + offset; // |/ B \|
indices[1] = V9_SIZE_SQ + square + offset; // 129---130 ... 386
indices[2] = square + rowOffset + offset; // |\ /|
break; // | \ / |
case RIGHT: // | 128 | .. 255
indices[0] = V9_SIZE_SQ + square + offset; // | / \ |
indices[1] = square + V9_SIZE + 1 + rowOffset + offset; // |/ \|
indices[2] = square + 1 + rowOffset + offset; // 258---259 ... 515
break;
case BOTTOM:
indices[0] = (V9_SIZE_SQ)+square;
indices[1] = square+V9_SIZE+1+rowOffset;
indices[2] = square+V9_SIZE+rowOffset;
indices[0] = square + V9_SIZE + rowOffset + offset;
indices[1] = square + V9_SIZE + 1 + rowOffset + offset;
indices[2] = V9_SIZE_SQ + square + offset;
break;
default: break;
}
else
switch (triangle)
{ // 0-----1 .... 128
case TOP: // |\ |
indices[0] = square+rowOffset; // | \ T |
indices[1] = square+1+rowOffset; // | \ |
indices[2] = square+V9_SIZE+1+rowOffset; // | B \ |
break; // | \|
case BOTTOM: // 129---130 ... 386
indices[0] = square+rowOffset; // |\ |
indices[1] = square+V9_SIZE+1+rowOffset; // | \ |
indices[2] = square+V9_SIZE+rowOffset; // | \ |
break; // | \ |
default: break; // | \|
} // 258---259 ... 515
{ // 0-----1 .... 128
case TOP: // |\ |
indices[0] = square + V9_SIZE + 1 + rowOffset + offset; // | \ T |
indices[1] = square + 1 + rowOffset + offset; // | \ |
indices[2] = square + rowOffset + offset; // | B \ |
break; // | \|
case BOTTOM: // 129---130 ... 386
indices[0] = square + V9_SIZE + rowOffset + offset; // |\ |
indices[1] = square + V9_SIZE + 1 + rowOffset + offset; // | \ |
indices[2] = square + rowOffset + offset; // | \ |
break; // | \ |
default: break; // | \|
} // 258---259 ... 515
}
/**************************************************************************/
void TerrainBuilder::getLiquidCoord(int index, int index2, float xOffset, float yOffset, float* coord, float* v)
inline void TerrainBuilder::getLiquidCoord(int index, int index2, float xOffset, float yOffset, float* coord, float* v)
{
// wow coords: x, y, height
// coord is mirroed about the horizontal axes
coord[0] = (xOffset + index%(V9_SIZE)*GRID_PART_SIZE) * -1.f;
coord[1] = (yOffset + (int)(index/(V9_SIZE))*GRID_PART_SIZE) * -1.f;
coord[2] = v[index2];
coord[0] = (xOffset + (int)(index % V9_SIZE) * GRID_PART_SIZE) * -1.f;
coord[1] = v[index2];
coord[2] = (yOffset + (int)(index / (V9_SIZE)) * GRID_PART_SIZE) * -1.f;
}
/**************************************************************************/
bool TerrainBuilder::isHole(int square, uint8 const (&holes)[16][16][8])
inline bool TerrainBuilder::isHole(int square, uint8 const (&holes)[16][16][8])
{
int row = square / 128;
int col = square % 128;
@@ -557,7 +550,7 @@ namespace MMAP
}
/**************************************************************************/
map_liquidHeaderTypeFlags TerrainBuilder::getLiquidType(int square, map_liquidHeaderTypeFlags const (&liquid_type)[16][16])
inline map_liquidHeaderTypeFlags TerrainBuilder::getLiquidType(int square, map_liquidHeaderTypeFlags const (&liquid_type)[16][16])
{
int row = square / 128;
int col = square % 128;
@@ -602,36 +595,27 @@ namespace MMAP
// transform data
float scale = instance.iScale;
G3D::Matrix3 rotation = instance.GetInvRot();
G3D::Matrix3 const& 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)
{
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();
// first handle collision mesh
transform(tempVertices, transformedVertices, scale, rotation, position);
int offset = meshData.solidVerts.size() / 3;
copyVertices(transformedVertices, meshData.solidVerts);
copyIndices(tempTriangles, meshData.solidTris, offset, isM2);
transformVertices(it->GetVertices(), meshData.solidVerts, scale, rotation, position);
copyIndices(it->GetTriangles(), meshData.solidTris, offset, isM2);
// now handle liquid data
VMAP::WmoLiquid const* liquid = it->GetLiquid();
if (liquid && liquid->GetFlagsStorage())
{
std::vector<G3D::Vector3> liqVerts;
std::vector<int> liqTris;
uint32 tilesX, tilesY, vertsX, vertsY;
uint32 tilesX, tilesY;
G3D::Vector3 corner;
liquid->getPosInfo(tilesX, tilesY, corner);
vertsX = tilesX + 1;
vertsY = tilesY + 1;
uint32 vertsX = tilesX + 1;
uint32 vertsY = tilesY + 1;
uint8 const* flags = liquid->GetFlagsStorage();
float const* data = liquid->GetHeightStorage();
uint8 type = NAV_AREA_EMPTY;
@@ -649,54 +633,56 @@ namespace MMAP
// tile = x*tilesY+y
// flag = y*tilesY+x
G3D::Vector3 vert;
uint32 liqOffset = meshData.liquidVerts.size() / 3;
meshData.liquidVerts.resize(meshData.liquidVerts.size() + vertsX * vertsY * 3);
float* liquidVerts = meshData.liquidVerts.data();
for (uint32 x = 0; x < vertsX; ++x)
{
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]);
G3D::Vector3 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);
liquidVerts[(liqOffset + x * vertsY + y) * 3 + 0] = vert.y;
liquidVerts[(liqOffset + x * vertsY + y) * 3 + 1] = vert.z;
liquidVerts[(liqOffset + x * vertsY + y) * 3 + 2] = vert.x;
}
}
int idx1, idx2, idx3, idx4;
uint32 square;
std::size_t liquidSquares = 0;
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 square = x * tilesY + y;
int idx1 = square + x;
int idx2 = square + 1 + x;
int idx3 = square + tilesY + 1 + 1 + x;
int idx4 = square + tilesY + 1 + x;
std::size_t liquidTriOffset = meshData.liquidTris.size();
meshData.liquidTris.resize(liquidTriOffset + 6);
int* liquidTris = meshData.liquidTris.data() + liquidTriOffset;
// top triangle
liqTris.push_back(idx3);
liqTris.push_back(idx2);
liqTris.push_back(idx1);
liquidTris[0] = idx2 + liqOffset;
liquidTris[1] = idx1 + liqOffset;
liquidTris[2] = idx3 + liqOffset;
// bottom triangle
liqTris.push_back(idx4);
liqTris.push_back(idx3);
liqTris.push_back(idx1);
liquidTris[3] = idx3 + liqOffset;
liquidTris[4] = idx1 + liqOffset;
liquidTris[5] = idx4 + liqOffset;
++liquidSquares;
}
}
}
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);
}
meshData.liquidType.resize(meshData.liquidType.size() + liquidSquares * 2, type);
}
}
}
@@ -705,105 +691,90 @@ namespace MMAP
}
/**************************************************************************/
void TerrainBuilder::transform(std::vector<G3D::Vector3> const& source, std::vector<G3D::Vector3>& transformedVertices, float scale, G3D::Matrix3 const& rotation, G3D::Vector3 const& position)
void TerrainBuilder::transformVertices(std::vector<G3D::Vector3> const& source, std::vector<float>& dest, float scale, G3D::Matrix3 const& rotation, G3D::Vector3 const& position)
{
transformedVertices.reserve(transformedVertices.size() + source.size());
for (G3D::Vector3 const& vertex : source)
std::size_t offset = dest.size();
dest.resize(dest.size() + source.size() * 3);
float* d = dest.data();
for (std::size_t i = 0; i < source.size(); ++i)
{
// apply tranform, then mirror along the horizontal axes
G3D::Vector3 v(vertex * rotation * scale + position);
G3D::Vector3 v(source[i] * rotation * scale + position);
v.x *= -1.f;
v.y *= -1.f;
transformedVertices.push_back(v);
d[offset + i * 3 + 0] = v.y;
d[offset + i * 3 + 1] = v.z;
d[offset + i * 3 + 2] = v.x;
}
}
/**************************************************************************/
void TerrainBuilder::copyVertices(std::vector<G3D::Vector3> const& source, G3D::Array<float>& dest)
void TerrainBuilder::copyIndices(std::vector<VMAP::MeshTriangle> const& source, std::vector<int>& dest, int offset, bool flip)
{
dest.reserve(dest.size() + source.size() * 3);
for (G3D::Vector3 const& vertex : source)
{
dest.push_back(vertex.y);
dest.push_back(vertex.z);
dest.push_back(vertex.x);
}
}
/**************************************************************************/
void TerrainBuilder::copyIndices(std::vector<VMAP::MeshTriangle> const& source, G3D::Array<int>& dest, int offset, bool flip)
{
dest.reserve(dest.size() + source.size() * 3);
std::size_t destOffset = dest.size();
dest.resize(dest.size() + source.size() * 3);
int* d = dest.data();
if (flip)
{
for (VMAP::MeshTriangle const& triangle : source)
{
dest.push_back(triangle.idx2 + offset);
dest.push_back(triangle.idx1 + offset);
dest.push_back(triangle.idx0 + offset);
d[destOffset++] = triangle.idx2 + offset;
d[destOffset++] = triangle.idx1 + offset;
d[destOffset++] = triangle.idx0 + offset;
}
}
else
{
for (VMAP::MeshTriangle const& triangle : source)
{
dest.push_back(triangle.idx0 + offset);
dest.push_back(triangle.idx1 + offset);
dest.push_back(triangle.idx2 + offset);
}
static_assert(sizeof(VMAP::MeshTriangle) == 3 * sizeof(uint32));
std::ranges::transform(reinterpret_cast<uint32 const*>(source.data()), reinterpret_cast<uint32 const*>(source.data() + source.size()),
dest.data() + destOffset, [&](int src) { return src + offset; });
}
}
/**************************************************************************/
void TerrainBuilder::copyIndices(G3D::Array<int> const& source, G3D::Array<int>& dest, int offset)
void TerrainBuilder::copyIndices(std::vector<int> const& source, std::vector<int>& dest, int offset)
{
int const* src = source.getCArray();
dest.reserve(dest.size() + source.size());
for (int32 i = 0; i < source.size(); ++i)
dest.append(src[i] + offset);
std::size_t destOffset = dest.size();
dest.resize(destOffset + source.size());
std::ranges::transform(source, dest.data() + destOffset, [&](int src) { return src + offset; });
}
/**************************************************************************/
void TerrainBuilder::cleanVertices(G3D::Array<float>& verts, G3D::Array<int>& tris)
void TerrainBuilder::cleanVertices(std::vector<float>& verts, std::vector<int>& tris)
{
std::map<int, int> vertMap;
std::unordered_map<int, int> vertMap;
vertMap.reserve(tris.size());
int* t = tris.getCArray();
float* v = verts.getCArray();
int* t = tris.data();
float* v = verts.data();
G3D::Array<float> cleanVerts;
int index, count = 0;
std::vector<float> cleanVerts;
cleanVerts.reserve(verts.size());
int count = 0;
// collect all the vertex indices from triangle
for (int i = 0; i < tris.size(); ++i)
for (std::size_t i = 0; i < tris.size(); ++i)
{
if (vertMap.find(t[i]) != vertMap.end())
auto [vertItr, isNew] = vertMap.try_emplace(t[i], count);
if (!isNew)
continue;
std::pair<int, int> val;
val.first = t[i];
index = val.first;
val.second = count;
std::ptrdiff_t index = t[i];
vertMap.insert(val);
cleanVerts.append(v[index * 3], v[index * 3 + 1], v[index * 3 + 2]);
cleanVerts.insert(cleanVerts.end(), &v[index * 3], &v[index * 3 + 3]);
count++;
}
verts.fastClear();
verts.append(cleanVerts);
cleanVerts.clear();
verts = std::move(cleanVerts);
// update triangles to use new indices
for (int i = 0; i < tris.size(); ++i)
for (std::size_t i = 0; i < tris.size(); ++i)
{
std::map<int, int>::iterator it;
if ((it = vertMap.find(t[i])) == vertMap.end())
auto it = vertMap.find(t[i]);
if (it == vertMap.end())
continue;
t[i] = (*it).second;
t[i] = it->second;
}
vertMap.clear();
}
/**************************************************************************/
@@ -814,19 +785,19 @@ namespace MMAP
if (mapID != offMeshConnection.MapId || tileX != offMeshConnection.TileX || tileY != offMeshConnection.TileY)
continue;
meshData.offMeshConnections.append(offMeshConnection.From[1]);
meshData.offMeshConnections.append(offMeshConnection.From[2]);
meshData.offMeshConnections.append(offMeshConnection.From[0]);
meshData.offMeshConnections.push_back(offMeshConnection.From[1]);
meshData.offMeshConnections.push_back(offMeshConnection.From[2]);
meshData.offMeshConnections.push_back(offMeshConnection.From[0]);
meshData.offMeshConnections.append(offMeshConnection.To[1]);
meshData.offMeshConnections.append(offMeshConnection.To[2]);
meshData.offMeshConnections.append(offMeshConnection.To[0]);
meshData.offMeshConnections.push_back(offMeshConnection.To[1]);
meshData.offMeshConnections.push_back(offMeshConnection.To[2]);
meshData.offMeshConnections.push_back(offMeshConnection.To[0]);
meshData.offMeshConnectionDirs.append(offMeshConnection.Bidirectional ? 1 : 0);
meshData.offMeshConnectionRads.append(offMeshConnection.Radius); // agent size equivalent
meshData.offMeshConnectionDirs.push_back(offMeshConnection.Bidirectional ? 1 : 0);
meshData.offMeshConnectionRads.push_back(offMeshConnection.Radius); // agent size equivalent
// can be used same way as polygon flags
meshData.offMeshConnectionsAreas.append(offMeshConnection.AreaId);
meshData.offMeshConnectionsFlags.append(offMeshConnection.Flags);
meshData.offMeshConnectionsAreas.push_back(offMeshConnection.AreaId);
meshData.offMeshConnectionsFlags.push_back(offMeshConnection.Flags);
}
}
}

View File

@@ -19,8 +19,6 @@
#define _MMAP_TERRAIN_BUILDER_H
#include "WorldModel.h"
#include <G3D/Array.h>
#include <G3D/Vector3.h>
namespace VMAP
@@ -77,19 +75,19 @@ namespace MMAP
struct MeshData
{
G3D::Array<float> solidVerts;
G3D::Array<int> solidTris;
std::vector<float> solidVerts;
std::vector<int> solidTris;
G3D::Array<float> liquidVerts;
G3D::Array<int> liquidTris;
G3D::Array<uint8> liquidType;
std::vector<float> liquidVerts;
std::vector<int> liquidTris;
std::vector<uint8> liquidType;
// offmesh connection data
G3D::Array<float> offMeshConnections; // [p0y,p0z,p0x,p1y,p1z,p1x] - per connection
G3D::Array<float> offMeshConnectionRads;
G3D::Array<unsigned char> offMeshConnectionDirs;
G3D::Array<unsigned char> offMeshConnectionsAreas;
G3D::Array<unsigned short> offMeshConnectionsFlags;
std::vector<float> offMeshConnections; // [p0y,p0z,p0x,p1y,p1z,p1x] - per connection
std::vector<float> offMeshConnectionRads;
std::vector<unsigned char> offMeshConnectionDirs;
std::vector<unsigned char> offMeshConnectionsAreas;
std::vector<unsigned short> offMeshConnectionsFlags;
};
class TerrainBuilder
@@ -104,36 +102,35 @@ namespace MMAP
bool usesLiquids() const { return !m_skipLiquid; }
// vert and triangle methods
static void transform(std::vector<G3D::Vector3> const& source, std::vector<G3D::Vector3>& transformed,
static void transformVertices(std::vector<G3D::Vector3> const& source, std::vector<float>& dest,
float scale, G3D::Matrix3 const& rotation, G3D::Vector3 const& position);
static void copyVertices(std::vector<G3D::Vector3> const& source, G3D::Array<float>& dest);
static void copyIndices(std::vector<VMAP::MeshTriangle> const& source, G3D::Array<int>& dest, int offset, bool flip);
static void copyIndices(G3D::Array<int> const& source, G3D::Array<int>& dest, int offset);
static void cleanVertices(G3D::Array<float>& verts, G3D::Array<int>& tris);
static void copyIndices(std::vector<VMAP::MeshTriangle> const& source, std::vector<int>& dest, int offset, bool flip);
static void copyIndices(std::vector<int> const& source, std::vector<int>& dest, int offset);
static void cleanVertices(std::vector<float>& verts, std::vector<int>& tris);
private:
/// Loads a portion of a map's terrain
bool loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, VMAP::VMapManager* vmapManager, Spot portion);
/// Sets loop variables for selecting only certain parts of a map's terrain
void getLoopVars(Spot portion, int& loopStart, int& loopEnd, int& loopInc);
static void getLoopVars(Spot portion, int& loopStart, int& loopEnd, int& loopInc);
/// Controls whether liquids are loaded
bool m_skipLiquid;
/// Get the vector coordinate for a specific position
void getHeightCoord(int index, Grid grid, float xOffset, float yOffset, float* coord, float* v);
static void getHeightCoord(int index, Grid grid, float xOffset, float yOffset, float* coord, float* v);
/// Get the triangle's vector indices for a specific position
void getHeightTriangle(int square, Spot triangle, int* indices, bool liquid = false);
static void getHeightTriangle(int square, Spot triangle, int* indices, int offset, bool liquid = false);
/// Determines if the specific position's triangles should be rendered
bool isHole(int square, uint8 const (&holes)[16][16][8]);
static bool isHole(int square, uint8 const (&holes)[16][16][8]);
/// Get the liquid vector coordinate for a specific position
void getLiquidCoord(int index, int index2, float xOffset, float yOffset, float* coord, float* v);
static void getLiquidCoord(int index, int index2, float xOffset, float yOffset, float* coord, float* v);
/// Get the liquid type for a specific position
map_liquidHeaderTypeFlags getLiquidType(int square, map_liquidHeaderTypeFlags const (&liquid_type)[16][16]);
static map_liquidHeaderTypeFlags getLiquidType(int square, map_liquidHeaderTypeFlags const (&liquid_type)[16][16]);
};
}

View File

@@ -105,7 +105,7 @@ namespace MMAP
m_terrainBuilder.loadVMap(mapID, tileY, tileX, meshData, vmapManager.get());
// if there is no data, give up now
if (!meshData.solidVerts.size() && !meshData.liquidVerts.size())
if (meshData.solidVerts.empty() && meshData.liquidVerts.empty())
{
OnTileDone();
return;
@@ -115,20 +115,21 @@ namespace MMAP
TerrainBuilder::cleanVertices(meshData.solidVerts, meshData.solidTris);
TerrainBuilder::cleanVertices(meshData.liquidVerts, meshData.liquidTris);
// gather all mesh data for final data check, and bounds calculation
G3D::Array<float> allVerts;
allVerts.append(meshData.liquidVerts);
allVerts.append(meshData.solidVerts);
if (!allVerts.size())
if (meshData.liquidVerts.empty() && meshData.solidVerts.empty())
{
OnTileDone();
return;
}
// gather all mesh data for final data check, and bounds calculation
std::vector<float> allVerts(meshData.liquidVerts.size() + meshData.solidVerts.size());
auto allVertsOutput = allVerts.begin();
allVertsOutput = std::ranges::copy(meshData.liquidVerts, allVertsOutput).out;
allVertsOutput = std::ranges::copy(meshData.solidVerts, allVertsOutput).out;
// get bounds of current tile
float bmin[3], bmax[3];
getTileBounds(tileX, tileY, allVerts.getCArray(), allVerts.size() / 3, bmin, bmax);
getTileBounds(tileX, tileY, allVerts.data(), allVerts.size() / 3, bmin, bmax);
if (m_offMeshConnections)
m_terrainBuilder.loadOffMeshConnections(mapID, tileX, tileY, meshData, *m_offMeshConnections);
@@ -150,16 +151,16 @@ namespace MMAP
IntermediateValues iv;
float* tVerts = meshData.solidVerts.getCArray();
float* tVerts = meshData.solidVerts.data();
int tVertCount = meshData.solidVerts.size() / 3;
int* tTris = meshData.solidTris.getCArray();
int* tTris = meshData.solidTris.data();
int tTriCount = meshData.solidTris.size() / 3;
float* lVerts = meshData.liquidVerts.getCArray();
float* lVerts = meshData.liquidVerts.data();
int lVertCount = meshData.liquidVerts.size() / 3;
int* lTris = meshData.liquidTris.getCArray();
int* lTris = meshData.liquidTris.data();
int lTriCount = meshData.liquidTris.size() / 3;
uint8* lTriFlags = meshData.liquidType.getCArray();
uint8* lTriFlags = meshData.liquidType.data();
const TileConfig tileConfig = TileConfig(m_bigBaseUnit);
int TILES_PER_MAP = tileConfig.TILES_PER_MAP;
@@ -348,12 +349,12 @@ namespace MMAP
params.detailTris = iv.polyMeshDetail->tris;
params.detailTriCount = iv.polyMeshDetail->ntris;
params.offMeshConVerts = meshData.offMeshConnections.getCArray();
params.offMeshConVerts = meshData.offMeshConnections.data();
params.offMeshConCount = meshData.offMeshConnections.size() / 6;
params.offMeshConRad = meshData.offMeshConnectionRads.getCArray();
params.offMeshConDir = meshData.offMeshConnectionDirs.getCArray();
params.offMeshConAreas = meshData.offMeshConnectionsAreas.getCArray();
params.offMeshConFlags = meshData.offMeshConnectionsFlags.getCArray();
params.offMeshConRad = meshData.offMeshConnectionRads.data();
params.offMeshConDir = meshData.offMeshConnectionDirs.data();
params.offMeshConAreas = meshData.offMeshConnectionsAreas.data();
params.offMeshConFlags = meshData.offMeshConnectionsFlags.data();
params.walkableHeight = BASE_UNIT_DIM * config.walkableHeight; // agent height
params.walkableRadius = BASE_UNIT_DIM * config.walkableRadius; // agent radius