TrinityCore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
MMAP::TerrainBuilder Class Reference

#include <TerrainBuilder.h>

Public Member Functions

 TerrainBuilder (bool skipLiquid)
 
 ~TerrainBuilder ()
 
void loadMap (uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData)
 
bool loadVMap (uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData)
 
void loadOffMeshConnections (uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData, const char *offMeshFilePath)
 
bool usesLiquids ()
 

Static Public Member Functions

static void transform (std::vector< G3D::Vector3 > &original, std::vector< G3D::Vector3 > &transformed, float scale, G3D::Matrix3 &rotation, G3D::Vector3 &position)
 
static void copyVertices (std::vector< G3D::Vector3 > &source, G3D::Array< float > &dest)
 
static void copyIndices (std::vector< VMAP::MeshTriangle > &source, G3D::Array< int > &dest, int offest, bool flip)
 
static void copyIndices (G3D::Array< int > &src, G3D::Array< int > &dest, int offset)
 
static void cleanVertices (G3D::Array< float > &verts, G3D::Array< int > &tris)
 

Private Member Functions

bool loadMap (uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData, Spot portion)
 Loads a portion of a map's terrain. More...
 
void getLoopVars (Spot portion, int &loopStart, int &loopEnd, int &loopInc)
 Sets loop variables for selecting only certain parts of a map's terrain. More...
 
bool loadHeightMap (uint32 mapID, uint32 tileX, uint32 tileY, G3D::Array< float > &vertices, G3D::Array< int > &triangles, Spot portion)
 Load the map terrain from file. More...
 
void getHeightCoord (int index, Grid grid, float xOffset, float yOffset, float *coord, float *v)
 Get the vector coordinate for a specific position. More...
 
void getHeightTriangle (int square, Spot triangle, int *indices, bool liquid=false)
 Get the triangle's vector indices for a specific position. More...
 
bool isHole (int square, uint8 const holes[16][16][8])
 Determines if the specific position's triangles should be rendered. More...
 
void getLiquidCoord (int index, int index2, float xOffset, float yOffset, float *coord, float *v)
 Get the liquid vector coordinate for a specific position. More...
 
uint8 getLiquidType (int square, const uint8 liquid_type[16][16])
 Get the liquid type for a specific position. More...
 
 TerrainBuilder ()
 
 TerrainBuilder (const TerrainBuilder &tb)
 

Private Attributes

bool m_skipLiquid
 Controls whether liquids are loaded. More...
 

Constructor & Destructor Documentation

MMAP::TerrainBuilder::TerrainBuilder ( bool  skipLiquid)
85 : m_skipLiquid (skipLiquid){ }
bool m_skipLiquid
Controls whether liquids are loaded.
Definition: TerrainBuilder.h:105
MMAP::TerrainBuilder::~TerrainBuilder ( )
86 { }
MMAP::TerrainBuilder::TerrainBuilder ( )
private
MMAP::TerrainBuilder::TerrainBuilder ( const TerrainBuilder tb)
private

Member Function Documentation

void MMAP::TerrainBuilder::cleanVertices ( G3D::Array< float > &  verts,
G3D::Array< int > &  tris 
)
static
839  {
840  std::map<int, int> vertMap;
841 
842  int* t = tris.getCArray();
843  float* v = verts.getCArray();
844 
845  G3D::Array<float> cleanVerts;
846  int index, count = 0;
847  // collect all the vertex indices from triangle
848  for (int i = 0; i < tris.size(); ++i)
849  {
850  if (vertMap.find(t[i]) != vertMap.end())
851  continue;
852  std::pair<int, int> val;
853  val.first = t[i];
854 
855  index = val.first;
856  val.second = count;
857 
858  vertMap.insert(val);
859  cleanVerts.append(v[index * 3], v[index * 3 + 1], v[index * 3 + 2]);
860  count++;
861  }
862 
863  verts.fastClear();
864  verts.append(cleanVerts);
865  cleanVerts.clear();
866 
867  // update triangles to use new indices
868  for (int i = 0; i < tris.size(); ++i)
869  {
870  std::map<int, int>::iterator it;
871  if ((it = vertMap.find(t[i])) == vertMap.end())
872  continue;
873 
874  t[i] = (*it).second;
875  }
876 
877  vertMap.clear();
878  }
void fastClear()
Definition: Array.h:419
T * getCArray()
Definition: Array.h:256
void clear(bool shrink=true)
Definition: Array.h:407
int size() const
Definition: Array.h:430
T & first()
Definition: Array.h:948
void append(const T &value)
Definition: Array.h:583

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void MMAP::TerrainBuilder::copyIndices ( std::vector< VMAP::MeshTriangle > &  source,
G3D::Array< int > &  dest,
int  offest,
bool  flip 
)
static
808  {
809  if (flip)
810  {
811  for (std::vector<MeshTriangle>::iterator it = source.begin(); it != source.end(); ++it)
812  {
813  dest.push_back((*it).idx2+offset);
814  dest.push_back((*it).idx1+offset);
815  dest.push_back((*it).idx0+offset);
816  }
817  }
818  else
819  {
820  for (std::vector<MeshTriangle>::iterator it = source.begin(); it != source.end(); ++it)
821  {
822  dest.push_back((*it).idx0+offset);
823  dest.push_back((*it).idx1+offset);
824  dest.push_back((*it).idx2+offset);
825  }
826  }
827  }
void push_back(const T &v)
Definition: Array.h:779

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void MMAP::TerrainBuilder::copyIndices ( G3D::Array< int > &  src,
G3D::Array< int > &  dest,
int  offset 
)
static
831  {
832  int* src = source.getCArray();
833  for (int32 i = 0; i < source.size(); ++i)
834  dest.append(src[i] + offset);
835  }
T * getCArray()
Definition: Array.h:256
int32_t int32
Definition: Define.h:146
void append(const T &value)
Definition: Array.h:583

