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"
29 #ifdef _ASSEMBLER_DEBUG
37 //=================================================================
39 Vector3
ModelPosition::transform(const Vector3
& pIn
) const
42 Vector3 out
= pIn
* iScale
;
49 //=================================================================
51 TileAssembler::TileAssembler(const std::string
& pSrcDirName
, const std::string
& pDestDirName
)
53 iCurrentUniqueNameId
= 0;
55 iSrcDir
= pSrcDirName
;
56 iDestDir
= pDestDirName
;
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
)
93 if(!iUniqueNameIds
.containsKey(pName
))
95 ++iCurrentUniqueNameId
;
96 iUniqueNameIds
.set(pName
, iCurrentUniqueNameId
);
98 result
= iUniqueNameIds
.get(pName
);
102 //=================================================================
104 std::string
TileAssembler::getDirEntryNameFromModName(unsigned int pMapId
, const std::string
& pModPosName
)
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");
127 //=================================================================
129 void emptyArray(Array
<ModelContainer
*>& mc
)
140 //=================================================================
141 bool TileAssembler::convertWorld()
143 #ifdef _ASSEMBLER_DEBUG
145 ::g_df
= fopen("../TileAssembler_debug.txt", "wb");
147 ::g_df
= fopen("../TileAssembler_release.txt", "wb");
151 std::string fname
= iSrcDir
;
154 iCoordModelMapping
->setModelNameFilterMethod(iFilterMethod
);
156 printf("Read coordinate mapping...\n");
157 if(!iCoordModelMapping
->readCoordinateMapping(fname
))
160 Array
<unsigned int> mapIds
= iCoordModelMapping
->getMaps();
161 if(mapIds
.size() == 0)
163 printf("Fatal error: empty map list!\n");
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
)
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
)
188 Array
<ModelContainer
*> mc
;
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());
199 sprintf(buffer
, "%03u",mapId
);
200 dirname
= std::string(buffer
);
202 // prevent spam for small maps
204 printf("%s...\n",dirname
.c_str());
207 bool result
= fillModelContainerArray(dirname
, mapId
, x
, y
, mc
);
216 #ifdef _ASSEMBLER_DEBUG
217 if(::g_df
) fclose(::g_df
);
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");
238 printf("ERROR: Can't create file %s",dirfilename
);
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
);
259 pMC
.append(modelContainer
);
261 printf("warning: (if) problems in processing data for %s\n",destnamebuffer
);
264 // process the large singe files
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
]);
289 pMC
.append(modelContainer
);
291 printf("warning: (while) problems in processing data for %s\n",destFileName
.c_str());
301 //=================================================================
303 void removeEntriesFromTree(AABSPTree
<SubModel
*>* pTree
)
305 Array
<SubModel
*> submodelArray
;
306 pTree
->getMembers(submodelArray
);
307 int no
= submodelArray
.size();
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
*>();
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
))
339 if(result
&& mainTree
->size() > 0)
342 modelContainer
= new ModelContainer(mainTree
);
343 modelContainer
->writeFile(pDestFileName
);
345 removeEntriesFromTree(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");
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());
365 if(filename
.length() >0)
366 filename
.append("/");
367 filename
.append(baseModelFilename
);
368 rf
= fopen(filename
.c_str(), "rb");
373 printf("ERROR: Can't open model file in form: %s",pModelFilename
.c_str());
374 printf("... or form: %s",filename
);
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");
390 int endgroup
= INT_MAX
;
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)
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
408 READ_OR_RETURN(&tempNVectors
, sizeof(int));
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
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); }
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
++)
451 // indexes for each branch (not used jet)
452 READ_OR_RETURN(&indexes
, sizeof(G3D::uint32
));
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
));
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
);
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
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); }
492 vectorarray
= new float[nvectors
*sizeof(float)*3];
493 READ_OR_RETURN(vectorarray
, nvectors
*sizeof(float)*3);
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]);
510 v
= pModelPosition
.transform(v
);
516 tempVertexArray
.append(v
);
519 // ---- calculate triangles
520 int rest
= nindexes
%3;
526 for(unsigned int i
=0;i
<(nindexes
);)
528 Triangle t
= Triangle(tempVertexArray
[tempIndexArray
[i
+2]], tempVertexArray
[tempIndexArray
[i
+1]], tempVertexArray
[tempIndexArray
[i
+0]] );
531 if(g
>= startgroup
&& g
<= endgroup
)
537 // drop of temporary use defines
538 #undef READ_OR_RETURN
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());
557 sm
->setBasePosition(pModelPosition
.iPos
);
558 pMainTree
->insert(sm
);
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
)
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],
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 //==========================================