// 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); 
    
}
Exemplo n.º 2
0
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
}