+ Here is the call graph for this function:

void MMAP::TerrainBuilder::copyVertices ( std::vector< G3D::Vector3 > &  source,
G3D::Array< float > &  dest 
)
static
797  {
798  for (std::vector<G3D::Vector3>::iterator it = source.begin(); it != source.end(); ++it)
799  {
800  dest.push_back((*it).y);
801  dest.push_back((*it).z);
802  dest.push_back((*it).x);
803  }
804  }
void push_back(const T &v)
Definition: Array.h:779

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void MMAP::TerrainBuilder::getHeightCoord ( int  index,
Grid  grid,
float  xOffset,
float  yOffset,
float *  coord,
float *  v 
)
private

Get the vector coordinate for a specific position.

527  {
528  // wow coords: x, y, height
529  // coord is mirroed about the horizontal axes
530  switch (grid)
531  {
532  case GRID_V9:
533  coord[0] = (xOffset + index%(V9_SIZE)*GRID_PART_SIZE) * -1.f;
534  coord[1] = (yOffset + (int)(index/(V9_SIZE))*GRID_PART_SIZE) * -1.f;
535  coord[2] = v[index];
536  break;
537  case GRID_V8:
538  coord[0] = (xOffset + index%(V8_SIZE)*GRID_PART_SIZE + GRID_PART_SIZE/2.f) * -1.f;
539  coord[1] = (yOffset + (int)(index/(V8_SIZE))*GRID_PART_SIZE + GRID_PART_SIZE/2.f) * -1.f;
540  coord[2] = v[index];
541  break;
542  }
543  }
Definition: TerrainBuilder.h:43
static const int V8_SIZE
Definition: TerrainBuilder.h:48
Definition: TerrainBuilder.h:42
static const int V9_SIZE
Definition: TerrainBuilder.h:46
static const float GRID_PART_SIZE
Definition: TerrainBuilder.h:51

+ Here is the caller graph for this function:

void MMAP::TerrainBuilder::getHeightTriangle ( int  square,
Spot  triangle,
int *  indices,
bool  liquid = false 
)
private

Get the triangle's vector indices for a specific position.

547  {
548  int rowOffset = square/V8_SIZE;
549  if (!liquid)
550  switch (triangle)
551  {
552  case TOP:
553  indices[0] = square+rowOffset; // 0-----1 .... 128
554  indices[1] = square+1+rowOffset; // |\ T /|
555  indices[2] = (V9_SIZE_SQ)+square; // | \ / |
556  break; // |L 0 R| .. 127
557  case LEFT: // | / \ |
558  indices[0] = square+rowOffset; // |/ B \|
559  indices[1] = (V9_SIZE_SQ)+square; // 129---130 ... 386
560  indices[2] = square+V9_SIZE+rowOffset; // |\ /|
561  break; // | \ / |
562  case RIGHT: // | 128 | .. 255
563  indices[0] = square+1+rowOffset; // | / \ |
564  indices[1] = square+V9_SIZE+1+rowOffset; // |/ \|
565  indices[2] = (V9_SIZE_SQ)+square; // 258---259 ... 515
566  break;
567  case BOTTOM:
568  indices[0] = (V9_SIZE_SQ)+square;
569  indices[1] = square+V9_SIZE+1+rowOffset;
570  indices[2] = square+V9_SIZE+rowOffset;
571  break;
572  default: break;
573  }
574  else
575  switch (triangle)
576  { // 0-----1 .... 128
577  case TOP: // |\ |
578  indices[0] = square+rowOffset; // | \ T |
579  indices[1] = square+1+rowOffset; // | \ |
580  indices[2] = square+V9_SIZE+1+rowOffset; // | B \ |
581  break; // | \|
582  case BOTTOM: // 129---130 ... 386
583  indices[0] = square+rowOffset; // |\ |
584  indices[1] = square+V9_SIZE+1+rowOffset; // | \ |
585  indices[2] = square+V9_SIZE+rowOffset; // | \ |
586  break; // | \ |
587  default: break; // | \|
588  } // 258---259 ... 515
589 
590  }
Definition: TerrainBuilder.h:35
Definition: TerrainBuilder.h:34
Definition: adtfile.h:46
static const int V8_SIZE
Definition: TerrainBuilder.h:48
static const int V9_SIZE_SQ
Definition: TerrainBuilder.h:47
static const int V9_SIZE
Definition: TerrainBuilder.h:46
double square(double fValue)
Definition: g3dmath.h:698
Definition: TerrainBuilder.h:33
Definition: TerrainBuilder.h:36

+ Here is the caller graph for this function:

void MMAP::TerrainBuilder::getLiquidCoord ( int  index,
int  index2,
float  xOffset,
float  yOffset,
float *  coord,
float *  v 
)
private

Get the liquid vector coordinate for a specific position.

594  {
595  // wow coords: x, y, height
596  // coord is mirroed about the horizontal axes
597  coord[0] = (xOffset + index%(V9_SIZE)*GRID_PART_SIZE) * -1.f;
598  coord[1] = (yOffset + (int)(index/(V9_SIZE))*GRID_PART_SIZE) * -1.f;
599  coord[2] = v[index2];
600  }
static const int V9_SIZE
Definition: TerrainBuilder.h:46
static const float GRID_PART_SIZE
Definition: TerrainBuilder.h:51

+ Here is the caller graph for this function:

uint8 MMAP::TerrainBuilder::getLiquidType ( int  square,
const uint8  liquid_type[16][16] 
)
private

Get the liquid type for a specific position.

617  {
618  int row = square / 128;
619  int col = square % 128;
620  int cellRow = row / 8; // 8 squares per cell
621  int cellCol = col / 8;
622 
623  return liquid_type[cellRow][cellCol];
624  }
double square(double fValue)
Definition: g3dmath.h:698

+ Here is the caller graph for this function:

