int VirtualEnvironmentInit(const char *objectListFile)
{
    int      numObjects;
    FILE     *fp;
    char     buf[MAXPATHLEN];
    char     objectFullpath[MAXPATHLEN];
    int      i;
    ARdouble translation[3], rotation[4], scale[3];
    int      lightingFlag, markerIndex;

    ARLOGd("Initialising Virtual Environment.\n");

    // One-time OSG initialization.
    if (!VirtualEnvironment_AROSG)
    {
        VirtualEnvironment_AROSG = arOSGInit();
        if (!VirtualEnvironment_AROSG)
        {
            ARLOGe("Error: unable to init arOSG library.\n");
            return (0);
        }
    }

    // Locate and open the objects description file.
    if ((fp = fopen(objectListFile, "r")) == NULL)
    {
        ARLOGe("Error: unable to open object data file '%s'.\n", objectListFile);
        perror(NULL);
        goto bail1;
    }
    else
    {
        ARLOGe("Error: open object data file '%s'.\n", objectListFile);
    }

    // First line is number of objects to read.
    numObjects = 0;
    get_buff(buf, MAXPATHLEN, fp, 1);
    if (sscanf(buf, "%d", &numObjects) != 1)
    {
        ARLOGe("Error: unable to read number of objects to load from object data file.\n");
        goto bail2;
    }

    // Allocate space for the objects.
    if (objects)
    {
        free(objects); objects = NULL;
        objectCount            = 0;
    }

    objects = (VEObject*)calloc(numObjects, sizeof(VEObject));
    if (!objects)
    {
        goto bail2;
    }

    ARLOGd("Reading %d objects.\n", numObjects);

    for (i = 0; i < numObjects; i++)
    {
        // Read in all info relating to the object.

        // Read model file path (relative to objects description file).
        if (!get_buff(buf, MAXPATHLEN, fp, 1))
        {
            ARLOGe("Error: unable to read model file name from object data file.\n");
            goto bail3;
        }

        if (!arUtilGetDirectoryNameFromPath(objectFullpath, objectListFile, sizeof(objectFullpath), 1))   // Get directory prefix, with path separator.
        {
            goto bail3;
        }

        strncat(objectFullpath, buf, sizeof(objectFullpath) - strlen(objectFullpath) - 1); // Add name of file to open.

        // Read translation.
        get_buff(buf, MAXPATHLEN, fp, 1);
#ifdef ARDOUBLE_IS_FLOAT
        if (sscanf(buf, "%f %f %f", &translation[0], &translation[1], &translation[2]) != 3)
#else
        if (sscanf(buf, "%lf %lf %lf", &translation[0], &translation[1], &translation[2]) != 3)
#endif
        {
            goto bail3;
        }

        // Read rotation.
        get_buff(buf, MAXPATHLEN, fp, 1);
#ifdef ARDOUBLE_IS_FLOAT
        if (sscanf(buf, "%f %f %f %f", &rotation[0], &rotation[1], &rotation[2], &rotation[3]) != 4)
#else
        if (sscanf(buf, "%lf %lf %lf %lf", &rotation[0], &rotation[1], &rotation[2], &rotation[3]) != 4)
#endif
        {
            goto bail3;
        }

        // Read scale.
        get_buff(buf, MAXPATHLEN, fp, 1);
#ifdef ARDOUBLE_IS_FLOAT
        if (sscanf(buf, "%f %f %f", &scale[0], &scale[1], &scale[2]) != 3)
#else
        if (sscanf(buf, "%lf %lf %lf", &scale[0], &scale[1], &scale[2]) != 3)
#endif
        {
            goto bail3;
        }

        // Look for optional tokens. A blank line marks end of options.
        lightingFlag = 1; markerIndex = -1;

        while (get_buff(buf, MAXPATHLEN, fp, 0) && (buf[0] != '\0'))
        {
            if (strncmp(buf, "LIGHTING", 8) == 0)
            {
                if (sscanf(&(buf[8]), " %d", &lightingFlag) != 1)
                {
                    ARLOGe("Error in object file: LIGHTING token must be followed by an integer >= 0. Discarding.\n");
                }
            }
            else if (strncmp(buf, "MARKER", 6) == 0)
            {
                if (sscanf(&(buf[6]), " %d", &markerIndex) != 1)
                {
                    ARLOGe("Error in object file: MARKER token must be followed by an integer > 0. Discarding.\n");
                }
                else
                {
                    markerIndex--; // Marker numbers are zero-indexed, but in the config file they're 1-indexed.
                }
            }

            // Unknown tokens are ignored.
        }


        // Now attempt to load objects.
        ARLOGd("Reading object data file %s.\n", objectFullpath);
        objects[i].modelIndex = arOSGLoadModel2(VirtualEnvironment_AROSG, objectFullpath, translation, rotation, scale);
        if (objects[i].modelIndex < 0)
        {
            ARLOGe("Error attempting to read object data file %s.\n", objectFullpath);
            goto bail4;
        }

        // Set optional properties.
        arOSGSetModelLighting(VirtualEnvironment_AROSG, objects[i].modelIndex, lightingFlag);

        // If a valid marker index has been specified, save it.
        if (markerIndex >= 0 /*&& markerIndex < markersCount]*/)
        {
            arOSGSetModelVisibility(VirtualEnvironment_AROSG, objects[i].modelIndex, FALSE); // Objects tied to markers will not be initially visible.
            objects[i].markerIndex = markerIndex;
        }
        else
        {
            arOSGSetModelVisibility(VirtualEnvironment_AROSG, objects[i].modelIndex, TRUE); // All other objects will be initially visible.
            objects[i].markerIndex = -1;
        }

        objectCount++;
    }

    ARLOGd("Virtual Environment initialised.\n");
    fclose(fp);
    return (objectCount);

bail4:

    for (i--; i >= 0; i--)
    {
        arOSGUnloadModel(VirtualEnvironment_AROSG, i);
    }

bail3:
    free(objects);
    objects     = NULL;
    objectCount = 0;
bail2:
    fclose(fp);
bail1:
    if (VirtualEnvironment_AROSG)
    {
        arOSGFinal(VirtualEnvironment_AROSG);
        VirtualEnvironment_AROSG = NULL;
    }

#ifdef DEBUG
    ARLOGe("Virtual Environment initialisation failed.\n");
#endif
    return (0);
}
Example #2
0
char *arUtilGetResourcesDirectoryPath(AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR behavior)
#endif
{
#ifndef _WINRT
    char *wpath1;
    char *wpath2;
#  ifdef _WIN32
	DWORD len;
#  endif
#endif
    AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR behaviorW;

    if (behavior == AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_BEST) {
#if defined(__APPLE__)
        behaviorW = AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_BUNDLE_RESOURCES_DIR;
#elif defined(ANDROID)
        behaviorW = AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_APP_CACHE_DIR;
#elif defined(_WIN32) || defined(__linux)
        behaviorW = AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_EXECUTABLE_DIR;
#else
        behaviorW = AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_CWD;
#endif
    } else {
        behaviorW = behavior;
    }

	switch (behaviorW) {
            
            
        case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_EXECUTABLE_DIR:
#if (defined(_WIN32) && !defined(_WINRT)) || defined(__APPLE__) || defined(__linux)
            arMallocClear(wpath1, char, MAXPATHLEN);
#  if defined(_WIN32)
            len = GetModuleFileName(NULL, wpath1, MAXPATHLEN);    // NULL implies the current process.
            if (!len) {
                free (wpath1);
                return (NULL);
            }
#  elif defined(__APPLE__)
            uint32_t size = MAXPATHLEN;
            if (_NSGetExecutablePath(wpath1, &size) != 0) {
                free (wpath1);
                return (NULL);
            }
#  elif defined(__linux)
            ssize_t len;
            len = readlink("/proc/self/exe", wpath1, MAXPATHLEN - 1); // -1 as it is not NULL terminated.
            if (len == -1) {
                ARLOGperror(NULL);
                free (wpath1);
                return (NULL);
            }
            wpath1[len] = '\0'; // NULL terminate.
#  endif
            arMallocClear(wpath2, char, MAXPATHLEN);
            if (!arUtilGetDirectoryNameFromPath(wpath2, wpath1, MAXPATHLEN, 0)) {
                free (wpath1);
                free (wpath2);
                return (NULL);
            }
            free (wpath1);
            return (wpath2);
#else
            return (NULL); // Unsupported OS.
#endif
            break;
            
            
        case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_BUNDLE_RESOURCES_DIR:
            return (NULL); // Unsupported OS.
            break;
            
            
        case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_CWD:
#ifndef _WINRT

            arMallocClear(wpath1, char, MAXPATHLEN);
            if (!getcwd(wpath1, MAXPATHLEN)) {
                free(wpath1);
                return (NULL);
            }
            return (wpath1);
#else
			return (NULL); // Unsupported OS.
#endif
			break;
            
            
        case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_USER_ROOT:
#if defined(_WIN32) && !defined(_WINRT)
            arMallocClear(wpath1, char, MAXPATHLEN);
            if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, wpath1))) {
                free (wpath1);
                return (NULL);
            }
            return (wpath1);
