AzerothCore 3.3.5a
OpenSource WoW Emulator
Loading...
Searching...
No Matches
VMAP::TileAssembler Class Reference

#include "TileAssembler.h"

Public Member Functions

 TileAssembler (const std::string &pSrcDirName, const std::string &pDestDirName)
 
virtual ~TileAssembler ()
 
bool convertWorld2 ()
 
bool readMapSpawns ()
 
bool calculateTransformedBound (ModelSpawn &spawn)
 
void exportGameobjectModels ()
 
bool convertRawFile (const std::string &pModelFilename)
 

Private Attributes

std::string iDestDir
 
std::string iSrcDir
 
G3D::Table< std::string, unsigned int > iUniqueNameIds
 
MapData mapData
 
std::set< std::string > spawnedModelFiles
 

Detailed Description

Constructor & Destructor Documentation

◆ TileAssembler()

VMAP::TileAssembler::TileAssembler ( const std::string &  pSrcDirName,
const std::string &  pDestDirName 
)
56 : iDestDir(pDestDirName), iSrcDir(pSrcDirName)
57 {
58 boost::filesystem::create_directory(iDestDir);
59 //init();
60 }
std::string iSrcDir
Definition: TileAssembler.h:96
std::string iDestDir
Definition: TileAssembler.h:95

References iDestDir.

◆ ~TileAssembler()

VMAP::TileAssembler::~TileAssembler ( )
virtual
63 {
64 //delete iCoordModelMapping;
65 }

Member Function Documentation

◆ calculateTransformedBound()

bool VMAP::TileAssembler::calculateTransformedBound ( ModelSpawn spawn)
268 {
269 std::string modelFilename(iSrcDir);
270 modelFilename.push_back('/');
271 modelFilename.append(spawn.name);
272
273 ModelPosition modelPosition;
274 modelPosition.iDir = spawn.iRot;
275 modelPosition.iScale = spawn.iScale;
276 modelPosition.init();
277
278 WorldModel_Raw raw_model;
279 if (!raw_model.Read(modelFilename.c_str()))
280 {
281 return false;
282 }
283
284 uint32 groups = raw_model.groupsArray.size();
285 if (groups != 1)
286 {
287 printf("Warning: '%s' does not seem to be a M2 model!\n", modelFilename.c_str());
288 }
289
290 AABox modelBound;
291 bool boundEmpty = true;
292
293 for (uint32 g = 0; g < groups; ++g) // should be only one for M2 files...
294 {
295 std::vector<Vector3>& vertices = raw_model.groupsArray[g].vertexArray;
296
297 if (vertices.empty())
298 {
299 std::cout << "error: model '" << spawn.name << "' has no geometry!" << std::endl;
300 continue;
301 }
302
303 uint32 nvectors = vertices.size();
304 for (uint32 i = 0; i < nvectors; ++i)
305 {
306 Vector3 v = modelPosition.transform(vertices[i]);
307
308 if (boundEmpty)
309 {
310 modelBound = AABox(v, v), boundEmpty = false;
311 }
312 else
313 {
314 modelBound.merge(v);
315 }
316 }
317 }
318 spawn.iBound = modelBound + spawn.iPos;
319 spawn.flags |= MOD_HAS_BOUND;
320 return true;
321 }
std::uint32_t uint32
Definition: Define.h:108
@ MOD_HAS_BOUND
Definition: ModelInstance.h:38

References VMAP::ModelSpawn::flags, VMAP::WorldModel_Raw::groupsArray, VMAP::ModelSpawn::iBound, VMAP::ModelPosition::iDir, VMAP::ModelPosition::init(), VMAP::ModelSpawn::iPos, VMAP::ModelSpawn::iRot, VMAP::ModelPosition::iScale, VMAP::ModelSpawn::iScale, iSrcDir, VMAP::MOD_HAS_BOUND, VMAP::ModelSpawn::name, VMAP::WorldModel_Raw::Read(), and VMAP::ModelPosition::transform().

Referenced by convertWorld2().

◆ convertRawFile()

