// added by shenzhi for MSVC void ModelDB::SearchDirectory(char *pathname) { long handle; struct _finddata_t filestruct; //info for the file(or directory) char path_search[500]; // start the searching, find the first file or subdirectory under current path // "*" represents "search for everything", filestruct keeps the searching results handle = _findfirst("*", &filestruct); // if handle == -1, the directory is empty, stop search and return // ERROR MESSAGE 12 if((handle == -1)) throw MyException("Wrong model file or path value"); do{ // check whether the first object is a directory (filestruct.name is the pathname) if(::GetFileAttributes(filestruct.name) & FILE_ATTRIBUTE_DIRECTORY) { // if it is a directory, skip it; // the code commented below is to read recursively under the directory. /* // if it is a directory, enter it and recursively call search_directory // note: skip "." or ".." files if(filestruct.name[0] != '.') { _chdir(filestruct.name); SearchDirectory(pathname); // after searching, go back up a level _chdir(".."); } */ } // if it is a file, and not ending with ~ else if(filestruct.name[strlen(filestruct.name)-1]!='~') { // get the full path _getcwd(path_search, 500); // then get the pathname for the file (including the filename) strcat(path_search,"\\"); strcat(path_search,filestruct.name); // parse the file string modelID(filestruct.name); parseSingleModelFile(path_search, modelID); } } while (_findnext(handle, &filestruct)==0); _findclose(handle); }
void ModelTests::modelTreeTests(bool verbose) { int testsTaken = 0; int testsPassed = 0; int testsFailed = 0; if (verbose) { qDebug() << "******************************************************************************************"; } qDebug() << "ModelTests::modelTreeTests()"; // Tree, id, and model properties used in many tests below... ModelTree tree; uint32_t id = 1; ModelItemID modelID(id); modelID.isKnownID = false; // this is a temporary workaround to allow local tree models to be added with known IDs ModelItemProperties properties; float oneMeter = 1.0f; float halfMeter = oneMeter / 2.0f; float halfOfDomain = TREE_SCALE * 0.5f; glm::vec3 positionNearOriginInMeters(oneMeter, oneMeter, oneMeter); // when using properties, these are in meter not tree units glm::vec3 positionAtCenterInMeters(halfOfDomain, halfOfDomain, halfOfDomain); glm::vec3 positionNearOriginInTreeUnits = positionNearOriginInMeters / (float)TREE_SCALE; glm::vec3 positionAtCenterInTreeUnits = positionAtCenterInMeters / (float)TREE_SCALE; { testsTaken++; QString testName = "add model to tree and search"; if (verbose) { qDebug() << "Test" << testsTaken <<":" << qPrintable(testName); } properties.setPosition(positionAtCenterInMeters); properties.setRadius(halfMeter); properties.setModelURL("https://s3-us-west-1.amazonaws.com/highfidelity-public/ozan/theater.fbx"); tree.addModel(modelID, properties); float targetRadius = oneMeter * 2.0 / (float)TREE_SCALE; // in tree units const ModelItem* foundModelByRadius = tree.findClosestModel(positionAtCenterInTreeUnits, targetRadius); const ModelItem* foundModelByID = tree.findModelByID(id); if (verbose) { qDebug() << "foundModelByRadius=" << foundModelByRadius; qDebug() << "foundModelByID=" << foundModelByID; } bool passed = foundModelByRadius && foundModelByID && (foundModelByRadius == foundModelByID); if (passed) { testsPassed++; } else { testsFailed++; qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName); } } modelID.isKnownID = true; // this is a temporary workaround to allow local tree models to be added with known IDs { testsTaken++; QString testName = "change position of model in tree"; if (verbose) { qDebug() << "Test" << testsTaken <<":" << qPrintable(testName); } glm::vec3 newPosition = positionNearOriginInMeters; properties.setPosition(newPosition); tree.updateModel(modelID, properties); float targetRadius = oneMeter * 2.0 / (float)TREE_SCALE; // in tree units const ModelItem* foundModelByRadius = tree.findClosestModel(positionNearOriginInTreeUnits, targetRadius); const ModelItem* foundModelByID = tree.findModelByID(id); if (verbose) { qDebug() << "foundModelByRadius=" << foundModelByRadius; qDebug() << "foundModelByID=" << foundModelByID; } // NOTE: This test is currently expected to fail in the production code. There's a bug in ModelTree::updateModel() // that does not update the actual location of the model into the correct element when modified locally. So this // test will fail. There's a new optimized and correctly working version of updateModel() that fixes this problem. bool passed = foundModelByRadius && foundModelByID && (foundModelByRadius == foundModelByID); if (passed) { testsPassed++; qDebug() << "NOTE: Expected to FAIL - Test" << testsTaken <<":" << qPrintable(testName); } else { testsFailed++; qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName); qDebug() << "NOTE: Expected to FAIL - Test" << testsTaken <<":" << qPrintable(testName); } } { testsTaken++; QString testName = "change position of model in tree back to center"; if (verbose) { qDebug() << "Test" << testsTaken <<":" << qPrintable(testName); } glm::vec3 newPosition = positionAtCenterInMeters; properties.setPosition(newPosition); tree.updateModel(modelID, properties); float targetRadius = oneMeter * 2.0 / (float)TREE_SCALE; // in tree units const ModelItem* foundModelByRadius = tree.findClosestModel(positionAtCenterInTreeUnits, targetRadius); const ModelItem* foundModelByID = tree.findModelByID(id); if (verbose) { qDebug() << "foundModelByRadius=" << foundModelByRadius; qDebug() << "foundModelByID=" << foundModelByID; } bool passed = foundModelByRadius && foundModelByID && (foundModelByRadius == foundModelByID); if (passed) { testsPassed++; } else { testsFailed++; qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName); } } { testsTaken++; QString testName = "Performance - findClosestModel() 1,000,000 times"; if (verbose) { qDebug() << "Test" << testsTaken <<":" << qPrintable(testName); } float targetRadius = oneMeter * 2.0 / (float)TREE_SCALE; // in tree units const int TEST_ITERATIONS = 1000000; quint64 start = usecTimestampNow(); const ModelItem* foundModelByRadius = NULL; for (int i = 0; i < TEST_ITERATIONS; i++) { foundModelByRadius = tree.findClosestModel(positionAtCenterInTreeUnits, targetRadius); } quint64 end = usecTimestampNow(); if (verbose) { qDebug() << "foundModelByRadius=" << foundModelByRadius; } bool passed = foundModelByRadius; if (passed) { testsPassed++; } else { testsFailed++; qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName); } float USECS_PER_MSECS = 1000.0f; float elapsedInMSecs = (float)(end - start) / USECS_PER_MSECS; qDebug() << "TIME - Test" << testsTaken <<":" << qPrintable(testName) << "elapsed=" << elapsedInMSecs << "msecs"; } { testsTaken++; QString testName = "Performance - findModelByID() 1,000,000 times"; if (verbose) { qDebug() << "Test" << testsTaken <<":" << qPrintable(testName); } const int TEST_ITERATIONS = 1000000; quint64 start = usecTimestampNow(); const ModelItem* foundModelByID = NULL; for (int i = 0; i < TEST_ITERATIONS; i++) { foundModelByID = tree.findModelByID(id); } quint64 end = usecTimestampNow(); if (verbose) { qDebug() << "foundModelByID=" << foundModelByID; } bool passed = foundModelByID; if (passed) { testsPassed++; } else { testsFailed++; qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName); } float USECS_PER_MSECS = 1000.0f; float elapsedInMSecs = (float)(end - start) / USECS_PER_MSECS; qDebug() << "TIME - Test" << testsTaken <<":" << qPrintable(testName) << "elapsed=" << elapsedInMSecs << "msecs"; } { testsTaken++; QString testName = "Performance - add model to tree 10,000 times"; if (verbose) { qDebug() << "Test" << testsTaken <<":" << qPrintable(testName); } const int TEST_ITERATIONS = 10000; quint64 start = usecTimestampNow(); for (int i = 0; i < TEST_ITERATIONS; i++) { uint32_t id = i + 2; // make sure it doesn't collide with previous model ids ModelItemID modelID(id); modelID.isKnownID = false; // this is a temporary workaround to allow local tree models to be added with known IDs float randomX = randFloatInRange(0.0f ,(float)TREE_SCALE); float randomY = randFloatInRange(0.0f ,(float)TREE_SCALE); float randomZ = randFloatInRange(0.0f ,(float)TREE_SCALE); glm::vec3 randomPositionInMeters(randomX,randomY,randomZ); properties.setPosition(randomPositionInMeters); properties.setRadius(halfMeter); properties.setModelURL("https://s3-us-west-1.amazonaws.com/highfidelity-public/ozan/theater.fbx"); tree.addModel(modelID, properties); } quint64 end = usecTimestampNow(); bool passed = true; if (passed) { testsPassed++; } else { testsFailed++; qDebug() << "FAILED - Test" << testsTaken <<":" << qPrintable(testName); } float USECS_PER_MSECS = 1000.0f; float elapsedInMSecs = (float)(end - start) / USECS_PER_MSECS; qDebug() << "TIME - Test" << testsTaken <<":" << qPrintable(testName) << "elapsed=" << elapsedInMSecs << "msecs"; } qDebug() << " tests passed:" << testsPassed << "out of" << testsTaken; if (verbose) { qDebug() << "******************************************************************************************"; } }
void ModelDB::parseModelFileDir(string dirName){ #ifdef USE_GCC DIR * dirp = opendir(dirName.c_str()); struct dirent * dp; ifstream fin(dirName.c_str()); // if the path is a directory, parse the each model in this directory // ASSUMPTION: here it is only a two tier structure. no recursive reading. if (dirp) { errno = 0; // read each file while (( dp = readdir(dirp)) != NULL) { // if the file is . or .., skip it if(!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")){ continue; // do nothing for "useless" directories } // if the file ends with ~, skip it also if (dp->d_name[strlen(dp->d_name)-1]=='~') { continue; } // otherwise, use the fileName as the modelID string modelID(dp->d_name); string fullpath=dirName+"/"+dp->d_name; // parse the single model file then parseSingleModelFile(fullpath, modelID); } } // if the path is a file, use the file name as the modelID else if (fin) { bDir = false; int pos = dirName.find_last_of("/"); if (pos!=-1) { string modelID(dirName.substr(pos+1)); parseSingleModelFile(dirName,modelID); } else { parseSingleModelFile(dirName,dirName); } } // otherwise, error msg else{ cerr << "\n parseDirectoryModel: Can't open directory " << dirName << endl; exit (1); } #endif //USE_GCC #ifdef _MSC_VER // I couldn't find good apis to read a directory. If this is the only // way, then I don't understand why microsoft doesn't provide a better // wrapper for these functions. -- Bing Bai. long hfile = -1; int status = 0; char fullpath[MAXPATHLEN] = {0}; int curDrive; char curPath[MAXPATHLEN]; // store the information of the file/directory struct stat st; // preprocess the name, get rid the last char if it is '\' if(dirName.at(dirName.length()-1)=='\\') { dirName = dirName.substr(0, dirName.length()-1); } // if it is not empty if( stat(dirName.c_str(), &st)==0 ){ // if is a directory if (st.st_mode & _S_IFDIR) { // keep the current driver and path info curDrive = _getdrive(); _getcwd(curPath, MAXPATHLEN); // go into the directory status = _chdir(dirName.c_str()); // check each file in the directory SearchDirectory((char*)dirName.c_str()); // go back to the original place _chdrive(curDrive); _chdir(curPath); } // if it is a file else { bDir = false; int pos = dirName.find_last_of("\\"); if (pos!=-1) { string modelID(dirName.substr(pos+1)); parseSingleModelFile(dirName,modelID); } else { parseSingleModelFile(dirName,dirName); } } } #endif //_MSC_VER }