#elif defined(ANDROID)
        {
            // Make JNI calls to get the external storage directory.
            
            // To begin, get a reference to the env and attach to it.
            JNIEnv *env;
            int isAttached = 0;
            jthrowable exception;
            if (((*gJavaVM)->GetEnv(gJavaVM, (void**)&env, JNI_VERSION_1_6)) < 0) {
                // Couldn't get JNI environment, so this thread is native.
                if (((*gJavaVM)->AttachCurrentThread(gJavaVM, &env, NULL)) < 0) {
                    ARLOGe("Error: Couldn't attach to Java VM.\n");
                    return (NULL);
                }
                isAttached = 1;
            }
            
            // Get File object for the external storage directory.
            jclass classEnvironment = (*env)->FindClass(env, "android/os/Environment");
            if (!classEnvironment) goto bailAndroid;
            jmethodID methodIDgetExternalStorageDirectory = (*env)->GetStaticMethodID(env, classEnvironment, "getExternalStorageDirectory", "()Ljava/io/File;"); // public static File getExternalStorageDirectory ()
            if (!methodIDgetExternalStorageDirectory) goto bailAndroid;
            jobject objectFile = (*env)->CallStaticObjectMethod(env, classEnvironment, methodIDgetExternalStorageDirectory);
            exception = (*env)->ExceptionOccurred(env);
            if (exception) {
                (*env)->ExceptionDescribe(env);
                (*env)->ExceptionClear(env);
            }
            
            // Call method on File object to retrieve String object.
            jclass classFile = (*env)->GetObjectClass(env, objectFile);
            if (!classFile) goto bailAndroid;
            jmethodID methodIDgetAbsolutePath = (*env)->GetMethodID(env, classFile, "getAbsolutePath", "()Ljava/lang/String;");
            if (!methodIDgetAbsolutePath) goto bailAndroid;
            jstring stringPath = (*env)->CallObjectMethod(env, objectFile, methodIDgetAbsolutePath);
            exception = (*env)->ExceptionOccurred(env);
            if (exception) {
                (*env)->ExceptionDescribe(env);
                (*env)->ExceptionClear(env);
            }
            // Extract a C string from the String object and copy it.
            const char *wpath3 = (*env)->GetStringUTFChars(env, stringPath, NULL);
            wpath1 = strdup(wpath3);
            (*env)->ReleaseStringUTFChars(env, stringPath, wpath3);
            
            goto retAndroid;
            
        bailAndroid:
            ARLOGe("Error: JNI call failure.\n");
            wpath1 = NULL;
        retAndroid:
            if (isAttached) (*gJavaVM)->DetachCurrentThread(gJavaVM); // Clean up.
            return (wpath1);
        }