bool VMAP::TileAssembler::convertRawFile ( const std::string &  pModelFilename)
335 {
336 bool success = true;
337 std::string filename = iSrcDir;
338 if (filename.length() > 0)
339 {
340 filename.push_back('/');
341 }
342 filename.append(pModelFilename);
343
344 WorldModel_Raw raw_model;
345 if (!raw_model.Read(filename.c_str()))
346 {
347 return false;
348 }
349
350 // write WorldModel
351 WorldModel model;
352 model.setRootWmoID(raw_model.RootWMOID);
353 if (!raw_model.groupsArray.empty())
354 {
355 std::vector<GroupModel> groupsArray;
356
357 uint32 groups = raw_model.groupsArray.size();
358 for (uint32 g = 0; g < groups; ++g)
359 {
360 GroupModel_Raw& raw_group = raw_model.groupsArray[g];
361 groupsArray.push_back(GroupModel(raw_group.mogpflags, raw_group.GroupWMOID, raw_group.bounds ));
362 groupsArray.back().setMeshData(raw_group.vertexArray, raw_group.triangles);
363 groupsArray.back().setLiquidData(raw_group.liquid);
364 }
365
366 model.setGroupModels(groupsArray);
367 }
368
369 success = model.writeFile(iDestDir + "/" + pModelFilename + ".vmo");
370 //std::cout << "readRawFile2: '" << pModelFilename << "' tris: " << nElements << " nodes: " << nNodes << std::endl;
371 return success;
372 }

References VMAP::GroupModel_Raw::bounds, VMAP::WorldModel_Raw::groupsArray, VMAP::GroupModel_Raw::GroupWMOID, iDestDir, iSrcDir, VMAP::GroupModel_Raw::liquid, VMAP::GroupModel_Raw::mogpflags, VMAP::WorldModel_Raw::Read(), VMAP::WorldModel_Raw::RootWMOID, VMAP::WorldModel::setGroupModels(), VMAP::WorldModel::setRootWmoID(), VMAP::GroupModel_Raw::triangles, VMAP::GroupModel_Raw::vertexArray, and VMAP::WorldModel::writeFile().

Referenced by convertWorld2().

◆ convertWorld2()