void MMAP::TerrainBuilder::getLoopVars ( Spot  portion,
int &  loopStart,
int &  loopEnd,
int &  loopInc 
)
private

Sets loop variables for selecting only certain parts of a map's terrain.

90  {
91  switch (portion)
92  {
93  case ENTIRE:
94  loopStart = 0;
95  loopEnd = V8_SIZE_SQ;
96  loopInc = 1;
97  break;
98  case TOP:
99  loopStart = 0;
100  loopEnd = V8_SIZE;
101  loopInc = 1;
102  break;
103  case LEFT:
104  loopStart = 0;
105  loopEnd = V8_SIZE_SQ - V8_SIZE + 1;
106  loopInc = V8_SIZE;
107  break;
108  case RIGHT:
109  loopStart = V8_SIZE - 1;
110  loopEnd = V8_SIZE_SQ;
111  loopInc = V8_SIZE;
112  break;
113  case BOTTOM:
114  loopStart = V8_SIZE_SQ - V8_SIZE;
115  loopEnd = V8_SIZE_SQ;
116  loopInc = 1;
117  break;
118  }
119  }
Definition: TerrainBuilder.h:35
Definition: TerrainBuilder.h:34
static const int V8_SIZE
Definition: TerrainBuilder.h:48
Definition: TerrainBuilder.h:37
Definition: TerrainBuilder.h:33
Definition: TerrainBuilder.h:36
static const int V8_SIZE_SQ
Definition: TerrainBuilder.h:49

+ Here is the caller graph for this function:

bool MMAP::TerrainBuilder::isHole ( int  square,
uint8 const  holes[16][16][8] 
)
private

Determines if the specific position's triangles should be rendered.

604  {
605  int row = square / 128;
606  int col = square % 128;
607  int cellRow = row / 8; // 8 squares per cell
608  int cellCol = col / 8;
609  int holeRow = row % 8;
610  int holeCol = (square - (row * 128 + cellCol * 8));
611 
612  return (holes[cellRow][cellCol][holeRow] & (1 << holeCol)) != 0;
613  }
double square(double fValue)
Definition: g3dmath.h:698
uint8 holes[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID][8]
Definition: System.cpp:444

+ Here is the caller graph for this function:

bool MMAP::TerrainBuilder::loadHeightMap ( uint32  mapID,
uint32  tileX,
uint32  tileY,
G3D::Array< float > &  vertices,
G3D::Array< int > &  triangles,
Spot  portion 
)
private

Load the map terrain from file.

void MMAP::TerrainBuilder::loadMap ( uint32  mapID,
uint32  tileX,
uint32  tileY,
MeshData meshData 
)
123  {
124  if (loadMap(mapID, tileX, tileY, meshData, ENTIRE))
125  {
126  loadMap(mapID, tileX+1, tileY, meshData, LEFT);
127  loadMap(mapID, tileX-1, tileY, meshData, RIGHT);
128  loadMap(mapID, tileX, tileY+1, meshData, TOP);
129  loadMap(mapID, tileX, tileY-1, meshData, BOTTOM);
130  }
131  }
Definition: TerrainBuilder.h:35
Definition: TerrainBuilder.h:34
void loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData)
Definition: TerrainBuilder.cpp:122
Definition: TerrainBuilder.h:37
Definition: TerrainBuilder.h:33
Definition: TerrainBuilder.h:36

+ Here is the caller graph for this function:

bool MMAP::TerrainBuilder::loadMap ( uint32  mapID,
uint32  tileX,
uint32  tileY,
MeshData meshData,
Spot  portion 
)
private

Loads a portion of a map's terrain.