#elif defined(__linux) || defined(__APPLE__)
            if (!((wpath1 = getenv("HOME")))) {
                return (NULL);
            }
            return (strdup(wpath1));
#else
            return (NULL); // Unsupported OS.
#endif
            break;
            
            
        case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_APP_CACHE_DIR:
#if defined(_WIN32)
            return (NULL);
#elif defined(ANDROID)
        {
            // Make JNI calls to get the Context's cache directory.
            
            // To begin, get a reference to the env and attach to it.
            JNIEnv *env;
            int isAttached = 0;
            int ret = 0;
            jthrowable exception;
            if (((*gJavaVM)->GetEnv(gJavaVM, (void**)&env, JNI_VERSION_1_6)) < 0) {
                // Couldn't get JNI environment, so this thread is native.
                if (((*gJavaVM)->AttachCurrentThread(gJavaVM, &env, NULL)) < 0) {
                    ARLOGe("Error: Couldn't attach to Java VM.\n");
                    return (NULL);
                }
                isAttached = 1;
            }
            
            // Get File object for the Context's files directory. This only works
            // if a subclass of Context is supplied.
            // e.g. JNIEXPORT void JNICALL Java_com_test_TestActivity_test(JNIEnv * env, jobject obj)
            // so make sure before call.
            jclass classOfSuppliedObject = (*env)->GetObjectClass(env, instanceOfAndroidContext);
            if (!classOfSuppliedObject) goto bailAndroid1;
            jclass classContext = (*env)->FindClass(env, "android/content/Context");
            if (!classContext) goto bailAndroid1;
            if (!(*env)->IsInstanceOf(env, instanceOfAndroidContext, classContext)) {
                ARLOGe("Error: supplied object is not an instance of android/content/Context.\n");
                wpath1 = NULL; // Bad parameter.
                goto retAndroid1;
            }
            jmethodID methodGetDir = (*env)->GetMethodID(env, classOfSuppliedObject, "getCacheDir", "()Ljava/io/File;"); // public abstract File getCacheDir();
            //jmethodID methodGetDir = (*env)->GetMethodID(env, classOfSuppliedObject, "getFilesDir", "(Ljava/lang/String;)Ljava/io/File;"); // public abstract File getFilesDir(String type);
            if (!methodGetDir) goto bailAndroid1;
            jobject objectFile = (*env)->CallObjectMethod(env, instanceOfAndroidContext, methodGetDir);
            exception = (*env)->ExceptionOccurred(env);
            if (exception) {
                (*env)->ExceptionDescribe(env);
                (*env)->ExceptionClear(env);
            }
            
            // Call method on File object to retrieve String object.
            jclass classFile = (*env)->GetObjectClass(env, objectFile);
            if (!classFile) goto bailAndroid1;
            jmethodID methodIDgetAbsolutePath = (*env)->GetMethodID(env, classFile, "getAbsolutePath", "()Ljava/lang/String;");
            if (!methodIDgetAbsolutePath) goto bailAndroid1;
            jstring stringPath = (*env)->CallObjectMethod(env, objectFile, methodIDgetAbsolutePath);
            exception = (*env)->ExceptionOccurred(env);
            if (exception) {
                (*env)->ExceptionDescribe(env);
                (*env)->ExceptionClear(env);
            }
            // Extract a C string from the String object, and chdir() to it.
            const char *wpath3 = (*env)->GetStringUTFChars(env, stringPath, NULL);
            wpath1 = strdup(wpath3);
            (*env)->ReleaseStringUTFChars(env, stringPath, wpath3);
            
            goto retAndroid1;
            
        bailAndroid1:
            ARLOGe("Error: JNI call failure.\n");
            wpath1 = NULL;
        retAndroid1:
            if (isAttached) (*gJavaVM)->DetachCurrentThread(gJavaVM); // Clean up.
            return (wpath1);
        }