bool VMAP::TileAssembler::convertWorld2 ( )
Todo:
remove extractor hack and uncomment below line:
68 {
69 bool success = readMapSpawns();
70 if (!success)
71 {
72 return false;
73 }
74
75 // export Map data
76 for (MapData::iterator map_iter = mapData.begin(); map_iter != mapData.end() && success; ++map_iter)
77 {
78 // build global map tree
79 std::vector<ModelSpawn*> mapSpawns;
80 UniqueEntryMap::iterator entry;
81 printf("Calculating model bounds for map %u...\n", map_iter->first);
82 for (entry = map_iter->second->UniqueEntries.begin(); entry != map_iter->second->UniqueEntries.end(); ++entry)
83 {
84 // M2 models don't have a bound set in WDT/ADT placement data, i still think they're not used for LoS at all on retail
85 if (entry->second.flags & MOD_M2)
86 {
87 if (!calculateTransformedBound(entry->second))
88 {
89 break;
90 }
91 }
92 else if (entry->second.flags & MOD_WORLDSPAWN) // WMO maps and terrain maps use different origin, so we need to adapt :/
93 {
95 //entry->second.iPos += Vector3(533.33333f*32, 533.33333f*32, 0.f);
96 entry->second.iBound = entry->second.iBound + Vector3(533.33333f * 32, 533.33333f * 32, 0.f);
97 }
98 mapSpawns.push_back(&(entry->second));
99 spawnedModelFiles.insert(entry->second.name);
100 }
101
102 printf("Creating map tree for map %u...\n", map_iter->first);
103 BIH pTree;
104
105 try
106 {
107 pTree.build(mapSpawns, BoundsTrait<ModelSpawn*>::GetBounds);
108 }
109 catch (std::exception& e)
110 {
111 printf("Exception ""%s"" when calling pTree.build", e.what());
112 return false;
113 }
114
115 // ===> possibly move this code to StaticMapTree class
116 std::map<uint32, uint32> modelNodeIdx;
117 for (uint32 i = 0; i < mapSpawns.size(); ++i)
118 {
119 modelNodeIdx.insert(pair<uint32, uint32>(mapSpawns[i]->ID, i));
120 }
121
122 // write map tree file
123 std::stringstream mapfilename;
124 mapfilename << iDestDir << '/' << std::setfill('0') << std::setw(3) << map_iter->first << ".vmtree";
125 FILE* mapfile = fopen(mapfilename.str().c_str(), "wb");
126 if (!mapfile)
127 {
128 success = false;
129 printf("Cannot open %s\n", mapfilename.str().c_str());
130 break;
131 }
132
133 //general info
134 if (success && fwrite(VMAP_MAGIC, 1, 8, mapfile) != 8) { success = false; }
135 uint32 globalTileID = StaticMapTree::packTileID(65, 65);
136 pair<TileMap::iterator, TileMap::iterator> globalRange = map_iter->second->TileEntries.equal_range(globalTileID);
137 char isTiled = globalRange.first == globalRange.second; // only maps without terrain (tiles) have global WMO
138 if (success && fwrite(&isTiled, sizeof(char), 1, mapfile) != 1) { success = false; }
139 // Nodes
140 if (success && fwrite("NODE", 4, 1, mapfile) != 1) { success = false; }
141 if (success) { success = pTree.writeToFile(mapfile); }
142 // global map spawns (WDT), if any (most instances)
143 if (success && fwrite("GOBJ", 4, 1, mapfile) != 1) { success = false; }
144
145 for (TileMap::iterator glob = globalRange.first; glob != globalRange.second && success; ++glob)
146 {
147 success = ModelSpawn::writeToFile(mapfile, map_iter->second->UniqueEntries[glob->second]);
148 }
149
150 fclose(mapfile);
151
152 // <====
153
154 // write map tile files, similar to ADT files, only with extra BSP tree node info
155 TileMap& tileEntries = map_iter->second->TileEntries;
156 TileMap::iterator tile;
157 for (tile = tileEntries.begin(); tile != tileEntries.end(); ++tile)
158 {
159 const ModelSpawn& spawn = map_iter->second->UniqueEntries[tile->second];
160 if (spawn.flags & MOD_WORLDSPAWN) // WDT spawn, saved as tile 65/65 currently...
161 {
162 continue;
163 }
164 uint32 nSpawns = tileEntries.count(tile->first);
165 std::stringstream tilefilename;
166 tilefilename.fill('0');
167 tilefilename << iDestDir << '/' << std::setw(3) << map_iter->first << '_';
168 uint32 x, y;
169 StaticMapTree::unpackTileID(tile->first, x, y);
170 tilefilename << std::setw(2) << x << '_' << std::setw(2) << y << ".vmtile";
171 if (FILE* tilefile = fopen(tilefilename.str().c_str(), "wb"))
172 {
173 // file header
174 if (success && fwrite(VMAP_MAGIC, 1, 8, tilefile) != 8) { success = false; }
175 // write number of tile spawns
176 if (success && fwrite(&nSpawns, sizeof(uint32), 1, tilefile) != 1) { success = false; }
177 // write tile spawns
178 for (uint32 s = 0; s < nSpawns; ++s)
179 {
180 if (s)
181 {
182 ++tile;
183 }
184 const ModelSpawn& spawn2 = map_iter->second->UniqueEntries[tile->second];
185 success = success && ModelSpawn::writeToFile(tilefile, spawn2);
186 // MapTree nodes to update when loading tile:
187 std::map<uint32, uint32>::iterator nIdx = modelNodeIdx.find(spawn2.ID);
188 if (success && fwrite(&nIdx->second, sizeof(uint32), 1, tilefile) != 1) { success = false; }
189 }
190 fclose(tilefile);
191 }
192 }
193 // break; //test, extract only first map; TODO: remvoe this line
194 }
195
196 // add an object models, listed in temp_gameobject_models file
198 // export objects
199 std::cout << "\nConverting Model Files" << std::endl;
200 for (std::set<std::string>::iterator mfile = spawnedModelFiles.begin(); mfile != spawnedModelFiles.end(); ++mfile)
201 {
202 std::cout << "Converting " << *mfile << std::endl;
203 if (!convertRawFile(*mfile))
204 {
205 std::cout << "error converting " << *mfile << std::endl;
206 success = false;
207 break;
208 }
209 }
210
211 //cleanup:
212 for (MapData::iterator map_iter = mapData.begin(); map_iter != mapData.end(); ++map_iter)
213 {
214 delete map_iter->second;
215 }
216 return success;
217 }
const char VMAP_MAGIC[]
Definition: VMapDefinitions.h:26
std::multimap< uint32, uint32 > TileMap
Definition: TileAssembler.h:55
@ MOD_WORLDSPAWN
Definition: ModelInstance.h:37
@ MOD_M2
Definition: ModelInstance.h:36
Definition: BoundingIntervalHierarchy.h:67
bool writeToFile(FILE *wf) const
Definition: BoundingIntervalHierarchy.cpp:273
void build(const PrimArray &primitives, BoundsFunc &GetBounds, uint32 leafSize=3, bool printStats=false)
Definition: BoundingIntervalHierarchy.h:80
static uint32 packTileID(uint32 tileX, uint32 tileY)
Definition: MapTree.h:66
static void unpackTileID(uint32 ID, uint32 &tileX, uint32 &tileY)
Definition: MapTree.h:67
void exportGameobjectModels()
Definition: TileAssembler.cpp:374
bool readMapSpawns()
Definition: TileAssembler.cpp:219
MapData mapData
Definition: TileAssembler.h:98
bool convertRawFile(const std::string &pModelFilename)
Definition: TileAssembler.cpp:334
std::set< std::string > spawnedModelFiles
Definition: TileAssembler.h:99
bool calculateTransformedBound(ModelSpawn &spawn)
Definition: TileAssembler.cpp:267
static bool writeToFile(FILE *rw, const ModelSpawn &spawn)
Definition: ModelInstance.cpp:208

