[7913] Fixed vmap_assambler sources. Updated binary.
[getmangos.git] / src / shared / vmap / TileAssembler.cpp
blobb8434a7ef12798a791443047770977756660b98a
1 /*
2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <G3D/Vector3.h>
20 #include <G3D/Triangle.h>
22 #include "TileAssembler.h"
23 #include "CoordModelMapping.h"
24 #include "ModelContainer.h"
26 #include <limits.h>
27 #include <string.h>
29 #ifdef _ASSEMBLER_DEBUG
30 FILE *g_df = NULL;
31 #endif
33 using namespace G3D;
35 namespace VMAP
37 //=================================================================
39 Vector3 ModelPosition::transform(const Vector3& pIn) const
41 //return(pIn);
42 Vector3 out = pIn * iScale;
43 out = izMatrix * out;
44 out = ixMatrix * out;
45 out = iyMatrix * out;
46 return(out);
49 //=================================================================
51 TileAssembler::TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName)
53 iCurrentUniqueNameId = 0;
54 iFilterMethod = NULL;
55 iSrcDir = pSrcDirName;
56 iDestDir = pDestDirName;
57 //mkdir(iDestDir);
58 init();
61 //=================================================================
63 TileAssembler::~TileAssembler()
65 delete iCoordModelMapping;
68 //=================================================================
70 void TileAssembler::init()
72 iCoordModelMapping = new CoordModelMapping();
73 addWorldAreaMapId(0); //Azeroth
74 addWorldAreaMapId(1); //Kalimdor
75 addWorldAreaMapId(530); //Expansion01
76 addWorldAreaMapId(571); //Expansion02
78 //=================================================================
80 std::string getModNameFromModPosName(const std::string& pModPosName)
82 size_t spos = pModPosName.find_first_of('#');
83 std::string modelFileName = pModPosName.substr(0,spos);
84 return(modelFileName);
87 //=================================================================
89 unsigned int TileAssembler::getUniqueNameId(const std::string pName)
91 unsigned int result;
93 if(!iUniqueNameIds.containsKey(pName))
95 ++iCurrentUniqueNameId;
96 iUniqueNameIds.set(pName, iCurrentUniqueNameId);
98 result = iUniqueNameIds.get(pName);
99 return result;
102 //=================================================================
104 std::string TileAssembler::getDirEntryNameFromModName(unsigned int pMapId, const std::string& pModPosName)
106 size_t spos;
107 char buffer[20];
109 std::string modelFileName = getModNameFromModPosName(pModPosName);
110 //std::string fext = pModPosName.substr(modelFileName.length(),pModPosName.length());
111 unsigned int fextId = getUniqueNameId(pModPosName);
112 sprintf(buffer, "_%07d",fextId);
113 std::string fext(buffer);
114 spos = modelFileName.find_last_of('/');
115 std::string fname = modelFileName.substr(spos+1, modelFileName.length());
116 spos = fname.find_last_of('.');
117 fname = fname.substr(0,spos);
118 sprintf(buffer, "%03u", pMapId);
119 std::string dirEntry(buffer);
120 dirEntry.append("_");
121 dirEntry.append(fname);
122 dirEntry.append(fext);
123 dirEntry.append(".vmap");
124 return(dirEntry);
127 //=================================================================
129 void emptyArray(Array<ModelContainer*>& mc)
131 int no=mc.size();
132 while(no > 0)
134 --no;
135 delete mc[no];
136 mc.remove(no);
140 //=================================================================
141 bool TileAssembler::convertWorld()
143 #ifdef _ASSEMBLER_DEBUG
144 # ifdef _DEBUG
145 ::g_df = fopen("../TileAssembler_debug.txt", "wb");
146 # else
147 ::g_df = fopen("../TileAssembler_release.txt", "wb");
148 # endif
149 #endif
151 std::string fname = iSrcDir;
152 fname.append("/");
153 fname.append("dir");
154 iCoordModelMapping->setModelNameFilterMethod(iFilterMethod);
156 printf("Read coordinate mapping...\n");
157 if(!iCoordModelMapping->readCoordinateMapping(fname))
158 return false;
160 Array<unsigned int> mapIds = iCoordModelMapping->getMaps();
161 if(mapIds.size() == 0)
163 printf("Fatal error: empty map list!\n");
164 return false;
167 for(int i=0; i<mapIds.size(); ++i)
169 unsigned int mapId = mapIds[i];
171 #ifdef _ASSEMBLER_DEBUG
172 if(mapId == 0) // "Azeroth" just for debug
174 for(int x=28; x<29; ++x) //debug
176 for(int y=28; y<29; ++y)
178 #else
179 // ignore DeeprunTram (369) it is too large for short vector and not important
180 // ignore test (13), Test (29) , development (451)
181 if(mapId != 369 && mapId != 13 && mapId != 29 && mapId != 451)
183 for(int x=0; x<66; ++x)
185 for(int y=0; y<66; ++y)
187 #endif
188 Array<ModelContainer*> mc;
189 std::string dirname;
190 char buffer[100];
191 if(iCoordModelMapping->isWorldAreaMap(mapId) && x<65 && y<65)
193 sprintf(buffer, "%03u_%d_%d",mapId,y,x); // Let's flip x and y here
194 dirname = std::string(buffer);
195 printf("%s...\n",dirname.c_str());
197 else
199 sprintf(buffer, "%03u",mapId);
200 dirname = std::string(buffer);
202 // prevent spam for small maps
203 if(x==0 && y==0)
204 printf("%s...\n",dirname.c_str());
207 bool result = fillModelContainerArray(dirname, mapId, x, y, mc);
208 emptyArray(mc);
210 if(!result)
211 return false;
216 #ifdef _ASSEMBLER_DEBUG
217 if(::g_df) fclose(::g_df);
218 #endif
220 return true;
223 //=================================================================
225 bool TileAssembler::fillModelContainerArray(const std::string& pDirFileName, unsigned int pMapId, int pXPos, int pYPos, Array<ModelContainer*>& pMC)
227 ModelContainer* modelContainer;
229 NameCollection nameCollection = iCoordModelMapping->getFilenamesForCoordinate(pMapId, pXPos, pYPos);
230 if(nameCollection.size() == 0)
231 return true; // no data...
233 char dirfilename[500];
234 sprintf(dirfilename,"%s/%s.vmdir",iDestDir.c_str(),pDirFileName.c_str());
235 FILE *dirfile = fopen(dirfilename, "ab");
236 if(!dirfile)
238 printf("ERROR: Can't create file %s",dirfilename);
239 return false;
242 char destnamebuffer[500];
243 char fullnamedestnamebuffer[500];
245 if(nameCollection.iMainFiles.size() >0)
247 sprintf(destnamebuffer,"%03u_%i_%i.vmap",pMapId, pYPos, pXPos); // flip it here too
248 std::string checkDoubleStr = std::string(dirfilename);
249 checkDoubleStr.append("##");
250 checkDoubleStr.append(std::string(destnamebuffer));
251 // Check, if same file already is in the same dir file
252 if(!iCoordModelMapping->isAlreadyProcessedSingleFile(checkDoubleStr))
254 iCoordModelMapping->addAlreadyProcessedSingleFile(checkDoubleStr);
255 fprintf(dirfile, "%s\n",destnamebuffer);
256 sprintf(fullnamedestnamebuffer,"%s/%s",iDestDir.c_str(),destnamebuffer);
257 modelContainer = processNames(nameCollection.iMainFiles, fullnamedestnamebuffer);
258 if(modelContainer)
259 pMC.append(modelContainer);
260 else
261 printf("warning: (if) problems in processing data for %s\n",destnamebuffer);
264 // process the large singe files
265 int pos = 0;
266 while(pos < nameCollection.iSingeFiles.size())
268 std::string destFileName = iDestDir;
269 destFileName.append("/");
270 std::string dirEntryName = getDirEntryNameFromModName(pMapId,nameCollection.iSingeFiles[pos]);
271 std::string checkDoubleStr = std::string(dirfilename);
272 checkDoubleStr.append("##");
273 checkDoubleStr.append(nameCollection.iSingeFiles[pos]);
274 // Check, if same file already is in the same dir file
275 if(!iCoordModelMapping->isAlreadyProcessedSingleFile(checkDoubleStr))
277 iCoordModelMapping->addAlreadyProcessedSingleFile(checkDoubleStr);
278 fprintf(dirfile, "%s\n",dirEntryName.c_str());
279 destFileName.append(dirEntryName);
281 Array<std::string> positionarray;
282 positionarray.append(nameCollection.iSingeFiles[pos]);
284 if(!iCoordModelMapping->isAlreadyProcessedSingleFile(nameCollection.iSingeFiles[pos]))
286 modelContainer = processNames(positionarray, destFileName.c_str());
287 iCoordModelMapping->addAlreadyProcessedSingleFile(nameCollection.iSingeFiles[pos]);
288 if(modelContainer)
289 pMC.append(modelContainer);
290 else
291 printf("warning: (while) problems in processing data for %s\n",destFileName.c_str());
294 ++pos;
297 fclose(dirfile);
298 return true;
301 //=================================================================
303 void removeEntriesFromTree(AABSPTree<SubModel *>* pTree)
305 Array<SubModel *> submodelArray;
306 pTree->getMembers(submodelArray);
307 int no = submodelArray.size();
308 while(no > 0)
310 --no;
311 delete submodelArray[no];
315 //=================================================================
317 ModelContainer* TileAssembler::processNames(const Array<std::string>& pPositions, const char* pDestFileName)
319 ModelContainer *modelContainer = 0;
321 Vector3 basepos = Vector3(0,0,0);
322 AABSPTree<SubModel *>* mainTree = new AABSPTree<SubModel *>();
324 int pos = 0;
326 bool result = true;
327 while(result && (pos < pPositions.size()))
329 std::string modelPosString = pPositions[pos];
330 std::string modelFileName = getModNameFromModPosName(modelPosString);
332 if(!fillModelIntoTree(mainTree, basepos, modelPosString, modelFileName))
334 result = false;
335 break;
337 ++pos;
339 if(result && mainTree->size() > 0)
341 mainTree->balance();
342 modelContainer = new ModelContainer(mainTree);
343 modelContainer->writeFile(pDestFileName);
345 removeEntriesFromTree(mainTree);
347 delete mainTree;
349 return(modelContainer);
352 //=================================================================
353 bool TileAssembler::readRawFile(std::string& pModelFilename, ModelPosition& pModelPosition, AABSPTree<SubModel *> *pMainTree)
355 std::string filename = iSrcDir;
356 if(filename.length() >0)
357 filename.append("/");
358 filename.append(pModelFilename);
359 FILE *rf = fopen(filename.c_str(), "rb");
360 if(!rf)
362 // depending on the extractor version, the data could be located in the root dir
363 std::string baseModelFilename = pModelFilename.substr((pModelFilename.find_first_of("/")+1),pModelFilename.length());
364 filename = iSrcDir;
365 if(filename.length() >0)
366 filename.append("/");
367 filename.append(baseModelFilename);
368 rf = fopen(filename.c_str(), "rb");
371 if(!rf)
373 printf("ERROR: Can't open model file in form: %s",pModelFilename.c_str());
374 printf("... or form: %s",filename );
375 return false;
378 char ident[8];
380 int trianglecount =0;
382 #ifdef _ASSEMBLER_DEBUG
383 int startgroup = 0; //2;
384 int endgroup = INT_MAX; //2;
385 fprintf(::g_df,"-------------------------------------------------\n");
386 fprintf(::g_df,"%s\n", pModelFilename.c_str());
387 fprintf(::g_df,"-------------------------------------------------\n");
388 #else
389 int startgroup = 0;
390 int endgroup = INT_MAX;
391 #endif
393 // temporary use defines to simplify read/check code (close file and return at fail)
394 #define READ_OR_RETURN(V,S) if(fread((V), (S), 1, rf) != 1) { \
395 fclose(rf); return(false); }
396 #define CMP_OR_RETURN(V,S) if(strcmp((V),(S)) != 0) { \
397 fclose(rf); return(false); }
399 READ_OR_RETURN(&ident, 8);
400 if(strcmp(ident, "VMAP001") == 0)
402 // OK, do nothing
404 else if(strcmp(ident, "VMAP002") == 0)
406 // we have to read one int. This is needed during the export and we have to skip it here
407 int tempNVectors;
408 READ_OR_RETURN(&tempNVectors, sizeof(int));
411 else
413 // wrong version
414 fclose(rf);
415 return(false);
417 G3D::uint32 groups;
418 char blockId[5];
419 blockId[4] = 0;
420 int blocksize;
422 READ_OR_RETURN(&groups, sizeof(G3D::uint32));
424 for(int g=0;g<(int)groups;g++)
426 // group MUST NOT have more then 65536 indexes !! Array will have a problem with that !! (strange ...)
427 Array<int> tempIndexArray;
428 Array<Vector3> tempVertexArray;
430 AABSPTree<Triangle> *gtree = new AABSPTree<Triangle>();
432 // add free gtree at fail
433 #undef READ_OR_RETURN
434 #undef CMP_OR_RETURN
435 #define READ_OR_RETURN(V,S) if(fread((V), (S), 1, rf) != 1) { \
436 fclose(rf); delete gtree; return(false); }
437 #define CMP_OR_RETURN(V,S) if(strcmp((V),(S)) != 0) { \
438 fclose(rf); delete gtree; return(false); }
440 G3D::uint32 flags;
441 READ_OR_RETURN(&flags, sizeof(G3D::uint32));
443 G3D::uint32 branches;
444 READ_OR_RETURN(&blockId, 4);
445 CMP_OR_RETURN(blockId, "GRP ");
446 READ_OR_RETURN(&blocksize, sizeof(int));
447 READ_OR_RETURN(&branches, sizeof(G3D::uint32));
448 for(int b=0;b<(int)branches; b++)
450 G3D::uint32 indexes;
451 // indexes for each branch (not used jet)
452 READ_OR_RETURN(&indexes, sizeof(G3D::uint32));
455 // ---- indexes
456 READ_OR_RETURN(&blockId, 4);
457 CMP_OR_RETURN(blockId, "INDX");
458 READ_OR_RETURN(&blocksize, sizeof(int));
459 unsigned int nindexes;
460 READ_OR_RETURN(&nindexes, sizeof(G3D::uint32));
461 if(nindexes >0)
463 unsigned short *indexarray = new unsigned short[nindexes*sizeof(unsigned short)];
464 READ_OR_RETURN(indexarray, nindexes*sizeof(unsigned short));
465 for(int i=0;i<(int)nindexes; i++)
467 unsigned short val = indexarray[i];
468 tempIndexArray.append(val);
470 delete[] indexarray;
473 // ---- vectors
474 READ_OR_RETURN(&blockId, 4);
475 CMP_OR_RETURN(blockId, "VERT");
476 READ_OR_RETURN(&blocksize, sizeof(int));
477 unsigned int nvectors;
478 READ_OR_RETURN(&nvectors, sizeof(int));
480 float *vectorarray = 0;
482 // add vectorarray free
483 #undef READ_OR_RETURN
484 #undef CMP_OR_RETURN
485 #define READ_OR_RETURN(V,S) if(fread((V), (S), 1, rf) != 1) { \
486 fclose(rf); delete gtree; delete[] vectorarray; return(false); }
487 #define CMP_OR_RETURN(V,S) if(strcmp((V),(S)) != 0) { \
488 fclose(rf); delete gtree; delete[] vectorarray; return(false); }
490 if(nvectors >0)
492 vectorarray = new float[nvectors*sizeof(float)*3];
493 READ_OR_RETURN(vectorarray, nvectors*sizeof(float)*3);
495 // ----- liquit
496 if(flags & 1)
498 // we have liquit -> not handled yet ... skip
499 READ_OR_RETURN(&blockId, 4);
500 CMP_OR_RETURN(blockId, "LIQU");
501 READ_OR_RETURN(&blocksize, sizeof(int));
502 fseek(rf, blocksize, SEEK_CUR);
506 for(unsigned int i=0, indexNo=0; indexNo<nvectors; indexNo++)
508 Vector3 v = Vector3(vectorarray[i+2], vectorarray[i+1], vectorarray[i+0]);
509 i+=3;
510 v = pModelPosition.transform(v);
512 float swapy = v.y;
513 v.y = v.x;
514 v.x = swapy;
516 tempVertexArray.append(v);
519 // ---- calculate triangles
520 int rest = nindexes%3;
521 if(rest != 0)
523 nindexes -= rest;
526 for(unsigned int i=0;i<(nindexes);)
528 Triangle t = Triangle(tempVertexArray[tempIndexArray[i+2]], tempVertexArray[tempIndexArray[i+1]], tempVertexArray[tempIndexArray[i+0]] );
529 i+=3;
530 ++trianglecount;
531 if(g>= startgroup && g <= endgroup)
533 gtree->insert(t);
537 // drop of temporary use defines
538 #undef READ_OR_RETURN
539 #undef CMP_OR_RETURN
541 if(vectorarray != 0)
543 delete vectorarray;
546 if(gtree->size() >0)
548 gtree->balance();
549 SubModel *sm = new SubModel(gtree);
550 #ifdef _ASSEMBLER_DEBUG
551 if(::g_df) fprintf(::g_df,"group trianglies: %d, Tris: %d, Nodes: %d, gtree.triangles: %d\n", g, sm->getNTriangles(), sm->getNNodes(), gtree->memberTable.size());
552 if(sm->getNTriangles() != gtree->memberTable.size())
554 if(::g_df) fprintf(::g_df,"ERROR !!!! group trianglies: %d, Tris: %d, Nodes: %d, gtree.triangles: %d\n", g, sm->getNTriangles(), sm->getNNodes(), gtree->memberTable.size());
556 #endif
557 sm->setBasePosition(pModelPosition.iPos);
558 pMainTree->insert(sm);
560 delete gtree;
562 fclose(rf);
563 return true;
566 //=================================================================
568 bool TileAssembler::fillModelIntoTree(AABSPTree<SubModel *> *pMainTree, const Vector3& pBasePos, std::string& pPos, std::string& pModelFilename)
570 ModelPosition modelPosition;
571 getModelPosition(pPos, modelPosition);
572 // all should be relative to object base position
573 modelPosition.moveToBasePos(pBasePos);
575 modelPosition.init();
577 return readRawFile(pModelFilename, modelPosition, pMainTree);
580 //=================================================================
581 void TileAssembler::getModelPosition(std::string& pPosString, ModelPosition& pModelPosition)
583 float vposarray[3];
584 float vdirarray[3];
585 float scale;
587 size_t spos = pPosString.find_first_of('#');
588 std::string stripedPosString = pPosString.substr(spos+1,pPosString.length());
590 sscanf(stripedPosString.c_str(), "%f,%f,%f_%f,%f,%f_%f",
591 &vposarray[0],&vposarray[1],&vposarray[2],
592 &vdirarray[0],&vdirarray[1],&vdirarray[2],
593 &scale);
595 pModelPosition.iPos = Vector3(vposarray[0], vposarray[1], vposarray[2]);
596 pModelPosition.iDir = Vector3(vdirarray[0], vdirarray[1], vdirarray[2]);
597 pModelPosition.iScale = scale;
600 //==========================================
601 } // VMAP