#else
            return (NULL); // Unsupported OS.
#endif
            break;

		case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_APP_DATA_DIR:
#ifdef _WINRT
			//auto folder = Windows::Storage::ApplicationData::Current->LocalFolder;
			//wpath1 = strdup(folder->Path->Data().c_str());
			//return (wpath1);
			return (NULL); // Unsupported OS.
#else
			return (NULL); // Unsupported OS.
#endif
			break;

        case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_SUPPLIED_PATH:
        default:
            return (NULL); // Undefined behaviour.
            break;
    }
}
ARMultiMarkerInfoT *arMultiReadConfigFile( const char *filename, ARPattHandle *pattHandle )
{
    FILE                   *fp;
    ARMultiEachMarkerInfoT *marker;
    ARMultiMarkerInfoT     *marker_info;
    ARdouble               wpos3d[4][2];
    char                   buf[256], pattPath[2048], dummy;
    int                    num;
    int                    patt_type = 0;
    int                    i, j;

    if ((fp = fopen(filename, "r")) == NULL) {
        ARLOGe("Error: unable to open multimarker config file '%s'.\n", filename);
        ARLOGperror(NULL);
        return NULL;
    }

    get_buff(buf, 256, fp);
    if( sscanf(buf, "%d", &num) != 1 ) {
        ARLOGe("Error processing multimarker config file '%s': First line must be number of marker configs to read.\n", filename);
        fclose(fp);
        return NULL;
    }
    ARLOGd("Reading %d markers from multimarker file '%s'\n", num, filename);

    arMalloc(marker, ARMultiEachMarkerInfoT, num);

    for( i = 0; i < num; i++ ) {
        get_buff(buf, 256, fp);
        if (sscanf(buf, 
#if defined(__LP64__) && !defined(__APPLE__)
                        "%lu%c",
#else
                        "%llu%c",
#endif
                         &(marker[i].globalID), &dummy) != 1) { // Try first as matrix code.
            
            if (!pattHandle) {
                ARLOGe("Error processing multimarker config file '%s': pattern '%s' specified in multimarker configuration while in barcode-only mode.\n", filename, buf);
                goto bail;
            }
            if (!arUtilGetDirectoryNameFromPath(pattPath, filename, sizeof(pattPath), 1)) { // Get directory prefix.
                ARLOGe("Error processing multimarker config file '%s': Unable to determine directory name.\n", filename);
                goto bail;
            }
            strncat(pattPath, buf, sizeof(pattPath) - strlen(pattPath) - 1); // Add name of file to open.
            if ((marker[i].patt_id = arPattLoad(pattHandle, pattPath)) < 0) {
                ARLOGe("Error processing multimarker config file '%s': Unable to load pattern '%s'.\n", filename, pattPath);
                goto bail;
            }
            marker[i].patt_type = AR_MULTI_PATTERN_TYPE_TEMPLATE;
            patt_type |= 0x01;
        } else {
            
            if ((marker[i].globalID & 0xffff8000ULL) == 0ULL) marker[i].patt_id = (int)(marker[i].globalID & 0x00007fffULL); // If upper 33 bits are zero, use lower 31 bits as regular matrix code.
            else marker[i].patt_id = 0;
            ARLOGd("Marker %3d is matrix code %llu.\n", i + 1, marker[i].globalID);
            marker[i].patt_type = AR_MULTI_PATTERN_TYPE_MATRIX;
            patt_type |= 0x02;
        }

        get_buff(buf, 256, fp);
        if( sscanf(buf,
#ifdef ARDOUBLE_IS_FLOAT
                   "%f",
#else
                   "%lf",
#endif
                   &marker[i].width) != 1 ) {
            ARLOGe("Error processing multimarker config file '%s', marker definition %3d: First line must be pattern width.\n", filename, i + 1);
            goto bail;
        }
        
        j = 0;
        get_buff(buf, 256, fp);
        if( sscanf(buf,
#ifdef ARDOUBLE_IS_FLOAT
                   "%f %f %f %f",
#else
                   "%lf %lf %lf %lf",
#endif
                   &marker[i].trans[j][0],
                   &marker[i].trans[j][1],
                   &marker[i].trans[j][2],
                   &marker[i].trans[j][3]) != 4 ) {
            // Perhaps this is an old ARToolKit v2.x multimarker file?
            // If so, then the next line is two values (center) and should be skipped.
            float t1, t2;
            if( sscanf(buf,
                       "%f %f",
                       &t1, &t2) != 2 ) {
                ARLOGe("Error processing multimarker config file '%s', marker definition %3d: Lines 2 - 4 must be marker transform.\n", filename, i + 1);
                goto bail;
            }
        } else j++;
        do {
            get_buff(buf, 256, fp);
            if( sscanf(buf, 
#ifdef ARDOUBLE_IS_FLOAT
                       "%f %f %f %f",
#else
                       "%lf %lf %lf %lf",
#endif
                       &marker[i].trans[j][0],
                       &marker[i].trans[j][1],
                       &marker[i].trans[j][2],
                       &marker[i].trans[j][3]) != 4 ) {
                ARLOGe("Error processing multimarker config file '%s', marker definition %3d: Lines 2 - 4 must be marker transform.\n", filename, i + 1);
                goto bail;
            }
            j++;
        } while (j < 3);
        arUtilMatInv( (const ARdouble (*)[4])marker[i].trans, marker[i].itrans );

        wpos3d[0][0] =  -marker[i].width/2.0;
        wpos3d[0][1] =   marker[i].width/2.0;
        wpos3d[1][0] =   marker[i].width/2.0;
        wpos3d[1][1] =   marker[i].width/2.0;
        wpos3d[2][0] =   marker[i].width/2.0;
        wpos3d[2][1] =  -marker[i].width/2.0;
        wpos3d[3][0] =  -marker[i].width/2.0;
        wpos3d[3][1] =  -marker[i].width/2.0;
        for( j = 0; j < 4; j++ ) {
            marker[i].pos3d[j][0] = marker[i].trans[0][0] * wpos3d[j][0]
                                  + marker[i].trans[0][1] * wpos3d[j][1]
                                  + marker[i].trans[0][3];
            marker[i].pos3d[j][1] = marker[i].trans[1][0] * wpos3d[j][0]
                                  + marker[i].trans[1][1] * wpos3d[j][1]
                                  + marker[i].trans[1][3];
            marker[i].pos3d[j][2] = marker[i].trans[2][0] * wpos3d[j][0]
                                  + marker[i].trans[2][1] * wpos3d[j][1]
                                  + marker[i].trans[2][3];
        }
    }

    fclose(fp);

    arMalloc(marker_info, ARMultiMarkerInfoT, 1);
    marker_info->marker     = marker;
    marker_info->marker_num = num;
    marker_info->prevF      = 0;
    if( (patt_type & 0x03) == 0x03 ) marker_info->patt_type = AR_MULTI_PATTERN_DETECTION_MODE_TEMPLATE_AND_MATRIX;
    else if( patt_type & 0x01 )    marker_info->patt_type = AR_MULTI_PATTERN_DETECTION_MODE_TEMPLATE;
    else                           marker_info->patt_type = AR_MULTI_PATTERN_DETECTION_MODE_MATRIX;
    marker_info->cfPattCutoff = AR_MULTI_CONFIDENCE_PATTERN_CUTOFF_DEFAULT;
    marker_info->cfMatrixCutoff = AR_MULTI_CONFIDENCE_MATRIX_CUTOFF_DEFAULT;

    return marker_info;
    
bail:
    fclose(fp);
    free(marker);
    return NULL;
}
Example #4
0
char *arUtilGetResourcesDirectoryPath(AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR behavior)
#endif
{
#ifndef _WINRT
    char *wpath1;
    char *wpath2;
#  ifdef _WIN32
	DWORD len;
#  endif
#endif
    AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR behaviorW;

    if (behavior == AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_BEST) {
#if defined(__APPLE__)
        behaviorW = AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_BUNDLE_RESOURCES_DIR;
#elif defined(ANDROID)
        behaviorW = AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_APP_CACHE_DIR;
#elif defined(_WIN32) || defined(__linux)
        behaviorW = AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_EXECUTABLE_DIR;
#else
        behaviorW = AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_CWD;
#endif
    } else {
        behaviorW = behavior;
    }

	switch (behaviorW) {
            
            
        case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_EXECUTABLE_DIR:
#if (defined(_WIN32) && !defined(_WINRT)) || defined(__APPLE__) || defined(__linux)
            arMallocClear(wpath1, char, MAXPATHLEN);
#  if defined(_WIN32)
            len = GetModuleFileName(NULL, wpath1, MAXPATHLEN);    // NULL implies the current process.
            if (!len) {
                free (wpath1);
                return (NULL);
            }
#  elif defined(__APPLE__)
            uint32_t size = MAXPATHLEN;
            if (_NSGetExecutablePath(wpath1, &size) != 0) {
                free (wpath1);
                return (NULL);
            }
#  elif defined(__linux)
            ssize_t len;
            len = readlink("/proc/self/exe", wpath1, MAXPATHLEN - 1); // -1 as it is not NULL terminated.
            if (len == -1) {
                ARLOGperror(NULL);
                free (wpath1);
                return (NULL);
            }
            wpath1[len] = '\0'; // NULL terminate.
#  endif
            arMallocClear(wpath2, char, MAXPATHLEN);
            if (!arUtilGetDirectoryNameFromPath(wpath2, wpath1, MAXPATHLEN, 0)) {
                free (wpath1);
                free (wpath2);
                return (NULL);
            }
            free (wpath1);
            return (wpath2);
#else
            return (NULL); // Unsupported OS.
#endif
            break;
            
            
        case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_BUNDLE_RESOURCES_DIR:
#if defined(__APPLE__)
        {
            // Change working directory to resources directory inside app bundle.
            wpath1 = NULL;
            CFURLRef pathCFURLRef = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); // Get relative path to resources directory.
            if (pathCFURLRef) {
                wpath1 = (char *)calloc(MAXPATHLEN, sizeof(char)); //getcwd(path, MAXPATHLEN);
                if (wpath1) {
                    if (!CFURLGetFileSystemRepresentation(pathCFURLRef, true, (UInt8*)wpath1, MAXPATHLEN)) { // true in param 2 resolves against base.
                        ARLOGe("Error: Unable to get file system representation of a CFURL.\n");
                        free(wpath1);
                        wpath1 = NULL;
                    }
                }
                CFRelease(pathCFURLRef);
            }
            return (wpath1);
        }
#else
            return (NULL); // Unsupported OS.
#endif
            break;
            
            
        case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_CWD:
#ifndef _WINRT

            arMallocClear(wpath1, char, MAXPATHLEN);
            if (!getcwd(wpath1, MAXPATHLEN)) {
                free(wpath1);
                return (NULL);
            }
            return (wpath1);
#else
			return (NULL); // Unsupported OS.
#endif
			break;
            
            
        case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_USER_ROOT:
#if defined(_WIN32) && !defined(_WINRT)
            arMallocClear(wpath1, char, MAXPATHLEN);
            if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, wpath1))) {
                free (wpath1);
                return (NULL);
            }
            return (wpath1);