135  {
136  char mapFileName[255];
137  sprintf(mapFileName, "maps/%04u_%02u_%02u.map", mapID, tileY, tileX);
138 
139  FILE* mapFile = fopen(mapFileName, "rb");
140  if (!mapFile)
141  return false;
142 
143  map_fileheader fheader;
144  if (fread(&fheader, sizeof(map_fileheader), 1, mapFile) != 1 ||
145  fheader.versionMagic != *((uint32 const*)(MAP_VERSION_MAGIC)))
146  {
147  fclose(mapFile);
148  printf("%s is the wrong version, please extract new .map files\n", mapFileName);
149  return false;
150  }
151 
152  map_heightHeader hheader;
153  fseek(mapFile, fheader.heightMapOffset, SEEK_SET);
154 
155  bool haveTerrain = false;
156  bool haveLiquid = false;
157  if (fread(&hheader, sizeof(map_heightHeader), 1, mapFile) == 1)
158  {
159  haveTerrain = !(hheader.flags & MAP_HEIGHT_NO_HEIGHT);
160  haveLiquid = fheader.liquidMapOffset && !m_skipLiquid;
161  }
162 
163  // no data in this map file
164  if (!haveTerrain && !haveLiquid)
165  {
166  fclose(mapFile);
167  return false;
168  }
169 
170  // data used later
171  uint8 holes[16][16][8];
172  memset(holes, 0, sizeof(holes));
173  uint8 liquid_type[16][16];
174  memset(liquid_type, 0, sizeof(liquid_type));
175  G3D::Array<int> ltriangles;
176  G3D::Array<int> ttriangles;
177 
178  // terrain data
179  if (haveTerrain)
180  {
181  float heightMultiplier;
182  float V9[V9_SIZE_SQ], V8[V8_SIZE_SQ];
183  int expected = V9_SIZE_SQ + V8_SIZE_SQ;
184 
185  if (hheader.flags & MAP_HEIGHT_AS_INT8)
186  {
187  uint8 v9[V9_SIZE_SQ];
188  uint8 v8[V8_SIZE_SQ];
189  int count = 0;
190  count += fread(v9, sizeof(uint8), V9_SIZE_SQ, mapFile);
191  count += fread(v8, sizeof(uint8), V8_SIZE_SQ, mapFile);
192  if (count != expected)
193  printf("TerrainBuilder::loadMap: Failed to read some data expected %d, read %d\n", expected, count);
194 
195  heightMultiplier = (hheader.gridMaxHeight - hheader.gridHeight) / 255;
196 
197  for (int i = 0; i < V9_SIZE_SQ; ++i)
198  V9[i] = (float)v9[i]*heightMultiplier + hheader.gridHeight;
199 
200  for (int i = 0; i < V8_SIZE_SQ; ++i)
201  V8[i] = (float)v8[i]*heightMultiplier + hheader.gridHeight;
202  }
203  else if (hheader.flags & MAP_HEIGHT_AS_INT16)
204  {
205  uint16 v9[V9_SIZE_SQ];
206  uint16 v8[V8_SIZE_SQ];
207  int count = 0;
208  count += fread(v9, sizeof(uint16), V9_SIZE_SQ, mapFile);
209  count += fread(v8, sizeof(uint16), V8_SIZE_SQ, mapFile);
210  if (count != expected)
211  printf("TerrainBuilder::loadMap: Failed to read some data expected %d, read %d\n", expected, count);
212 
213  heightMultiplier = (hheader.gridMaxHeight - hheader.gridHeight) / 65535;
214 
215  for (int i = 0; i < V9_SIZE_SQ; ++i)
216  V9[i] = (float)v9[i]*heightMultiplier + hheader.gridHeight;
217 
218  for (int i = 0; i < V8_SIZE_SQ; ++i)
219  V8[i] = (float)v8[i]*heightMultiplier + hheader.gridHeight;
220  }
221  else
222  {
223  int count = 0;
224  count += fread(V9, sizeof(float), V9_SIZE_SQ, mapFile);
225  count += fread(V8, sizeof(float), V8_SIZE_SQ, mapFile);
226  if (count != expected)
227  printf("TerrainBuilder::loadMap: Failed to read some data expected %d, read %d\n", expected, count);
228  }
229 
230  // hole data
231  if (fheader.holesSize != 0)
232  {
233  memset(holes, 0, fheader.holesSize);
234  fseek(mapFile, fheader.holesOffset, SEEK_SET);
235  if (fread(holes, fheader.holesSize, 1, mapFile) != 1)
236  printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
237  }
238 
239  int count = meshData.solidVerts.size() / 3;
240  float xoffset = (float(tileX)-32)*GRID_SIZE;
241  float yoffset = (float(tileY)-32)*GRID_SIZE;
242 
243  float coord[3];
244 
245  for (int i = 0; i < V9_SIZE_SQ; ++i)
246  {
247  getHeightCoord(i, GRID_V9, xoffset, yoffset, coord, V9);
248  meshData.solidVerts.append(coord[0]);
249  meshData.solidVerts.append(coord[2]);
250  meshData.solidVerts.append(coord[1]);
251  }
252 
253  for (int i = 0; i < V8_SIZE_SQ; ++i)
254  {
255  getHeightCoord(i, GRID_V8, xoffset, yoffset, coord, V8);
256  meshData.solidVerts.append(coord[0]);
257  meshData.solidVerts.append(coord[2]);
258  meshData.solidVerts.append(coord[1]);
259  }
260 
261  int indices[] = { 0, 0, 0 };
262  int loopStart = 0, loopEnd = 0, loopInc = 0;
263  getLoopVars(portion, loopStart, loopEnd, loopInc);
264  for (int i = loopStart; i < loopEnd; i+=loopInc)
265  for (int j = TOP; j <= BOTTOM; j+=1)
266  {
267  getHeightTriangle(i, Spot(j), indices);
268  ttriangles.append(indices[2] + count);
269  ttriangles.append(indices[1] + count);
270  ttriangles.append(indices[0] + count);
271  }
272  }
273 
274  // liquid data
275  if (haveLiquid)
276  {
277  map_liquidHeader lheader;
278  fseek(mapFile, fheader.liquidMapOffset, SEEK_SET);
279  if (fread(&lheader, sizeof(map_liquidHeader), 1, mapFile) != 1)
280  printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
281 
282 
283  float* liquid_map = NULL;
284 
285  if (!(lheader.flags & MAP_LIQUID_NO_TYPE))
286  if (fread(liquid_type, sizeof(liquid_type), 1, mapFile) != 1)
287  printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
288 
289  if (!(lheader.flags & MAP_LIQUID_NO_HEIGHT))
290  {
291  uint32 toRead = lheader.width * lheader.height;
292  liquid_map = new float [toRead];
293  if (fread(liquid_map, sizeof(float), toRead, mapFile) != toRead)
294  printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
295  }
296 
297  if (liquid_map)
298  {
299  int count = meshData.liquidVerts.size() / 3;
300  float xoffset = (float(tileX)-32)*GRID_SIZE;
301  float yoffset = (float(tileY)-32)*GRID_SIZE;
302 
303  float coord[3];
304  int row, col;
305 
306  // generate coordinates
307  if (!(lheader.flags & MAP_LIQUID_NO_HEIGHT))
308  {
309  int j = 0;
310  for (int i = 0; i < V9_SIZE_SQ; ++i)
311  {
312  row = i / V9_SIZE;
313  col = i % V9_SIZE;
314 
315  if (row < lheader.offsetY || row >= lheader.offsetY + lheader.height ||
316  col < lheader.offsetX || col >= lheader.offsetX + lheader.width)
317  {
318  // dummy vert using invalid height
319  meshData.liquidVerts.append((xoffset+col*GRID_PART_SIZE)*-1, INVALID_MAP_LIQ_HEIGHT, (yoffset+row*GRID_PART_SIZE)*-1);
320  continue;
321  }
322 
323  getLiquidCoord(i, j, xoffset, yoffset, coord, liquid_map);
324  meshData.liquidVerts.append(coord[0]);
325  meshData.liquidVerts.append(coord[2]);
326  meshData.liquidVerts.append(coord[1]);
327  j++;
328  }
329  }
330  else
331  {
332  for (int i = 0; i < V9_SIZE_SQ; ++i)
333  {
334  row = i / V9_SIZE;
335  col = i % V9_SIZE;
336  meshData.liquidVerts.append((xoffset+col*GRID_PART_SIZE)*-1, lheader.liquidLevel, (yoffset+row*GRID_PART_SIZE)*-1);
337  }
338  }
339 
340  delete [] liquid_map;
341 
342  int indices[] = { 0, 0, 0 };
343  int loopStart = 0, loopEnd = 0, loopInc = 0, triInc = BOTTOM-TOP;
344  getLoopVars(portion, loopStart, loopEnd, loopInc);
345 
346  // generate triangles
347  for (int i = loopStart; i < loopEnd; i+=loopInc)
348  for (int j = TOP; j <= BOTTOM; j+= triInc)
349  {
350  getHeightTriangle(i, Spot(j), indices, true);
351  ltriangles.append(indices[2] + count);
352  ltriangles.append(indices[1] + count);
353  ltriangles.append(indices[0] + count);
354  }
355  }
356  }
357 
358  fclose(mapFile);
359 
360  // now that we have gathered the data, we can figure out which parts to keep:
361  // liquid above ground, ground above liquid
362  int loopStart = 0, loopEnd = 0, loopInc = 0, tTriCount = 4;
363  bool useTerrain, useLiquid;
364 
365  float* lverts = meshData.liquidVerts.getCArray();
366  int* ltris = ltriangles.getCArray();
367 
368  float* tverts = meshData.solidVerts.getCArray();
369  int* ttris = ttriangles.getCArray();
370 
371  if ((ltriangles.size() + ttriangles.size()) == 0)
372  return false;
373 
374  // make a copy of liquid vertices
375  // used to pad right-bottom frame due to lost vertex data at extraction
376  float* lverts_copy = NULL;
377  if (meshData.liquidVerts.size())
378  {
379  lverts_copy = new float[meshData.liquidVerts.size()];
380  memcpy(lverts_copy, lverts, sizeof(float)*meshData.liquidVerts.size());
381  }
382 
383  getLoopVars(portion, loopStart, loopEnd, loopInc);
384  for (int i = loopStart; i < loopEnd; i+=loopInc)
385  {
386  for (int j = 0; j < 2; ++j)
387  {
388  // default is true, will change to false if needed
389  useTerrain = true;
390  useLiquid = true;
391  uint8 liquidType = MAP_LIQUID_TYPE_NO_WATER;
392  // FIXME: "warning: the address of ‘liquid_type’ will always evaluate as ‘true’"
393 
394  // if there is no liquid, don't use liquid
395  if (!meshData.liquidVerts.size() || !ltriangles.size())
396  useLiquid = false;
397  else
398  {
399  liquidType = getLiquidType(i, liquid_type);
400  switch (liquidType)
401  {
402  default:
403  useLiquid = false;
404  break;
407  // merge different types of water
408  liquidType = NAV_WATER;
409  break;
411  liquidType = NAV_MAGMA;
412  break;
414  liquidType = NAV_SLIME;
415  break;
417  // players should not be here, so logically neither should creatures
418  useTerrain = false;
419  useLiquid = false;
420  break;
421  }
422  }
423 
424  // if there is no terrain, don't use terrain
425  if (!ttriangles.size())
426  useTerrain = false;
427 
428  // while extracting ADT data we are losing right-bottom vertices
429  // this code adds fair approximation of lost data
430  if (useLiquid)
431  {
432  float quadHeight = 0;
433  uint32 validCount = 0;
434  for(uint32 idx = 0; idx < 3; idx++)
435  {
436  float h = lverts_copy[ltris[idx]*3 + 1];
438  {
439  quadHeight += h;
440  validCount++;
441  }
442  }
443 
444  // update vertex height data
445  if (validCount > 0 && validCount < 3)
446  {
447  quadHeight /= validCount;
448  for(uint32 idx = 0; idx < 3; idx++)
449  {
450  float h = lverts[ltris[idx]*3 + 1];
452  lverts[ltris[idx]*3 + 1] = quadHeight;
453  }
454  }
455 
456  // no valid vertexes - don't use this poly at all
457  if (validCount == 0)
458  useLiquid = false;
459  }
460 
461  // if there is a hole here, don't use the terrain
462  if (useTerrain && fheader.holesSize != 0)
463  useTerrain = !isHole(i, holes);
464 
465  // we use only one terrain kind per quad - pick higher one
466  if (useTerrain && useLiquid)
467  {
468  float minLLevel = INVALID_MAP_LIQ_HEIGHT_MAX;
469  float maxLLevel = INVALID_MAP_LIQ_HEIGHT;
470  for(uint32 x = 0; x < 3; x++)
471  {
472  float h = lverts[ltris[x]*3 + 1];
473  if (minLLevel > h)
474  minLLevel = h;
475 
476  if (maxLLevel < h)
477  maxLLevel = h;
478  }
479 
480  float maxTLevel = INVALID_MAP_LIQ_HEIGHT;
481  float minTLevel = INVALID_MAP_LIQ_HEIGHT_MAX;
482  for(uint32 x = 0; x < 6; x++)
483  {
484  float h = tverts[ttris[x]*3 + 1];
485  if (maxTLevel < h)
486  maxTLevel = h;
487 
488  if (minTLevel > h)
489  minTLevel = h;
490  }
491 
492  // terrain under the liquid?
493  if (minLLevel > maxTLevel)
494  useTerrain = false;
495 
496  //liquid under the terrain?
497  if (minTLevel > maxLLevel)
498  useLiquid = false;
499  }
500 
501  // store the result
502  if (useLiquid)
503  {
504  meshData.liquidType.append(liquidType);
505  for (int k = 0; k < 3; ++k)
506  meshData.liquidTris.append(ltris[k]);
507  }
508 
509  if (useTerrain)
510  for (int k = 0; k < 3*tTriCount/2; ++k)
511  meshData.solidTris.append(ttris[k]);
512 
513  // advance to next set of triangles
514  ltris += 3;
515  ttris += 3*tTriCount/2;
516  }
517  }
518 
519  if (lverts_copy)
520  delete [] lverts_copy;
521 
522  return meshData.solidTris.size() || meshData.liquidTris.size();
523  }
Definition: TerrainBuilder.h:43
Definition: MapDefines.h:26
#define MAP_LIQUID_TYPE_OCEAN
Definition: TerrainBuilder.cpp:74
void getHeightCoord(int index, Grid grid, float xOffset, float yOffset, float *coord, float *v)
Get the vector coordinate for a specific position.
Definition: TerrainBuilder.cpp:526
Definition: MapDefines.h:28
uint8 offsetY
Definition: Map.h:125
float V8[ADT_GRID_SIZE][ADT_GRID_SIZE]
Definition: System.cpp:433
uint8 height
Definition: Map.h:127
uint16 flags
Definition: Map.h:122
#define MAP_LIQUID_TYPE_NO_WATER
Definition: TerrainBuilder.cpp:72
Definition: TerrainBuilder.h:42
float gridMaxHeight
Definition: Map.h:113
#define MAP_HEIGHT_AS_INT16
Definition: TerrainBuilder.cpp:46
uint8 offsetX
Definition: Map.h:124
static const int V9_SIZE_SQ
Definition: TerrainBuilder.h:47
bool isHole(int square, uint8 const holes[16][16][8])
Determines if the specific position's triangles should be rendered.
Definition: TerrainBuilder.cpp:603
Definition: MapDefines.h:27
T * getCArray()
Definition: Array.h:256
uint32 flags
Definition: Map.h:111
arena_t NULL
Definition: jemalloc_internal.h:624
#define MAP_HEIGHT_NO_HEIGHT
Definition: TerrainBuilder.cpp:45
#define MAP_LIQUID_TYPE_MAGMA
Definition: TerrainBuilder.cpp:75
uint8 width
Definition: Map.h:126
float liquidLevel
Definition: Map.h:128
bool m_skipLiquid
Controls whether liquids are loaded.
Definition: TerrainBuilder.h:105
Definition: Map.h:79
Definition: Map.h:119
void getLiquidCoord(int index, int index2, float xOffset, float yOffset, float *coord, float *v)
Get the liquid vector coordinate for a specific position.
Definition: TerrainBuilder.cpp:593
uint32 heightMapOffset
Definition: Map.h:86
uint8 getLiquidType(int square, const uint8 liquid_type[16][16])
Get the liquid type for a specific position.
Definition: TerrainBuilder.cpp:616
static const float INVALID_MAP_LIQ_HEIGHT_MAX
Definition: TerrainBuilder.h:55
std::string sprintf(CStringRef format, ArgList args)
Definition: format.h:3096
#define MAP_HEIGHT_AS_INT8
Definition: TerrainBuilder.cpp:47
uint32 holesOffset
Definition: Map.h:90
static const int V9_SIZE
Definition: TerrainBuilder.h:46
uint32_t uint32
Definition: Define.h:150
uint16_t uint16
Definition: Define.h:151
uint8 holes[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID][8]
Definition: System.cpp:444
#define MAP_LIQUID_NO_TYPE
Definition: TerrainBuilder.cpp:57
uint32 liquidMapOffset
Definition: Map.h:88
float V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]
Definition: System.cpp:434
int size() const
Definition: Array.h:430
Definition: TerrainBuilder.h:33
#define SEEK_SET
Definition: zconf.h:475
float gridHeight
Definition: Map.h:112
void getLoopVars(Spot portion, int &loopStart, int &loopEnd, int &loopInc)
Sets loop variables for selecting only certain parts of a map's terrain.
Definition: TerrainBuilder.cpp:89
Spot
Definition: TerrainBuilder.h:31
static const float INVALID_MAP_LIQ_HEIGHT
Definition: TerrainBuilder.h:54
#define MAP_LIQUID_TYPE_DARK_WATER
Definition: TerrainBuilder.cpp:77
uint8_t uint8
Definition: Define.h:152
Definition: TerrainBuilder.h:36
static const int V8_SIZE_SQ
Definition: TerrainBuilder.h:49
G3D::int16 x
Definition: Vector2int16.h:37
static const float GRID_PART_SIZE
Definition: TerrainBuilder.h:51
#define MAP_LIQUID_TYPE_SLIME
Definition: TerrainBuilder.cpp:76
void append(const T &value)
Definition: Array.h:583
#define MAP_LIQUID_TYPE_WATER
Definition: TerrainBuilder.cpp:73
static const float GRID_SIZE
Definition: TerrainBuilder.h:50
#define MAP_LIQUID_NO_HEIGHT
Definition: TerrainBuilder.cpp:58
char const * MAP_VERSION_MAGIC
Definition: TerrainBuilder.cpp:83
uint32 holesSize
Definition: Map.h:91
void getHeightTriangle(int square, Spot triangle, int *indices, bool liquid=false)
Get the triangle's vector indices for a specific position.
Definition: TerrainBuilder.cpp:546
u_map_magic versionMagic
Definition: Map.h:82
void printf(BasicWriter< Char > &w, BasicCStringRef< Char > format, ArgList args)
Definition: format.h:3083
Definition: Map.h:108