References BIH::build(), calculateTransformedBound(), convertRawFile(), exportGameobjectModels(), VMAP::ModelSpawn::flags, VMAP::ModelSpawn::ID, iDestDir, mapData, VMAP::MOD_M2, VMAP::MOD_WORLDSPAWN, VMAP::StaticMapTree::packTileID(), readMapSpawns(), spawnedModelFiles, VMAP::StaticMapTree::unpackTileID(), VMAP::VMAP_MAGIC, VMAP::ModelSpawn::writeToFile(), and BIH::writeToFile().

Referenced by main().

◆ exportGameobjectModels()

void VMAP::TileAssembler::exportGameobjectModels ( )
375 {
376 FILE* model_list = fopen((iSrcDir + "/" + "temp_gameobject_models").c_str(), "rb");
377 if (!model_list)
378 {
379 return;
380 }
381
382 char ident[8];
383 if (fread(ident, 1, 8, model_list) != 8 || memcmp(ident, VMAP::RAW_VMAP_MAGIC, 8) != 0)
384 {
385 fclose(model_list);
386 return;
387 }
388
389 FILE* model_list_copy = fopen((iDestDir + "/" + GAMEOBJECT_MODELS).c_str(), "wb");
390 if (!model_list_copy)
391 {
392 fclose(model_list);
393 return;
394 }
395
396 fwrite(VMAP::VMAP_MAGIC, 1, 8, model_list_copy);
397
398 uint32 name_length, displayId;
399 uint8 isWmo;
400 char buff[500];
401 while (!feof(model_list))
402 {
403 if (fread(&displayId, sizeof(uint32), 1, model_list) != 1)
404 if (feof(model_list)) // EOF flag is only set after failed reading attempt
405 {
406 break;
407 }
408
409 if (fread(&isWmo, sizeof(uint8), 1, model_list) != 1
410 || fread(&name_length, sizeof(uint32), 1, model_list) != 1
411 || name_length >= sizeof(buff)
412 || fread(&buff, sizeof(char), name_length, model_list) != name_length)
413 {
414 std::cout << "\nFile 'temp_gameobject_models' seems to be corrupted" << std::endl;
415 break;
416 }
417
418 std::string model_name(buff, name_length);
419
420 WorldModel_Raw raw_model;
421 if ( !raw_model.Read((iSrcDir + "/" + model_name).c_str()) )
422 {
423 continue;
424 }
425
426 spawnedModelFiles.insert(model_name);
427 AABox bounds;
428 bool boundEmpty = true;
429 for (uint32 g = 0; g < raw_model.groupsArray.size(); ++g)
430 {
431 std::vector<Vector3>& vertices = raw_model.groupsArray[g].vertexArray;
432
433 uint32 nvectors = vertices.size();
434 for (uint32 i = 0; i < nvectors; ++i)
435 {
436 Vector3& v = vertices[i];
437 if (boundEmpty)
438 {
439 bounds = AABox(v, v), boundEmpty = false;
440 }
441 else
442 {
443 bounds.merge(v);
444 }
445 }
446 }
447
448 fwrite(&displayId, sizeof(uint32), 1, model_list_copy);
449 fwrite(&isWmo, sizeof(uint8), 1, model_list_copy);
450 fwrite(&name_length, sizeof(uint32), 1, model_list_copy);
451 fwrite(&buff, sizeof(char), name_length, model_list_copy);
452 fwrite(&bounds.low(), sizeof(Vector3), 1, model_list_copy);
453 fwrite(&bounds.high(), sizeof(Vector3), 1, model_list_copy);
454 }
455
456 fclose(model_list);
457 fclose(model_list_copy);
458 }
ModelList model_list
Definition: GameObjectModel.cpp:43
std::uint8_t uint8
Definition: Define.h:110
const char RAW_VMAP_MAGIC[]
Definition: VMapDefinitions.h:27
const char GAMEOBJECT_MODELS[]
Definition: VMapDefinitions.h:28