#elif defined(ANDROID)
        {
            // Make JNI calls to get the external storage directory.
            
            // To begin, get a reference to the env and attach to it.
            JNIEnv *env;
            int isAttached = 0;
            jthrowable exception;
            if (((*gJavaVM)->GetEnv(gJavaVM, (void**)&env, JNI_VERSION_1_6)) < 0) {
                // Couldn't get JNI environment, so this thread is native.
                if (((*gJavaVM)->AttachCurrentThread(gJavaVM, &env, NULL)) < 0) {
                    ARLOGe("Error: Couldn't attach to Java VM.\n");
                    return (NULL);
                }
                isAttached = 1;
            }
            
            // Get File object for the external storage directory.
            jclass classEnvironment = (*env)->FindClass(env, "android/os/Environment");
            if (!classEnvironment) goto bailAndroid;
            jmethodID methodIDgetExternalStorageDirectory = (*env)->GetStaticMethodID(env, classEnvironment, "getExternalStorageDirectory", "()Ljava/io/File;"); // public static File getExternalStorageDirectory ()
            if (!methodIDgetExternalStorageDirectory) goto bailAndroid;
            jobject objectFile = (*env)->CallStaticObjectMethod(env, classEnvironment, methodIDgetExternalStorageDirectory);
            exception = (*env)->ExceptionOccurred(env);
            if (exception) {
                (*env)->ExceptionDescribe(env);
                (*env)->ExceptionClear(env);
            }
            
            // Call method on File object to retrieve String object.
            jclass classFile = (*env)->GetObjectClass(env, objectFile);
            if (!classFile) goto bailAndroid;
            jmethodID methodIDgetAbsolutePath = (*env)->GetMethodID(env, classFile, "getAbsolutePath", "()Ljava/lang/String;");
            if (!methodIDgetAbsolutePath) goto bailAndroid;
            jstring stringPath = (*env)->CallObjectMethod(env, objectFile, methodIDgetAbsolutePath);
            exception = (*env)->ExceptionOccurred(env);
            if (exception) {
                (*env)->ExceptionDescribe(env);
                (*env)->ExceptionClear(env);
            }
            // Extract a C string from the String object and copy it.
            const char *wpath3 = (*env)->GetStringUTFChars(env, stringPath, NULL);
            wpath1 = strdup(wpath3);
            (*env)->ReleaseStringUTFChars(env, stringPath, wpath3);
            
            goto retAndroid;
            
        bailAndroid:
            ARLOGe("Error: JNI call failure.\n");
            wpath1 = NULL;
        retAndroid:
            if (isAttached) (*gJavaVM)->DetachCurrentThread(gJavaVM); // Clean up.
            return (wpath1);
        }
