diff --git a/.gitignore b/.gitignore index 2c0b3d9..79d784a 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ PanoPainter.sdf *.iml android/.idea android/android/build/ +android/android/gradle/ android/android/.gradle/ android/android/.externalNativeBuild/ android/android/.idea diff --git a/.gitmodules b/.gitmodules index 8c2fd0f..c389aad 100644 --- a/.gitmodules +++ b/.gitmodules @@ -49,3 +49,6 @@ [submodule "libs/fmt"] path = libs/fmt url = https://github.com/fmtlib/fmt.git +[submodule "libs/ovr_mobile"] + path = libs/ovr_mobile + url = https://bitbucket.org/omigamedev/ovr_mobile.git diff --git a/android/android/build.gradle b/android/android/build.gradle index 40bba67..49cee59 100644 --- a/android/android/build.gradle +++ b/android/android/build.gradle @@ -138,7 +138,7 @@ android { sourceSets { main { manifest.srcFile 'src/main/AndroidManifest.xml' - java.srcDirs = ['../src/java'] + java.srcDirs = ['../src/java', 'src/main/java'] //jniLibs.srcDir 'libs' res.srcDirs = ['../src/res'] //assets.srcDirs = ['../../assets'] diff --git a/android/android/src/main/java/com/omixlab/panopainter/Platform.java b/android/android/src/main/java/com/omixlab/panopainter/Platform.java new file mode 100644 index 0000000..f472ab4 --- /dev/null +++ b/android/android/src/main/java/com/omixlab/panopainter/Platform.java @@ -0,0 +1,5 @@ +package com.omixlab.panopainter; + +public class Platform { + public static final String[] Libs = new String[]{}; +} diff --git a/android/quest/CMakeLists.txt b/android/quest/CMakeLists.txt index 86de1d8..e6ee6ab 100644 --- a/android/quest/CMakeLists.txt +++ b/android/quest/CMakeLists.txt @@ -11,8 +11,11 @@ add_library( ) add_library(vrapi SHARED IMPORTED) -set_target_properties(vrapi PROPERTIES IMPORTED_LOCATION - C:/ovr_sdk_mobile_1.23/VrApi/Libs/Android/${ANDROID_ABI}/Release/libvrapi.so) +set_target_properties( + vrapi + PROPERTIES IMPORTED_LOCATION + ${CMAKE_SOURCE_DIR}/../../libs/ovr_mobile/lib/${ANDROID_ABI}/libvrapi.so +) # Specifies a library name, specifies whether the library is STATIC or @@ -47,6 +50,7 @@ add_library( ../../libs/poly2tri/poly2tri/sweep/sweep.cc ../../libs/fmt/src/format.cc ../src/cpp/main.cpp + src/main/cpp/oculus_vr.cpp ../../src/pch.cpp ../../src/util.cpp ../../src/rtt.cpp @@ -116,7 +120,8 @@ add_library( ) target_include_directories(native-lib PRIVATE - C:/ovr_sdk_mobile_1.23/VrApi/Include + ../../libs/ovr_mobile/include + src/main/cpp ../src/cpp ../../src ../../libs/glm diff --git a/android/quest/build.gradle b/android/quest/build.gradle index 7dd082e..64e9cf8 100644 --- a/android/quest/build.gradle +++ b/android/quest/build.gradle @@ -83,7 +83,7 @@ android { // Sets optional flags for the C compiler. //cFlags "-D_EXAMPLE_C_FLAG1", "-D_EXAMPLE_C_FLAG2" // Sets a flag to enable format macro constants for the C++ compiler. - //cppFlags "-D__STDC_FORMAT_MACROS" + cppFlags "-D__QUEST__" arguments "-DANDROID_TOOLCHAIN=clang", //"-DANDROID_PLATFORM=android-19", "-DANDROID_STL=c++_shared", @@ -138,8 +138,8 @@ android { sourceSets { main { manifest.srcFile 'src/main/AndroidManifest.xml' - java.srcDirs = ['../src/java'] - //jniLibs.srcDir 'libs' + java.srcDirs = ['../src/java', 'src/main/java'] + jniLibs.srcDirs = ['../../libs/ovr_mobile/lib'] res.srcDirs = ['../src/res'] //assets.srcDirs = ['../../assets'] } diff --git a/android/quest/src/main/AndroidManifest.xml b/android/quest/src/main/AndroidManifest.xml index bad0994..ab712d5 100644 --- a/android/quest/src/main/AndroidManifest.xml +++ b/android/quest/src/main/AndroidManifest.xml @@ -1,18 +1,23 @@ + + + + + + android:launchMode="singleTask" + android:configChanges="screenSize|screenLayout|orientation|keyboardHidden|keyboard|navigation|uiMode" + android:screenOrientation="landscape"> diff --git a/android/quest/src/main/cpp/oculus_vr.cpp b/android/quest/src/main/cpp/oculus_vr.cpp new file mode 100644 index 0000000..820ac32 --- /dev/null +++ b/android/quest/src/main/cpp/oculus_vr.cpp @@ -0,0 +1,126 @@ +#include "pch.h" +#include "oculus_vr.h" +#include "log.h" +#include "rtt.h" +#include "app.h" +#include + +ovrJava java; +RTT ovr_eyes[3][2]; +ovrTextureSwapChain* swap_chain[2]; +int swap_chain_count = 0; +int swap_chain_index = 0; +ovrMobile* ovr_context = nullptr; +uint64_t ovr_frame = 0; + +void oculus_init(JavaVM* vm, JNIEnv* jni, jobject activity_class) +{ + java.Vm = vm; + java.Env = jni; + java.ActivityObject = activity_class; + + LOG("init OVR"); + const ovrInitParms initParms = vrapi_DefaultInitParms( &java ); + int32_t initResult = vrapi_Initialize( &initParms ); + if ( initResult != VRAPI_INITIALIZE_SUCCESS ) + { + // If intialization failed, vrapi_* function calls will not be available. + exit( 0 ); + } +} + +void oculus_init_vr(EGLDisplay display, EGLContext context, ANativeWindow* surface) +{ + LOG("init swapchain"); + int rtt_w = vrapi_GetSystemPropertyInt(&java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_WIDTH); + int rtt_h = vrapi_GetSystemPropertyInt(&java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_HEIGHT); + LOG("ovr suggested texture size %d %d", rtt_w, rtt_h); + for (int eye = 0; eye < 2; eye++) + { + swap_chain[eye] = vrapi_CreateTextureSwapChain3(VRAPI_TEXTURE_TYPE_2D, GL_RGBA8, rtt_w, rtt_h, 1, 3); + swap_chain_count = vrapi_GetTextureSwapChainLength(swap_chain[eye]); + for (int i = 0; i < swap_chain_count; i++) + { + auto texid = vrapi_GetTextureSwapChainHandle(swap_chain[eye], i); + if (!ovr_eyes[i][eye].create(rtt_w, rtt_h, texid, GL_RGBA8, true)) + { + ovr_eyes[i][eye].bindFramebuffer(); + ovr_eyes[i][eye].clear({1, 0, 1, 1}); + ovr_eyes[i][eye].unbindFramebuffer(); + LOG("FAILED create fb for eye %d", eye); + } + else + { + LOG("create eye %d", eye); + } + } + } + + LOG("vrapi_DefaultModeParms"); + ovrModeParms parms = vrapi_DefaultModeParms( &java ); + // No need to reset the FLAG_FULLSCREEN window flag when using a View + //parms.Flags &= ~VRAPI_MODE_FLAG_RESET_WINDOW_FULLSCREEN; + + parms.Flags |= VRAPI_MODE_FLAG_NATIVE_WINDOW; + parms.Display = (size_t)display; + parms.WindowSurface = (size_t)surface; + parms.ShareContext = (size_t)context; + LOG("enter vr mode"); + ovr_context = vrapi_EnterVrMode(&parms); + if (!ovr_context) + { + LOG("EnterVRMode FAILED"); + } + LOG("vr mode entered"); + + vrapi_SetClockLevels(ovr_context, 2, 2); + vrapi_SetPerfThread(ovr_context, VRAPI_PERF_THREAD_TYPE_MAIN, gettid()); + vrapi_SetPerfThread(ovr_context, VRAPI_PERF_THREAD_TYPE_RENDERER, 0); +} + +void oculus_draw() +{ + // BEGIN OVR + const double predictedDisplayTime = vrapi_GetPredictedDisplayTime(ovr_context, ovr_frame); + const ovrTracking2 tracking = vrapi_GetPredictedTracking2(ovr_context, predictedDisplayTime); + auto layer = vrapi_DefaultLayerProjection2(); + //ovrVector4f red = {1, 1, 0, 1}; + //auto layer = vrapi_DefaultLayerSolidColorProjection2(&red); + layer.HeadPose = tracking.HeadPose; + for (int eye = 0; eye < 2; eye++) + { + auto& rtt = ovr_eyes[swap_chain_index][eye]; + rtt.bindFramebuffer(); + rtt.clear({1, 0, 1, 1}); + glViewport(0, 0, rtt.getWidth(), rtt.getHeight()); + auto proj_ovr = ovrMatrix4f_Transpose(&tracking.Eye[eye].ProjectionMatrix); + glm::mat4 proj = glm::make_mat4(reinterpret_cast(&proj_ovr)); + auto view_ovr = ovrMatrix4f_Transpose(&tracking.Eye[eye].ViewMatrix); + glm::mat4 view = glm::make_mat4(reinterpret_cast(&view_ovr)); + auto pose_ovr = ovrMatrix4f_CreateFromQuaternion(&tracking.HeadPose.Pose.Orientation); + auto pose_ovr_tp = ovrMatrix4f_Transpose(&pose_ovr); + glm::mat4 pose = glm::make_mat4(reinterpret_cast(&pose_ovr_tp)); + App::I.vr_draw(proj, view, pose); + rtt.unbindFramebuffer(); + layer.Textures[eye].ColorSwapChain = swap_chain[eye]; + layer.Textures[eye].SwapChainIndex = swap_chain_index; + layer.Textures[eye].TexCoordsFromTanAngles = + ovrMatrix4f_TanAngleMatrixFromProjection(&tracking.Eye[eye].ProjectionMatrix); + } + layer.Header.Flags |= VRAPI_FRAME_LAYER_FLAG_CHROMATIC_ABERRATION_CORRECTION; + + const ovrLayerHeader2 * layers[] = { &layer.Header }; + + ovrSubmitFrameDescription2 frameDesc = { 0 }; + frameDesc.Flags = 0; + frameDesc.SwapInterval = 1; + frameDesc.FrameIndex = ovr_frame; + frameDesc.DisplayTime = predictedDisplayTime; + frameDesc.LayerCount = 1; + frameDesc.Layers = layers; + + vrapi_SubmitFrame2(ovr_context, &frameDesc); + + ovr_frame++; + swap_chain_index = (swap_chain_index + 1) % swap_chain_count; +} diff --git a/android/quest/src/main/cpp/oculus_vr.h b/android/quest/src/main/cpp/oculus_vr.h new file mode 100644 index 0000000..2146fcc --- /dev/null +++ b/android/quest/src/main/cpp/oculus_vr.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include + +void oculus_init(JavaVM* vm, JNIEnv* jni, jobject activity_class); +void oculus_init_vr(EGLDisplay display, EGLContext context, ANativeWindow* surface); +void oculus_draw(); diff --git a/android/quest/src/main/java/com/omixlab/panopainter/Platform.java b/android/quest/src/main/java/com/omixlab/panopainter/Platform.java new file mode 100644 index 0000000..8b69b47 --- /dev/null +++ b/android/quest/src/main/java/com/omixlab/panopainter/Platform.java @@ -0,0 +1,5 @@ +package com.omixlab.panopainter; + +public class Platform { + public static final String[] Libs = new String[]{"vrapi"}; +} diff --git a/android/src/cpp/main.cpp b/android/src/cpp/main.cpp index 81f4ade..1d0bae6 100644 --- a/android/src/cpp/main.cpp +++ b/android/src/cpp/main.cpp @@ -26,11 +26,7 @@ #include #include #include // for prctl( PR_SET_NAME ) - -#include "VrApi.h" -#include "VrApi_Helpers.h" -#include "VrApi_SystemUtils.h" -#include "VrApi_Input.h" +#include #include "pch.h" #include "app.h" @@ -39,6 +35,10 @@ #include "main.h" #include "com_omixlab_panopainter_MainActivity.h" +#ifdef __QUEST__ +#include "oculus_vr.h" +#endif + typedef void (*GLDEBUGPROC)(GLenum source, GLenum type, GLuint id, @@ -62,6 +62,7 @@ EGLContext g_context = EGL_NO_CONTEXT; std::recursive_mutex mutex; int mutex_count = 0; struct engine g_engine; +JNIEnv* jni; jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/) { @@ -87,39 +88,25 @@ int GetUnicodeChar(struct android_app* app, int eventType, int keyCode, int meta #define COMBINING_ACCENT 0x80000000 #define COMBINING_ACCENT_MASK 0x7fffffff - JavaVM* javaVM = app->activity->vm; - JNIEnv* jniEnv = app->activity->env; - - JavaVMAttachArgs attachArgs; - attachArgs.version = JNI_VERSION_1_6; - attachArgs.name = "NativeThread"; - attachArgs.group = NULL; - - jint result = javaVM->AttachCurrentThread(&jniEnv, &attachArgs); - if(result == JNI_ERR) - { - return 0; - } - - jclass class_key_event = jniEnv->FindClass("android/view/KeyEvent"); + jclass class_key_event = jni->FindClass("android/view/KeyEvent"); int unicodeKey; if(metaState == 0) { - jmethodID method_get_unicode_char = jniEnv->GetMethodID(class_key_event, "getUnicodeChar", "()I"); - jmethodID eventConstructor = jniEnv->GetMethodID(class_key_event, "", "(II)V"); - jobject eventObj = jniEnv->NewObject(class_key_event, eventConstructor, eventType, keyCode); + jmethodID method_get_unicode_char = jni->GetMethodID(class_key_event, "getUnicodeChar", "()I"); + jmethodID eventConstructor = jni->GetMethodID(class_key_event, "", "(II)V"); + jobject eventObj = jni->NewObject(class_key_event, eventConstructor, eventType, keyCode); - unicodeKey = jniEnv->CallIntMethod(eventObj, method_get_unicode_char); + unicodeKey = jni->CallIntMethod(eventObj, method_get_unicode_char); } else { - jmethodID method_get_unicode_char = jniEnv->GetMethodID(class_key_event, "getUnicodeChar", "(I)I"); - jmethodID eventConstructor = jniEnv->GetMethodID(class_key_event, "", "(II)V"); - jobject eventObj = jniEnv->NewObject(class_key_event, eventConstructor, eventType, keyCode); + jmethodID method_get_unicode_char = jni->GetMethodID(class_key_event, "getUnicodeChar", "(I)I"); + jmethodID eventConstructor = jni->GetMethodID(class_key_event, "", "(II)V"); + jobject eventObj = jni->NewObject(class_key_event, eventConstructor, eventType, keyCode); - unicodeKey = jniEnv->CallIntMethod(eventObj, method_get_unicode_char, metaState); + unicodeKey = jni->CallIntMethod(eventObj, method_get_unicode_char, metaState); } if ((unicodeKey & COMBINING_ACCENT) != 0) @@ -127,8 +114,6 @@ int GetUnicodeChar(struct android_app* app, int eventType, int keyCode, int meta unicodeKey = unicodeKey & COMBINING_ACCENT_MASK; } - javaVM->DetachCurrentThread(); - LOG("Unicode key is: %d", unicodeKey); return unicodeKey; } @@ -174,88 +159,67 @@ struct locker // see https://groups.google.com/forum/#!topic/android-ndk/Tk3g00wLKhk void displayKeyboard(android_app* mApplication, bool pShow) { - // Attaches the current thread to the JVM. - jint lResult; - jint lFlags = 0; - - JavaVM* lJavaVM = mApplication->activity->vm; - JNIEnv* lJNIEnv = mApplication->activity->env; - - JavaVMAttachArgs lJavaVMAttachArgs; - lJavaVMAttachArgs.version = JNI_VERSION_1_6; - lJavaVMAttachArgs.name = "NativeThread"; - lJavaVMAttachArgs.group = NULL; - - lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, - &lJavaVMAttachArgs); - if (lResult == JNI_ERR) { - return; - } - // Retrieves NativeActivity. jobject lNativeActivity = mApplication->activity->clazz; - jclass ClassNativeActivity = lJNIEnv->GetObjectClass(lNativeActivity); + jclass ClassNativeActivity = jni->GetObjectClass(lNativeActivity); // Retrieves Context.INPUT_METHOD_SERVICE. - jclass ClassContext = lJNIEnv->FindClass("android/content/Context"); + jclass ClassContext = jni->FindClass("android/content/Context"); jfieldID FieldINPUT_METHOD_SERVICE = - lJNIEnv->GetStaticFieldID(ClassContext, "INPUT_METHOD_SERVICE", "Ljava/lang/String;"); + jni->GetStaticFieldID(ClassContext, "INPUT_METHOD_SERVICE", "Ljava/lang/String;"); jobject INPUT_METHOD_SERVICE = - lJNIEnv->GetStaticObjectField(ClassContext, + jni->GetStaticObjectField(ClassContext, FieldINPUT_METHOD_SERVICE); //jniCheck(INPUT_METHOD_SERVICE); // Runs getSystemService(Context.INPUT_METHOD_SERVICE). - jclass ClassInputMethodManager = lJNIEnv->FindClass( + jclass ClassInputMethodManager = jni->FindClass( "android/view/inputmethod/InputMethodManager"); - jmethodID MethodGetSystemService = lJNIEnv->GetMethodID( + jmethodID MethodGetSystemService = jni->GetMethodID( ClassNativeActivity, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"); - jobject lInputMethodManager = lJNIEnv->CallObjectMethod( + jobject lInputMethodManager = jni->CallObjectMethod( lNativeActivity, MethodGetSystemService, INPUT_METHOD_SERVICE); // Runs getWindow().getDecorView(). - jmethodID MethodGetWindow = lJNIEnv->GetMethodID( + jmethodID MethodGetWindow = jni->GetMethodID( ClassNativeActivity, "getWindow", "()Landroid/view/Window;"); - jobject lWindow = lJNIEnv->CallObjectMethod(lNativeActivity, + jobject lWindow = jni->CallObjectMethod(lNativeActivity, MethodGetWindow); - jclass ClassWindow = lJNIEnv->FindClass( + jclass ClassWindow = jni->FindClass( "android/view/Window"); - jmethodID MethodGetDecorView = lJNIEnv->GetMethodID( + jmethodID MethodGetDecorView = jni->GetMethodID( ClassWindow, "getDecorView", "()Landroid/view/View;"); - jobject lDecorView = lJNIEnv->CallObjectMethod(lWindow, + jobject lDecorView = jni->CallObjectMethod(lWindow, MethodGetDecorView); if (pShow) { // Runs lInputMethodManager.showSoftInput(...). - jmethodID MethodShowSoftInput = lJNIEnv->GetMethodID( + jmethodID MethodShowSoftInput = jni->GetMethodID( ClassInputMethodManager, "showSoftInput", "(Landroid/view/View;I)Z"); - jboolean lResult = lJNIEnv->CallBooleanMethod( + jboolean lResult = jni->CallBooleanMethod( lInputMethodManager, MethodShowSoftInput, - lDecorView, lFlags); + lDecorView, 0); } else { // Runs lWindow.getViewToken() - jclass ClassView = lJNIEnv->FindClass( + jclass ClassView = jni->FindClass( "android/view/View"); - jmethodID MethodGetWindowToken = lJNIEnv->GetMethodID( + jmethodID MethodGetWindowToken = jni->GetMethodID( ClassView, "getWindowToken", "()Landroid/os/IBinder;"); - jobject lBinder = lJNIEnv->CallObjectMethod(lDecorView, + jobject lBinder = jni->CallObjectMethod(lDecorView, MethodGetWindowToken); // lInputMethodManager.hideSoftInput(...). - jmethodID MethodHideSoftInput = lJNIEnv->GetMethodID( + jmethodID MethodHideSoftInput = jni->GetMethodID( ClassInputMethodManager, "hideSoftInputFromWindow", "(Landroid/os/IBinder;I)Z"); - jboolean lRes = lJNIEnv->CallBooleanMethod( + jboolean lRes = jni->CallBooleanMethod( lInputMethodManager, MethodHideSoftInput, - lBinder, lFlags); + lBinder, 0); } - - // Finished with the JVM. - lJavaVM->DetachCurrentThread(); } /* @@ -315,102 +279,39 @@ JNIEXPORT void JNICALL Java_com_omixlab_panopainter_MainActivity_contentRectChan void android_pick_file(android_app* mApplication, std::function callback) { - // Attaches the current thread to the JVM. - jint lResult; - jint lFlags = 0; - - JavaVM* lJavaVM = mApplication->activity->vm; - JNIEnv* lJNIEnv = mApplication->activity->env; - - JavaVMAttachArgs lJavaVMAttachArgs; - lJavaVMAttachArgs.version = JNI_VERSION_1_6; - lJavaVMAttachArgs.name = "NativeThread"; - lJavaVMAttachArgs.group = NULL; - - lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs); - if (lResult == JNI_ERR) - { - return; - } - pick_file_callback = callback; // Retrieves NativeActivity. jobject lNativeActivity = mApplication->activity->clazz; - jclass ClassNativeActivity = lJNIEnv->GetObjectClass(lNativeActivity); + jclass ClassNativeActivity = jni->GetObjectClass(lNativeActivity); - jmethodID MethodPickFile = lJNIEnv->GetMethodID(ClassNativeActivity, "pickFile", "()V"); - lJNIEnv->CallVoidMethod(lNativeActivity, MethodPickFile); - - // Finished with the JVM. - lJavaVM->DetachCurrentThread(); + jmethodID MethodPickFile = jni->GetMethodID(ClassNativeActivity, "pickFile", "()V"); + jni->CallVoidMethod(lNativeActivity, MethodPickFile); } float get_display_density(android_app* mApplication) { - // Attaches the current thread to the JVM. - jint lResult; - jint lFlags = 0; - - JavaVM* lJavaVM = mApplication->activity->vm; - JNIEnv* lJNIEnv = mApplication->activity->env; - - JavaVMAttachArgs lJavaVMAttachArgs; - lJavaVMAttachArgs.version = JNI_VERSION_1_6; - lJavaVMAttachArgs.name = "NativeThread"; - lJavaVMAttachArgs.group = NULL; - - lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs); - if (lResult == JNI_ERR) - { - return 1; - } - // Retrieves NativeActivity. jobject lNativeActivity = mApplication->activity->clazz; - jclass ClassNativeActivity = lJNIEnv->GetObjectClass(lNativeActivity); + jclass ClassNativeActivity = jni->GetObjectClass(lNativeActivity); - jmethodID MethodPickFile = lJNIEnv->GetMethodID(ClassNativeActivity, "getDensity", "()F"); - float density = lJNIEnv->CallFloatMethod(lNativeActivity, MethodPickFile); - - // Finished with the JVM. - lJavaVM->DetachCurrentThread(); + jmethodID MethodPickFile = jni->GetMethodID(ClassNativeActivity, "getDensity", "()F"); + float density = jni->CallFloatMethod(lNativeActivity, MethodPickFile); return density; } std::string get_data_path(android_app* mApplication) { - // Attaches the current thread to the JVM. - jint lResult; - jint lFlags = 0; - - JavaVM* lJavaVM = mApplication->activity->vm; - JNIEnv* lJNIEnv = mApplication->activity->env; - - JavaVMAttachArgs lJavaVMAttachArgs; - lJavaVMAttachArgs.version = JNI_VERSION_1_6; - lJavaVMAttachArgs.name = "NativeThread"; - lJavaVMAttachArgs.group = NULL; - - lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs); - if (lResult == JNI_ERR) - { - return ""; - } - // Retrieves NativeActivity. jobject lNativeActivity = mApplication->activity->clazz; - jclass ClassNativeActivity = lJNIEnv->GetObjectClass(lNativeActivity); + jclass ClassNativeActivity = jni->GetObjectClass(lNativeActivity); - jmethodID MethodPickFile = lJNIEnv->GetMethodID(ClassNativeActivity, "getDataPath", "()Ljava/lang/String;"); - jstring path = (jstring)lJNIEnv->CallObjectMethod(lNativeActivity, MethodPickFile); + jmethodID MethodPickFile = jni->GetMethodID(ClassNativeActivity, "getDataPath", "()Ljava/lang/String;"); + jstring path = (jstring)jni->CallObjectMethod(lNativeActivity, MethodPickFile); - const char* path_utf = lJNIEnv->GetStringUTFChars(path, nullptr); + const char* path_utf = jni->GetStringUTFChars(path, nullptr); std::string file_path = path_utf; // create a copy - lJNIEnv->ReleaseStringUTFChars(path, path_utf); - - // Finished with the JVM. - lJavaVM->DetachCurrentThread(); + jni->ReleaseStringUTFChars(path, path_utf); return file_path; } @@ -427,11 +328,15 @@ static int engine_init_display(struct engine* engine) { * component compatible with on-screen windows */ const EGLint attribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, - EGL_DEPTH_SIZE, 24, + EGL_ALPHA_SIZE, 8, + EGL_DEPTH_SIZE, 0, + EGL_STENCIL_SIZE, 0, + EGL_SAMPLES, 0, EGL_NONE }; EGLint w, h, dummy, format; @@ -460,12 +365,13 @@ static int engine_init_display(struct engine* engine) { auto i = 0; for (; i < numConfigs; i++) { auto& cfg = supportedConfigs[i]; - EGLint r, g, b, d; + EGLint r, g, b, a, d; if (eglGetConfigAttrib(display, cfg, EGL_RED_SIZE, &r) && eglGetConfigAttrib(display, cfg, EGL_GREEN_SIZE, &g) && eglGetConfigAttrib(display, cfg, EGL_BLUE_SIZE, &b) && + eglGetConfigAttrib(display, cfg, EGL_ALPHA_SIZE, &a) && eglGetConfigAttrib(display, cfg, EGL_DEPTH_SIZE, &d) && - r == 8 && g == 8 && b == 8 && d == 0 ) { + r == 8 && g == 8 && b == 8 && a == 8 && d == 0 ) { config = supportedConfigs[i]; break; @@ -483,9 +389,9 @@ static int engine_init_display(struct engine* engine) { surface = eglCreateWindowSurface(display, config, engine->app->window, NULL); const EGLint attribs_test[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_CONTEXT_CLIENT_VERSION, 3, EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR | EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, - //EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR, + EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR, EGL_NONE }; @@ -503,7 +409,7 @@ static int engine_init_display(struct engine* engine) { { LOG("EGL: debug and forward context failed"); const EGLint attribs_test[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_CONTEXT_CLIENT_VERSION, 3, EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, EGL_NONE }; @@ -512,7 +418,7 @@ static int engine_init_display(struct engine* engine) { { LOG("EGL: only forward context failed"); const EGLint attribs_test[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_CONTEXT_CLIENT_VERSION, 3, EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, //EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR, EGL_NONE @@ -522,7 +428,7 @@ static int engine_init_display(struct engine* engine) { { LOG("EGL: only debug context failed"); const EGLint attribs_test[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE }; context = eglCreateContext(display, config, EGL_NO_CONTEXT, attribs_test); @@ -565,9 +471,9 @@ static int engine_init_display(struct engine* engine) { engine->height = h; engine->state.angle = 0; - float density = get_display_density(engine->app); - LOG("density %f", density); - App::I.zoom = density / 1.5; + //float density = get_display_density(engine->app); + //LOG("density %f", density); + //App::I.zoom = density / 1.5; g_display = display; g_context = context; @@ -673,6 +579,10 @@ static int engine_init_display(struct engine* engine) { //LOG("PROP: %s", os_props[""].c_str()); //LOG("PROP: %s", os_props[""].c_str()); +#ifdef __QUEST__ + oculus_init_vr(display, context, engine->app->window); +#endif + // Initialize GL state. android_async_lock(engine); @@ -696,6 +606,7 @@ static int engine_init_display(struct engine* engine) { App::I.height = h; App::I.redraw = true; App::I.init(); + App::I.resize(w, h); LOG("All ready"); engine->animating = 1; @@ -710,11 +621,38 @@ static int engine_init_display(struct engine* engine) { static void engine_draw_frame(struct engine* engine) { static auto start = std::chrono::high_resolution_clock::now(); static float elapsed = 0; + static float elapsed_1s = 0; + static int rendered_frames = 0; locker _lock(engine); if (engine->display == EGL_NO_DISPLAY) return; + auto now = std::chrono::high_resolution_clock::now(); + auto dt = std::chrono::duration(now - start); + start = now; + elapsed += dt.count(); + elapsed_1s += dt.count(); + App::I.tick(dt.count()); + + if (elapsed_1s > 1.f) + { + LOG("vr %d fps", rendered_frames); + elapsed_1s = 0; + rendered_frames = 0; + } + + const float fps60 = 1.f / 60.f; + if (elapsed < fps60) + return; + + rendered_frames++; + elapsed = 0; + +#ifdef __QUEST__ + App::I.vr_draw_ui(); + oculus_draw(); +#else /* int w, h; eglQuerySurface(engine->display, engine->surface, EGL_WIDTH, &w); @@ -729,12 +667,6 @@ static void engine_draw_frame(struct engine* engine) { } */ - auto now = std::chrono::high_resolution_clock::now(); - auto dt = std::chrono::duration(now - start); - start = now; - elapsed += dt.count(); - App::I.tick(dt.count()); - if (!(App::I.redraw || App::I.animate)) return; @@ -743,6 +675,7 @@ static void engine_draw_frame(struct engine* engine) { elapsed = 0; eglSwapBuffers(engine->display, engine->surface); +#endif } /** @@ -1051,23 +984,14 @@ void android_main(struct android_app* state) { ANativeActivity_setWindowFlags(state->activity, AWINDOW_FLAG_KEEP_SCREEN_ON, 0 ); - ovrJava java; - java.Vm = state->activity->vm; - (*java.Vm).AttachCurrentThread(&java.Env, NULL ); - java.ActivityObject = state->activity->clazz; + state->activity->vm->AttachCurrentThread(&jni, nullptr); + +#ifdef __QUEST__ + oculus_init(state->activity->vm, jni, state->activity->clazz); +#endif // Note that AttachCurrentThread will reset the thread name. - prctl( PR_SET_NAME, (long)"OVR::Main", 0, 0, 0 ); - - const ovrInitParms initParms = vrapi_DefaultInitParms( &java ); - int32_t initResult = vrapi_Initialize( &initParms ); - if ( initResult != VRAPI_INITIALIZE_SUCCESS ) - { - // If intialization failed, vrapi_* function calls will not be available. - exit( 0 ); - } - - // END OVR + prctl(PR_SET_NAME, (long)"PanoPainter Main", 0, 0, 0); // Prepare to monitor accelerometer /* @@ -1098,7 +1022,7 @@ void android_main(struct android_app* state) { // If animating, we loop until all events are read, then continue // to draw the next frame of animation. bool used = false; - int timeout = g_engine.display != EGL_NO_DISPLAY ? 100 : -1; + int timeout = g_engine.display != EGL_NO_DISPLAY ? 0 : -1; while (!used && (ident=ALooper_pollOnce(timeout, NULL, &events, (void**)&source)) != ALOOPER_POLL_ERROR) { diff --git a/android/src/java/com/omixlab/panopainter/MainActivity.java b/android/src/java/com/omixlab/panopainter/MainActivity.java index 4cb3ca8..1c4f0c7 100644 --- a/android/src/java/com/omixlab/panopainter/MainActivity.java +++ b/android/src/java/com/omixlab/panopainter/MainActivity.java @@ -1,7 +1,6 @@ package com.omixlab.panopainter; import android.Manifest; -import android.app.Activity; import android.app.NativeActivity; import android.content.Intent; import android.content.pm.PackageManager; @@ -14,14 +13,13 @@ import android.view.View; import android.view.ViewTreeObserver; import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileWriter; -import java.io.IOException; -import java.net.URISyntaxException; + +import com.omixlab.panopainter.Platform; public class MainActivity extends NativeActivity { static { + for (String lib : Platform.Libs) + System.loadLibrary(lib); System.loadLibrary("native-lib"); } diff --git a/libs/ovr_mobile b/libs/ovr_mobile new file mode 160000 index 0000000..fceeb64 --- /dev/null +++ b/libs/ovr_mobile @@ -0,0 +1 @@ +Subproject commit fceeb641f1d49d794f9bde05f1e3e821ce429967