References VMAP::GAMEOBJECT_MODELS, VMAP::WorldModel_Raw::groupsArray, iDestDir, iSrcDir, model_list, VMAP::RAW_VMAP_MAGIC, VMAP::WorldModel_Raw::Read(), spawnedModelFiles, and VMAP::VMAP_MAGIC.

Referenced by convertWorld2().

◆ readMapSpawns()

bool VMAP::TileAssembler::readMapSpawns ( )
220 {
221 std::string fname = iSrcDir + "/dir_bin";
222 FILE* dirf = fopen(fname.c_str(), "rb");
223 if (!dirf)
224 {
225 printf("Could not read dir_bin file!\n");
226 return false;
227 }
228 printf("Read coordinate mapping...\n");
229 uint32 mapID, tileX, tileY, check = 0;
230 G3D::Vector3 v1, v2;
231 ModelSpawn spawn;
232 while (!feof(dirf))
233 {
234 // read mapID, tileX, tileY, Flags, NameSet, UniqueId, Pos, Rot, Scale, Bound_lo, Bound_hi, name
235 check = fread(&mapID, sizeof(uint32), 1, dirf);
236 if (check == 0) // EoF...
237 {
238 break;
239 }
240 check += fread(&tileX, sizeof(uint32), 1, dirf);
241 check += fread(&tileY, sizeof(uint32), 1, dirf);
242 if (!ModelSpawn::readFromFile(dirf, spawn))
243 {
244 break;
245 }
246
247 MapSpawns* current;
248 MapData::iterator map_iter = mapData.find(mapID);
249 if (map_iter == mapData.end())
250 {
251 printf("spawning Map %d\n", mapID);
252 mapData[mapID] = current = new MapSpawns();
253 }
254 else
255 {
256 current = map_iter->second;
257 }
258
259 current->UniqueEntries.emplace(spawn.ID, spawn);
260 current->TileEntries.insert(pair<uint32, uint32>(StaticMapTree::packTileID(tileX, tileY), spawn.ID));
261 }
262 bool success = (ferror(dirf) == 0);
263 fclose(dirf);
264 return success;
265 }
static bool readFromFile(FILE *rf, ModelSpawn &spawn)
Definition: ModelInstance.cpp:160

References VMAP::ModelSpawn::ID, iSrcDir, mapData, VMAP::StaticMapTree::packTileID(), VMAP::ModelSpawn::readFromFile(), VMAP::MapSpawns::TileEntries, and VMAP::MapSpawns::UniqueEntries.

Referenced by convertWorld2().

Member Data Documentation

◆ iDestDir

std::string VMAP::TileAssembler::iDestDir
private

◆ iSrcDir

std::string VMAP::TileAssembler::iSrcDir
private

◆ iUniqueNameIds

G3D::Table<std::string, unsigned int > VMAP::TileAssembler::iUniqueNameIds
private

◆ mapData

MapData VMAP::TileAssembler::mapData
private

Referenced by convertWorld2(), and readMapSpawns().

◆ spawnedModelFiles

std::set<std::string> VMAP::TileAssembler::spawnedModelFiles
private