// NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This source file has been modified by the following contributors: // Copyright (C) 2020 Jan BOON (Kaetemi) // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "nel/misc/path.h" #include "nel/misc/file.h" #include #include "lod_texture_builder.h" #include "nel/3d/mesh.h" #include "nel/3d/mesh_mrm.h" #include "nel/3d/register_3d.h" #include "nel/misc/config_file.h" #include "nel/misc/algo.h" using namespace std; using namespace NLMISC; using namespace NL3D; // *************************************************************************** bool computeOneShape(const char *lodFile, const char *shapeIn, const char *shapeOut) { try { // Load the clod. CLodCharacterShapeBuild theLod; CIFile fIn; if(!fIn.open(lodFile)) throw Exception("Can't load %s", lodFile); fIn.serial(theLod); fIn.close(); // Load the shape. CSmartPtr theShape; if(!fIn.open(shapeIn)) throw Exception("Can't load %s", shapeIn); CShapeStream ss; fIn.serial(ss); if(!ss.getShapePointer()) throw Exception("Can't load %s", shapeIn); theShape= ss.getShapePointer(); fIn.close(); // init the LodBuilder CLodTextureBuilder lodBuilder; lodBuilder.setLod(theLod); // compute the texture. CLodCharacterTexture lodTexture; CMesh *mesh= dynamic_cast((IShape*)theShape); CMeshMRM *meshMRM= dynamic_cast((IShape*)theShape); CMeshMRMSkinned *meshMRMSkinned= dynamic_cast((IShape*)theShape); CMeshBase *base = NULL; if(mesh) { base = mesh; lodBuilder.computeTexture(*mesh, lodTexture); } else if(meshMRM) { base = meshMRM; lodBuilder.computeTexture(*meshMRM, lodTexture); } else if(meshMRMSkinned) { base = meshMRMSkinned; lodBuilder.computeTexture(*meshMRMSkinned, lodTexture); } else throw Exception("The shape %s is not a Mesh, a MeshMRM or MeshMMRMSkinned", shapeIn); // store in mesh nlassert (base); base->setupLodCharacterTexture(lodTexture); // serial COFile fOut; if(!fOut.open(shapeOut)) throw Exception("Can't open %s for writing", shapeOut); ss.setShapePointer(theShape); fOut.serial(ss); // TestYoyo /*CBitmap dbg; dbg.resize(lodTexture.getWidth(), lodTexture.getHeight()); memcpy(&dbg.getPixels(0)[0], &lodTexture.Texture[0], dbg.getSize()*4); COFile dbgF("testDBG.tga"); dbg.writeTGA(dbgF, 32);*/ } catch(const Exception &e) { nlwarning("ERROR: %s", e.what()); return false; } return true; } // *************************************************************************** int main(int argc, char *argv[]) { // Filter addSearchPath NLMISC::createDebug(); NLMISC::InfoLog->addNegativeFilter ("adding the path"); NL3D::registerSerial3d(); // What usage? bool usageSingle= argc==4; bool usageDir= argc==6 && argv[1]==string("-d"); if (! (usageSingle || usageDir) ) { string execName= CFile::getFilename(argv[0]); printf("%s compute a Lod textureInfo to put in a shape\n", execName.c_str()); printf(" usage 1: %s clod_in shape_in shape_out \n", execName.c_str()); printf(" usage 2: %s -d clod_filters.cfg clod_dir_in shape_dir_in shape_dir_out \n", execName.c_str()); printf(" This usage type try to build lod_tex according to 'clod_tex_shape_filters' variable in the cfg.\n"); printf(" 'clod_tex_shape_filters' is a list of tuple: lod_file / shape file expression\n"); printf(" eg: clod_tex_shape_filters= {\n"); printf(" \"HOM_LOD\", \"FY_HOM*\", \n"); printf(" \"HOM_LOD\", \"??_HOM*\", \n"); printf(" }; \n"); printf(" NB: unmatched shapes are just copied into dest directory\n"); printf(" NB: if error in config_file, shapes are just copied into dest directory\n"); printf(" NB: file date is checked, allowing caching\n"); exit(-1); } if(usageSingle) { computeOneShape(argv[1], argv[2], argv[3]); } else { string clod_cfg= argv[2]; string clod_dir_in= argv[3]; string shape_dir_in= argv[4]; string shape_dir_out= argv[5]; // dir check if(!CFile::isDirectory(clod_dir_in)) nlwarning("ERROR: %s is not a directory", clod_dir_in.c_str()); if(!CFile::isDirectory(shape_dir_in)) nlwarning("ERROR: %s is not a directory", shape_dir_in.c_str()); if(!CFile::isDirectory(shape_dir_out)) nlwarning("ERROR: %s is not a directory", shape_dir_out.c_str()); // Open the CFG, and read the vars. vector LodNames; vector LodFilters; try { CConfigFile fcfg; fcfg.load(clod_cfg); CConfigFile::CVar &var= fcfg.getVar("clod_tex_shape_filters"); if(var.size()<2) throw Exception("Must have 2+ strings in clod_tex_shape_filters"); LodNames.resize(var.size()/2); LodFilters.resize(var.size()/2); for(uint i=0;i fileList; CPath::getPathContent(shape_dir_in, false, false, true, fileList); // For all files. for(uint i=0;i=fileInDate) { // if the out file is newer than the clod, then don't need rebuild uint32 clodDate= CFile::getFileModificationDate(clodFile); if(fileOutDate>=clodDate) { NLMISC::InfoLog->displayRaw("Skiping %s\n", fileNameIn.c_str()); // skip other wildcards skipped= true; break; } } // Ok, try to do the compute. NLMISC::InfoLog->displayRaw("Processing %s", fileNameIn.c_str()); if( computeOneShape( clodFile.c_str(), pathNameIn.c_str(), pathNameOut.c_str() ) ) { // succed => stop NLMISC::InfoLog->displayRaw(" - CLod Textured with %s\n", LodNames[j].c_str()); break; } } } // if skip this shape if(skipped) continue; // if fail to find a valid filter, just do a copy if(j==LodFilters.size()) { CFile::copyFile(pathNameOut, pathNameIn); NLMISC::InfoLog->displayRaw("Processing %s - Copied\n", fileNameIn.c_str()); } } } return 0; }