/* * Copyright (C) 2005-2008 MaNGOS * * Copyright (C) 2008 Trinity * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "TileAssembler.h" #include "CoordModelMapping.h" #include "ModelContainer.h" #include #include #ifdef _ASSEMBLER_DEBUG FILE *g_df = NULL; #endif using namespace G3D; namespace VMAP { //================================================================= Vector3 ModelPosition::transform(const Vector3& pIn) const { //return(pIn); Vector3 out = pIn * iScale; out = izMatrix * out; out = ixMatrix * out; out = iyMatrix * out; return(out); } //================================================================= TileAssembler::TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName) { iCurrentUniqueNameId = 0; iFilterMethod = NULL; iSrcDir = pSrcDirName; iDestDir = pDestDirName; //mkdir(iDestDir); init(); } //================================================================= TileAssembler::~TileAssembler() { delete iCoordModelMapping; } //================================================================= void TileAssembler::init() { iCoordModelMapping = new CoordModelMapping(); addWorldAreaMapId(0); //Azeroth addWorldAreaMapId(1); //Kalimdor addWorldAreaMapId(530); //Expansion01 } //================================================================= std::string getModNameFromModPosName(const std::string& pModPosName) { size_t spos = pModPosName.find_first_of('#'); std::string modelFileName = pModPosName.substr(0,spos); return(modelFileName); } //================================================================= unsigned int TileAssembler::getUniqueNameId(const std::string pName) { unsigned int result; if(!iUniqueNameIds.containsKey(pName)) { ++iCurrentUniqueNameId; iUniqueNameIds.set(pName, iCurrentUniqueNameId); } result = iUniqueNameIds.get(pName); return result; } //================================================================= std::string TileAssembler::getDirEntryNameFromModName(unsigned int pMapId, const std::string& pModPosName) { size_t spos; char buffer[20]; std::string modelFileName = getModNameFromModPosName(pModPosName); //std::string fext = pModPosName.substr(modelFileName.length(),pModPosName.length()); unsigned int fextId = getUniqueNameId(pModPosName); sprintf(buffer, "_%07d",fextId); std::string fext(buffer); spos = modelFileName.find_last_of('/'); std::string fname = modelFileName.substr(spos+1, modelFileName.length()); spos = fname.find_last_of('.'); fname = fname.substr(0,spos); sprintf(buffer, "%03u", pMapId); std::string dirEntry(buffer); dirEntry.append("_"); dirEntry.append(fname); dirEntry.append(fext); dirEntry.append(".vmap"); return(dirEntry); } //================================================================= void emptyArray(Array& mc) { int no=mc.size(); while(no > 0) { --no; delete mc[no]; mc.remove(no); } } //================================================================= bool TileAssembler::convertWorld() { #ifdef _ASSEMBLER_DEBUG # ifdef _DEBUG ::g_df = fopen("../TileAssembler_debug.txt", "wb"); # else ::g_df = fopen("../TileAssembler_release.txt", "wb"); # endif #endif bool result = true; std::string fname = iSrcDir; fname.append("/"); fname.append("dir"); iCoordModelMapping->setModelNameFilterMethod(iFilterMethod); iCoordModelMapping->readCoordinateMapping(fname); Array mapIds = iCoordModelMapping->getMaps(); if(mapIds.size() == 0) { result = false; } for(int i=0; i mc; std::string dirname; char buffer[100]; if(iCoordModelMapping->isWorldAreaMap(mapId) && x<65 && y<65) { sprintf(buffer, "%03u_%d_%d",mapId,y,x); // Let's flip x and y here dirname = std::string(buffer); } else { sprintf(buffer, "%03u",mapId); dirname = std::string(buffer); } result = fillModelContainerArray(dirname, mapId, x, y, mc); emptyArray(mc); } } } } #ifdef _ASSEMBLER_DEBUG if(::g_df) fclose(::g_df); #endif return result; } //================================================================= bool TileAssembler::fillModelContainerArray(const std::string& pDirFileName, unsigned int pMapId, int pXPos, int pYPos, Array& pMC) { bool result = true; ModelContainer* modelContainer; NameCollection nameCollection = iCoordModelMapping->getFilenamesForCoordinate(pMapId, pXPos, pYPos); if(nameCollection.size() > 0) { result = false; char dirfilename[500]; sprintf(dirfilename,"%s/%s.vmdir",iDestDir.c_str(),pDirFileName.c_str()); FILE *dirfile = fopen(dirfilename, "ab"); if(dirfile) { result = true; char destnamebuffer[500]; char fullnamedestnamebuffer[500]; if(nameCollection.iMainFiles.size() >0) { sprintf(destnamebuffer,"%03u_%i_%i.vmap",pMapId, pYPos, pXPos); // flip it here too std::string checkDoubleStr = std::string(dirfilename); checkDoubleStr.append("##"); checkDoubleStr.append(std::string(destnamebuffer)); // Check, if same file already is in the same dir file if(!iCoordModelMapping->isAlreadyProcessedSingleFile(checkDoubleStr)) { iCoordModelMapping->addAlreadyProcessedSingleFile(checkDoubleStr); fprintf(dirfile, "%s\n",destnamebuffer); sprintf(fullnamedestnamebuffer,"%s/%s",iDestDir.c_str(),destnamebuffer); modelContainer = processNames(nameCollection.iMainFiles, fullnamedestnamebuffer); if(modelContainer) { pMC.append(modelContainer); } else { result = false; } } } // process the large singe files int pos = 0; while(result && (pos < nameCollection.iSingeFiles.size())) { std::string destFileName = iDestDir; destFileName.append("/"); std::string dirEntryName = getDirEntryNameFromModName(pMapId,nameCollection.iSingeFiles[pos]); std::string checkDoubleStr = std::string(dirfilename); checkDoubleStr.append("##"); checkDoubleStr.append(nameCollection.iSingeFiles[pos]); // Check, if same file already is in the same dir file if(!iCoordModelMapping->isAlreadyProcessedSingleFile(checkDoubleStr)) { iCoordModelMapping->addAlreadyProcessedSingleFile(checkDoubleStr); fprintf(dirfile, "%s\n",dirEntryName.c_str()); destFileName.append(dirEntryName); Array positionarray; positionarray.append(nameCollection.iSingeFiles[pos]); if(!iCoordModelMapping->isAlreadyProcessedSingleFile(nameCollection.iSingeFiles[pos])) { modelContainer = processNames(positionarray, destFileName.c_str()); iCoordModelMapping->addAlreadyProcessedSingleFile(nameCollection.iSingeFiles[pos]); if(modelContainer) { pMC.append(modelContainer); } else { result = false; } } } ++pos; } fclose(dirfile); } } return(result); } //================================================================= void removeEntriesFromTree(AABSPTree* pTree) { Array submodelArray; pTree->getMembers(submodelArray); int no = submodelArray.size(); while(no > 0) { --no; delete submodelArray[no]; } } //================================================================= ModelContainer* TileAssembler::processNames(const Array& pPositions, const char* pDestFileName) { ModelContainer *modelContainer = 0; Vector3 basepos = Vector3(0,0,0); AABSPTree* mainTree = new AABSPTree(); int pos = 0; bool result = true; while(result && (pos < pPositions.size())) { std::string modelPosString = pPositions[pos]; std::string modelFileName = getModNameFromModPosName(modelPosString); if(!fillModelIntoTree(mainTree, basepos, modelPosString, modelFileName)) { result = false; break; } ++pos; } if(result && mainTree->size() > 0) { mainTree->balance(); modelContainer = new ModelContainer(mainTree); modelContainer->writeFile(pDestFileName); } removeEntriesFromTree(mainTree); delete mainTree; return(modelContainer); } //================================================================= bool TileAssembler::readRawFile(std::string& pModelFilename, ModelPosition& pModelPosition, AABSPTree *pMainTree) { bool result = false; std::string filename = iSrcDir; if(filename.length() >0) filename.append("/"); filename.append(pModelFilename); FILE *rf = fopen(filename.c_str(), "rb"); if(!rf) { // depending on the extractor version, the data could be located in the root dir std::string baseModelFilename = pModelFilename.substr((pModelFilename.find_first_of("/")+1),pModelFilename.length()); filename = iSrcDir; if(filename.length() >0) filename.append("/"); filename.append(baseModelFilename); rf = fopen(filename.c_str(), "rb"); } char ident[8]; int trianglecount =0; #ifdef _ASSEMBLER_DEBUG int startgroup = 0; //2; int endgroup = INT_MAX; //2; fprintf(::g_df,"-------------------------------------------------\n"); fprintf(::g_df,"%s\n", pModelFilename.c_str()); fprintf(::g_df,"-------------------------------------------------\n"); #else int startgroup = 0; int endgroup = INT_MAX; #endif if(rf) { if(fread(&ident, 8, 1, rf) != 1) { fclose(rf); return(false); } if(strcmp(ident, "VMAP001") == 0) { // OK, do nothing } else if(strcmp(ident, "VMAP002") == 0) { // we have to read one int. This is needed during the export and we have to skip it here int tempNVectors; if(fread(&tempNVectors, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); } } else { // wrong version fclose(rf); return(false); } G3D::uint32 groups; char blockId[5]; blockId[4] = 0; int blocksize; if(fread(&groups, sizeof(G3D::uint32), 1, rf) != 1) { fclose(rf); return(false); } for(int g=0;g<(int)groups;g++) { // group MUST NOT have more then 65536 indexes !! Array will have a problem with that !! (strange ...) Array tempIndexArray; Array tempVertexArray; AABSPTree *gtree = new AABSPTree(); G3D::uint32 flags; if(fread(&flags, sizeof(G3D::uint32), 1, rf) != 1) { fclose(rf); return(false); } G3D::uint32 branches; if(fread(&blockId, 4, 1, rf) != 1) { fclose(rf); return(false); } if(strcmp(blockId, "GRP ") != 0) { fclose(rf); return(false); } if(fread(&blocksize, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); } if(fread(&branches, sizeof(G3D::uint32), 1, rf) != 1) { fclose(rf); return(false); } for(int b=0;b<(int)branches; b++) { G3D::uint32 indexes; // indexes for each branch (not used jet) if(fread(&indexes, sizeof(G3D::uint32), 1, rf) != 1) { fclose(rf); return(false); } } // ---- indexes if(fread(&blockId, 4, 1, rf) != 1) { fclose(rf); return(false); } if(strcmp(blockId, "INDX") != 0) { fclose(rf); return(false); } if(fread(&blocksize, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); } unsigned int nindexes; if(fread(&nindexes, sizeof(G3D::uint32), 1, rf) != 1) { fclose(rf); return(false); } if(nindexes >0) { unsigned short *indexarray = new unsigned short[nindexes*sizeof(unsigned short)]; if(fread(indexarray, sizeof(unsigned short), nindexes, rf) != nindexes) { fclose(rf); return(false); } for(int i=0;i<(int)nindexes; i++) { unsigned short val = indexarray[i]; tempIndexArray.append(val); } delete indexarray; } // ---- vectors if(fread(&blockId, 4, 1, rf) != 1) {fclose(rf); return(false); } if(strcmp(blockId, "VERT") != 0) { fclose(rf); return(false); } if(fread(&blocksize, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); } unsigned int nvectors; if(fread(&nvectors, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); } float *vectorarray = 0; if(nvectors >0) { vectorarray = new float[nvectors*sizeof(float)*3]; if(fread(vectorarray, sizeof(float)*3, nvectors, rf) != nvectors) { fclose(rf); return(false); } } // ----- liquit if(flags & 1) { // we have liquit -> not handled yet ... skip if(fread(&blockId, 4, 1, rf) != 1) { fclose(rf); return(false); } if(strcmp(blockId, "LIQU") != 0) { fclose(rf); return(false); } if(fread(&blocksize, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); } fseek(rf, blocksize, SEEK_CUR); } for(unsigned int i=0, indexNo=0; indexNo= startgroup && g <= endgroup) { gtree->insert(t); } } if(vectorarray != 0) { delete vectorarray; } if(gtree->size() >0) { gtree->balance(); SubModel *sm = new SubModel(gtree); #ifdef _ASSEMBLER_DEBUG 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()); if(sm->getNTriangles() != gtree->memberTable.size()) { 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()); } #endif sm->setBasePosition(pModelPosition.iPos); pMainTree->insert(sm); } delete gtree; } fclose(rf); result = true; } return(result); } //================================================================= bool TileAssembler::fillModelIntoTree(AABSPTree *pMainTree, const Vector3& pBasePos, std::string& pPos, std::string& pModelFilename) { bool result = false; ModelPosition modelPosition; getModelPosition(pPos, modelPosition); // all should be relative to object base position modelPosition.moveToBasePos(pBasePos); modelPosition.init(); if(readRawFile(pModelFilename, modelPosition, pMainTree)) { result = true; } return result; } //================================================================= void TileAssembler::getModelPosition(std::string& pPosString, ModelPosition& pModelPosition) { float vposarray[3]; float vdirarray[3]; float scale; size_t spos = pPosString.find_first_of('#'); std::string stripedPosString = pPosString.substr(spos+1,pPosString.length()); sscanf(stripedPosString.c_str(), "%f,%f,%f_%f,%f,%f_%f", &vposarray[0],&vposarray[1],&vposarray[2], &vdirarray[0],&vdirarray[1],&vdirarray[2], &scale); pModelPosition.iPos = Vector3(vposarray[0], vposarray[1], vposarray[2]); pModelPosition.iDir = Vector3(vdirarray[0], vdirarray[1], vdirarray[2]); pModelPosition.iScale = scale; } //========================================== } // VMAP