#elif defined(__APPLE__) && defined(__OBJC__) // iOS/OS X.
        {
            NSString *nssHomeDir = NSHomeDirectory(); // CoreFoundation equivalent is CFCopyHomeDirectoryURL(), iOS 6.0+ only.
            if (!nssHomeDir) {
                return (NULL);
            }
            wpath1 = strdup([nssHomeDir UTF8String]);
            return wpath1;
        }
#elif defined(__linux)
            if (!((wpath1 = getenv("HOME")))) {
                return (NULL);
            }
            return (strdup(wpath1));
#else
            return (NULL); // Unsupported OS.
#endif
            break;
            
            
        case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_APP_CACHE_DIR:
#if defined(_WIN32)
            return (NULL);
#elif defined(__APPLE__) // iOS/OS X.
        {
#  ifdef __OBJC__
            NSURL *cacheDir = [[[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] objectAtIndex:0];
            if (!cacheDir) {
                return (NULL);
            }
            wpath1 = strdup([[cacheDir path] UTF8String]);
#  else
            size_t len = confstr(_CS_DARWIN_USER_CACHE_DIR, NULL, 0);
            if (!len) return (NULL);
            wpath1 = (char *)malloc(len);
            len = confstr(_CS_DARWIN_USER_CACHE_DIR, wpath1, len); // On OS X, returns a folder in the sandbox hierachy under /var/folders/.
            if (!len) return (NULL);
#  endif
            return (wpath1);
        }
#elif defined(ANDROID)
        {
            // Make JNI calls to get the Context's cache directory.
            
            // To begin, get a reference to the env and attach to it.
            JNIEnv *env;
            int isAttached = 0;
            int ret = 0;
            jthrowable exception;
            if (((*gJavaVM)->GetEnv(gJavaVM, (void**)&env, JNI_VERSION_1_6)) < 0) {
                // Couldn't get JNI environment, so this thread is native.
                if (((*gJavaVM)->AttachCurrentThread(gJavaVM, &env, NULL)) < 0) {
                    ARLOGe("Error: Couldn't attach to Java VM.\n");
                    return (NULL);
                }
                isAttached = 1;
            }
            
            // Get File object for the Context's files directory. This only works
            // if a subclass of Context is supplied.
            // e.g. JNIEXPORT void JNICALL Java_com_test_TestActivity_test(JNIEnv * env, jobject obj)
            // so make sure before call.
            jclass classOfSuppliedObject = (*env)->GetObjectClass(env, instanceOfAndroidContext);
            if (!classOfSuppliedObject) goto bailAndroid1;
            jclass classContext = (*env)->FindClass(env, "android/content/Context");
            if (!classContext) goto bailAndroid1;
            if (!(*env)->IsInstanceOf(env, instanceOfAndroidContext, classContext)) {
                ARLOGe("Error: supplied object is not an instance of android/content/Context.\n");
                wpath1 = NULL; // Bad parameter.
                goto retAndroid1;
            }
            jmethodID methodGetDir = (*env)->GetMethodID(env, classOfSuppliedObject, "getCacheDir", "()Ljava/io/File;"); // public abstract File getCacheDir();
            //jmethodID methodGetDir = (*env)->GetMethodID(env, classOfSuppliedObject, "getFilesDir", "(Ljava/lang/String;)Ljava/io/File;"); // public abstract File getFilesDir(String type);
            if (!methodGetDir) goto bailAndroid1;
            jobject objectFile = (*env)->CallObjectMethod(env, instanceOfAndroidContext, methodGetDir);
            exception = (*env)->ExceptionOccurred(env);
            if (exception) {
                (*env)->ExceptionDescribe(env);
                (*env)->ExceptionClear(env);
            }
            
            // Call method on File object to retrieve String object.
            jclass classFile = (*env)->GetObjectClass(env, objectFile);
            if (!classFile) goto bailAndroid1;
            jmethodID methodIDgetAbsolutePath = (*env)->GetMethodID(env, classFile, "getAbsolutePath", "()Ljava/lang/String;");
            if (!methodIDgetAbsolutePath) goto bailAndroid1;
            jstring stringPath = (*env)->CallObjectMethod(env, objectFile, methodIDgetAbsolutePath);
            exception = (*env)->ExceptionOccurred(env);
            if (exception) {
                (*env)->ExceptionDescribe(env);
                (*env)->ExceptionClear(env);
            }
            // Extract a C string from the String object, and chdir() to it.
            const char *wpath3 = (*env)->GetStringUTFChars(env, stringPath, NULL);
            wpath1 = strdup(wpath3);
            (*env)->ReleaseStringUTFChars(env, stringPath, wpath3);
            
            goto retAndroid1;
            
        bailAndroid1:
            ARLOGe("Error: JNI call failure.\n");
            wpath1 = NULL;
        retAndroid1:
            if (isAttached) (*gJavaVM)->DetachCurrentThread(gJavaVM); // Clean up.
            return (wpath1);
        }
#else
            return (NULL); // Unsupported OS.
#endif
            break;

		case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_APP_DATA_DIR:
#ifdef _WINRT
			//auto folder = Windows::Storage::ApplicationData::Current->LocalFolder;
			//wpath1 = strdup(folder->Path->Data().c_str());
			//return (wpath1);
			return (NULL); // Unsupported OS.
#else
			return (NULL); // Unsupported OS.
#endif
			break;

        case AR_UTIL_RESOURCES_DIRECTORY_BEHAVIOR_USE_SUPPLIED_PATH:
        default:
            return (NULL); // Undefined behaviour.
            break;
    }
}