+ Here is the call graph for this function:

void MMAP::TerrainBuilder::loadOffMeshConnections ( uint32  mapID,
uint32  tileX,
uint32  tileY,
MeshData meshData,
const char *  offMeshFilePath 
)
882  {
883  // no meshfile input given?
884  if (offMeshFilePath == NULL)
885  return;
886 
887  FILE* fp = fopen(offMeshFilePath, "rb");
888  if (!fp)
889  {
890  printf(" loadOffMeshConnections:: input file %s not found!\n", offMeshFilePath);
891  return;
892  }
893 
894  // pretty silly thing, as we parse entire file and load only the tile we need
895  // but we don't expect this file to be too large
896  char* buf = new char[512];
897  while(fgets(buf, 512, fp))
898  {
899  float p0[3], p1[3];
900  uint32 mid, tx, ty;
901  float size;
902  if (sscanf(buf, "%u %u,%u (%f %f %f) (%f %f %f) %f", &mid, &tx, &ty,
903  &p0[0], &p0[1], &p0[2], &p1[0], &p1[1], &p1[2], &size) != 10)
904  continue;
905 
906  if (mapID == mid && tileX == tx && tileY == ty)
907  {
908  meshData.offMeshConnections.append(p0[1]);
909  meshData.offMeshConnections.append(p0[2]);
910  meshData.offMeshConnections.append(p0[0]);
911 
912  meshData.offMeshConnections.append(p1[1]);
913  meshData.offMeshConnections.append(p1[2]);
914  meshData.offMeshConnections.append(p1[0]);
915 
916  meshData.offMeshConnectionDirs.append(1); // 1 - both direction, 0 - one sided
917  meshData.offMeshConnectionRads.append(size); // agent size equivalent
918  // can be used same way as polygon flags
919  meshData.offMeshConnectionsAreas.append((unsigned char)0xFF);
920  meshData.offMeshConnectionsFlags.append((unsigned short)0xFF); // all movement masks can make this path
921  }
922 
923  }
924 
925  delete [] buf;
926  fclose(fp);
927  }
arena_t NULL
Definition: jemalloc_internal.h:624
uint32_t uint32
Definition: Define.h:150
void printf(BasicWriter< Char > &w, BasicCStringRef< Char > format, ArgList args)
Definition: format.h:3083

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool MMAP::TerrainBuilder::loadVMap ( uint32  mapID,
uint32  tileX,
uint32  tileY,
MeshData meshData 
)
628  {
629  IVMapManager* vmapManager = new VMapManager2();
630  int result = vmapManager->loadMap("vmaps", mapID, tileX, tileY);
631  bool retval = false;
632 
633  do
634  {
635  if (result == VMAP_LOAD_RESULT_ERROR)
636  break;
637 
638  InstanceTreeMap instanceTrees;
639  ((VMapManager2*)vmapManager)->getInstanceMapTree(instanceTrees);
640 
641  if (!instanceTrees[mapID])
642  break;
643 
644  ModelInstance* models = NULL;
645  uint32 count = 0;
646  instanceTrees[mapID]->getModelInstances(models, count);
647 
648  if (!models)
649  break;
650 
651  for (uint32 i = 0; i < count; ++i)
652  {
653  ModelInstance instance = models[i];
654 
655  // model instances exist in tree even though there are instances of that model in this tile
656  WorldModel* worldModel = instance.getWorldModel();
657  if (!worldModel)
658  continue;
659 
660  // now we have a model to add to the meshdata
661  retval = true;
662 
663  std::vector<GroupModel> groupModels;
664  worldModel->getGroupModels(groupModels);
665 
666  // all M2s need to have triangle indices reversed
667  bool isM2 = instance.name.find(".m2") != std::string::npos || instance.name.find(".M2") != std::string::npos;
668 
669  // transform data
670  float scale = instance.iScale;
671  G3D::Matrix3 rotation = G3D::Matrix3::fromEulerAnglesXYZ(G3D::pi()*instance.iRot.z/-180.f, G3D::pi()*instance.iRot.x/-180.f, G3D::pi()*instance.iRot.y/-180.f);
672  G3D::Vector3 position = instance.iPos;
673  position.x -= 32*GRID_SIZE;
674  position.y -= 32*GRID_SIZE;
675 
676  for (std::vector<GroupModel>::iterator it = groupModels.begin(); it != groupModels.end(); ++it)
677  {
678  std::vector<G3D::Vector3> tempVertices;
679  std::vector<G3D::Vector3> transformedVertices;
680  std::vector<MeshTriangle> tempTriangles;
681  WmoLiquid* liquid = NULL;
682 
683  it->getMeshData(tempVertices, tempTriangles, liquid);
684 
685  // first handle collision mesh
686  transform(tempVertices, transformedVertices, scale, rotation, position);
687 
688  int offset = meshData.solidVerts.size() / 3;
689 
690  copyVertices(transformedVertices, meshData.solidVerts);
691  copyIndices(tempTriangles, meshData.solidTris, offset, isM2);
692 
693  // now handle liquid data
694  if (liquid)
695  {
696  std::vector<G3D::Vector3> liqVerts;
697  std::vector<int> liqTris;
698  uint32 tilesX, tilesY, vertsX, vertsY;
699  G3D::Vector3 corner;
700  liquid->getPosInfo(tilesX, tilesY, corner);
701  vertsX = tilesX + 1;
702  vertsY = tilesY + 1;
703  uint8* flags = liquid->GetFlagsStorage();
704  float* data = liquid->GetHeightStorage();
705  uint8 type = NAV_EMPTY;
706 
707  // convert liquid type to NavTerrain
708  switch (liquid->GetType())
709  {
710  case 0:
711  case 1:
712  type = NAV_WATER;
713  break;
714  case 2:
715  type = NAV_MAGMA;
716  break;
717  case 3:
718  type = NAV_SLIME;
719  break;
720  }
721 
722  // indexing is weird...
723  // after a lot of trial and error, this is what works:
724  // vertex = y*vertsX+x
725  // tile = x*tilesY+y
726  // flag = y*tilesY+x
727 
728  G3D::Vector3 vert;
729  for (uint32 x = 0; x < vertsX; ++x)
730  for (uint32 y = 0; y < vertsY; ++y)
731  {
732  vert = G3D::Vector3(corner.x + x * GRID_PART_SIZE, corner.y + y * GRID_PART_SIZE, data[y*vertsX + x]);
733  vert = vert * rotation * scale + position;
734  vert.x *= -1.f;
735  vert.y *= -1.f;
736  liqVerts.push_back(vert);
737  }
738 
739  int idx1, idx2, idx3, idx4;
740  uint32 square;
741  for (uint32 x = 0; x < tilesX; ++x)
742  for (uint32 y = 0; y < tilesY; ++y)
743  if ((flags[x+y*tilesX] & 0x0f) != 0x0f)
744  {
745  square = x * tilesY + y;
746  idx1 = square+x;
747  idx2 = square+1+x;
748  idx3 = square+tilesY+1+1+x;
749  idx4 = square+tilesY+1+x;
750 
751  // top triangle
752  liqTris.push_back(idx3);
753  liqTris.push_back(idx2);
754  liqTris.push_back(idx1);
755  // bottom triangle
756  liqTris.push_back(idx4);
757  liqTris.push_back(idx3);
758  liqTris.push_back(idx1);
759  }
760 
761  uint32 liqOffset = meshData.liquidVerts.size() / 3;
762  for (uint32 i = 0; i < liqVerts.size(); ++i)
763  meshData.liquidVerts.append(liqVerts[i].y, liqVerts[i].z, liqVerts[i].x);
764 
765  for (uint32 i = 0; i < liqTris.size() / 3; ++i)
766  {
767  meshData.liquidTris.append(liqTris[i*3+1] + liqOffset, liqTris[i*3+2] + liqOffset, liqTris[i*3] + liqOffset);
768  meshData.liquidType.append(type);
769  }
770  }
771  }
772  }
773  }
774  while (false);
775 
776  vmapManager->unloadMap(mapID, tileX, tileY);
777  delete vmapManager;
778 
779  return retval;
780  }
Definition: MapDefines.h:26
virtual void unloadMap(unsigned int pMapId, int x, int y)=0
G3D::Vector3 iPos
Definition: ModelInstance.h:49
Definition: MapDefines.h:28
WorldModel * getWorldModel()
Definition: ModelInstance.h:73
float x
Definition: Vector3.h:62
Definition: VMapManager2.h:78
std::unordered_map< uint32, StaticMapTree * > InstanceTreeMap
Definition: VMapManager2.h:67
Definition: MapDefines.h:27
arena_t NULL
Definition: jemalloc_internal.h:624
double pi()
Definition: g3dmath.h:147
float * GetHeightStorage()
Definition: WorldModel.h:56
float y
Definition: Vector3.h:62
float iScale
Definition: ModelInstance.h:51
Definition: IVMapManager.h:36
Definition: Vector3.h:58
virtual int loadMap(const char *pBasePath, unsigned int pMapId, int x, int y)=0
void getPosInfo(uint32 &tilesX, uint32 &tilesY, G3D::Vector3 &corner) const
Definition: WorldModel.cpp:253
Definition: WorldModel.h:106
static void transform(std::vector< G3D::Vector3 > &original, std::vector< G3D::Vector3 > &transformed, float scale, G3D::Matrix3 &rotation, G3D::Vector3 &position)
Definition: TerrainBuilder.cpp:783
void getGroupModels(std::vector< GroupModel > &outGroupModels)
Definition: WorldModel.cpp:601
uint32_t uint32
Definition: Define.h:150
G3D::int16 y
Definition: Vector2int16.h:38
Definition: IVMapManager.h:45
double square(double fValue)
Definition: g3dmath.h:698
Definition: Matrix3.h:37
uint8 * GetFlagsStorage()
Definition: WorldModel.h:57
static void copyVertices(std::vector< G3D::Vector3 > &source, G3D::Array< float > &dest)
Definition: TerrainBuilder.cpp:796
Definition: WorldModel.h:47
float z
Definition: Vector3.h:62
uint8_t uint8
Definition: Define.h:152
std::string name
Definition: ModelInstance.h:53
uint8 flags
Definition: DisableMgr.cpp:44
G3D::int16 x
Definition: Vector2int16.h:37
static const float GRID_PART_SIZE
Definition: TerrainBuilder.h:51
Definition: MapDefines.h:24
uint32 GetType() const
Definition: WorldModel.h:55
static const float GRID_SIZE
Definition: TerrainBuilder.h:50
static void copyIndices(std::vector< VMAP::MeshTriangle > &source, G3D::Array< int > &dest, int offest, bool flip)
Definition: TerrainBuilder.cpp:807
G3D::Vector3 iRot
Definition: ModelInstance.h:50
static Matrix3 fromEulerAnglesXYZ(float fYAngle, float fPAngle, float fRAngle)
Definition: Matrix3.cpp:1557
Definition: ModelInstance.h:63

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void MMAP::TerrainBuilder::transform ( std::vector< G3D::Vector3 > &  original,
std::vector< G3D::Vector3 > &  transformed,
float  scale,
G3D::Matrix3 rotation,
G3D::Vector3 position 
)
static
784  {
785  for (std::vector<G3D::Vector3>::iterator it = source.begin(); it != source.end(); ++it)
786  {
787  // apply tranform, then mirror along the horizontal axes
788  G3D::Vector3 v((*it) * rotation * scale + position);
789  v.x *= -1.f;
790  v.y *= -1.f;
791  transformedVertices.push_back(v);
792  }
793  }
Definition: Vector3.h:58

+ Here is the caller graph for this function:

bool MMAP::TerrainBuilder::usesLiquids ( )
inline
88 { return !m_skipLiquid; }
bool m_skipLiquid
Controls whether liquids are loaded.
Definition: TerrainBuilder.h:105

+ Here is the caller graph for this function:

Member Data Documentation

bool MMAP::TerrainBuilder::m_skipLiquid
private

Controls whether liquids are loaded.


The documentation for this class was generated from the following files: