diff --git a/apks/controller_emulator.apk b/apks/controller_emulator.apk index 7702ea4c..30c2d8e0 100644 Binary files a/apks/controller_emulator.apk and b/apks/controller_emulator.apk differ diff --git a/build.gradle b/build.gradle index 426447f5..1f2f70d7 100644 --- a/build.gradle +++ b/build.gradle @@ -35,13 +35,13 @@ task clean(type: Delete) { // The dependencies for NDK builds live inside the .aar files so they need to // be extracted before NDK targets can build. task extractAudioSo(type: Copy) { - from zipTree("${project.rootDir}/libraries/sdk-audio-1.160.0.aar") + from zipTree("${project.rootDir}/libraries/sdk-audio-1.170.0.aar") into "${project.rootDir}/libraries/" include "jni/**/libgvr_audio.so" } task extractGvrSo(type: Copy) { - from zipTree("${project.rootDir}/libraries/sdk-base-1.160.0.aar") + from zipTree("${project.rootDir}/libraries/sdk-base-1.170.0.aar") into "${project.rootDir}/libraries/" include "jni/**/libgvr.so" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index c44b679a..758de960 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradlew.bat b/gradlew.bat index f9553162..e95643d6 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,84 +1,84 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/libraries/headers/vr/gvr/capi/include/gvr_gesture.h b/libraries/headers/vr/gvr/capi/include/gvr_gesture.h index e2d1ac85..ed3c23c7 100644 --- a/libraries/headers/vr/gvr/capi/include/gvr_gesture.h +++ b/libraries/headers/vr/gvr/capi/include/gvr_gesture.h @@ -40,6 +40,9 @@ extern "C" { /// If you are writing C++ code, you might prefer to use the C++ wrapper rather /// than implement this C API directly. /// +/// If you are using multiple controllers, you will need to create multiple +/// gvr_gesture_context objects, one for each controller. +/// /// Example API usage: /// /// Initialization: @@ -216,6 +219,9 @@ typedef gvr_gesture Gesture; /// calls to C calls provided by this wrapper runs entirely in the client's /// binary and is compiled by the client's compiler. /// +/// If you are using multiple controllers, you will need to create multiple +/// GestureApi objects, one for each controller. +/// /// Methods in this class are only documented insofar as the C++ wrapping logic /// is concerned; for information about the method itself, please refer to the /// corresponding function in the C API. diff --git a/libraries/headers/vr/gvr/capi/include/gvr_version.h b/libraries/headers/vr/gvr/capi/include/gvr_version.h index be29fde6..7b16b527 100644 --- a/libraries/headers/vr/gvr/capi/include/gvr_version.h +++ b/libraries/headers/vr/gvr/capi/include/gvr_version.h @@ -23,14 +23,14 @@ extern "C" { /// A string representation of the current GVR build version. This is of /// the form "MAJOR.MINOR.PATCH". Note that this may differ from the runtime /// GVR version as reported by gvr_get_version_string(). -#define GVR_SDK_VERSION_STRING "1.160.0" +#define GVR_SDK_VERSION_STRING "1.170.0" /// Semantic components for the current GVR build version. Note that these /// values may differ from the runtime GVR version as reported by /// gvr_get_version(). enum { GVR_SDK_MAJOR_VERSION = 1, - GVR_SDK_MINOR_VERSION = 160, + GVR_SDK_MINOR_VERSION = 170, GVR_SDK_PATCH_VERSION = 0, }; diff --git a/libraries/sdk-audio-1.160.0.aar b/libraries/sdk-audio-1.160.0.aar deleted file mode 100644 index 3ba101f9..00000000 Binary files a/libraries/sdk-audio-1.160.0.aar and /dev/null differ diff --git a/libraries/sdk-audio-1.170.0.aar b/libraries/sdk-audio-1.170.0.aar new file mode 100644 index 00000000..dccd76f5 Binary files /dev/null and b/libraries/sdk-audio-1.170.0.aar differ diff --git a/libraries/sdk-audio-1.160.0.pom b/libraries/sdk-audio-1.170.0.pom similarity index 92% rename from libraries/sdk-audio-1.160.0.pom rename to libraries/sdk-audio-1.170.0.pom index 854b8551..bc878ff7 100644 --- a/libraries/sdk-audio-1.160.0.pom +++ b/libraries/sdk-audio-1.170.0.pom @@ -4,7 +4,7 @@ com.google.vr sdk-audio - 1.160.0 + 1.170.0 aar Google VR SDK-Audio @@ -19,7 +19,7 @@ com.google.vr sdk-base aar - 1.160.0 + 1.170.0 diff --git a/libraries/sdk-base-1.160.0.aar b/libraries/sdk-base-1.160.0.aar deleted file mode 100644 index de74c6b4..00000000 Binary files a/libraries/sdk-base-1.160.0.aar and /dev/null differ diff --git a/libraries/sdk-base-1.170.0.aar b/libraries/sdk-base-1.170.0.aar new file mode 100644 index 00000000..e4fbebf4 Binary files /dev/null and b/libraries/sdk-base-1.170.0.aar differ diff --git a/libraries/sdk-base-1.160.0.pom b/libraries/sdk-base-1.170.0.pom similarity index 92% rename from libraries/sdk-base-1.160.0.pom rename to libraries/sdk-base-1.170.0.pom index 21ba82f8..12c8114c 100644 --- a/libraries/sdk-base-1.160.0.pom +++ b/libraries/sdk-base-1.170.0.pom @@ -4,7 +4,7 @@ com.google.vr sdk-base - 1.160.0 + 1.170.0 aar Google VR SDK-Base @@ -19,7 +19,7 @@ com.google.vr sdk-common aar - 1.160.0 + 1.170.0 diff --git a/libraries/sdk-common-1.160.0.aar b/libraries/sdk-common-1.160.0.aar deleted file mode 100644 index 05258911..00000000 Binary files a/libraries/sdk-common-1.160.0.aar and /dev/null differ diff --git a/libraries/sdk-common-1.170.0.aar b/libraries/sdk-common-1.170.0.aar new file mode 100644 index 00000000..23e61111 Binary files /dev/null and b/libraries/sdk-common-1.170.0.aar differ diff --git a/libraries/sdk-common-1.160.0.pom b/libraries/sdk-common-1.170.0.pom similarity index 96% rename from libraries/sdk-common-1.160.0.pom rename to libraries/sdk-common-1.170.0.pom index 9a340994..328d6525 100644 --- a/libraries/sdk-common-1.160.0.pom +++ b/libraries/sdk-common-1.170.0.pom @@ -4,7 +4,7 @@ com.google.vr sdk-common - 1.160.0 + 1.170.0 aar Google VR SDK-Common diff --git a/libraries/sdk-commonwidget-1.160.0.aar b/libraries/sdk-commonwidget-1.160.0.aar deleted file mode 100644 index 50365771..00000000 Binary files a/libraries/sdk-commonwidget-1.160.0.aar and /dev/null differ diff --git a/libraries/sdk-commonwidget-1.170.0.aar b/libraries/sdk-commonwidget-1.170.0.aar new file mode 100644 index 00000000..dbce5c4d Binary files /dev/null and b/libraries/sdk-commonwidget-1.170.0.aar differ diff --git a/libraries/sdk-commonwidget-1.160.0.pom b/libraries/sdk-commonwidget-1.170.0.pom similarity index 92% rename from libraries/sdk-commonwidget-1.160.0.pom rename to libraries/sdk-commonwidget-1.170.0.pom index 0945f8a1..ee98c471 100644 --- a/libraries/sdk-commonwidget-1.160.0.pom +++ b/libraries/sdk-commonwidget-1.170.0.pom @@ -4,7 +4,7 @@ com.google.vr sdk-commonwidget - 1.160.0 + 1.170.0 aar Google VR SDK-CommonWidget @@ -19,7 +19,7 @@ com.google.vr sdk-common aar - 1.160.0 + 1.170.0 diff --git a/libraries/sdk-controller-1.160.0.aar b/libraries/sdk-controller-1.160.0.aar deleted file mode 100644 index 5e001b51..00000000 Binary files a/libraries/sdk-controller-1.160.0.aar and /dev/null differ diff --git a/libraries/sdk-controller-1.170.0.aar b/libraries/sdk-controller-1.170.0.aar new file mode 100644 index 00000000..df846519 Binary files /dev/null and b/libraries/sdk-controller-1.170.0.aar differ diff --git a/libraries/sdk-controller-1.160.0.pom b/libraries/sdk-controller-1.170.0.pom similarity index 92% rename from libraries/sdk-controller-1.160.0.pom rename to libraries/sdk-controller-1.170.0.pom index bf4b353b..8e35a093 100644 --- a/libraries/sdk-controller-1.160.0.pom +++ b/libraries/sdk-controller-1.170.0.pom @@ -4,7 +4,7 @@ com.google.vr sdk-controller - 1.160.0 + 1.170.0 aar Google VR SDK-Controller @@ -19,7 +19,7 @@ com.google.vr sdk-base aar - 1.160.0 + 1.170.0 diff --git a/libraries/sdk-panowidget-1.160.0.aar b/libraries/sdk-panowidget-1.160.0.aar deleted file mode 100644 index 623bea66..00000000 Binary files a/libraries/sdk-panowidget-1.160.0.aar and /dev/null differ diff --git a/libraries/sdk-panowidget-1.170.0.aar b/libraries/sdk-panowidget-1.170.0.aar new file mode 100644 index 00000000..d0a53c42 Binary files /dev/null and b/libraries/sdk-panowidget-1.170.0.aar differ diff --git a/libraries/sdk-panowidget-1.160.0.pom b/libraries/sdk-panowidget-1.170.0.pom similarity index 92% rename from libraries/sdk-panowidget-1.160.0.pom rename to libraries/sdk-panowidget-1.170.0.pom index dad347e6..c90180e4 100644 --- a/libraries/sdk-panowidget-1.160.0.pom +++ b/libraries/sdk-panowidget-1.170.0.pom @@ -4,7 +4,7 @@ com.google.vr sdk-panowidget - 1.160.0 + 1.170.0 aar Google VR SDK-CommonWidget @@ -19,7 +19,7 @@ com.google.vr sdk-commonwidget aar - 1.160.0 + 1.170.0 diff --git a/libraries/sdk-videowidget-1.160.0.aar b/libraries/sdk-videowidget-1.160.0.aar deleted file mode 100644 index 700b0e1e..00000000 Binary files a/libraries/sdk-videowidget-1.160.0.aar and /dev/null differ diff --git a/libraries/sdk-videowidget-1.170.0.aar b/libraries/sdk-videowidget-1.170.0.aar new file mode 100644 index 00000000..5d38831a Binary files /dev/null and b/libraries/sdk-videowidget-1.170.0.aar differ diff --git a/libraries/sdk-videowidget-1.160.0.pom b/libraries/sdk-videowidget-1.170.0.pom similarity index 94% rename from libraries/sdk-videowidget-1.160.0.pom rename to libraries/sdk-videowidget-1.170.0.pom index 122c90c4..f60773f3 100644 --- a/libraries/sdk-videowidget-1.160.0.pom +++ b/libraries/sdk-videowidget-1.170.0.pom @@ -4,7 +4,7 @@ com.google.vr sdk-videowidget - 1.160.0 + 1.170.0 aar Google VR SDK-CommonWidget @@ -32,7 +32,7 @@ com.google.vr sdk-commonwidget aar - 1.160.0 + 1.170.0 diff --git a/samples/ndk-controllerpaint/CMakeLists.txt b/samples/ndk-controllerpaint/CMakeLists.txt deleted file mode 100644 index 23e9ae78..00000000 --- a/samples/ndk-controllerpaint/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -# For more information about using CMake with Android Studio, read the -# documentation: https://d.android.com/studio/projects/add-native-code.html - -cmake_minimum_required(VERSION 3.4.1) - -# Configure the sample code. -file(GLOB native_srcs "src/main/jni/*.cc") -add_library(controllerpaint_jni - SHARED - ${native_srcs}) - -# Include the GVR headers & libraries. -include_directories(${GVR_INCLUDE}) - -add_library(gvr-lib SHARED IMPORTED) -set_target_properties( - gvr-lib - PROPERTIES IMPORTED_LOCATION ${GVR_LIBPATH}/${ANDROID_ABI}/libgvr.so) - -# Include general Android libraries. -find_library(android-lib android) -find_library(EGL-lib EGL) -find_library(GLESv2-lib GLESv2) -find_library(log-lib log) - -# Build final libcontrollerpaint_jni.so -target_link_libraries(controllerpaint_jni - gvr-lib - - ${android-lib} - ${EGL-lib} - ${GLESv2-lib} - ${log-lib} ) diff --git a/samples/ndk-controllerpaint/build.gradle b/samples/ndk-controllerpaint/build.gradle deleted file mode 100644 index 3c85f92d..00000000 --- a/samples/ndk-controllerpaint/build.gradle +++ /dev/null @@ -1,48 +0,0 @@ -apply plugin: 'com.android.application' - -android { - compileSdkVersion 26 - defaultConfig { - applicationId "com.google.vr.ndk.samples.controllerpaint" - minSdkVersion 24 - targetSdkVersion 24 - versionCode 1 - versionName "1.0" - externalNativeBuild { - cmake { - cppFlags "-std=gnu++11" - arguments "-DGVR_LIBPATH=${project.rootDir}/libraries/jni", - "-DGVR_INCLUDE=${project.rootDir}/libraries/headers" - } - } - buildTypes { - release { - minifyEnabled = true - proguardFiles.add(file("${project.rootDir}/proguard-gvr.txt")) - } - } - ndk { - // This sample builds all architectures by default. Note that if you - // only want to build for a specific architecture, you need to - // remove the appropriate lines below. You also need to remove the - // .so files from the apk using - // "packagingOptions {exclude('lib/armeabi-v7a/*')}" in the android - // section. - abiFilters "arm64-v8a" - abiFilters "armeabi-v7a" - abiFilters "x86" - } - } - externalNativeBuild { - cmake { - path "CMakeLists.txt" - } - } -} - - -dependencies { - compile 'com.google.vr:sdk-base:1.160.0' -} - -build.dependsOn(':extractNdk') diff --git a/samples/ndk-controllerpaint/src/main/AndroidManifest.xml b/samples/ndk-controllerpaint/src/main/AndroidManifest.xml deleted file mode 100644 index ad3e8734..00000000 --- a/samples/ndk-controllerpaint/src/main/AndroidManifest.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/ndk-controllerpaint/src/main/assets/ground_texture64x64.bin b/samples/ndk-controllerpaint/src/main/assets/ground_texture64x64.bin deleted file mode 100644 index 756dd10a..00000000 --- a/samples/ndk-controllerpaint/src/main/assets/ground_texture64x64.bin +++ /dev/null @@ -1 +0,0 @@ -ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸwwwwwwĻĻĻĻĻĻwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwĻĻĻĻĻĻwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻĻ \ No newline at end of file diff --git a/samples/ndk-controllerpaint/src/main/assets/paint_texture64x64.bin b/samples/ndk-controllerpaint/src/main/assets/paint_texture64x64.bin deleted file mode 100644 index 3ffe1ecc..00000000 --- a/samples/ndk-controllerpaint/src/main/assets/paint_texture64x64.bin +++ /dev/null @@ -1 +0,0 @@ -’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’ \ No newline at end of file diff --git a/samples/ndk-controllerpaint/src/main/java/com/google/vr/ndk/samples/controllerpaint/MainActivity.java b/samples/ndk-controllerpaint/src/main/java/com/google/vr/ndk/samples/controllerpaint/MainActivity.java deleted file mode 100644 index f7807a1d..00000000 --- a/samples/ndk-controllerpaint/src/main/java/com/google/vr/ndk/samples/controllerpaint/MainActivity.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright 2017 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.vr.ndk.samples.controllerpaint; - -import android.app.Activity; -import android.content.res.AssetManager; -import android.opengl.GLSurfaceView; -import android.os.Bundle; -import android.util.Log; -import android.view.KeyEvent; -import android.view.View; -import android.view.WindowManager; -import com.google.vr.ndk.base.AndroidCompat; -import com.google.vr.ndk.base.GvrLayout; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.opengles.GL10; - -/** - * A Google VR NDK sample application. - * - *

This app is a "paint program" that allows the user to paint in virtual space using the - * controller. A cursor shows where the controller is pointing at. Touching or clicking the touchpad - * begins drawing. Then, as the user moves their hand, lines are drawn. The user can switch the - * drawing color by swiping to the right or left on the touchpad. The user can also change the - * drawing stroke width by moving their finger up and down on the touchpad. - * - *

This is the main Activity for the sample application. It initializes a GLSurfaceView to allow - * rendering, a GvrLayout for GVR API access, and forwards relevant events to the native demo app - * instance where rendering and interaction are handled. - */ -public class MainActivity extends Activity { - private static final String TAG = "MainActivity"; - - static { - // Load our JNI code. - System.loadLibrary("controllerpaint_jni"); - } - - // Opaque native pointer to the DemoApp C++ object. - // This object is owned by the MainActivity instance and passed to the native methods. - private long nativeControllerPaint; - - private GvrLayout gvrLayout; - private GLSurfaceView surfaceView; - private AssetManager assetManager; - - // Note that pause and resume signals to the native app are performed on the GL thread, ensuring - // thread-safety. - private final Runnable pauseNativeRunnable = - new Runnable() { - @Override - public void run() { - nativeOnPause(nativeControllerPaint); - } - }; - - private final Runnable resumeNativeRunnable = - new Runnable() { - @Override - public void run() { - nativeOnResume(nativeControllerPaint); - } - }; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setImmersiveSticky(); - getWindow() - .getDecorView() - .setOnSystemUiVisibilityChangeListener( - new View.OnSystemUiVisibilityChangeListener() { - @Override - public void onSystemUiVisibilityChange(int visibility) { - if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { - setImmersiveSticky(); - } - } - }); - - // Enable VR mode, if the device supports it. - AndroidCompat.setVrModeEnabled(this, true); - - // Get the GvrLayout. - gvrLayout = new GvrLayout(this); - - // Enable async reprojection, if possible. - if (gvrLayout.setAsyncReprojectionEnabled(true)) { - Log.d(TAG, "Successfully enabled async reprojection."); - // Async reprojection decouples the app framerate from the display framerate, - // allowing immersive interaction even at the throttled clockrates set by - // sustained performance mode. - AndroidCompat.setSustainedPerformanceMode(this, true); - } else { - Log.w(TAG, "Failed to enable async reprojection."); - } - - // Configure the GLSurfaceView. - surfaceView = new GLSurfaceView(this); - surfaceView.setEGLContextClientVersion(2); - surfaceView.setEGLConfigChooser(8, 8, 8, 0, 0, 0); - surfaceView.setRenderer(renderer); - - // Note that we are not setting setPreserveEGLContextOnPause(true) here, - // even though it is recommended. This is done so that we have at least - // one demo that provides some testing coverage for no-preserve contexts. - - // Set the GLSurfaceView as the GvrLayout's presentation view. - gvrLayout.setPresentationView(surfaceView); - - // Add the GvrLayout to the View hierarchy. - setContentView(gvrLayout); - - assetManager = getResources().getAssets(); - - nativeControllerPaint = - nativeOnCreate(assetManager, gvrLayout.getGvrApi().getNativeGvrContext()); - - // Prevent screen from dimming/locking. - getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - // Destruction order is important; shutting down the GvrLayout will detach - // the GLSurfaceView and stop the GL thread, allowing safe shutdown of - // native resources from the UI thread. - gvrLayout.shutdown(); - nativeOnDestroy(nativeControllerPaint); - nativeControllerPaint = 0; - } - - @Override - protected void onPause() { - surfaceView.queueEvent(pauseNativeRunnable); - surfaceView.onPause(); - gvrLayout.onPause(); - super.onPause(); - } - - @Override - protected void onResume() { - super.onResume(); - gvrLayout.onResume(); - surfaceView.onResume(); - surfaceView.queueEvent(resumeNativeRunnable); - } - - @Override - public void onBackPressed() { - super.onBackPressed(); - gvrLayout.onBackPressed(); - } - - @Override - public void onWindowFocusChanged(boolean hasFocus) { - super.onWindowFocusChanged(hasFocus); - if (hasFocus) { - setImmersiveSticky(); - } - } - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - // Avoid accidental volume key presses while the phone is in the VR headset. - if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP - || event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN) { - return true; - } - return super.dispatchKeyEvent(event); - } - - private void setImmersiveSticky() { - getWindow() - .getDecorView() - .setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); - } - - private final GLSurfaceView.Renderer renderer = - new GLSurfaceView.Renderer() { - @Override - public void onSurfaceCreated(GL10 gl, EGLConfig config) { - nativeOnSurfaceCreated(nativeControllerPaint); - } - - @Override - public void onSurfaceChanged(GL10 gl, int width, int height) { - nativeOnSurfaceChanged(width, height, nativeControllerPaint); - } - - @Override - public void onDrawFrame(GL10 gl) { - nativeOnDrawFrame(nativeControllerPaint); - } - }; - - private native long nativeOnCreate(AssetManager assetManager, long gvrContextPtr); - private native void nativeOnDestroy(long controllerPaintJptr); - private native void nativeOnResume(long controllerPaintJptr); - private native void nativeOnPause(long controllerPaintJptr); - private native void nativeOnSurfaceCreated(long controllerPaintJptr); - private native void nativeOnSurfaceChanged(int width, int height, long controllerPaintJptr); - private native void nativeOnDrawFrame(long controllerPaintJptr); -} diff --git a/samples/ndk-controllerpaint/src/main/jni/app_jni.cc b/samples/ndk-controllerpaint/src/main/jni/app_jni.cc deleted file mode 100644 index 9185459c..00000000 --- a/samples/ndk-controllerpaint/src/main/jni/app_jni.cc +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2017 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "app_jni.h" // NOLINT - -#include - -#include "demoapp.h" // NOLINT -#include "utils.h" // NOLINT - -namespace { -inline jlong jptr(DemoApp* ptr) { return reinterpret_cast(ptr); } - -inline DemoApp* ptr(jlong jptr) { return reinterpret_cast(jptr); } - -} // namespace - -NATIVE_METHOD(jlong, nativeOnCreate) -(JNIEnv* env, jobject obj, jobject asset_mgr, jlong gvr_context_ptr) { - return jptr(new DemoApp(env, asset_mgr, gvr_context_ptr)); -} - -NATIVE_METHOD(void, nativeOnResume) -(JNIEnv* env, jobject obj, jlong controller_paint_jptr) { - ptr(controller_paint_jptr)->OnResume(); -} - -NATIVE_METHOD(void, nativeOnPause) -(JNIEnv* env, jobject obj, jlong controller_paint_jptr) { - ptr(controller_paint_jptr)->OnPause(); -} - -NATIVE_METHOD(void, nativeOnSurfaceCreated) -(JNIEnv* env, jobject obj, jlong controller_paint_jptr) { - ptr(controller_paint_jptr)->OnSurfaceCreated(); -} - -NATIVE_METHOD(void, nativeOnSurfaceChanged) -(JNIEnv* env, jobject obj, jint width, jint height, - jlong controller_paint_jptr) { - ptr(controller_paint_jptr) - ->OnSurfaceChanged(static_cast(width), static_cast(height)); -} - -NATIVE_METHOD(void, nativeOnDrawFrame) -(JNIEnv* env, jobject obj, jlong controller_paint_jptr) { - ptr(controller_paint_jptr)->OnDrawFrame(); -} - -NATIVE_METHOD(void, nativeOnDestroy) -(JNIEnv* env, jobject obj, jlong controller_paint_jptr) { - delete ptr(controller_paint_jptr); -} - diff --git a/samples/ndk-controllerpaint/src/main/jni/app_jni.h b/samples/ndk-controllerpaint/src/main/jni/app_jni.h deleted file mode 100644 index 518c1514..00000000 --- a/samples/ndk-controllerpaint/src/main/jni/app_jni.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2017 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CONTROLLER_PAINT_APP_SRC_MAIN_JNI_APP_JNI_H_ // NOLINT -#define CONTROLLER_PAINT_APP_SRC_MAIN_JNI_APP_JNI_H_ - -#include -#include - -#define NATIVE_METHOD(return_type, method_name) \ - JNIEXPORT return_type JNICALL \ - Java_com_google_vr_ndk_samples_controllerpaint_MainActivity_##method_name - -extern "C" { - -NATIVE_METHOD(jlong, nativeOnCreate) -(JNIEnv* env, jobject obj, jobject asset_mgr, jlong gvrContextPtr); -NATIVE_METHOD(void, nativeOnResume) -(JNIEnv* env, jobject obj, jlong controller_paint_jptr); -NATIVE_METHOD(void, nativeOnPause) -(JNIEnv* env, jobject obj, jlong controller_paint_jptr); -NATIVE_METHOD(void, nativeOnSurfaceCreated) -(JNIEnv* env, jobject obj, jlong controller_paint_jptr); -NATIVE_METHOD(void, nativeOnSurfaceChanged) -(JNIEnv* env, jobject obj, jint width, jint height, - jlong controller_paint_jptr); -NATIVE_METHOD(void, nativeOnDrawFrame) -(JNIEnv* env, jobject obj, jlong controller_paint_jptr); -NATIVE_METHOD(void, nativeOnDestroy) -(JNIEnv* env, jobject obj, jlong controller_paint_jptr); -} - -#endif // CONTROLLER_PAINT_APP_SRC_MAIN_JNI_APP_JNI_H_ // NOLINT diff --git a/samples/ndk-controllerpaint/src/main/jni/demoapp.cc b/samples/ndk-controllerpaint/src/main/jni/demoapp.cc deleted file mode 100644 index 77530747..00000000 --- a/samples/ndk-controllerpaint/src/main/jni/demoapp.cc +++ /dev/null @@ -1,615 +0,0 @@ -/* - * Copyright 2017 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "demoapp.h" // NOLINT - -#include -#include -#include -#include - -#include "utils.h" // NOLINT - -namespace { - -// If true, requires the click button for painting. If false, the user can -// paint by simply touching the touchpad. -static const bool kRequireClickToPaint = true; - -// Near and far clipping planes. -static const float kNearClip = 0.01f; -static const float kFarClip = 100.0f; - -// The distance at which we paint. -static const float kDefaultPaintDistance = 2.0f; - -// File name for the paint texture. This is stored in the app's assets. -// The paint texture is stored in raw RGB format, with each three bytes -// encoding a pixel (the first byte is R, the second is G, the third is B). -static const char kPaintTexturePath[] = "paint_texture64x64.bin"; -static const char kGroundTexturePath[] = "ground_texture64x64.bin"; - -// Width and height of the paint texture, in pixels. -static const int kPaintTextureWidth = 64; -static const int kPaintTextureHeight = 64; -static const int kGroundTextureWidth = 64; -static const int kGroundTextureHeight = 64; - -// Colors (R, G, B). -static const std::array kSkyColor = Utils::ColorFromHex(0xff131e35); -static const std::array kGroundColor = - Utils::ColorFromHex(0xff172644); -static const std::array kCursorBorderColor = - { 1.0f, 1.0f, 1.0f, 1.0f }; - -// Vertex shader. -static const char* kPaintShaderVp = - "uniform mat4 u_MVP;\n" - "attribute vec4 a_Position;\n" - "attribute vec2 a_TexCoords;\n" - "varying vec2 v_TexCoords;\n" - "void main() {\n" - " gl_Position = u_MVP * a_Position;\n" - " v_TexCoords = a_TexCoords;\n" - "}\n"; - -// Fragment shader. -static const char* kPaintShaderFp = - "precision mediump float;\n" - "uniform vec4 u_Color;\n" - "varying vec2 v_TexCoords;\n" - "uniform sampler2D u_Sampler;\n" - "void main() {\n" - " gl_FragColor = u_Color * texture2D(u_Sampler, vec2(\n" - " fract(v_TexCoords.s), fract(v_TexCoords.t)));\n" - "}\n"; - -// In geometry data, this is the offset where texture coordinates start. -static int kGeomTexCoordOffset = 3; // in elements, not bytes. - -// In geometry data, this is how many bytes we skip ahead to get to the -// data about the next vertex (3 floats for vertex coords, 2 for texture -// coords). -static int kGeomDataStride = 5 * sizeof(float); - -// Repetitions of the ground texture. -static float kGroundTexRepeat = 20.0f; - -// Size of the ground plane. -static float kGroundSize = 30.0f; - -// Y coordinate of the ground plane, in meters. If this (and other distances) -// are too far, 6DOF tracking will have no visible effect. -static float kDefaultGroundY = -2.0f; - -// Geometry of the ground plane. -static float kGroundGeom[] = { - // Data is X, Y, Z (vertex coords), S, T (texture coords). - kGroundSize, 0.0f, -kGroundSize, kGroundTexRepeat, 0.0f, - -kGroundSize, 0.0f, -kGroundSize, 0.0f, 0.0f, - -kGroundSize, 0.0f, kGroundSize, 0.0f, kGroundTexRepeat, - kGroundSize, 0.0f, -kGroundSize, kGroundTexRepeat, 0.0f, - -kGroundSize, 0.0f, kGroundSize, 0.0f, kGroundTexRepeat, - kGroundSize, 0.0f, kGroundSize, kGroundTexRepeat, kGroundTexRepeat, -}; -static int kGroundVertexCount = 6; - -// Size of the cursor. -static float kCursorScale = 0.01f; - -// Geometry of the cursor. -static float kCursorGeom[] = { - // Data is X, Y, Z (vertex coords), S, T (texture coords). - kCursorScale, kCursorScale, 0.0f, 1.0f, 0.0f, - -kCursorScale, kCursorScale, 0.0f, 0.0f, 0.0f, - -kCursorScale, -kCursorScale, 0.0f, 0.0f, 1.0f, - kCursorScale, kCursorScale, 0.0f, 1.0f, 0.0f, - -kCursorScale, -kCursorScale, 0.0f, 0.0f, 1.0f, - kCursorScale, -kCursorScale, 0.0f, 1.0f, 1.0f, -}; -static int kCursorVertexCount = 6; - -// Available colors the user can paint with. -static const std::array, 10> kColors = { - Utils::ColorFromHex(0xa029b6f6), // light blue - Utils::ColorFromHex(0xa0338400), // green - Utils::ColorFromHex(0xa0845f00), // brown - Utils::ColorFromHex(0xa0c13100), // red - Utils::ColorFromHex(0xa0c100ae), // pink - Utils::ColorFromHex(0xa06700c1), // violet - Utils::ColorFromHex(0xa0003ac1), // blue - Utils::ColorFromHex(0xa000aec1), // light blue - Utils::ColorFromHex(0xa09d9d9d), // gray - Utils::ColorFromHex(0xa0e0e0e0), // white -}; - -// When the user moves their finger horizontally by more than this -// threshold distance, we switch colors. -// This is given as a fraction of the touch pad. -static const float kColorSwitchThreshold = 0.4f; - -// Maximum number of drawn vertices to allow a color switch. -// If more than this number of vertices have been drawn, then a color -// switch gesture is forbidden. -static const int kMaxVerticesForColorSwitch = 10; - -// Prediction time to use when estimating head pose. -static const int64_t kPredictionTimeWithoutVsyncNanos = 50000000; // 50ms - -// Minimum length of any paint segment. If the user tries to draw something -// smaller than this length, it is ignored. -static const float kMinPaintSegmentLength = 0.04f; - -// When the number of vertices in the recently drawn geometry exceeds this -// number, we commit the geometry to the GPU as a VBO. -static const int kVboCommitThreshold = 50; - -// Minimum and maximum stroke widths. -static const float kMinStrokeWidth = 0.015f; -static const float kMaxStrokeWidth = 0.04f; - -} // namespace - -DemoApp::DemoApp(JNIEnv* env, jobject asset_mgr_obj, jlong gvr_context_ptr) - : // This is the GVR context pointer obtained from Java: - gvr_context_(reinterpret_cast(gvr_context_ptr)), - // Wrap the gvr_context* into a GvrApi C++ object for convenience: - gvr_api_(gvr::GvrApi::WrapNonOwned(gvr_context_)), - gvr_api_initialized_(false), - viewport_list_(gvr_api_->CreateEmptyBufferViewportList()), - scratch_viewport_(gvr_api_->CreateBufferViewport()), - shader_(-1), - shader_u_color_(-1), - shader_u_mvp_matrix_(-1), - shader_u_sampler_(-1), - shader_a_position_(-1), - shader_a_texcoords_(-1), - ground_texture_(-1), - paint_texture_(-1), - asset_mgr_(AAssetManager_fromJava(env, asset_mgr_obj)), - recent_geom_vertex_count_(0), - brush_stroke_total_vertices_(0), - selected_color_(0), - painting_(false), - has_continuation_(false), - switched_color_(false), - stroke_width_(kMinStrokeWidth) { - CHECK(asset_mgr_); - LOGD("DemoApp initialized."); -} - -DemoApp::~DemoApp() { - LOGD("DemoApp shutdown."); -} - -void DemoApp::OnResume() { - LOGD("DemoApp::OnResume"); - if (gvr_api_initialized_) { - gvr_api_->RefreshViewerProfile(); - gvr_api_->ResumeTracking(); - } - if (controller_api_) controller_api_->Resume(); -} - -void DemoApp::OnPause() { - LOGD("DemoApp::OnPause"); - // The GL context is not preserved when pausing. Delete the drawing VBOs to - // avoid dangling GL object IDs. - ClearDrawing(); - if (gvr_api_initialized_) gvr_api_->PauseTracking(); - if (controller_api_) controller_api_->Pause(); -} - -void DemoApp::OnSurfaceCreated() { - LOGD("DemoApp::OnSurfaceCreated"); - - LOGD("Initializing GL on GvrApi."); - gvr_api_->InitializeGl(); - - LOGD("Initializing ControllerApi."); - controller_api_.reset(new gvr::ControllerApi); - CHECK(controller_api_); - CHECK(controller_api_->Init(gvr::ControllerApi::DefaultOptions(), - gvr_context_)); - controller_api_->Resume(); - - LOGD("Initializing framebuffer."); - std::vector specs; - specs.push_back(gvr_api_->CreateBufferSpec()); - framebuf_size_ = gvr_api_->GetMaximumEffectiveRenderTargetSize(); - // Because we are using 2X MSAA, we can render to half as many pixels and - // achieve similar quality. Scale each dimension by sqrt(2)/2 ~= 7/10ths. - framebuf_size_.width = (7 * framebuf_size_.width) / 10; - framebuf_size_.height = (7 * framebuf_size_.height) / 10; - - specs[0].SetSize(framebuf_size_); - specs[0].SetColorFormat(GVR_COLOR_FORMAT_RGBA_8888); - specs[0].SetDepthStencilFormat(GVR_DEPTH_STENCIL_FORMAT_DEPTH_16); - specs[0].SetSamples(2); - swapchain_.reset(new gvr::SwapChain(gvr_api_->CreateSwapChain(specs))); - - LOGD("Compiling shaders."); - int vp = Utils::BuildShader(GL_VERTEX_SHADER, kPaintShaderVp); - int fp = Utils::BuildShader(GL_FRAGMENT_SHADER, kPaintShaderFp); - shader_ = Utils::BuildProgram(vp, fp); - shader_u_color_ = glGetUniformLocation(shader_, "u_Color"); - shader_u_mvp_matrix_ = glGetUniformLocation(shader_, "u_MVP"); - shader_u_sampler_ = glGetUniformLocation(shader_, "u_Sampler"); - shader_a_position_ = glGetAttribLocation(shader_, "a_Position"); - shader_a_texcoords_ = glGetAttribLocation(shader_, "a_TexCoords"); - CHECK(glGetError() == GL_NO_ERROR); - - LOGD("Loading textures."); - paint_texture_ = Utils::LoadRawTextureFromAsset( - asset_mgr_, kPaintTexturePath, kPaintTextureWidth, kPaintTextureHeight); - ground_texture_ = Utils::LoadRawTextureFromAsset( - asset_mgr_, kGroundTexturePath, kGroundTextureWidth, - kGroundTextureHeight); - - CHECK(glGetError() == GL_NO_ERROR); - gvr_api_initialized_ = true; - - - LOGD("Init complete."); -} - -void DemoApp::OnSurfaceChanged(int width, int height) { - LOGD("DemoApp::OnSurfaceChanged %dx%d", width, height); -} - -void DemoApp::OnDrawFrame() { - PrepareFramebuffer(); - - // Enable blending so we get a transparency effect. - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - - viewport_list_.SetToRecommendedBufferViewports(); - gvr::ClockTimePoint pred_time = gvr::GvrApi::GetTimePointNow(); - pred_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos; - - gvr::Mat4f head_view = - gvr_api_->GetHeadSpaceFromStartSpaceTransform(pred_time); - const gvr::Mat4f left_eye_view = - Utils::MatrixMul(gvr_api_->GetEyeFromHeadMatrix(GVR_LEFT_EYE), - head_view); - const gvr::Mat4f right_eye_view = - Utils::MatrixMul(gvr_api_->GetEyeFromHeadMatrix(GVR_RIGHT_EYE), - head_view); - - const int32_t old_status = controller_state_.GetApiStatus(); - const int32_t old_connection_state = controller_state_.GetConnectionState(); - - const gvr::ControllerBatteryLevel old_battery_level = - controller_state_.GetBatteryLevel(); - const bool old_battery_charging = - controller_state_.GetBatteryCharging(); - - // Read current controller state. - controller_state_.Update(*controller_api_); - - // Print new API status and connection state, if they changed. - if (controller_state_.GetApiStatus() != old_status || - controller_state_.GetConnectionState() != old_connection_state) { - LOGD("DemoApp: controller API status: %s, connection state: %s", - gvr_controller_api_status_to_string(controller_state_.GetApiStatus()), - gvr_controller_connection_state_to_string( - controller_state_.GetConnectionState())); - } - // Print new controller battery level and charging state, if they changed. - if (controller_state_.GetBatteryLevel() != old_battery_level || - controller_state_.GetBatteryCharging() != old_battery_charging) { - LOGD("DemoApp: controller battery level: %s, charging: %s", - gvr::ControllerApi::ToString(controller_state_.GetBatteryLevel()), - controller_state_.GetBatteryCharging() ? "true" : "false"); - } - - gvr::Frame frame = swapchain_->AcquireFrame(); - frame.BindBuffer(0); - - glClearColor(kSkyColor[0], kSkyColor[1], kSkyColor[2], 1.0f); - viewport_list_.GetBufferViewport(0, &scratch_viewport_); - DrawEye(GVR_LEFT_EYE, left_eye_view, scratch_viewport_); - viewport_list_.GetBufferViewport(1, &scratch_viewport_); - DrawEye(GVR_RIGHT_EYE, right_eye_view, scratch_viewport_); - frame.Unbind(); - frame.Submit(viewport_list_, head_view); -} - -void DemoApp::PrepareFramebuffer() { - gvr::Sizei recommended_size = gvr_api_->GetMaximumEffectiveRenderTargetSize(); - // Because we are using 2X MSAA, we can render to half as many pixels and - // achieve similar quality. Scale each dimension by sqrt(2)/2 ~= 7/10ths. - recommended_size.width = (7 * recommended_size.width) / 10; - recommended_size.height = (7 * recommended_size.height) / 10; - if (framebuf_size_.width != recommended_size.width || - framebuf_size_.height != recommended_size.height) { - // We need to resize the framebuffer. - swapchain_->ResizeBuffer(0, recommended_size); - framebuf_size_ = recommended_size; - } -} - -void DemoApp::CheckColorSwitch() { - if (switched_color_ || !controller_state_.IsTouching()) return; - float x_diff = fabs(controller_state_.GetTouchPos().x - touch_down_x_); - if (x_diff < kColorSwitchThreshold) return; - if (brush_stroke_total_vertices_ > kMaxVerticesForColorSwitch) return; - if (controller_state_.GetTouchPos().x > touch_down_x_) { - selected_color_ = (selected_color_ + 1) % kColors.size(); - } else { - selected_color_ = selected_color_ == 0 ? kColors.size() - 1 : - selected_color_ - 1; - } - switched_color_ = true; -} - -void DemoApp::CheckChangeStrokeWidth() { - if (!controller_state_.IsTouching()) return; - float delta_y = controller_state_.GetTouchPos().y - touch_down_y_; - float delta_width = -delta_y * (kMaxStrokeWidth - kMinStrokeWidth); - stroke_width_ = touch_down_stroke_width_ + delta_width; - stroke_width_ = stroke_width_ < kMinStrokeWidth ? kMinStrokeWidth : - stroke_width_ > kMaxStrokeWidth ? kMaxStrokeWidth : stroke_width_; -} - -void DemoApp::DrawEye(gvr::Eye which_eye, const gvr::Mat4f& eye_view_matrix, - const gvr::BufferViewport& viewport) { - Utils::SetUpViewportAndScissor(framebuf_size_, viewport); - - gvr::Mat4f proj_matrix = - Utils::PerspectiveMatrixFromView(viewport.GetSourceFov(), kNearClip, - kFarClip); - - // Figure out the point the cursor is pointing to. - const gvr::Mat4f cursor_mat = - Utils::ControllerQuatToMatrix(controller_state_.GetOrientation()); - const std::array neutral_pos = { 0, 0, -kDefaultPaintDistance }; - const std::array target_pos = Utils::MatrixVectorMul( - cursor_mat, neutral_pos); - - bool paint_button_down = - kRequireClickToPaint - ? controller_state_.GetButtonDown(gvr::kControllerButtonClick) - : controller_state_.GetTouchDown(); - bool paint_button_up = - kRequireClickToPaint - ? controller_state_.GetButtonUp(gvr::kControllerButtonClick) - : controller_state_.GetTouchUp(); - - if (paint_button_down) { - StartPainting(target_pos); - } else if (paint_button_up) { - StopPainting(true); - } - - if (controller_state_.GetTouchDown()) { - touch_down_x_ = controller_state_.GetTouchPos().x; - touch_down_y_ = controller_state_.GetTouchPos().y; - touch_down_stroke_width_ = stroke_width_; - } else if (controller_state_.GetTouchUp()) { - switched_color_ = false; - } - - if (!painting_ && - controller_state_.GetButtonDown(gvr::kControllerButtonApp)) { - ClearDrawing(); - } - - CheckColorSwitch(); - CheckChangeStrokeWidth(); - - if (painting_) { - const float dist = Utils::VecNorm( - Utils::VecAdd(1, paint_anchor_, -1, target_pos)); - if (dist > kMinPaintSegmentLength) { - AddPaintSegment(paint_anchor_, target_pos); - paint_anchor_ = target_pos; - } - } - - glUseProgram(shader_); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, ground_texture_); - DrawGround(eye_view_matrix, proj_matrix); - glBindTexture(GL_TEXTURE_2D, paint_texture_); - DrawPaintedGeometry(eye_view_matrix, proj_matrix); - DrawCursor(eye_view_matrix, proj_matrix); - - CHECK(glGetError() == GL_NO_ERROR); -} - -void DemoApp::AddVertex(const std::array& coords, float u, float v) { - ++recent_geom_vertex_count_; - ++brush_stroke_total_vertices_; - recent_geom_.push_back(coords[0]); - recent_geom_.push_back(coords[1]); - recent_geom_.push_back(coords[2]); - recent_geom_.push_back(u); - recent_geom_.push_back(v); -} - -void DemoApp::AddPaintSegment(const std::array& start_point, - const std::array& end_point) { - std::array to_end = Utils::VecAdd(1, end_point, -1, start_point); - std::array cross = Utils::VecNormalize( - Utils::VecCrossProd(start_point, to_end)); - - std::array start_top; - std::array start_bottom; - - if (has_continuation_) { - // Continue from where we left off to form a continuous shape. - start_top = continuation_points_[0]; - start_bottom = continuation_points_[1]; - } else { - // Start of a new shape. - start_top = Utils::VecAdd(1, start_point, stroke_width_, cross); - start_bottom = Utils::VecAdd(1, start_point, -stroke_width_, cross); - } - - const std::array end_top = Utils::VecAdd( - 1, end_point, stroke_width_, cross); - const std::array end_bottom = Utils::VecAdd( - 1, end_point, -stroke_width_, cross); - AddVertex(start_top, 0.0f, 0.0f); - AddVertex(start_bottom, 0.0f, 1.0f); - AddVertex(end_top, 1.0f, 0.0f); - AddVertex(start_bottom, 0.0f, 1.0f); - AddVertex(end_bottom, 1.0f, 1.0f); - AddVertex(end_top, 1.0f, 0.0f); - if (recent_geom_vertex_count_ > kVboCommitThreshold) { - CommitToVbo(); - } - - has_continuation_ = true; - continuation_points_[0] = end_top; - continuation_points_[1] = end_bottom; -} - -void DemoApp::StartPainting(const std::array paint_start_pos) { - if (painting_) return; - painting_ = true; - paint_anchor_ = paint_start_pos; -} - -void DemoApp::StopPainting(bool commit_cur_segment) { - if (!painting_) return; - if (commit_cur_segment) { - CommitToVbo(); - } - recent_geom_.clear(); - recent_geom_vertex_count_ = 0; - painting_ = false; - has_continuation_ = false; - brush_stroke_total_vertices_ = 0; -} - -void DemoApp::ClearDrawing() { - for (auto it : committed_vbos_) { - glDeleteBuffers(1, &it.vbo); - } - committed_vbos_.clear(); -} - -void DemoApp::DrawObject(const gvr::Mat4f& mvp, - const std::array& color, const float* data, - GLuint vbo, int vertex_count) { - if (!data) { - // Use VBO. - glBindBuffer(GL_ARRAY_BUFFER, vbo); - } - - glUniform1i(shader_u_sampler_, 0); // texture unit 0 - glUniformMatrix4fv(shader_u_mvp_matrix_, 1, GL_FALSE, - Utils::MatrixToGLArray(mvp).data()); - glUniform4f(shader_u_color_, color[0], color[1], color[2], color[3]); - glEnableVertexAttribArray(shader_a_position_); - glEnableVertexAttribArray(shader_a_texcoords_); - glVertexAttribPointer(shader_a_position_, 3, GL_FLOAT, false, - kGeomDataStride, data); - glVertexAttribPointer(shader_a_texcoords_, 2, GL_FLOAT, false, - kGeomDataStride, data + kGeomTexCoordOffset); - glDrawArrays(GL_TRIANGLES, 0, vertex_count); - glDisableVertexAttribArray(shader_a_position_); - glDisableVertexAttribArray(shader_a_texcoords_); - - if (!data) { - glBindBuffer(GL_ARRAY_BUFFER, 0); - } -} - -void DemoApp::DrawGround(const gvr::Mat4f& view_matrix, - const gvr::Mat4f& proj_matrix) { - gvr::Value floor_height; - // This may change when the floor height changes so it's computed every frame. - float ground_y = gvr_api_->GetCurrentProperties().Get( - GVR_PROPERTY_TRACKING_FLOOR_HEIGHT, &floor_height) - ? floor_height.f - : kDefaultGroundY; - const gvr::Mat4f ground_model_matrix = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, ground_y, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, - }; - - gvr::Mat4f mv = Utils::MatrixMul(view_matrix, ground_model_matrix); - gvr::Mat4f mvp = Utils::MatrixMul(proj_matrix, mv); - - DrawObject(mvp, kGroundColor, kGroundGeom, 0, kGroundVertexCount); -} - -void DemoApp::DrawPaintedGeometry(const gvr::Mat4f& view_matrix, - const gvr::Mat4f& proj_matrix) { - gvr::Mat4f mv = view_matrix; - gvr::Mat4f mvp = Utils::MatrixMul(proj_matrix, mv); - - // Draw committed VBOs. - for (auto it : committed_vbos_) { - DrawObject(mvp, kColors[it.color], 0, it.vbo, it.vertex_count); - } - - // Draw recent geometry (directly from main memory). - if (recent_geom_vertex_count_ > 0) { - DrawObject(mvp, kColors[selected_color_], recent_geom_.data(), 0, - recent_geom_vertex_count_); - } -} - -void DemoApp::CommitToVbo() { - // Only commit if we have at least a triangle. - if (recent_geom_vertex_count_ > 2) { - VboInfo info; - glGenBuffers(1, &info.vbo); - glBindBuffer(GL_ARRAY_BUFFER, info.vbo); - glBufferData(GL_ARRAY_BUFFER, recent_geom_.size() * sizeof(float), - recent_geom_.data(), GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - info.vertex_count = recent_geom_vertex_count_; - info.color = selected_color_; - committed_vbos_.push_back(info); - } - recent_geom_.clear(); - recent_geom_vertex_count_ = 0; -} - -void DemoApp::DrawCursorRect(float scale, const std::array color, - const gvr::Mat4f& view_matrix, - const gvr::Mat4f& proj_matrix) { - gvr::Mat4f neutral_matrix = { - scale, 0.0f, 0.0f, 0.0f, 0.0f, scale, - 0.0f, 0.0f, 0.0f, 0.0f, scale, -kDefaultPaintDistance, - 0.0f, 0.0f, 0.0f, 1.0f, - }; - gvr::Mat4f controller_matrix = - Utils::ControllerQuatToMatrix(controller_state_.GetOrientation()); - gvr::Mat4f model_matrix = Utils::MatrixMul(controller_matrix, neutral_matrix); - gvr::Mat4f mv = Utils::MatrixMul(view_matrix, model_matrix); - gvr::Mat4f mvp = Utils::MatrixMul(proj_matrix, mv); - DrawObject(mvp, color, kCursorGeom, 0, kCursorVertexCount); -} - -void DemoApp::DrawCursor(const gvr::Mat4f& view_matrix, - const gvr::Mat4f& proj_matrix) { - float scale = stroke_width_ / kMinStrokeWidth; - DrawCursorRect(scale * 1.50f, kCursorBorderColor, view_matrix, proj_matrix); - DrawCursorRect(scale * 1.25f, { 0.0f, 0.0f, 0.0f, 1.0f }, view_matrix, - proj_matrix); - DrawCursorRect(scale * 1.00f, kColors[selected_color_], view_matrix, - proj_matrix); -} - diff --git a/samples/ndk-controllerpaint/src/main/jni/demoapp.h b/samples/ndk-controllerpaint/src/main/jni/demoapp.h deleted file mode 100644 index c6d09b4e..00000000 --- a/samples/ndk-controllerpaint/src/main/jni/demoapp.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright 2017 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CONTROLLER_PAINT_APP_SRC_MAIN_JNI_DEMOAPP_H_ // NOLINT -#define CONTROLLER_PAINT_APP_SRC_MAIN_JNI_DEMOAPP_H_ - -#include -#include -#include - -#include -#include // NOLINT -#include -#include - -#include "vr/gvr/capi/include/gvr.h" -#include "vr/gvr/capi/include/gvr_controller.h" - -// This demo app is a "paint program" that allows the user to paint in -// virtual space using the controller. A cursor shows where the controller -// is pointing at. Touching or clicking the touchpad begins drawing. -// Then, as the user moves their hand, lines are drawn. The user can switch -// the drawing color by swiping to the right or left on the touchpad. -// The user can also change the drawing stroke width by moving their finger -// up and down on the touchpad. -// -// This demo uses GvrApi and ControllerApi and shows how to use -// them together. -class DemoApp { - public: - // Initializes the demo app. - // |asset_manager| is the Android Asset Manager obtained from Java. - // |gvr_context_ptr| a jlong representing a pointer to the GVR context - // obtained from Java. - DemoApp(JNIEnv* env, jobject asset_manager, jlong gvr_context_ptr); - ~DemoApp(); - // Must be called when the Activity gets onResume(). - // Must be called on the UI thread. - void OnResume(); - // Must be called when the Activity gets onPause(). - // Must be called on the UI thread. - void OnPause(); - // Must be called when the GL renderer gets onSurfaceCreated(). - // Must be called on the rendering thread. - void OnSurfaceCreated(); - // Must be called when the GL renderer gets onSurfaceChanged(). - // Must be called on the rendering thread. - void OnSurfaceChanged(int width, int height); - // Must be called when the GL renderer gets onDrawFrame(). - // Must be called on the rendering thread. - void OnDrawFrame(); - - private: - // Quick explanation of the implementation: - // - // When the user paints, we generate geometry (a series of connected - // triangles). - // - // When the user starts painting, we accumulate the new geometry - // (vertices and texture coordinates) in the |recent_geom_| array. - // When that gets too crowded (exceeds a threshold number of vertices), - // we commit the geometry to the GPU using a VBO (Vertex Buffer Object). - // From then on, that piece of geometry resides in the GPU and can be - // rendered quickly without us needing to push it down the bus from - // CPU to GPU on every frame. - - // Prepares the GvrApi framebuffer for rendering, resizing if needed. - void PrepareFramebuffer(); - - // Draws the image for the indicated eye. - void DrawEye(gvr::Eye which_eye, const gvr::Mat4f& eye_view_matrix, - const gvr::BufferViewport& params); - - // Draws the ground plane below the player. - void DrawGround(const gvr::Mat4f& view_matrix, const gvr::Mat4f& proj_matrix); - - // Draws the cursor that indicates where the controller is pointing. - // This method obtains the current cursor orientation from - // |controller_state_|, which is assumed to be up to date. - void DrawCursor(const gvr::Mat4f& view_matrix, const gvr::Mat4f& proj_matrix); - - // Draws a rectangle. The cursor is made of several rectangles. - void DrawCursorRect(float scale, const std::array color, - const gvr::Mat4f& view_matrix, - const gvr::Mat4f& proj_matrix); - - // Adds a new segment to the geometry currently being drawn. The new - // segment will be created in such a way that is connects to the - // last created paint segment to produce the effect of a continuous - // brush stroke. - void AddPaintSegment(const std::array& start_point, - const std::array& end_point); - - // Starts painting. This means that as the cursor moves, new geometry - // will be created to represent the brush stroke. - void StartPainting(const std::array paint_start_pos); - - // Stops painting. This means that the cursor's motion will cease to - // create new geometry. - void StopPainting(bool commit_cur_segment); - - // Adds a single vertex to the geometry. - void AddVertex(const std::array& coords, float u, float v); - - // Renders all the geometry the user painted, including the recent - // uncommitted geometry and the committed VBOs. - void DrawPaintedGeometry(const gvr::Mat4f& view_matrix, - const gvr::Mat4f& proj_matrix); - - // Pushes the current geometry to the GPU in the form of a VBO. This - // does not mean painting needs to stop: it just offloads vertices - // to the GPU for performance. If painting was active, it continues - // normally. - void CommitToVbo(); - - // Draws a single object, which may have its geometry specified via a regular - // pointer, or as a VBO handle. - // - // @param mvp The model-view-projection matrix to use. - // @param color The color to use. - // @param data If non-NULL, points to the data to draw. - // If this is NULL, then this method will use a VBO to draw. - // @param vbo If data == NULL, this is the VBO to use. - // @param vertex_count The number of vertices to draw. - void DrawObject(const gvr::Mat4f& mvp, const std::array& color, - const float* data, GLuint vbo, int vertex_count); - - // Checks if the user performed the "switch color" gesture and switches - // color, if applicable. - void CheckColorSwitch(); - - // Checks if the user wants to change the stroke width. - void CheckChangeStrokeWidth(); - - // Clears the whole drawing. - void ClearDrawing(); - - // Gvr API entry point. - gvr_context* gvr_context_; - std::unique_ptr gvr_api_; - bool gvr_api_initialized_; - - // Controller API entry point. - std::unique_ptr controller_api_; - - // Handle to the swapchain. On every frame, we have to check if the buffers - // are still the right size for the frame (since they can be resized at any - // time). This is done by PrepareFramebuffer(). - std::unique_ptr swapchain_; - - // List of rendering params (used to render each eye). - gvr::BufferViewportList viewport_list_; - gvr::BufferViewport scratch_viewport_; - - // Size of the offscreen framebuffer. - gvr::Sizei framebuf_size_; - - // The shader we use to render our geometry. Since this is a very simple - // demo, we use only one shader. - int shader_; - - // Uniform/attrib locations in the shader. These are looked up after we - // compile/link the shader. - int shader_u_color_; - int shader_u_mvp_matrix_; // Model-view-projection matrix. - int shader_u_sampler_; - int shader_a_position_; - int shader_a_texcoords_; - - // Ground texture. - int ground_texture_; - - // Paint texture. This is the texture we use for painting. - int paint_texture_; - - // Android asset manager (we use it to load the texture). - AAssetManager* asset_mgr_; - - // The last controller state (updated once per frame). - gvr::ControllerState controller_state_; - - // The vertex and texture coordinates representing recently painted geometry. - // As this array grows beyond a certain limit, we commit that geometry - // to a VBO for performance. This is formatted for rendering, with - // each group of 5 floats meaning vx, vy, vz, s, t, where (vx, vy, vz) are the - // vertex coordinates in world space and s,t are the texture coordinates. - std::vector recent_geom_; - - // Count of vertices in recent_geom_. - int recent_geom_vertex_count_; - - // Total vertices in the current brush stroke (the brush - // stroke starts when the user first touches the touchpad and continues - // until they release it). - int brush_stroke_total_vertices_; - - // Currently selected color (index). - int selected_color_; - - // If true, we are currently painting. - bool painting_; - - // If painting_ == true, then this is the position where the last - // paint segment ended (or the position where painting began, if no - // segments were added yet). - std::array paint_anchor_; - - // Indicates whether we have continuation points to continue the shape - // from (for smooth drawing). - bool has_continuation_; - - // If has_continuation_ == true, these are the continuation points. - std::array, 2> continuation_points_; - - // This is the list of committed VBOs that contains the static parts - // of the current drawing. As the drawing accumulates in painted_geom_, - // we push it to a static VBO on the GPU for performance. - struct VboInfo { - GLuint vbo; - int vertex_count; - int color; - }; - std::vector committed_vbos_; - - // Touchpad coordinates where touch started. We use this to detect - // the swipe gestures that cause the drawing color to change. - float touch_down_x_; - float touch_down_y_; - - // If true, a color switch already happened during this touch cycle. - bool switched_color_; - - // Width of the painting stroke. - float stroke_width_; - - // Width of the painting stroke when the user last started touching the - // touchpad. - float touch_down_stroke_width_; - - // Disallow copy and assign. - DemoApp(const DemoApp& other) = delete; - DemoApp& operator=(const DemoApp& other) = delete; -}; - -#endif // CONTROLLER_PAINT_APP_SRC_MAIN_JNI_DEMOAPP_H_ // NOLINT diff --git a/samples/ndk-controllerpaint/src/main/jni/utils.cc b/samples/ndk-controllerpaint/src/main/jni/utils.cc deleted file mode 100644 index ceb5b996..00000000 --- a/samples/ndk-controllerpaint/src/main/jni/utils.cc +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright 2017 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "utils.h" // NOLINT - -void Utils::SetUpViewportAndScissor(const gvr::Sizei& framebuf_size, - const gvr::BufferViewport& params) { - const gvr::Rectf& rect = params.GetSourceUv(); - int left = static_cast(rect.left * framebuf_size.width); - int bottom = static_cast(rect.bottom * framebuf_size.width); - int width = static_cast((rect.right - rect.left) * framebuf_size.width); - int height = - static_cast((rect.top - rect.bottom) * framebuf_size.height); - glViewport(left, bottom, width, height); - glEnable(GL_SCISSOR_TEST); - glScissor(left, bottom, width, height); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - CHECK(glGetError() == GL_NO_ERROR); -} - -gvr::Mat4f Utils::MatrixMul(const gvr::Mat4f& m1, const gvr::Mat4f& m2) { - gvr::Mat4f result; - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 4; ++j) { - result.m[i][j] = 0.0f; - for (int k = 0; k < 4; ++k) { - result.m[i][j] += m1.m[i][k] * m2.m[k][j]; - } - } - } - return result; -} - -std::array Utils::MatrixVectorMul(const gvr::Mat4f& matrix, - const std::array& vec) { - // Use homogeneous coordinates for the multiplication. - std::array vec_h = {{ vec[0], vec[1], vec[2], 1.0f }}; - std::array result; - for (int i = 0; i < 4; ++i) { - result[i] = 0; - for (int k = 0; k < 4; ++k) { - result[i] += matrix.m[i][k] * vec_h[k]; - } - } - // Convert back from homogeneous coordinates. - float rw = 1.0f / result[3]; - return {{ rw * result[0], rw * result[1], rw * result[2] }}; -} - - -std::array Utils::VecAdd( - float scale_a, const std::array& a, - float scale_b, const std::array& b) { - std::array result; - for (int i = 0; i < 3; ++i) { - result[i] = scale_a * a[i] + scale_b * b[i]; - } - return result; -} - -float Utils::VecNorm(const std::array& vec) { - float sum = 0.0f; - for (int i = 0; i < 3; ++i) { - sum += vec[i] * vec[i]; - } - return static_cast(sqrt(sum)); -} - -std::array Utils::VecNormalize(const std::array& vec) { - std::array result; - float scale = 1.0f / VecNorm(vec); - for (int i = 0; i < 3; ++i) { - result[i] = vec[i] * scale; - } - return result; -} - -std::array Utils::VecCrossProd( - const std::array& a, const std::array& b) { - std::array result; - result[0] = a[1] * b[2] - a[2] * b[1]; - result[1] = a[2] * b[0] - a[0] * b[2]; - result[2] = a[0] * b[1] - a[1] * b[0]; - return result; -} - -jobject Utils::GetClassLoaderFromActivity(JNIEnv* env, jobject activity) { - jclass activity_class = env->GetObjectClass(activity); - CHECK(activity_class); - jmethodID get_classloader_mid = env->GetMethodID( - activity_class, "getClassLoader", "()Ljava/lang/ClassLoader;"); - CHECK(get_classloader_mid); - jobject class_loader = env->CallObjectMethod(activity, get_classloader_mid); - CHECK(class_loader); - env->DeleteLocalRef(activity_class); - return class_loader; -} - -int Utils::BuildShader(int type, const char* source) { - int shader = glCreateShader(type); - CHECK(shader); - glShaderSource(shader, 1, &source, nullptr); - glCompileShader(shader); - int status; - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - CHECK_NE(0, status); - return shader; -} - -int Utils::BuildProgram(int vertex_shader, int frag_shader) { - int program = glCreateProgram(); - CHECK(program); - glAttachShader(program, vertex_shader); - glAttachShader(program, frag_shader); - glLinkProgram(program); - int status; - glGetProgramiv(program, GL_LINK_STATUS, &status); - CHECK_NE(0, status); - return program; -} - -gvr::Mat4f Utils::PerspectiveMatrixFromView(const gvr::Rectf& fov, - float near_clip, float far_clip) { - gvr::Mat4f result; - const float x_left = -tan(fov.left * M_PI / 180.0f) * near_clip; - const float x_right = tan(fov.right * M_PI / 180.0f) * near_clip; - const float y_bottom = -tan(fov.bottom * M_PI / 180.0f) * near_clip; - const float y_top = tan(fov.top * M_PI / 180.0f) * near_clip; - const float zero = 0.0f; - - CHECK(x_left < x_right && y_bottom < y_top && near_clip < far_clip && - near_clip > zero && far_clip > zero); - const float X = (2 * near_clip) / (x_right - x_left); - const float Y = (2 * near_clip) / (y_top - y_bottom); - const float A = (x_right + x_left) / (x_right - x_left); - const float B = (y_top + y_bottom) / (y_top - y_bottom); - const float C = (near_clip + far_clip) / (near_clip - far_clip); - const float D = (2 * near_clip * far_clip) / (near_clip - far_clip); - - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 4; ++j) { - result.m[i][j] = 0.0f; - } - } - result.m[0][0] = X; - result.m[0][2] = A; - result.m[1][1] = Y; - result.m[1][2] = B; - result.m[2][2] = C; - result.m[2][3] = D; - result.m[3][2] = -1; - - return result; -} - -std::array Utils::MatrixToGLArray(const gvr::Mat4f& matrix) { - // Note that this performs a *tranpose* to a column-major matrix array, as - // expected by GL. - std::array result; - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 4; ++j) { - result[j * 4 + i] = matrix.m[i][j]; - } - } - return result; -} - -int Utils::LoadRawTextureFromAsset( - AAssetManager* asset_mgr, const char* asset_path, int width, int height) { - const int bytes_per_pixel = 3; // RGB - AAsset* asset = AAssetManager_open(asset_mgr, asset_path, AASSET_MODE_BUFFER); - CHECK(asset); - - int length = static_cast(AAsset_getLength(asset)); - CHECK(length == width * height * bytes_per_pixel); - - const uint8_t* source_buf = reinterpret_cast( - AAsset_getBuffer(asset)); - CHECK(source_buf); - - GLuint tex_id; - glGenTextures(1, &tex_id); - glBindTexture(GL_TEXTURE_2D, tex_id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, - GL_UNSIGNED_BYTE, source_buf); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glBindTexture(GL_TEXTURE_2D, 0); - CHECK(glGetError() == GL_NO_ERROR); - - AAsset_close(asset); - return tex_id; -} - -gvr::Mat4f Utils::ControllerQuatToMatrix(const gvr::ControllerQuat& quat) { - gvr::Mat4f result; - const float x = quat.qx; - const float x2 = quat.qx * quat.qx; - const float y = quat.qy; - const float y2 = quat.qy * quat.qy; - const float z = quat.qz; - const float z2 = quat.qz * quat.qz; - const float w = quat.qw; - const float xy = quat.qx * quat.qy; - const float xz = quat.qx * quat.qz; - const float xw = quat.qx * quat.qw; - const float yz = quat.qy * quat.qz; - const float yw = quat.qy * quat.qw; - const float zw = quat.qz * quat.qw; - - const float m11 = 1.0f - 2.0f * y2 - 2.0f * z2; - const float m12 = 2.0f * (xy - zw); - const float m13 = 2.0f * (xz + yw); - const float m21 = 2.0f * (xy + zw); - const float m22 = 1.0f - 2.0f * x2 - 2.0f * z2; - const float m23 = 2.0f * (yz - xw); - const float m31 = 2.0f * (xz - yw); - const float m32 = 2.0f * (yz + xw); - const float m33 = 1.0f - 2.0f * x2 - 2.0f * y2; - - return { - m11, m12, m13, 0.0f, - m21, m22, m23, 0.0f, - m31, m32, m33, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - }; -} - -std::array Utils::ColorFromHex(int hex) { - int a = (hex & 0xff000000) >> 24; - int r = (hex & 0xff0000) >> 16; - int g = (hex & 0xff00) >> 8; - int b = (hex & 0xff); - return { r / 256.0f, g / 256.0f, b / 256.0f, a / 256.0f }; -} - diff --git a/samples/ndk-controllerpaint/src/main/jni/utils.h b/samples/ndk-controllerpaint/src/main/jni/utils.h deleted file mode 100644 index 0f5e275a..00000000 --- a/samples/ndk-controllerpaint/src/main/jni/utils.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2017 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CONTROLLER_PAINT_APP_SRC_MAIN_JNI_UTILS_H_ // NOLINT -#define CONTROLLER_PAINT_APP_SRC_MAIN_JNI_UTILS_H_ - -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include "vr/gvr/capi/include/gvr.h" -#include "vr/gvr/capi/include/gvr_controller.h" - -#ifdef __ANDROID__ - #define LOG_TAG "ControllerDemoCPP" - #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) - #define LOGW(...) \ - __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) - #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) -#else - #define LOGD(...) - #define LOGW(...) - #define LOGE(...) -#endif // #ifdef __ANDROID__ - -#define CHECK(condition) if (!(condition)) { \ - LOGE("*** CHECK FAILED at %s:%d: %s", __FILE__, __LINE__, #condition); \ - abort(); } -#define CHECK_EQ(a, b) CHECK((a) == (b)) -#define CHECK_NE(a, b) CHECK((a) != (b)) - -// Assorted utilities and boilerplate code. -class Utils { - public: - // Obtains the ClassLoader associated to a given Android Activity. - static jobject GetClassLoaderFromActivity(JNIEnv* env, jobject activity); - - // Multiplies matrices. - static gvr::Mat4f MatrixMul(const gvr::Mat4f& m1, const gvr::Mat4f& m2); - - // Multiplies a matrix by a vector. - static std::array MatrixVectorMul(const gvr::Mat4f& matrix, - const std::array& vec); - - // Adds two vectors together. - static std::array VecAdd( - float scale_a, const std::array& a, - float scale_b, const std::array& b); - - // Computes the norm of a vector. - static float VecNorm(const std::array& vec); - - // Normalizes a vector (returns a vector with the same direction as - // the input vector, but with unit length). Result is undefined if - // the input vector has magnitude zero or almost zero. - static std::array VecNormalize(const std::array& vec); - - // Computes the cross product between the two given vectors. - static std::array VecCrossProd( - const std::array& a, const std::array& b); - - // Sets up the viewport and scissor regions in preparation for rendering, - // according to the given RenderTextureParams object. - static void SetUpViewportAndScissor(const gvr::Sizei& framebuf_size, - const gvr::BufferViewport& params); - - // Compiles a shader of the given type (GL_VERTEX_SHADER or - // GL_FRAGMENT_SHADER) and returns its handle. Aborts on failure. - static int BuildShader(int type, const char* source); - - // Links a vertex shader and a fragment shader together to produce a program. - // Returns the handle of that program. - static int BuildProgram(int vertex_shader, int frag_shader); - - // Calculates a perspective matrix from the given view parameters. - static gvr::Mat4f PerspectiveMatrixFromView(const gvr::Rectf& fov, - float near_clip, float far_clip); - - // Converts a row-major matrix to a column-major, GL-compatible matrix array. - static std::array MatrixToGLArray(const gvr::Mat4f& matrix); - - // Loads a texture from the given asset file. Returns the handle of the - // texture. - static int LoadRawTextureFromAsset( - AAssetManager* asset_mgr, const char* asset_path, int width, int height); - - // Converts a controller quaternion to a rotation matrix. - static gvr::Mat4f ControllerQuatToMatrix(const gvr::ControllerQuat& quat); - - // Convertes a color from hexadecimal notation to a GL-friendly float array. - static std::array ColorFromHex(int hex); -}; - -#endif // CONTROLLER_PAINT_APP_SRC_MAIN_JNI_UTILS_H_ // NOLINT diff --git a/samples/ndk-controllerpaint/src/main/res/drawable-nodpi/vr_icon.png b/samples/ndk-controllerpaint/src/main/res/drawable-nodpi/vr_icon.png deleted file mode 100644 index 36e26e68..00000000 Binary files a/samples/ndk-controllerpaint/src/main/res/drawable-nodpi/vr_icon.png and /dev/null differ diff --git a/samples/ndk-controllerpaint/src/main/res/drawable-nodpi/vr_icon_background.png b/samples/ndk-controllerpaint/src/main/res/drawable-nodpi/vr_icon_background.png deleted file mode 100644 index d336da3f..00000000 Binary files a/samples/ndk-controllerpaint/src/main/res/drawable-nodpi/vr_icon_background.png and /dev/null differ diff --git a/samples/ndk-controllerpaint/src/main/res/values/strings.xml b/samples/ndk-controllerpaint/src/main/res/values/strings.xml deleted file mode 100644 index 96fc7e84..00000000 --- a/samples/ndk-controllerpaint/src/main/res/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - NativeControllerPaint - - diff --git a/samples/ndk-hellovr/build.gradle b/samples/ndk-hellovr/build.gradle index 7760613d..d2bd4336 100644 --- a/samples/ndk-hellovr/build.gradle +++ b/samples/ndk-hellovr/build.gradle @@ -58,8 +58,8 @@ android { dependencies { - compile 'com.google.vr:sdk-audio:1.160.0' - compile 'com.google.vr:sdk-base:1.160.0' + compile 'com.google.vr:sdk-audio:1.170.0' + compile 'com.google.vr:sdk-base:1.170.0' } build.dependsOn(':extractNdk') diff --git a/samples/ndk-hellovr/src/main/AndroidManifest.xml b/samples/ndk-hellovr/src/main/AndroidManifest.xml index e65ad4a2..fda3e372 100644 --- a/samples/ndk-hellovr/src/main/AndroidManifest.xml +++ b/samples/ndk-hellovr/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="180716036" + android:versionName="1.170.0"> diff --git a/samples/ndk-treasurehunt/CMakeLists.txt b/samples/ndk-treasurehunt/CMakeLists.txt deleted file mode 100644 index 89427ba4..00000000 --- a/samples/ndk-treasurehunt/CMakeLists.txt +++ /dev/null @@ -1,39 +0,0 @@ -# For more information about using CMake with Android Studio, read the -# documentation: https://d.android.com/studio/projects/add-native-code.html - -cmake_minimum_required(VERSION 3.4.1) - -# Configure the sample code. -file(GLOB native_srcs "src/main/jni/*.cc") -add_library(treasurehunt_jni - SHARED - ${native_srcs}) - -# Include the GVR headers & libraries. -include_directories(${GVR_INCLUDE}) - -add_library(gvr-lib SHARED IMPORTED) -set_target_properties( - gvr-lib - PROPERTIES IMPORTED_LOCATION ${GVR_LIBPATH}/${ANDROID_ABI}/libgvr.so) - -add_library(gvraudio-lib SHARED IMPORTED) -set_target_properties( - gvraudio-lib - PROPERTIES IMPORTED_LOCATION ${GVR_LIBPATH}/${ANDROID_ABI}/libgvr_audio.so) - -# Include general Android libraries. -find_library(android-lib android) -find_library(EGL-lib EGL) -find_library(GLESv2-lib GLESv2) -find_library(log-lib log) - -# Build final libtreasurehunt_jni.so -target_link_libraries(treasurehunt_jni - gvr-lib - gvraudio-lib - - ${android-lib} - ${EGL-lib} - ${GLESv2-lib} - ${log-lib} ) diff --git a/samples/ndk-treasurehunt/build.gradle b/samples/ndk-treasurehunt/build.gradle deleted file mode 100644 index b071bf27..00000000 --- a/samples/ndk-treasurehunt/build.gradle +++ /dev/null @@ -1,49 +0,0 @@ -apply plugin: 'com.android.application' - -android { - compileSdkVersion 26 - defaultConfig { - applicationId "com.google.vr.ndk.samples.treasurehunt" - minSdkVersion 19 - targetSdkVersion 24 - versionCode 1 - versionName "1.0" - externalNativeBuild { - cmake { - cppFlags "-std=gnu++11" - arguments "-DGVR_LIBPATH=${project.rootDir}/libraries/jni", - "-DGVR_INCLUDE=${project.rootDir}/libraries/headers" - } - } - buildTypes { - release { - minifyEnabled = true - proguardFiles.add(file("${project.rootDir}/proguard-gvr.txt")) - } - } - ndk { - // This sample builds all architectures by default. Note that if you - // only want to build for a specific architecture, you need to - // remove the appropriate lines below. You also need to remove the - // .so files from the apk using - // "packagingOptions {exclude('lib/armeabi-v7a/*')}" in the android - // section. - abiFilters "arm64-v8a" - abiFilters "armeabi-v7a" - abiFilters "x86" - } - } - externalNativeBuild { - cmake { - path "CMakeLists.txt" - } - } -} - - -dependencies { - compile 'com.google.vr:sdk-audio:1.160.0' - compile 'com.google.vr:sdk-base:1.160.0' -} - -build.dependsOn(':extractNdk') diff --git a/samples/ndk-treasurehunt/src/main/AndroidManifest.xml b/samples/ndk-treasurehunt/src/main/AndroidManifest.xml deleted file mode 100644 index 5eb01242..00000000 --- a/samples/ndk-treasurehunt/src/main/AndroidManifest.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/ndk-treasurehunt/src/main/assets/cube_sound.wav b/samples/ndk-treasurehunt/src/main/assets/cube_sound.wav deleted file mode 100644 index ac7b3234..00000000 Binary files a/samples/ndk-treasurehunt/src/main/assets/cube_sound.wav and /dev/null differ diff --git a/samples/ndk-treasurehunt/src/main/assets/success.wav b/samples/ndk-treasurehunt/src/main/assets/success.wav deleted file mode 100644 index 656272a3..00000000 Binary files a/samples/ndk-treasurehunt/src/main/assets/success.wav and /dev/null differ diff --git a/samples/ndk-treasurehunt/src/main/java/com/google/vr/ndk/samples/treasurehunt/MainActivity.java b/samples/ndk-treasurehunt/src/main/java/com/google/vr/ndk/samples/treasurehunt/MainActivity.java deleted file mode 100644 index e5c98a72..00000000 --- a/samples/ndk-treasurehunt/src/main/java/com/google/vr/ndk/samples/treasurehunt/MainActivity.java +++ /dev/null @@ -1,228 +0,0 @@ -/* Copyright 2017 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.vr.ndk.samples.treasurehunt; - -import android.app.Activity; -import android.content.Context; -import android.opengl.GLSurfaceView; -import android.os.Bundle; -import android.os.Vibrator; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import com.google.vr.ndk.base.AndroidCompat; -import com.google.vr.ndk.base.GvrLayout; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.opengles.GL10; - -/** - * A Google VR NDK sample application. - * - *

This app presents a scene consisting of a planar ground grid and a floating "treasure" cube. - * When the user finds the "treasure", they can invoke the trigger action, and the cube will be - * randomly repositioned. When in Cardboard mode, the user must gaze at the cube and use the - * Cardboard trigger button. When in Daydream mode, the user can use the controller to position the - * cursor, and use the controller buttons to invoke the trigger action. - * - *

This is the main Activity for the sample application. It initializes a GLSurfaceView to allow - * rendering, a GvrLayout for GVR API access, and forwards relevant events to the native renderer - * where rendering and interaction are handled. - */ -public class MainActivity extends Activity { - static { - System.loadLibrary("gvr"); - System.loadLibrary("gvr_audio"); - System.loadLibrary("treasurehunt_jni"); - } - - // Opaque native pointer to the native TreasureHuntRenderer instance. - private long nativeTreasureHuntRenderer; - - private GvrLayout gvrLayout; - private GLSurfaceView surfaceView; - - // Note that pause and resume signals to the native renderer are performed on the GL thread, - // ensuring thread-safety. - private final Runnable pauseNativeRunnable = - new Runnable() { - @Override - public void run() { - nativeOnPause(nativeTreasureHuntRenderer); - } - }; - - private final Runnable resumeNativeRunnable = - new Runnable() { - @Override - public void run() { - nativeOnResume(nativeTreasureHuntRenderer); - } - }; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Ensure fullscreen immersion. - setImmersiveSticky(); - getWindow() - .getDecorView() - .setOnSystemUiVisibilityChangeListener( - new View.OnSystemUiVisibilityChangeListener() { - @Override - public void onSystemUiVisibilityChange(int visibility) { - if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { - setImmersiveSticky(); - } - } - }); - - // Initialize GvrLayout and the native renderer. - gvrLayout = new GvrLayout(this); - nativeTreasureHuntRenderer = - nativeCreateRenderer( - getClass().getClassLoader(), - this.getApplicationContext(), - gvrLayout.getGvrApi().getNativeGvrContext()); - - // Add the GLSurfaceView to the GvrLayout. - surfaceView = new GLSurfaceView(this); - surfaceView.setEGLContextClientVersion(2); - surfaceView.setEGLConfigChooser(8, 8, 8, 0, 0, 0); - surfaceView.setPreserveEGLContextOnPause(true); - surfaceView.setRenderer( - new GLSurfaceView.Renderer() { - @Override - public void onSurfaceCreated(GL10 gl, EGLConfig config) { - nativeInitializeGl(nativeTreasureHuntRenderer); - } - - @Override - public void onSurfaceChanged(GL10 gl, int width, int height) {} - - @Override - public void onDrawFrame(GL10 gl) { - nativeDrawFrame(nativeTreasureHuntRenderer); - } - }); - surfaceView.setOnTouchListener( - new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - // Give user feedback and signal a trigger event. - ((Vibrator) getSystemService(Context.VIBRATOR_SERVICE)).vibrate(50); - surfaceView.queueEvent( - new Runnable() { - @Override - public void run() { - nativeOnTriggerEvent(nativeTreasureHuntRenderer); - } - }); - return true; - } - return false; - } - }); - gvrLayout.setPresentationView(surfaceView); - - // Add the GvrLayout to the View hierarchy. - setContentView(gvrLayout); - - // Enable async reprojection. - if (gvrLayout.setAsyncReprojectionEnabled(true)) { - // Async reprojection decouples the app framerate from the display framerate, - // allowing immersive interaction even at the throttled clockrates set by - // sustained performance mode. - AndroidCompat.setSustainedPerformanceMode(this, true); - } - - // Enable VR Mode. - AndroidCompat.setVrModeEnabled(this, true); - } - - @Override - protected void onPause() { - surfaceView.queueEvent(pauseNativeRunnable); - surfaceView.onPause(); - gvrLayout.onPause(); - super.onPause(); - } - - @Override - protected void onResume() { - super.onResume(); - gvrLayout.onResume(); - surfaceView.onResume(); - surfaceView.queueEvent(resumeNativeRunnable); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - // Destruction order is important; shutting down the GvrLayout will detach - // the GLSurfaceView and stop the GL thread, allowing safe shutdown of - // native resources from the UI thread. - gvrLayout.shutdown(); - nativeDestroyRenderer(nativeTreasureHuntRenderer); - nativeTreasureHuntRenderer = 0; - } - - @Override - public void onBackPressed() { - super.onBackPressed(); - gvrLayout.onBackPressed(); - } - - @Override - public void onWindowFocusChanged(boolean hasFocus) { - super.onWindowFocusChanged(hasFocus); - if (hasFocus) { - setImmersiveSticky(); - } - } - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - // Avoid accidental volume key presses while the phone is in the VR headset. - if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP - || event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN) { - return true; - } - return super.dispatchKeyEvent(event); - } - - private void setImmersiveSticky() { - getWindow() - .getDecorView() - .setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); - } - - private native long nativeCreateRenderer( - ClassLoader appClassLoader, Context context, long nativeGvrContext); - private native void nativeDestroyRenderer(long nativeTreasureHuntRenderer); - private native void nativeInitializeGl(long nativeTreasureHuntRenderer); - private native long nativeDrawFrame(long nativeTreasureHuntRenderer); - private native void nativeOnTriggerEvent(long nativeTreasureHuntRenderer); - private native void nativeOnPause(long nativeTreasureHuntRenderer); - private native void nativeOnResume(long nativeTreasureHuntRenderer); -} diff --git a/samples/ndk-treasurehunt/src/main/jni/treasure_hunt_jni.cc b/samples/ndk-treasurehunt/src/main/jni/treasure_hunt_jni.cc deleted file mode 100644 index 565d1244..00000000 --- a/samples/ndk-treasurehunt/src/main/jni/treasure_hunt_jni.cc +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright 2017 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include - -#include "treasure_hunt_renderer.h" // NOLINT -#include "vr/gvr/capi/include/gvr.h" -#include "vr/gvr/capi/include/gvr_audio.h" - -#define JNI_METHOD(return_type, method_name) \ - JNIEXPORT return_type JNICALL \ - Java_com_google_vr_ndk_samples_treasurehunt_MainActivity_##method_name - -namespace { - -inline jlong jptr(TreasureHuntRenderer *native_treasure_hunt) { - return reinterpret_cast(native_treasure_hunt); -} - -inline TreasureHuntRenderer *native(jlong ptr) { - return reinterpret_cast(ptr); -} -} // anonymous namespace - -extern "C" { - -JNI_METHOD(jlong, nativeCreateRenderer) -(JNIEnv *env, jclass clazz, jobject class_loader, jobject android_context, - jlong native_gvr_api) { - std::unique_ptr audio_context(new gvr::AudioApi); - audio_context->Init(env, android_context, class_loader, - GVR_AUDIO_RENDERING_BINAURAL_HIGH_QUALITY); - - return jptr( - new TreasureHuntRenderer(reinterpret_cast(native_gvr_api), - std::move(audio_context))); -} - -JNI_METHOD(void, nativeDestroyRenderer) -(JNIEnv *env, jclass clazz, jlong native_treasure_hunt) { - delete native(native_treasure_hunt); -} - -JNI_METHOD(void, nativeInitializeGl) -(JNIEnv *env, jobject obj, jlong native_treasure_hunt) { - native(native_treasure_hunt)->InitializeGl(); -} - -JNI_METHOD(void, nativeDrawFrame) -(JNIEnv *env, jobject obj, jlong native_treasure_hunt) { - native(native_treasure_hunt)->DrawFrame(); -} - -JNI_METHOD(void, nativeOnTriggerEvent) -(JNIEnv *env, jobject obj, jlong native_treasure_hunt) { - native(native_treasure_hunt)->OnTriggerEvent(); -} - -JNI_METHOD(void, nativeOnPause) -(JNIEnv *env, jobject obj, jlong native_treasure_hunt) { - native(native_treasure_hunt)->OnPause(); -} - -JNI_METHOD(void, nativeOnResume) -(JNIEnv *env, jobject obj, jlong native_treasure_hunt) { - native(native_treasure_hunt)->OnResume(); -} - -} // extern "C" diff --git a/samples/ndk-treasurehunt/src/main/jni/treasure_hunt_renderer.cc b/samples/ndk-treasurehunt/src/main/jni/treasure_hunt_renderer.cc deleted file mode 100644 index 6b3c266a..00000000 --- a/samples/ndk-treasurehunt/src/main/jni/treasure_hunt_renderer.cc +++ /dev/null @@ -1,849 +0,0 @@ -/* Copyright 2017 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "treasure_hunt_renderer.h" // NOLINT -#include "treasure_hunt_shaders.h" // NOLINT - -#include -#include -#include -#include -#include - -#include "vr/gvr/capi/include/gvr_version.h" - -#define LOG_TAG "TreasureHuntCPP" -#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) -#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) -#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) -#define CHECK(condition) \ - if (!(condition)) { \ - LOGE("*** CHECK FAILED at %s:%d: %s", __FILE__, __LINE__, #condition); \ - abort(); \ - } - -namespace { -static const float kZNear = 0.01f; -static const float kZFar = 10.0f; -static const float kNeckModelFactor = 1.0f; - -// For now, to avoid writing a raycasting system, put the reticle closer than -// any objects. -static const float kMinCubeDistance = 3.5f; -static const float kMaxCubeDistance = 7.0f; -static const float kReticleDistance = 2.0f; - -// Depth of the ground plane, in meters. If this (and other distances) -// are too far, 6DOF tracking will have no visible effect. -static const float kDefaultFloorHeight = -2.0f; - -static const int kCoordsPerVertex = 3; - -static const uint64_t kPredictionTimeWithoutVsyncNanos = 50000000; - -// Angle threshold for determining whether the controller is pointing at the -// object. -static const float kAngleLimit = 0.2f; - -// Sound file in APK assets. -static const char* kObjectSoundFile = "cube_sound.wav"; -static const char* kSuccessSoundFile = "success.wav"; - -// Convert a GVR matrix to an array of floats suitable for passing to OpenGL. -static std::array MatrixToGLArray(const gvr::Mat4f& matrix) { - // Note that this performs a *transpose* to a column-major matrix array, as - // expected by GL. - std::array result; - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 4; ++j) { - result[j * 4 + i] = matrix.m[i][j]; - } - } - return result; -} - -// Flatten a pair of mat4's into an array of 32 floats, useful when feeding -// uniform values to OpenGL for multiview. -static std::array MatrixPairToGLArray(const gvr::Mat4f matrix[]) { - std::array result; - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 4; ++j) { - result[j * 4 + i] = matrix[0].m[i][j]; - result[16 + j * 4 + i] = matrix[1].m[i][j]; - } - } - return result; -} - -// Flatten a pair of vec3's into an array of 6 floats, useful when feeding -// uniform values to OpenGL for multiview. -static std::array VectorPairToGLArray( - const std::array vec[]) { - std::array result; - for (int k = 0; k < 3; ++k) { - result[k] = vec[0][k]; - result[k + 3] = vec[1][k]; - } - return result; -} - -// Multiply a vector by a matrix. -static std::array MatrixVectorMul(const gvr::Mat4f& matrix, - const std::array& vec) { - std::array result; - for (int i = 0; i < 4; ++i) { - result[i] = 0; - for (int k = 0; k < 4; ++k) { - result[i] += matrix.m[i][k] * vec[k]; - } - } - return result; -} - -// Multiply two matrices. -static gvr::Mat4f MatrixMul(const gvr::Mat4f& matrix1, - const gvr::Mat4f& matrix2) { - gvr::Mat4f result; - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 4; ++j) { - result.m[i][j] = 0.0f; - for (int k = 0; k < 4; ++k) { - result.m[i][j] += matrix1.m[i][k] * matrix2.m[k][j]; - } - } - } - return result; -} - -// Drop the last element of a vector. -static std::array Vec4ToVec3(const std::array& vec) { - return {vec[0], vec[1], vec[2]}; -} - -// Given a field of view in degrees, compute the corresponding projection -// matrix. -static gvr::Mat4f PerspectiveMatrixFromView(const gvr::Rectf& fov, float z_near, - float z_far) { - gvr::Mat4f result; - const float x_left = -std::tan(fov.left * M_PI / 180.0f) * z_near; - const float x_right = std::tan(fov.right * M_PI / 180.0f) * z_near; - const float y_bottom = -std::tan(fov.bottom * M_PI / 180.0f) * z_near; - const float y_top = std::tan(fov.top * M_PI / 180.0f) * z_near; - const float zero = 0.0f; - - assert(x_left < x_right && y_bottom < y_top && z_near < z_far && - z_near > zero && z_far > zero); - const float X = (2 * z_near) / (x_right - x_left); - const float Y = (2 * z_near) / (y_top - y_bottom); - const float A = (x_right + x_left) / (x_right - x_left); - const float B = (y_top + y_bottom) / (y_top - y_bottom); - const float C = (z_near + z_far) / (z_near - z_far); - const float D = (2 * z_near * z_far) / (z_near - z_far); - - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 4; ++j) { - result.m[i][j] = 0.0f; - } - } - result.m[0][0] = X; - result.m[0][2] = A; - result.m[1][1] = Y; - result.m[1][2] = B; - result.m[2][2] = C; - result.m[2][3] = D; - result.m[3][2] = -1; - - return result; -} - -// Multiplies both X coordinates of the rectangle by the given width and both Y -// coordinates by the given height. -static gvr::Rectf ModulateRect(const gvr::Rectf& rect, float width, - float height) { - gvr::Rectf result = {rect.left * width, rect.right * width, - rect.bottom * height, rect.top * height}; - return result; -} - -// Given the size of a texture in pixels and a rectangle in UV coordinates, -// computes the corresponding rectangle in pixel coordinates. -static gvr::Recti CalculatePixelSpaceRect(const gvr::Sizei& texture_size, - const gvr::Rectf& texture_rect) { - const float width = static_cast(texture_size.width); - const float height = static_cast(texture_size.height); - const gvr::Rectf rect = ModulateRect(texture_rect, width, height); - const gvr::Recti result = { - static_cast(rect.left), static_cast(rect.right), - static_cast(rect.bottom), static_cast(rect.top)}; - return result; -} - -// Generate a random floating point number between 0 and 1. -static float RandomUniformFloat() { - static std::random_device random_device; - static std::mt19937 random_generator(random_device()); - static std::uniform_real_distribution random_distribution(0, 1); - return random_distribution(random_generator); -} - -static void CheckGLError(const char* label) { - int gl_error = glGetError(); - if (gl_error != GL_NO_ERROR) { - LOGW("GL error @ %s: %d", label, gl_error); - // Crash immediately to make OpenGL errors obvious. - abort(); - } -} - -// Computes a texture size that has approximately half as many pixels. This is -// equivalent to scaling each dimension by approximately sqrt(2)/2. -static gvr::Sizei HalfPixelCount(const gvr::Sizei& in) { - // Scale each dimension by sqrt(2)/2 ~= 7/10ths. - gvr::Sizei out; - out.width = (7 * in.width) / 10; - out.height = (7 * in.height) / 10; - return out; -} - -// Convert the quaternion describing the controller's orientation to a -// rotation matrix. -static gvr::Mat4f ControllerQuatToMatrix(const gvr::ControllerQuat& quat) { - gvr::Mat4f result; - const float x = quat.qx; - const float x2 = quat.qx * quat.qx; - const float y = quat.qy; - const float y2 = quat.qy * quat.qy; - const float z = quat.qz; - const float z2 = quat.qz * quat.qz; - const float w = quat.qw; - const float xy = quat.qx * quat.qy; - const float xz = quat.qx * quat.qz; - const float xw = quat.qx * quat.qw; - const float yz = quat.qy * quat.qz; - const float yw = quat.qy * quat.qw; - const float zw = quat.qz * quat.qw; - - const float m11 = 1.0f - 2.0f * y2 - 2.0f * z2; - const float m12 = 2.0f * (xy - zw); - const float m13 = 2.0f * (xz + yw); - const float m21 = 2.0f * (xy + zw); - const float m22 = 1.0f - 2.0f * x2 - 2.0f * z2; - const float m23 = 2.0f * (yz - xw); - const float m31 = 2.0f * (xz - yw); - const float m32 = 2.0f * (yz + xw); - const float m33 = 1.0f - 2.0f * x2 - 2.0f * y2; - - return {{{m11, m12, m13, 0.0f}, - {m21, m22, m23, 0.0f}, - {m31, m32, m33, 0.0f}, - {0.0f, 0.0f, 0.0f, 1.0f}}}; -} - -static inline float VectorNorm(const std::array& vect) { - return std::sqrt(vect[0] * vect[0] + vect[1] * vect[1] + vect[2] * vect[2]); -} - -static float VectorInnerProduct(const std::array& vect1, - const std::array& vect2) { - float product = 0; - for (int i = 0; i < 3; i++) { - product += vect1[i] * vect2[i]; - } - return product; -} -} // anonymous namespace - -TreasureHuntRenderer::TreasureHuntRenderer( - gvr_context* gvr_context, std::unique_ptr gvr_audio_api) - : gvr_api_(gvr::GvrApi::WrapNonOwned(gvr_context)), - gvr_audio_api_(std::move(gvr_audio_api)), - viewport_left_(gvr_api_->CreateBufferViewport()), - viewport_right_(gvr_api_->CreateBufferViewport()), - floor_vertices_(world_layout_data_.floor_coords.data()), - cube_vertices_(world_layout_data_.cube_coords.data()), - cube_colors_(world_layout_data_.cube_colors.data()), - cube_found_colors_(world_layout_data_.cube_found_color.data()), - cube_normals_(world_layout_data_.cube_normals.data()), - reticle_vertices_(world_layout_data_.reticle_coords.data()), - reticle_render_size_{128, 128}, - light_pos_world_space_({0.0f, 2.0f, 0.0f, 1.0f}), - object_distance_(kMinCubeDistance), - audio_source_id_(-1), - success_source_id_(-1), - gvr_controller_api_(nullptr), - gvr_viewer_type_(gvr_api_->GetViewerType()) { - ResumeControllerApiAsNeeded(); - - LOGD("Built with GVR version: %s", GVR_SDK_VERSION_STRING); - if (gvr_viewer_type_ == GVR_VIEWER_TYPE_CARDBOARD) { - LOGD("Viewer type: CARDBOARD"); - } else if (gvr_viewer_type_ == GVR_VIEWER_TYPE_DAYDREAM) { - LOGD("Viewer type: DAYDREAM"); - } else { - LOGE("Unexpected viewer type."); - } -} - -TreasureHuntRenderer::~TreasureHuntRenderer() { - // Join the audio initialization thread in case it still exists. - if (audio_initialization_thread_.joinable()) { - audio_initialization_thread_.join(); - } -} - -void TreasureHuntRenderer::InitializeGl() { - gvr_api_->InitializeGl(); - multiview_enabled_ = gvr_api_->IsFeatureSupported(GVR_FEATURE_MULTIVIEW); - LOGD(multiview_enabled_ ? "Using multiview." : "Not using multiview."); - - int index = multiview_enabled_ ? 1 : 0; - const int vertex_shader = - LoadGLShader(GL_VERTEX_SHADER, &kDiffuseLightingVertexShaders[index]); - const int grid_shader = - LoadGLShader(GL_FRAGMENT_SHADER, &kGridFragmentShaders[index]); - const int pass_through_shader = - LoadGLShader(GL_FRAGMENT_SHADER, &kPassthroughFragmentShaders[index]); - const int reticle_vertex_shader = - LoadGLShader(GL_VERTEX_SHADER, &kReticleVertexShaders[index]); - const int reticle_fragment_shader = - LoadGLShader(GL_FRAGMENT_SHADER, &kReticleFragmentShaders[index]); - - cube_program_ = glCreateProgram(); - glAttachShader(cube_program_, vertex_shader); - glAttachShader(cube_program_, pass_through_shader); - glLinkProgram(cube_program_); - glUseProgram(cube_program_); - - cube_position_param_ = glGetAttribLocation(cube_program_, "a_Position"); - cube_normal_param_ = glGetAttribLocation(cube_program_, "a_Normal"); - cube_color_param_ = glGetAttribLocation(cube_program_, "a_Color"); - - cube_model_param_ = glGetUniformLocation(cube_program_, "u_Model"); - cube_modelview_param_ = glGetUniformLocation(cube_program_, "u_MVMatrix"); - cube_modelview_projection_param_ = - glGetUniformLocation(cube_program_, "u_MVP"); - cube_light_pos_param_ = glGetUniformLocation(cube_program_, "u_LightPos"); - - CheckGLError("Cube program params"); - - floor_program_ = glCreateProgram(); - glAttachShader(floor_program_, vertex_shader); - glAttachShader(floor_program_, grid_shader); - glLinkProgram(floor_program_); - glUseProgram(floor_program_); - - CheckGLError("Floor program"); - - floor_position_param_ = glGetAttribLocation(floor_program_, "a_Position"); - floor_normal_param_ = glGetAttribLocation(floor_program_, "a_Normal"); - floor_color_param_ = glGetAttribLocation(floor_program_, "a_Color"); - - floor_model_param_ = glGetUniformLocation(floor_program_, "u_Model"); - floor_modelview_param_ = glGetUniformLocation(floor_program_, "u_MVMatrix"); - floor_modelview_projection_param_ = - glGetUniformLocation(floor_program_, "u_MVP"); - floor_light_pos_param_ = glGetUniformLocation(floor_program_, "u_LightPos"); - - CheckGLError("Floor program params"); - - reticle_program_ = glCreateProgram(); - glAttachShader(reticle_program_, reticle_vertex_shader); - glAttachShader(reticle_program_, reticle_fragment_shader); - glLinkProgram(reticle_program_); - glUseProgram(reticle_program_); - - CheckGLError("Reticle program"); - - reticle_position_param_ = glGetAttribLocation(reticle_program_, "a_Position"); - reticle_modelview_projection_param_ = - glGetUniformLocation(reticle_program_, "u_MVP"); - - CheckGLError("Reticle program params"); - - // Object first appears directly in front of user. - model_cube_ = {{{1.0f, 0.0f, 0.0f, 0.0f}, - {0.0f, 0.707f, -0.707f, 0.0f}, - {0.0f, 0.707f, 0.707f, -object_distance_}, - {0.0f, 0.0f, 0.0f, 1.0f}}}; - const float rs = 0.04f; // Reticle scale. - model_reticle_ = {{{rs, 0.0f, 0.0f, 0.0f}, - {0.0f, rs, 0.0f, 0.0f}, - {0.0f, 0.0f, rs, -kReticleDistance}, - {0.0f, 0.0f, 0.0f, 1.0f}}}; - - // Because we are using 2X MSAA, we can render to half as many pixels and - // achieve similar quality. - render_size_ = - HalfPixelCount(gvr_api_->GetMaximumEffectiveRenderTargetSize()); - std::vector specs; - - specs.push_back(gvr_api_->CreateBufferSpec()); - specs[0].SetColorFormat(GVR_COLOR_FORMAT_RGBA_8888); - specs[0].SetDepthStencilFormat(GVR_DEPTH_STENCIL_FORMAT_DEPTH_16); - specs[0].SetSamples(2); - - // With multiview, the distortion buffer is a texture array with two layers - // whose width is half the display width. - if (multiview_enabled_) { - gvr::Sizei half_size = { render_size_.width / 2, render_size_.height }; - specs[0].SetMultiviewLayers(2); - specs[0].SetSize(half_size); - } else { - specs[0].SetSize(render_size_); - } - - specs.push_back(gvr_api_->CreateBufferSpec()); - specs[1].SetSize(reticle_render_size_); - specs[1].SetColorFormat(GVR_COLOR_FORMAT_RGBA_8888); - specs[1].SetDepthStencilFormat(GVR_DEPTH_STENCIL_FORMAT_NONE); - specs[1].SetSamples(1); - swapchain_.reset(new gvr::SwapChain(gvr_api_->CreateSwapChain(specs))); - - viewport_list_.reset( - new gvr::BufferViewportList(gvr_api_->CreateEmptyBufferViewportList())); - - // Initialize audio engine and preload sample in a separate thread to avoid - // any delay during construction and app initialization. Only do this once. - if (!audio_initialization_thread_.joinable()) { - audio_initialization_thread_ = - std::thread(&TreasureHuntRenderer::LoadAndPlayCubeSound, this); - } -} - -void TreasureHuntRenderer::ResumeControllerApiAsNeeded() { - switch (gvr_viewer_type_) { - case GVR_VIEWER_TYPE_CARDBOARD: - gvr_controller_api_.reset(); - break; - case GVR_VIEWER_TYPE_DAYDREAM: - if (!gvr_controller_api_) { - // Initialized controller api. - gvr_controller_api_.reset(new gvr::ControllerApi); - CHECK(gvr_controller_api_); - CHECK(gvr_controller_api_->Init(gvr::ControllerApi::DefaultOptions(), - gvr_api_->cobj())); - } - gvr_controller_api_->Resume(); - break; - default: - LOGE("unexpected viewer type."); - break; - } -} - -void TreasureHuntRenderer::ProcessControllerInput() { - if (gvr_viewer_type_ == GVR_VIEWER_TYPE_CARDBOARD) return; - const int old_status = gvr_controller_state_.GetApiStatus(); - const int old_connection_state = gvr_controller_state_.GetConnectionState(); - - // Read current controller state. - gvr_controller_state_.Update(*gvr_controller_api_); - - // Print new API status and connection state, if they changed. - if (gvr_controller_state_.GetApiStatus() != old_status || - gvr_controller_state_.GetConnectionState() != old_connection_state) { - LOGD("TreasureHuntApp: controller API status: %s, connection state: %s", - gvr_controller_api_status_to_string( - gvr_controller_state_.GetApiStatus()), - gvr_controller_connection_state_to_string( - gvr_controller_state_.GetConnectionState())); - } - - // Trigger click event if app/click button is clicked. - if (gvr_controller_state_.GetButtonDown(GVR_CONTROLLER_BUTTON_APP) || - gvr_controller_state_.GetButtonDown(GVR_CONTROLLER_BUTTON_CLICK)) { - OnTriggerEvent(); - } -} - -void TreasureHuntRenderer::UpdateReticlePosition() { - if (gvr_viewer_type_ == GVR_VIEWER_TYPE_DAYDREAM) { - ProcessControllerInput(); - gvr::Mat4f controller_matrix = - ControllerQuatToMatrix(gvr_controller_state_.GetOrientation()); - modelview_reticle_ = - MatrixMul(head_view_, MatrixMul(controller_matrix, model_reticle_)); - } else { - modelview_reticle_ = model_reticle_; - } -} - -void TreasureHuntRenderer::DrawFrame() { - PrepareFramebuffer(); - gvr::Frame frame = swapchain_->AcquireFrame(); - - // A client app does its rendering here. - gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow(); - target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos; - gvr::BufferViewport* viewport[2] = { - &viewport_left_, - &viewport_right_, - }; - // Note that neck model application is a no-op if the viewer supports 6DoF - // head tracking - head_view_ = gvr_api_->ApplyNeckModel( - gvr_api_->GetHeadSpaceFromStartSpaceTransform(target_time), - kNeckModelFactor); - viewport_list_->SetToRecommendedBufferViewports(); - - gvr::BufferViewport reticle_viewport = gvr_api_->CreateBufferViewport(); - reticle_viewport.SetSourceBufferIndex(1); - if (gvr_viewer_type_ == GVR_VIEWER_TYPE_CARDBOARD) { - // Do not reproject the reticle if it's head-locked. - reticle_viewport.SetReprojection(GVR_REPROJECTION_NONE); - } - const gvr_rectf fullscreen = { 0, 1, 0, 1 }; - reticle_viewport.SetSourceUv(fullscreen); - UpdateReticlePosition(); - - gvr::Value floor_height; - // This may change when the floor height changes so it's computed every frame. - float ground_y = gvr_api_->GetCurrentProperties().Get( - GVR_PROPERTY_TRACKING_FLOOR_HEIGHT, &floor_height) - ? floor_height.f - : kDefaultFloorHeight; - model_floor_ = {{{1.0f, 0.0f, 0.0f, 0.0f}, - {0.0f, 1.0f, 0.0f, ground_y}, - {0.0f, 0.0f, 1.0f, 0.0f}, - {0.0f, 0.0f, 0.0f, 1.0f}}}; - - gvr::Mat4f eye_views[2]; - for (int eye = 0; eye < 2; ++eye) { - const gvr::Eye gvr_eye = eye == 0 ? GVR_LEFT_EYE : GVR_RIGHT_EYE; - const gvr::Mat4f eye_from_head = gvr_api_->GetEyeFromHeadMatrix(gvr_eye); - eye_views[eye] = MatrixMul(eye_from_head, head_view_); - - viewport_list_->GetBufferViewport(eye, viewport[eye]); - - if (multiview_enabled_) { - viewport[eye]->SetSourceUv(fullscreen); - viewport[eye]->SetSourceLayer(eye); - viewport_list_->SetBufferViewport(eye, *viewport[eye]); - } - - reticle_viewport.SetTransform(MatrixMul(eye_from_head, modelview_reticle_)); - reticle_viewport.SetTargetEye(gvr_eye); - // The first two viewports are for the 3D scene (one for each eye), the - // latter two viewports are for the reticle (one for each eye). - viewport_list_->SetBufferViewport(2 + eye, reticle_viewport); - - modelview_cube_[eye] = MatrixMul(eye_views[eye], model_cube_); - modelview_floor_[eye] = MatrixMul(eye_views[eye], model_floor_); - const gvr_rectf fov = viewport[eye]->GetSourceFov(); - const gvr::Mat4f perspective = - PerspectiveMatrixFromView(fov, kZNear, kZFar); - modelview_projection_cube_[eye] = - MatrixMul(perspective, modelview_cube_[eye]); - modelview_projection_floor_[eye] = - MatrixMul(perspective, modelview_floor_[eye]); - light_pos_eye_space_[eye] = - Vec4ToVec3(MatrixVectorMul(eye_views[eye], light_pos_world_space_)); - } - - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - - // Draw the world. - frame.BindBuffer(0); - glClearColor(0.1f, 0.1f, 0.1f, 0.5f); // Dark background so text shows up. - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - if (multiview_enabled_) { - DrawWorld(kMultiview); - } else { - DrawWorld(kLeftView); - DrawWorld(kRightView); - } - frame.Unbind(); - - // Draw the reticle on a separate layer. - frame.BindBuffer(1); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Transparent background. - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - DrawReticle(); - frame.Unbind(); - - // Submit frame. - frame.Submit(*viewport_list_, head_view_); - - CheckGLError("onDrawFrame"); - - // Update audio head rotation in audio API. - gvr_audio_api_->SetHeadPose(head_view_); - gvr_audio_api_->Update(); -} - -void TreasureHuntRenderer::PrepareFramebuffer() { - // Because we are using 2X MSAA, we can render to half as many pixels and - // achieve similar quality. - const gvr::Sizei recommended_size = - HalfPixelCount(gvr_api_->GetMaximumEffectiveRenderTargetSize()); - if (render_size_.width != recommended_size.width || - render_size_.height != recommended_size.height) { - // We need to resize the framebuffer. Note that multiview uses two texture - // layers, each with half the render width. - gvr::Sizei framebuffer_size = recommended_size; - if (multiview_enabled_) { - framebuffer_size.width /= 2; - } - swapchain_->ResizeBuffer(0, framebuffer_size); - render_size_ = recommended_size; - } -} - -void TreasureHuntRenderer::OnTriggerEvent() { - if (IsPointingAtObject()) { - success_source_id_ = gvr_audio_api_->CreateStereoSound(kSuccessSoundFile); - gvr_audio_api_->PlaySound(success_source_id_, false /* looping disabled */); - HideObject(); - } -} - -void TreasureHuntRenderer::OnPause() { - gvr_api_->PauseTracking(); - gvr_audio_api_->Pause(); - if (gvr_controller_api_) gvr_controller_api_->Pause(); -} - -void TreasureHuntRenderer::OnResume() { - gvr_api_->ResumeTracking(); - gvr_api_->RefreshViewerProfile(); - gvr_audio_api_->Resume(); - gvr_viewer_type_ = gvr_api_->GetViewerType(); - ResumeControllerApiAsNeeded(); -} - -/** - * Converts a raw text file, saved as a resource, into an OpenGL ES shader. - * - * @param type The type of shader we will be creating. - * @param resId The resource ID of the raw text file. - * @return The shader object handler. - */ -int TreasureHuntRenderer::LoadGLShader(int type, const char** shadercode) { - int shader = glCreateShader(type); - glShaderSource(shader, 1, shadercode, nullptr); - glCompileShader(shader); - - // Get the compilation status. - int compileStatus; - glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus); - - // If the compilation failed, delete the shader. - if (compileStatus == 0) { - glDeleteShader(shader); - shader = 0; - } - - return shader; -} - -/** - * Draws a frame for a particular view. - * - * @param view The view to render: left, right, or both (multiview). - */ -void TreasureHuntRenderer::DrawWorld(ViewType view) { - if (view == kMultiview) { - glViewport(0, 0, render_size_.width / 2, render_size_.height); - } else { - const gvr::BufferViewport& viewport = - view == kLeftView ? viewport_left_ : viewport_right_; - const gvr::Recti pixel_rect = - CalculatePixelSpaceRect(render_size_, viewport.GetSourceUv()); - glViewport(pixel_rect.left, pixel_rect.bottom, - pixel_rect.right - pixel_rect.left, - pixel_rect.top - pixel_rect.bottom); - } - DrawCube(view); - DrawFloor(view); -} - -void TreasureHuntRenderer::DrawCube(ViewType view) { - glUseProgram(cube_program_); - - if (view == kMultiview) { - glUniform3fv(cube_light_pos_param_, 2, - VectorPairToGLArray(light_pos_eye_space_).data()); - glUniformMatrix4fv(cube_modelview_param_, 2, GL_FALSE, - MatrixPairToGLArray(modelview_cube_).data()); - glUniformMatrix4fv(cube_modelview_projection_param_, 2, GL_FALSE, - MatrixPairToGLArray(modelview_projection_cube_).data()); - } else { - glUniform3fv(cube_light_pos_param_, 1, light_pos_eye_space_[view].data()); - glUniformMatrix4fv(cube_modelview_param_, 1, GL_FALSE, - MatrixToGLArray(modelview_cube_[view]).data()); - glUniformMatrix4fv( - cube_modelview_projection_param_, 1, GL_FALSE, - MatrixToGLArray(modelview_projection_cube_[view]).data()); - } - - // Set the Model in the shader, used to calculate lighting - glUniformMatrix4fv(cube_model_param_, 1, GL_FALSE, - MatrixToGLArray(model_cube_).data()); - - // Set the position of the cube - glVertexAttribPointer(cube_position_param_, kCoordsPerVertex, GL_FLOAT, false, - 0, cube_vertices_); - glEnableVertexAttribArray(cube_position_param_); - - // Set the normal positions of the cube, again for shading - glVertexAttribPointer(cube_normal_param_, 3, GL_FLOAT, false, 0, - cube_normals_); - glEnableVertexAttribArray(cube_normal_param_); - - // Set vertex colors - if (IsPointingAtObject()) { - const float* found_color = world_layout_data_.cube_found_color.data(); - glVertexAttrib4f(cube_color_param_, found_color[0], found_color[1], - found_color[2], 1.0f); - glDisableVertexAttribArray(cube_color_param_); - } else { - glVertexAttribPointer(cube_color_param_, 3, GL_FLOAT, false, 0, - cube_colors_); - glEnableVertexAttribArray(cube_color_param_); - } - - glDrawArrays(GL_TRIANGLES, 0, 36); - - glDisableVertexAttribArray(cube_position_param_); - glDisableVertexAttribArray(cube_normal_param_); - glDisableVertexAttribArray(cube_color_param_); - - CheckGLError("Drawing cube"); -} - -void TreasureHuntRenderer::DrawFloor(ViewType view) { - glUseProgram(floor_program_); - - if (view == kMultiview) { - glUniform3fv(floor_light_pos_param_, 2, - VectorPairToGLArray(light_pos_eye_space_).data()); - glUniformMatrix4fv(floor_modelview_param_, 2, GL_FALSE, - MatrixPairToGLArray(modelview_floor_).data()); - glUniformMatrix4fv(floor_modelview_projection_param_, 2, GL_FALSE, - MatrixPairToGLArray(modelview_projection_floor_).data()); - } else { - glUniform3fv(floor_light_pos_param_, 1, light_pos_eye_space_[view].data()); - glUniformMatrix4fv(floor_modelview_param_, 1, GL_FALSE, - MatrixToGLArray(modelview_floor_[view]).data()); - glUniformMatrix4fv( - floor_modelview_projection_param_, 1, GL_FALSE, - MatrixToGLArray(modelview_projection_floor_[view]).data()); - } - - glUniformMatrix4fv(floor_model_param_, 1, GL_FALSE, - MatrixToGLArray(model_floor_).data()); - glVertexAttribPointer(floor_position_param_, kCoordsPerVertex, GL_FLOAT, - false, 0, floor_vertices_); - glVertexAttrib3f(floor_normal_param_, 0.0f, 1.0f, 0.0f); - glVertexAttrib4f(floor_color_param_, 0.0f, 0.3398f, 0.9023f, 1.0f); - - glEnableVertexAttribArray(floor_position_param_); - glDrawArrays(GL_TRIANGLES, 0, 24); - glDisableVertexAttribArray(floor_position_param_); - - CheckGLError("Drawing floor"); -} - -void TreasureHuntRenderer::DrawReticle() { - glViewport(0, 0, reticle_render_size_.width, reticle_render_size_.height); - glUseProgram(reticle_program_); - const gvr::Mat4f uniform_matrix = {{{1.f, 0.f, 0.f, 0.f}, - {0.f, 1.f, 0.f, 0.f}, - {0.f, 0.f, 1.f, 0.f}, - {0.f, 0.f, 0.f, 1.f}}}; - glUniformMatrix4fv(reticle_modelview_projection_param_, 1, GL_FALSE, - MatrixToGLArray(uniform_matrix).data()); - glVertexAttribPointer(reticle_position_param_, kCoordsPerVertex, GL_FLOAT, - false, 0, reticle_vertices_); - glEnableVertexAttribArray(reticle_position_param_); - glDrawArrays(GL_TRIANGLES, 0, 6); - glDisableVertexAttribArray(reticle_position_param_); - - CheckGLError("Drawing reticle"); -} - -void TreasureHuntRenderer::HideObject() { - std::array cube_position = { - model_cube_.m[0][3], model_cube_.m[1][3], model_cube_.m[2][3], 1.f}; - - // First rotate in XZ plane, between pi/2 and 3pi/2 radians away, apply this - // to model_cube_ to keep the front face of the cube towards the user. - float angle_xz = M_PI * (RandomUniformFloat() + 0.5f); - gvr::Mat4f rotation_matrix = {{{cosf(angle_xz), 0.f, -sinf(angle_xz), 0.f}, - {0.f, 1.f, 0.f, 0.f}, - {sinf(angle_xz), 0.f, cosf(angle_xz), 0.f}, - {0.f, 0.f, 0.f, 1.f}}}; - cube_position = MatrixVectorMul(rotation_matrix, cube_position); - model_cube_ = MatrixMul(rotation_matrix, model_cube_); - - // Pick a new distance for the cube, and apply that scale to the position. - const float old_object_distance = object_distance_; - object_distance_ = - RandomUniformFloat() * (kMaxCubeDistance - kMinCubeDistance) + - kMinCubeDistance; - const float scale = object_distance_ / old_object_distance; - cube_position[0] *= scale; - cube_position[1] *= scale; - cube_position[2] *= scale; - - // Choose a random yaw for the cube between 0 and pi/4. - const float yaw = M_PI * (RandomUniformFloat()) / 4.0f; - cube_position[1] = tanf(yaw) * object_distance_; - - model_cube_.m[0][3] = cube_position[0]; - model_cube_.m[1][3] = cube_position[1]; - model_cube_.m[2][3] = cube_position[2]; - - if (audio_source_id_ >= 0) { - gvr_audio_api_->SetSoundObjectPosition(audio_source_id_, cube_position[0], - cube_position[1], cube_position[2]); - } -} - -bool TreasureHuntRenderer::IsPointingAtObject() { - // Compute vectors pointing towards the reticle and towards the cube in head - // space. - gvr::Mat4f head_from_reticle = modelview_reticle_; - gvr::Mat4f head_from_cube = MatrixMul(head_view_, model_cube_); - const std::array reticle_vector = - MatrixVectorMul(head_from_reticle, {0.f, 0.f, 0.f, 1.f}); - const std::array cube_vector = - MatrixVectorMul(head_from_cube, {0.f, 0.f, 0.f, 1.f}); - - // Compute the angle between the vector towards the reticle and the vector - // towards the cube by computing the arc cosine of their normalized dot - // product. - float angle = std::acos(std::max(-1.f, std::min(1.f, - VectorInnerProduct(reticle_vector, cube_vector) / - VectorNorm(reticle_vector) / VectorNorm(cube_vector)))); - return angle < kAngleLimit; -} - -void TreasureHuntRenderer::LoadAndPlayCubeSound() { - // Preload sound files. - gvr_audio_api_->PreloadSoundfile(kObjectSoundFile); - gvr_audio_api_->PreloadSoundfile(kSuccessSoundFile); - // Create sound file handler from preloaded sound file. - audio_source_id_ = gvr_audio_api_->CreateSoundObject(kObjectSoundFile); - // Set sound object to current cube position. - gvr_audio_api_->SetSoundObjectPosition(audio_source_id_, model_cube_.m[0][3], - model_cube_.m[1][3], - model_cube_.m[2][3]); - // Trigger sound object playback. - gvr_audio_api_->PlaySound(audio_source_id_, true /* looped playback */); -} diff --git a/samples/ndk-treasurehunt/src/main/jni/treasure_hunt_renderer.h b/samples/ndk-treasurehunt/src/main/jni/treasure_hunt_renderer.h deleted file mode 100644 index c25d404b..00000000 --- a/samples/ndk-treasurehunt/src/main/jni/treasure_hunt_renderer.h +++ /dev/null @@ -1,267 +0,0 @@ -/* Copyright 2017 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef TREASUREHUNT_APP_SRC_MAIN_JNI_TREASUREHUNTRENDERER_H_ // NOLINT -#define TREASUREHUNT_APP_SRC_MAIN_JNI_TREASUREHUNTRENDERER_H_ // NOLINT - -#include -#include -#include - -#include -#include -#include // NOLINT -#include - -#include "vr/gvr/capi/include/gvr.h" -#include "vr/gvr/capi/include/gvr_audio.h" -#include "vr/gvr/capi/include/gvr_controller.h" -#include "vr/gvr/capi/include/gvr_types.h" -#include "world_layout_data.h" // NOLINT - -class TreasureHuntRenderer { - public: - /** - * Create a TreasureHuntRenderer using a given |gvr_context|. - * - * @param gvr_api The (non-owned) gvr_context. - * @param gvr_audio_api The (owned) gvr::AudioApi context. - */ - TreasureHuntRenderer(gvr_context* gvr_context, - std::unique_ptr gvr_audio_api); - - /** - * Destructor. - */ - ~TreasureHuntRenderer(); - - /** - * Initialize any GL-related objects. This should be called on the rendering - * thread with a valid GL context. - */ - void InitializeGl(); - - /** - * Draw the TreasureHunt scene. This should be called on the rendering thread. - */ - void DrawFrame(); - - /** - * Hide the cube if it's being targeted. - */ - void OnTriggerEvent(); - - /** - * Pause head tracking. - */ - void OnPause(); - - /** - * Resume head tracking, refreshing viewer parameters if necessary. - */ - void OnResume(); - - private: - int CreateTexture(int width, int height, int textureFormat, int textureType); - - /* - * Prepares the GvrApi framebuffer for rendering, resizing if needed. - */ - void PrepareFramebuffer(); - - /** - * Converts a raw text file, saved as a resource, into an OpenGL ES shader. - * - * @param type The type of shader we will be creating. - * @param resId The resource ID of the raw text file. - * @return The shader object handler. - */ - int LoadGLShader(int type, const char** shadercode); - - enum ViewType { - kLeftView, - kRightView, - kMultiview - }; - - /** - * Draws all world-space objects for the given view type. - * - * @param view Specifies which view we are rendering. - */ - void DrawWorld(ViewType view); - - /** - * Draws the reticle. The reticle is positioned using viewport parameters, - * so no data about its eye-space position is needed here. - */ - void DrawReticle(); - - /** - * Draw the cube. - * - * We've set all of our transformation matrices. Now we simply pass them - * into the shader. - * - * @param view Specifies which eye we are rendering: left, right, or both. - */ - void DrawCube(ViewType view); - - /** - * Draw the floor. - * - * This feeds in data for the floor into the shader. Note that this doesn't - * feed in data about position of the light, so if we rewrite our code to - * draw the floor first, the lighting might look strange. - * - * @param view Specifies which eye we are rendering: left, right, or both. - */ - void DrawFloor(ViewType view); - - /** - * Find a new random position for the object. - * - * We'll rotate it around the Y-axis so it's out of sight, and then up or - * down by a little bit. - */ - void HideObject(); - - /** - * Update the position of the reticle based on controller data. - * In Cardboard mode, this function simply sets the position to the center - * of the view. - */ - void UpdateReticlePosition(); - - /** - * Check if user is pointing or looking at the object by calculating whether - * the angle between the user's gaze or controller orientation and the vector - * pointing towards the object is lower than some threshold. - * - * @return true if the user is pointing at the object. - */ - bool IsPointingAtObject(); - - /** - * Preloads the cube sound sample and starts the spatialized playback at the - * current cube location. This method is executed from a separate thread to - * avoid any delay during construction and app initialization. - */ - void LoadAndPlayCubeSound(); - - /** - * Process the controller input. - * - * The controller state is updated with the latest touch pad, button clicking - * information, connection state and status of the controller. A log message - * is reported if the controller status or connection state changes. A click - * event is triggered if a click on app/click button is detected. - */ - void ProcessControllerInput(); - - /* - * Resume the controller api if needed. - * - * If the viewer type is cardboard, set the controller api pointer to null. - * If the viewer type is daydream, initialize the controller api as needed and - * resume. - */ - void ResumeControllerApiAsNeeded(); - - std::unique_ptr gvr_api_; - std::unique_ptr gvr_audio_api_; - std::unique_ptr viewport_list_; - std::unique_ptr swapchain_; - gvr::BufferViewport viewport_left_; - gvr::BufferViewport viewport_right_; - - std::vector lightpos_; - - WorldLayoutData world_layout_data_; - - const float* floor_vertices_; - const float* cube_vertices_; - const float* cube_colors_; - const float* cube_found_colors_; - const float* cube_normals_; - const float* reticle_vertices_; - - int cube_program_; - int floor_program_; - int reticle_program_; - - int cube_position_param_; - int cube_normal_param_; - int cube_color_param_; - int cube_model_param_; - int cube_modelview_param_; - int cube_modelview_projection_param_; - int cube_light_pos_param_; - - int floor_position_param_; - int floor_normal_param_; - int floor_color_param_; - int floor_model_param_; - int floor_modelview_param_; - int floor_modelview_projection_param_; - int floor_light_pos_param_; - - int reticle_position_param_; - int reticle_modelview_projection_param_; - - const gvr::Sizei reticle_render_size_; - - const std::array light_pos_world_space_; - - gvr::Mat4f head_view_; - gvr::Mat4f model_cube_; - gvr::Mat4f camera_; - gvr::Mat4f view_; - gvr::Mat4f model_floor_; - gvr::Mat4f model_reticle_; - gvr::Mat4f modelview_reticle_; - gvr::Sizei render_size_; - - // View-dependent values. These are stored in length two arrays to allow - // syncing with uniforms consumed by the multiview vertex shader. For - // simplicity, we stash valid values in both elements (left, right) of these - // arrays even when multiview is disabled. - std::array light_pos_eye_space_[2]; - gvr::Mat4f modelview_projection_cube_[2]; - gvr::Mat4f modelview_projection_floor_[2]; - gvr::Mat4f modelview_cube_[2]; - gvr::Mat4f modelview_floor_[2]; - - int score_; - float object_distance_; - float reticle_distance_; - bool multiview_enabled_; - - gvr::AudioSourceId audio_source_id_; - - gvr::AudioSourceId success_source_id_; - - std::thread audio_initialization_thread_; - - // Controller API entry point. - std::unique_ptr gvr_controller_api_; - - // The latest controller state (updated once per frame). - gvr::ControllerState gvr_controller_state_; - - gvr::ViewerType gvr_viewer_type_; -}; - -#endif // TREASUREHUNT_APP_SRC_MAIN_JNI_TREASUREHUNTRENDERER_H_ // NOLINT diff --git a/samples/ndk-treasurehunt/src/main/jni/treasure_hunt_shaders.h b/samples/ndk-treasurehunt/src/main/jni/treasure_hunt_shaders.h deleted file mode 100644 index 43ce5e81..00000000 --- a/samples/ndk-treasurehunt/src/main/jni/treasure_hunt_shaders.h +++ /dev/null @@ -1,186 +0,0 @@ -/* Copyright 2017 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef TREASUREHUNT_APP_SRC_MAIN_JNI_TREASUREHUNTSHADERS_H_ // NOLINT -#define TREASUREHUNT_APP_SRC_MAIN_JNI_TREASUREHUNTSHADERS_H_ // NOLINT - -// Each shader has two variants: a single-eye ES 2.0 variant, and a multiview -// ES 3.0 variant. The multiview vertex shaders use transforms defined by -// arrays of mat4 uniforms, using gl_ViewID_OVR to determine the array index. - -static const char* kDiffuseLightingVertexShaders[] = { - R"glsl( - uniform mat4 u_Model; - uniform mat4 u_MVP; - uniform mat4 u_MVMatrix; - uniform vec3 u_LightPos; - attribute vec4 a_Position; - attribute vec4 a_Color; - attribute vec3 a_Normal; - varying vec4 v_Color; - varying vec3 v_Grid; - - void main() { - v_Grid = vec3(u_Model * a_Position); - vec3 modelViewVertex = vec3(u_MVMatrix * a_Position); - vec3 modelViewNormal = vec3(u_MVMatrix * vec4(a_Normal, 0.0)); - float distance = length(u_LightPos - modelViewVertex); - vec3 lightVector = normalize(u_LightPos - modelViewVertex); - float diffuse = max(dot(modelViewNormal, lightVector), 0.5); - diffuse = diffuse * (1.0 / (1.0 + (0.00001 * distance * distance))); - v_Color = vec4(a_Color.rgb * diffuse, a_Color.a); - gl_Position = u_MVP * a_Position; - })glsl", - - R"glsl(#version 300 es - #extension GL_OVR_multiview2 : enable - - layout(num_views=2) in; - - uniform mat4 u_Model; - uniform mat4 u_MVP[2]; - uniform mat4 u_MVMatrix[2]; - uniform vec3 u_LightPos[2]; - in vec4 a_Position; - in vec4 a_Color; - in vec3 a_Normal; - out vec4 v_Color; - out vec3 v_Grid; - - void main() { - mat4 mvp = u_MVP[gl_ViewID_OVR]; - mat4 modelview = u_MVMatrix[gl_ViewID_OVR]; - vec3 lightpos = u_LightPos[gl_ViewID_OVR]; - v_Grid = vec3(u_Model * a_Position); - vec3 modelViewVertex = vec3(modelview * a_Position); - vec3 modelViewNormal = vec3(modelview * vec4(a_Normal, 0.0)); - float distance = length(lightpos - modelViewVertex); - vec3 lightVector = normalize(lightpos - modelViewVertex); - float diffuse = max(dot(modelViewNormal, lightVector), 0.5); - diffuse = diffuse * (1.0 / (1.0 + (0.00001 * distance * distance))); - v_Color = vec4(a_Color.rgb * diffuse, a_Color.a); - gl_Position = mvp * a_Position; - })glsl" -}; - -static const char* kGridFragmentShaders[] = { - R"glsl( - precision mediump float; - varying vec4 v_Color; - varying vec3 v_Grid; - - void main() { - float depth = gl_FragCoord.z / gl_FragCoord.w; - if ((mod(abs(v_Grid.x), 1.0) < 0.01) || - (mod(abs(v_Grid.z), 1.0) < 0.01)) { - gl_FragColor = max(0.0, (9.0-depth) / 9.0) * - vec4(1.0, 1.0, 1.0, 1.0) + - min(1.0, depth / 9.0) * v_Color; - } else { - gl_FragColor = v_Color; - } - })glsl", - - R"glsl(#version 300 es - - precision mediump float; - in vec4 v_Color; - in vec3 v_Grid; - out vec4 FragColor; - - void main() { - float depth = gl_FragCoord.z / gl_FragCoord.w; - if ((mod(abs(v_Grid.x), 1.0) < 0.01) || - (mod(abs(v_Grid.z), 1.0) < 0.01)) { - FragColor = max(0.0, (9.0-depth) / 9.0) * - vec4(1.0, 1.0, 1.0, 1.0) + - min(1.0, depth / 9.0) * v_Color; - } else { - FragColor = v_Color; - } - })glsl" -}; - -static const char* kPassthroughFragmentShaders[] = { - R"glsl( - precision mediump float; - varying vec4 v_Color; - - void main() { - gl_FragColor = v_Color; - })glsl", - - R"glsl(#version 300 es - - precision mediump float; - in vec4 v_Color; - out vec4 FragColor; - - void main() { - FragColor = v_Color; - })glsl" -}; - -static const char* kReticleVertexShaders[] = { R"glsl( - uniform mat4 u_MVP; - attribute vec4 a_Position; - varying vec2 v_Coords; - - void main() { - v_Coords = a_Position.xy; - gl_Position = u_MVP * a_Position; - })glsl", - - R"glsl(#version 300 es - #extension GL_OVR_multiview2 : enable - - layout(num_views=2) in; - uniform mat4 u_MVP[2]; - in vec4 a_Position; - out vec2 v_Coords; - - void main() { - v_Coords = a_Position.xy; - gl_Position = u_MVP[gl_ViewID_OVR] * a_Position; - })glsl" -}; - -static const char* kReticleFragmentShaders[] = { R"glsl( - precision mediump float; - - varying vec2 v_Coords; - - void main() { - float r = length(v_Coords); - float alpha = smoothstep(0.5, 0.6, r) * (1.0 - smoothstep(0.8, 0.9, r)); - if (alpha == 0.0) discard; - gl_FragColor = vec4(alpha); - })glsl", - - R"glsl(#version 300 es - precision mediump float; - - in vec2 v_Coords; - out vec4 FragColor; - - void main() { - float r = length(v_Coords); - float alpha = smoothstep(0.5, 0.6, r) * (1.0 - smoothstep(0.8, 0.9, r)); - if (alpha == 0.0) discard; - FragColor = vec4(alpha); - })glsl" -}; - -#endif // TREASUREHUNT_APP_SRC_MAIN_JNI_TREASUREHUNTSHADERS_H_ // NOLINT diff --git a/samples/ndk-treasurehunt/src/main/jni/world_layout_data.h b/samples/ndk-treasurehunt/src/main/jni/world_layout_data.h deleted file mode 100644 index e45c47ae..00000000 --- a/samples/ndk-treasurehunt/src/main/jni/world_layout_data.h +++ /dev/null @@ -1,222 +0,0 @@ -/* Copyright 2017 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef TREASUREHUNT_APP_SRC_MAIN_JNI_WORLDLAYOUTDATA_H_ // NOLINT -#define TREASUREHUNT_APP_SRC_MAIN_JNI_WORLDLAYOUTDATA_H_ // NOLINT - -#include - -// Contains vertex, normal and other data. -class WorldLayoutData { - public: - const std::array cube_coords; - const std::array cube_colors; - const std::array cube_found_color; - const std::array cube_normals; - const std::array floor_coords; - const std::array reticle_coords; - - WorldLayoutData() : - cube_coords({{ - // Front face - -1.0f, 1.0f, 1.0f, - -1.0f, -1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, - -1.0f, -1.0f, 1.0f, - 1.0f, -1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, - - // Right face - 1.0f, 1.0f, 1.0f, - 1.0f, -1.0f, 1.0f, - 1.0f, 1.0f, -1.0f, - 1.0f, -1.0f, 1.0f, - 1.0f, -1.0f, -1.0f, - 1.0f, 1.0f, -1.0f, - - // Back face - 1.0f, 1.0f, -1.0f, - 1.0f, -1.0f, -1.0f, - -1.0f, 1.0f, -1.0f, - 1.0f, -1.0f, -1.0f, - -1.0f, -1.0f, -1.0f, - -1.0f, 1.0f, -1.0f, - - // Left face - -1.0f, 1.0f, -1.0f, - -1.0f, -1.0f, -1.0f, - -1.0f, 1.0f, 1.0f, - -1.0f, -1.0f, -1.0f, - -1.0f, -1.0f, 1.0f, - -1.0f, 1.0f, 1.0f, - - // Top face - -1.0f, 1.0f, -1.0f, - -1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, -1.0f, - -1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, -1.0f, - - // Bottom face - 1.0f, -1.0f, -1.0f, - 1.0f, -1.0f, 1.0f, - -1.0f, -1.0f, -1.0f, - 1.0f, -1.0f, 1.0f, - -1.0f, -1.0f, 1.0f, - -1.0f, -1.0f, -1.0f}}), - cube_colors({{ - // front, green - 0.0f, 0.5273f, 0.2656f, - 0.0f, 0.5273f, 0.2656f, - 0.0f, 0.5273f, 0.2656f, - 0.0f, 0.5273f, 0.2656f, - 0.0f, 0.5273f, 0.2656f, - 0.0f, 0.5273f, 0.2656f, - - // right, blue - 0.0f, 0.3398f, 0.9023f, - 0.0f, 0.3398f, 0.9023f, - 0.0f, 0.3398f, 0.9023f, - 0.0f, 0.3398f, 0.9023f, - 0.0f, 0.3398f, 0.9023f, - 0.0f, 0.3398f, 0.9023f, - - // back, also green - 0.0f, 0.5273f, 0.2656f, - 0.0f, 0.5273f, 0.2656f, - 0.0f, 0.5273f, 0.2656f, - 0.0f, 0.5273f, 0.2656f, - 0.0f, 0.5273f, 0.2656f, - 0.0f, 0.5273f, 0.2656f, - - // left, also blue - 0.0f, 0.3398f, 0.9023f, - 0.0f, 0.3398f, 0.9023f, - 0.0f, 0.3398f, 0.9023f, - 0.0f, 0.3398f, 0.9023f, - 0.0f, 0.3398f, 0.9023f, - 0.0f, 0.3398f, 0.9023f, - - // top, red - 0.8359375f, 0.17578125f, 0.125f, - 0.8359375f, 0.17578125f, 0.125f, - 0.8359375f, 0.17578125f, 0.125f, - 0.8359375f, 0.17578125f, 0.125f, - 0.8359375f, 0.17578125f, 0.125f, - 0.8359375f, 0.17578125f, 0.125f, - - // bottom, also red - 0.8359375f, 0.17578125f, 0.125f, - 0.8359375f, 0.17578125f, 0.125f, - 0.8359375f, 0.17578125f, 0.125f, - 0.8359375f, 0.17578125f, 0.125f, - 0.8359375f, 0.17578125f, 0.125f, - 0.8359375f, 0.17578125f, 0.125f}}), - cube_found_color({{ 1.0f, 0.6523f, 0.0f }}), // yellow - cube_normals({{ - // Front face - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, - - // Right face - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - - // Back face - 0.0f, 0.0f, -1.0f, - 0.0f, 0.0f, -1.0f, - 0.0f, 0.0f, -1.0f, - 0.0f, 0.0f, -1.0f, - 0.0f, 0.0f, -1.0f, - 0.0f, 0.0f, -1.0f, - - // Left face - -1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - - // Top face - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - - // Bottom face - 0.0f, -1.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.0f, -1.0f, 0.0f}}), - // The grid lines on the floor are rendered procedurally and large polygons - // cause floating point precision problems on some architectures. So we - // split the floor into 4 quadrants. - floor_coords({{ - // +X, +Z quadrant - 20.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 20.0f, - 20.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 20.0f, - 20.0f, 0.0f, 20.0f, - - // -X, +Z quadrant - 0.0f, 0.0f, 0.0f, - -20.0f, 0.0f, 0.0f, - -20.0f, 0.0f, 20.0f, - 0.0f, 0.0f, 0.0f, - -20.0f, 0.0f, 20.0f, - 0.0f, 0.0f, 20.0f, - - // +X, -Z quadrant - 20.0f, 0.0f, -20.0f, - 0.0f, 0.0f, -20.0f, - 0.0f, 0.0f, 0.0f, - 20.0f, 0.0f, -20.0f, - 0.0f, 0.0f, 0.0f, - 20.0f, 0.0f, 0.0f, - - // -X, -Z quadrant - 0.0f, 0.0f, -20.0f, - -20.0f, 0.0f, -20.0f, - -20.0f, 0.0f, 0.0f, - 0.0f, 0.0f, -20.0f, - -20.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, - }}), - reticle_coords({{ - -1.f, 1.f, 0.0f, - -1.f, -1.f, 0.0f, - 1.f, 1.f, 0.0f, - -1.f, -1.f, 0.0f, - 1.f, -1.f, 0.0f, - 1.f, 1.f, 0.0f, - }}) {} -}; -#endif // TREASUREHUNT_APP_SRC_MAIN_JNI_WORLDLAYOUTDATA_H_ // NOLINT diff --git a/samples/ndk-treasurehunt/src/main/res/drawable-nodpi/vr_icon.png b/samples/ndk-treasurehunt/src/main/res/drawable-nodpi/vr_icon.png deleted file mode 100644 index 06f896db..00000000 Binary files a/samples/ndk-treasurehunt/src/main/res/drawable-nodpi/vr_icon.png and /dev/null differ diff --git a/samples/ndk-treasurehunt/src/main/res/drawable-nodpi/vr_icon_background.png b/samples/ndk-treasurehunt/src/main/res/drawable-nodpi/vr_icon_background.png deleted file mode 100644 index 6b8d8569..00000000 Binary files a/samples/ndk-treasurehunt/src/main/res/drawable-nodpi/vr_icon_background.png and /dev/null differ diff --git a/samples/ndk-treasurehunt/src/main/res/values/strings.xml b/samples/ndk-treasurehunt/src/main/res/values/strings.xml deleted file mode 100644 index f3abcf79..00000000 --- a/samples/ndk-treasurehunt/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - NativeTreasureHunt - diff --git a/samples/sdk-controllerclient/build.gradle b/samples/sdk-controllerclient/build.gradle index f4371de1..86aba4e0 100644 --- a/samples/sdk-controllerclient/build.gradle +++ b/samples/sdk-controllerclient/build.gradle @@ -35,6 +35,6 @@ android { } dependencies { - compile 'com.google.vr:sdk-base:1.160.0' - compile 'com.google.vr:sdk-controller:1.160.0' + compile 'com.google.vr:sdk-base:1.170.0' + compile 'com.google.vr:sdk-controller:1.170.0' } diff --git a/samples/sdk-controllerclient/src/main/AndroidManifest.xml b/samples/sdk-controllerclient/src/main/AndroidManifest.xml index 5dddb804..d8d66955 100644 --- a/samples/sdk-controllerclient/src/main/AndroidManifest.xml +++ b/samples/sdk-controllerclient/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="180716036" + android:versionName="1.170.0"> diff --git a/samples/sdk-hellovr/build.gradle b/samples/sdk-hellovr/build.gradle index 01be5ced..c296f9f8 100644 --- a/samples/sdk-hellovr/build.gradle +++ b/samples/sdk-hellovr/build.gradle @@ -35,8 +35,8 @@ android { } dependencies { - compile 'com.google.vr:sdk-audio:1.160.0' - compile 'com.google.vr:sdk-base:1.160.0' + compile 'com.google.vr:sdk-audio:1.170.0' + compile 'com.google.vr:sdk-base:1.170.0' // Obj - a simple Wavefront OBJ file loader // https://github.com/javagl/Obj diff --git a/samples/sdk-hellovr/src/main/AndroidManifest.xml b/samples/sdk-hellovr/src/main/AndroidManifest.xml index 1f99d986..6a212781 100644 --- a/samples/sdk-hellovr/src/main/AndroidManifest.xml +++ b/samples/sdk-hellovr/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="180716036" + android:versionName="1.170.0"> diff --git a/samples/sdk-simplepanowidget/build.gradle b/samples/sdk-simplepanowidget/build.gradle index 09b443f5..1ae00730 100644 --- a/samples/sdk-simplepanowidget/build.gradle +++ b/samples/sdk-simplepanowidget/build.gradle @@ -35,5 +35,5 @@ android { } dependencies { - compile 'com.google.vr:sdk-panowidget:1.160.0' + compile 'com.google.vr:sdk-panowidget:1.170.0' } diff --git a/samples/sdk-simplepanowidget/src/main/AndroidManifest.xml b/samples/sdk-simplepanowidget/src/main/AndroidManifest.xml index 46c261af..34b6b98b 100644 --- a/samples/sdk-simplepanowidget/src/main/AndroidManifest.xml +++ b/samples/sdk-simplepanowidget/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="180716036" + android:versionName="1.170.0"> diff --git a/samples/sdk-simplevideowidget/build.gradle b/samples/sdk-simplevideowidget/build.gradle index 166c52a0..7b00d2f2 100644 --- a/samples/sdk-simplevideowidget/build.gradle +++ b/samples/sdk-simplevideowidget/build.gradle @@ -35,5 +35,5 @@ android { } dependencies { - compile 'com.google.vr:sdk-videowidget:1.160.0' + compile 'com.google.vr:sdk-videowidget:1.170.0' } diff --git a/samples/sdk-simplevideowidget/src/main/AndroidManifest.xml b/samples/sdk-simplevideowidget/src/main/AndroidManifest.xml index 77cc53b2..4ad6dfd6 100644 --- a/samples/sdk-simplevideowidget/src/main/AndroidManifest.xml +++ b/samples/sdk-simplevideowidget/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="180716036" + android:versionName="1.170.0"> diff --git a/samples/sdk-treasurehunt/build.gradle b/samples/sdk-treasurehunt/build.gradle deleted file mode 100644 index 5c23a8de..00000000 --- a/samples/sdk-treasurehunt/build.gradle +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2017 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -apply plugin: 'com.android.application' - -android { - compileSdkVersion 26 - - defaultConfig { - minSdkVersion 19 - targetSdkVersion 24 - versionCode 1 - versionName "1.0" - } - - buildTypes { - release { - minifyEnabled true - proguardFiles.add(file('../../proguard-gvr.txt')) - } - - } -} - -dependencies { - compile 'com.google.vr:sdk-audio:1.160.0' - compile 'com.google.vr:sdk-base:1.160.0' -} diff --git a/samples/sdk-treasurehunt/src/main/AndroidManifest.xml b/samples/sdk-treasurehunt/src/main/AndroidManifest.xml deleted file mode 100644 index 2f418503..00000000 --- a/samples/sdk-treasurehunt/src/main/AndroidManifest.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/sdk-treasurehunt/src/main/assets/cube_sound.wav b/samples/sdk-treasurehunt/src/main/assets/cube_sound.wav deleted file mode 100644 index ac7b3234..00000000 Binary files a/samples/sdk-treasurehunt/src/main/assets/cube_sound.wav and /dev/null differ diff --git a/samples/sdk-treasurehunt/src/main/assets/success.wav b/samples/sdk-treasurehunt/src/main/assets/success.wav deleted file mode 100644 index 656272a3..00000000 Binary files a/samples/sdk-treasurehunt/src/main/assets/success.wav and /dev/null differ diff --git a/samples/sdk-treasurehunt/src/main/java/com/google/vr/sdk/samples/treasurehunt/TreasureHuntActivity.java b/samples/sdk-treasurehunt/src/main/java/com/google/vr/sdk/samples/treasurehunt/TreasureHuntActivity.java deleted file mode 100644 index 02dd9d76..00000000 --- a/samples/sdk-treasurehunt/src/main/java/com/google/vr/sdk/samples/treasurehunt/TreasureHuntActivity.java +++ /dev/null @@ -1,611 +0,0 @@ -/* - * Copyright 2017 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.vr.sdk.samples.treasurehunt; - -import android.content.Context; -import android.opengl.GLES20; -import android.opengl.Matrix; -import android.os.Bundle; -import android.os.Vibrator; -import android.util.Log; -import com.google.vr.sdk.audio.GvrAudioEngine; -import com.google.vr.sdk.base.AndroidCompat; -import com.google.vr.sdk.base.Eye; -import com.google.vr.sdk.base.GvrActivity; -import com.google.vr.sdk.base.GvrView; -import com.google.vr.sdk.base.HeadTransform; -import com.google.vr.sdk.base.Viewport; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.FloatBuffer; -import javax.microedition.khronos.egl.EGLConfig; - -/** - * A Google VR sample application. - * - *

The TreasureHunt scene consists of a planar ground grid and a floating - * "treasure" cube. When the user looks at the cube, the cube will turn gold. - * While gold, the user can activate the Cardboard trigger, either directly - * using the touch trigger on their Cardboard viewer, or using the Daydream - * controller-based trigger emulation. Activating the trigger will in turn - * randomly reposition the cube. - */ -public class TreasureHuntActivity extends GvrActivity implements GvrView.StereoRenderer { - - protected float[] modelCube; - protected float[] modelPosition; - - private static final String TAG = "TreasureHuntActivity"; - - private static final float Z_NEAR = 0.1f; - private static final float Z_FAR = 100.0f; - - private static final float CAMERA_Z = 0.01f; - private static final float TIME_DELTA = 0.3f; - - private static final float YAW_LIMIT = 0.12f; - private static final float PITCH_LIMIT = 0.12f; - - private static final int COORDS_PER_VERTEX = 3; - - // We keep the light always position just above the user. - private static final float[] LIGHT_POS_IN_WORLD_SPACE = new float[] {0.0f, 2.0f, 0.0f, 1.0f}; - - // Convenience vector for extracting the position from a matrix via multiplication. - private static final float[] POS_MATRIX_MULTIPLY_VEC = {0, 0, 0, 1.0f}; - - private static final float MIN_MODEL_DISTANCE = 3.0f; - private static final float MAX_MODEL_DISTANCE = 7.0f; - - private static final String OBJECT_SOUND_FILE = "cube_sound.wav"; - private static final String SUCCESS_SOUND_FILE = "success.wav"; - - private final float[] lightPosInEyeSpace = new float[4]; - - private FloatBuffer floorVertices; - private FloatBuffer floorColors; - private FloatBuffer floorNormals; - - private FloatBuffer cubeVertices; - private FloatBuffer cubeColors; - private FloatBuffer cubeFoundColors; - private FloatBuffer cubeNormals; - - private int cubeProgram; - private int floorProgram; - - private int cubePositionParam; - private int cubeNormalParam; - private int cubeColorParam; - private int cubeModelParam; - private int cubeModelViewParam; - private int cubeModelViewProjectionParam; - private int cubeLightPosParam; - - private int floorPositionParam; - private int floorNormalParam; - private int floorColorParam; - private int floorModelParam; - private int floorModelViewParam; - private int floorModelViewProjectionParam; - private int floorLightPosParam; - - private float[] camera; - private float[] view; - private float[] headView; - private float[] modelViewProjection; - private float[] modelView; - private float[] modelFloor; - - private float[] tempPosition; - private float[] headRotation; - - private float objectDistance = MAX_MODEL_DISTANCE / 2.0f; - private float floorDepth = 20f; - - private Vibrator vibrator; - - private GvrAudioEngine gvrAudioEngine; - private volatile int sourceId = GvrAudioEngine.INVALID_ID; - private volatile int successSourceId = GvrAudioEngine.INVALID_ID; - - /** - * Converts a raw text file, saved as a resource, into an OpenGL ES shader. - * - * @param type The type of shader we will be creating. - * @param resId The resource ID of the raw text file about to be turned into a shader. - * @return The shader object handler. - */ - private int loadGLShader(int type, int resId) { - String code = readRawTextFile(resId); - int shader = GLES20.glCreateShader(type); - GLES20.glShaderSource(shader, code); - GLES20.glCompileShader(shader); - - // Get the compilation status. - final int[] compileStatus = new int[1]; - GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0); - - // If the compilation failed, delete the shader. - if (compileStatus[0] == 0) { - Log.e(TAG, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shader)); - GLES20.glDeleteShader(shader); - shader = 0; - } - - if (shader == 0) { - throw new RuntimeException("Error creating shader."); - } - - return shader; - } - - /** - * Checks if we've had an error inside of OpenGL ES, and if so what that error is. - * - * @param label Label to report in case of error. - */ - private static void checkGLError(String label) { - int error; - while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { - Log.e(TAG, label + ": glError " + error); - throw new RuntimeException(label + ": glError " + error); - } - } - - /** - * Sets the view to our GvrView and initializes the transformation matrices we will use - * to render our scene. - */ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - initializeGvrView(); - - modelCube = new float[16]; - camera = new float[16]; - view = new float[16]; - modelViewProjection = new float[16]; - modelView = new float[16]; - modelFloor = new float[16]; - tempPosition = new float[4]; - // Model first appears directly in front of user. - modelPosition = new float[] {0.0f, 0.0f, -MAX_MODEL_DISTANCE / 2.0f}; - headRotation = new float[4]; - headView = new float[16]; - vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); - - // Initialize 3D audio engine. - gvrAudioEngine = new GvrAudioEngine(this, GvrAudioEngine.RenderingMode.BINAURAL_HIGH_QUALITY); - } - - public void initializeGvrView() { - setContentView(R.layout.common_ui); - - GvrView gvrView = (GvrView) findViewById(R.id.gvr_view); - gvrView.setEGLConfigChooser(8, 8, 8, 8, 16, 8); - - gvrView.setRenderer(this); - gvrView.setTransitionViewEnabled(true); - - // Enable Cardboard-trigger feedback with Daydream headsets. This is a simple way of supporting - // Daydream controller input for basic interactions using the existing Cardboard trigger API. - gvrView.enableCardboardTriggerEmulation(); - - if (gvrView.setAsyncReprojectionEnabled(true)) { - // Async reprojection decouples the app framerate from the display framerate, - // allowing immersive interaction even at the throttled clockrates set by - // sustained performance mode. - AndroidCompat.setSustainedPerformanceMode(this, true); - } - - setGvrView(gvrView); - } - - @Override - public void onPause() { - gvrAudioEngine.pause(); - super.onPause(); - } - - @Override - public void onResume() { - super.onResume(); - gvrAudioEngine.resume(); - } - - @Override - public void onRendererShutdown() { - Log.i(TAG, "onRendererShutdown"); - } - - @Override - public void onSurfaceChanged(int width, int height) { - Log.i(TAG, "onSurfaceChanged"); - } - - /** - * Creates the buffers we use to store information about the 3D world. - * - *

OpenGL doesn't use Java arrays, but rather needs data in a format it can understand. - * Hence we use ByteBuffers. - * - * @param config The EGL configuration used when creating the surface. - */ - @Override - public void onSurfaceCreated(EGLConfig config) { - Log.i(TAG, "onSurfaceCreated"); - GLES20.glClearColor(0.1f, 0.1f, 0.1f, 0.5f); // Dark background so text shows up well. - - ByteBuffer bbVertices = ByteBuffer.allocateDirect(WorldLayoutData.CUBE_COORDS.length * 4); - bbVertices.order(ByteOrder.nativeOrder()); - cubeVertices = bbVertices.asFloatBuffer(); - cubeVertices.put(WorldLayoutData.CUBE_COORDS); - cubeVertices.position(0); - - ByteBuffer bbColors = ByteBuffer.allocateDirect(WorldLayoutData.CUBE_COLORS.length * 4); - bbColors.order(ByteOrder.nativeOrder()); - cubeColors = bbColors.asFloatBuffer(); - cubeColors.put(WorldLayoutData.CUBE_COLORS); - cubeColors.position(0); - - ByteBuffer bbFoundColors = - ByteBuffer.allocateDirect(WorldLayoutData.CUBE_FOUND_COLORS.length * 4); - bbFoundColors.order(ByteOrder.nativeOrder()); - cubeFoundColors = bbFoundColors.asFloatBuffer(); - cubeFoundColors.put(WorldLayoutData.CUBE_FOUND_COLORS); - cubeFoundColors.position(0); - - ByteBuffer bbNormals = ByteBuffer.allocateDirect(WorldLayoutData.CUBE_NORMALS.length * 4); - bbNormals.order(ByteOrder.nativeOrder()); - cubeNormals = bbNormals.asFloatBuffer(); - cubeNormals.put(WorldLayoutData.CUBE_NORMALS); - cubeNormals.position(0); - - // make a floor - ByteBuffer bbFloorVertices = ByteBuffer.allocateDirect(WorldLayoutData.FLOOR_COORDS.length * 4); - bbFloorVertices.order(ByteOrder.nativeOrder()); - floorVertices = bbFloorVertices.asFloatBuffer(); - floorVertices.put(WorldLayoutData.FLOOR_COORDS); - floorVertices.position(0); - - ByteBuffer bbFloorNormals = ByteBuffer.allocateDirect(WorldLayoutData.FLOOR_NORMALS.length * 4); - bbFloorNormals.order(ByteOrder.nativeOrder()); - floorNormals = bbFloorNormals.asFloatBuffer(); - floorNormals.put(WorldLayoutData.FLOOR_NORMALS); - floorNormals.position(0); - - ByteBuffer bbFloorColors = ByteBuffer.allocateDirect(WorldLayoutData.FLOOR_COLORS.length * 4); - bbFloorColors.order(ByteOrder.nativeOrder()); - floorColors = bbFloorColors.asFloatBuffer(); - floorColors.put(WorldLayoutData.FLOOR_COLORS); - floorColors.position(0); - - int vertexShader = loadGLShader(GLES20.GL_VERTEX_SHADER, R.raw.light_vertex); - int gridShader = loadGLShader(GLES20.GL_FRAGMENT_SHADER, R.raw.grid_fragment); - int passthroughShader = loadGLShader(GLES20.GL_FRAGMENT_SHADER, R.raw.passthrough_fragment); - - cubeProgram = GLES20.glCreateProgram(); - GLES20.glAttachShader(cubeProgram, vertexShader); - GLES20.glAttachShader(cubeProgram, passthroughShader); - GLES20.glLinkProgram(cubeProgram); - GLES20.glUseProgram(cubeProgram); - - checkGLError("Cube program"); - - cubePositionParam = GLES20.glGetAttribLocation(cubeProgram, "a_Position"); - cubeNormalParam = GLES20.glGetAttribLocation(cubeProgram, "a_Normal"); - cubeColorParam = GLES20.glGetAttribLocation(cubeProgram, "a_Color"); - - cubeModelParam = GLES20.glGetUniformLocation(cubeProgram, "u_Model"); - cubeModelViewParam = GLES20.glGetUniformLocation(cubeProgram, "u_MVMatrix"); - cubeModelViewProjectionParam = GLES20.glGetUniformLocation(cubeProgram, "u_MVP"); - cubeLightPosParam = GLES20.glGetUniformLocation(cubeProgram, "u_LightPos"); - - checkGLError("Cube program params"); - - floorProgram = GLES20.glCreateProgram(); - GLES20.glAttachShader(floorProgram, vertexShader); - GLES20.glAttachShader(floorProgram, gridShader); - GLES20.glLinkProgram(floorProgram); - GLES20.glUseProgram(floorProgram); - - checkGLError("Floor program"); - - floorModelParam = GLES20.glGetUniformLocation(floorProgram, "u_Model"); - floorModelViewParam = GLES20.glGetUniformLocation(floorProgram, "u_MVMatrix"); - floorModelViewProjectionParam = GLES20.glGetUniformLocation(floorProgram, "u_MVP"); - floorLightPosParam = GLES20.glGetUniformLocation(floorProgram, "u_LightPos"); - - floorPositionParam = GLES20.glGetAttribLocation(floorProgram, "a_Position"); - floorNormalParam = GLES20.glGetAttribLocation(floorProgram, "a_Normal"); - floorColorParam = GLES20.glGetAttribLocation(floorProgram, "a_Color"); - - checkGLError("Floor program params"); - - Matrix.setIdentityM(modelFloor, 0); - Matrix.translateM(modelFloor, 0, 0, -floorDepth, 0); // Floor appears below user. - - // Avoid any delays during start-up due to decoding of sound files. - new Thread( - new Runnable() { - @Override - public void run() { - // Start spatial audio playback of OBJECT_SOUND_FILE at the model position. The - // returned sourceId handle is stored and allows for repositioning the sound object - // whenever the cube position changes. - gvrAudioEngine.preloadSoundFile(OBJECT_SOUND_FILE); - sourceId = gvrAudioEngine.createSoundObject(OBJECT_SOUND_FILE); - gvrAudioEngine.setSoundObjectPosition( - sourceId, modelPosition[0], modelPosition[1], modelPosition[2]); - gvrAudioEngine.playSound(sourceId, true /* looped playback */); - // Preload an unspatialized sound to be played on a successful trigger on the cube. - gvrAudioEngine.preloadSoundFile(SUCCESS_SOUND_FILE); - } - }) - .start(); - - updateModelPosition(); - - checkGLError("onSurfaceCreated"); - } - - /** - * Updates the cube model position. - */ - protected void updateModelPosition() { - Matrix.setIdentityM(modelCube, 0); - Matrix.translateM(modelCube, 0, modelPosition[0], modelPosition[1], modelPosition[2]); - - // Update the sound location to match it with the new cube position. - if (sourceId != GvrAudioEngine.INVALID_ID) { - gvrAudioEngine.setSoundObjectPosition( - sourceId, modelPosition[0], modelPosition[1], modelPosition[2]); - } - checkGLError("updateCubePosition"); - } - - /** - * Converts a raw text file into a string. - * - * @param resId The resource ID of the raw text file about to be turned into a shader. - * @return The context of the text file, or null in case of error. - */ - private String readRawTextFile(int resId) { - InputStream inputStream = getResources().openRawResource(resId); - try { - BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); - StringBuilder sb = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - sb.append(line).append("\n"); - } - reader.close(); - return sb.toString(); - } catch (IOException e) { - Log.e(TAG, "Failed to load text file: " + e); - } - return null; - } - - /** - * Prepares OpenGL ES before we draw a frame. - * - * @param headTransform The head transformation in the new frame. - */ - @Override - public void onNewFrame(HeadTransform headTransform) { - setCubeRotation(); - - // Build the camera matrix and apply it to the ModelView. - Matrix.setLookAtM(camera, 0, 0.0f, 0.0f, CAMERA_Z, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); - - headTransform.getHeadView(headView, 0); - - // Update the 3d audio engine with the most recent head rotation. - headTransform.getQuaternion(headRotation, 0); - gvrAudioEngine.setHeadRotation( - headRotation[0], headRotation[1], headRotation[2], headRotation[3]); - // Regular update call to GVR audio engine. - gvrAudioEngine.update(); - - checkGLError("onReadyToDraw"); - } - - protected void setCubeRotation() { - Matrix.rotateM(modelCube, 0, TIME_DELTA, 0.5f, 0.5f, 1.0f); - } - - /** - * Draws a frame for an eye. - * - * @param eye The eye to render. Includes all required transformations. - */ - @Override - public void onDrawEye(Eye eye) { - GLES20.glEnable(GLES20.GL_DEPTH_TEST); - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); - - checkGLError("colorParam"); - - // Apply the eye transformation to the camera. - Matrix.multiplyMM(view, 0, eye.getEyeView(), 0, camera, 0); - - // Set the position of the light - Matrix.multiplyMV(lightPosInEyeSpace, 0, view, 0, LIGHT_POS_IN_WORLD_SPACE, 0); - - // Build the ModelView and ModelViewProjection matrices - // for calculating cube position and light. - float[] perspective = eye.getPerspective(Z_NEAR, Z_FAR); - Matrix.multiplyMM(modelView, 0, view, 0, modelCube, 0); - Matrix.multiplyMM(modelViewProjection, 0, perspective, 0, modelView, 0); - drawCube(); - - // Set modelView for the floor, so we draw floor in the correct location - Matrix.multiplyMM(modelView, 0, view, 0, modelFloor, 0); - Matrix.multiplyMM(modelViewProjection, 0, perspective, 0, modelView, 0); - drawFloor(); - } - - @Override - public void onFinishFrame(Viewport viewport) {} - - /** - * Draw the cube. - * - *

We've set all of our transformation matrices. Now we simply pass them into the shader. - */ - public void drawCube() { - GLES20.glUseProgram(cubeProgram); - - GLES20.glUniform3fv(cubeLightPosParam, 1, lightPosInEyeSpace, 0); - - // Set the Model in the shader, used to calculate lighting - GLES20.glUniformMatrix4fv(cubeModelParam, 1, false, modelCube, 0); - - // Set the ModelView in the shader, used to calculate lighting - GLES20.glUniformMatrix4fv(cubeModelViewParam, 1, false, modelView, 0); - - // Set the position of the cube - GLES20.glVertexAttribPointer( - cubePositionParam, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, cubeVertices); - - // Set the ModelViewProjection matrix in the shader. - GLES20.glUniformMatrix4fv(cubeModelViewProjectionParam, 1, false, modelViewProjection, 0); - - // Set the normal positions of the cube, again for shading - GLES20.glVertexAttribPointer(cubeNormalParam, 3, GLES20.GL_FLOAT, false, 0, cubeNormals); - GLES20.glVertexAttribPointer(cubeColorParam, 4, GLES20.GL_FLOAT, false, 0, - isLookingAtObject() ? cubeFoundColors : cubeColors); - - // Enable vertex arrays - GLES20.glEnableVertexAttribArray(cubePositionParam); - GLES20.glEnableVertexAttribArray(cubeNormalParam); - GLES20.glEnableVertexAttribArray(cubeColorParam); - - GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 36); - - // Disable vertex arrays - GLES20.glDisableVertexAttribArray(cubePositionParam); - GLES20.glDisableVertexAttribArray(cubeNormalParam); - GLES20.glDisableVertexAttribArray(cubeColorParam); - - checkGLError("Drawing cube"); - } - - /** - * Draw the floor. - * - *

This feeds in data for the floor into the shader. Note that this doesn't feed in data about - * position of the light, so if we rewrite our code to draw the floor first, the lighting might - * look strange. - */ - public void drawFloor() { - GLES20.glUseProgram(floorProgram); - - // Set ModelView, MVP, position, normals, and color. - GLES20.glUniform3fv(floorLightPosParam, 1, lightPosInEyeSpace, 0); - GLES20.glUniformMatrix4fv(floorModelParam, 1, false, modelFloor, 0); - GLES20.glUniformMatrix4fv(floorModelViewParam, 1, false, modelView, 0); - GLES20.glUniformMatrix4fv(floorModelViewProjectionParam, 1, false, modelViewProjection, 0); - GLES20.glVertexAttribPointer( - floorPositionParam, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, floorVertices); - GLES20.glVertexAttribPointer(floorNormalParam, 3, GLES20.GL_FLOAT, false, 0, floorNormals); - GLES20.glVertexAttribPointer(floorColorParam, 4, GLES20.GL_FLOAT, false, 0, floorColors); - - GLES20.glEnableVertexAttribArray(floorPositionParam); - GLES20.glEnableVertexAttribArray(floorNormalParam); - GLES20.glEnableVertexAttribArray(floorColorParam); - - GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 24); - - GLES20.glDisableVertexAttribArray(floorPositionParam); - GLES20.glDisableVertexAttribArray(floorNormalParam); - GLES20.glDisableVertexAttribArray(floorColorParam); - - checkGLError("drawing floor"); - } - - /** - * Called when the Cardboard trigger is pulled. - */ - @Override - public void onCardboardTrigger() { - Log.i(TAG, "onCardboardTrigger"); - - if (isLookingAtObject()) { - successSourceId = gvrAudioEngine.createStereoSound(SUCCESS_SOUND_FILE); - gvrAudioEngine.playSound(successSourceId, false /* looping disabled */); - hideObject(); - } - - // Always give user feedback. - vibrator.vibrate(50); - } - - /** - * Find a new random position for the object. - * - *

We'll rotate it around the Y-axis so it's out of sight, and then up or down by a little bit. - */ - protected void hideObject() { - float[] rotationMatrix = new float[16]; - float[] posVec = new float[4]; - - // First rotate in XZ plane, between 90 and 270 deg away, and scale so that we vary - // the object's distance from the user. - float angleXZ = (float) Math.random() * 180 + 90; - Matrix.setRotateM(rotationMatrix, 0, angleXZ, 0f, 1f, 0f); - float oldObjectDistance = objectDistance; - objectDistance = - (float) Math.random() * (MAX_MODEL_DISTANCE - MIN_MODEL_DISTANCE) + MIN_MODEL_DISTANCE; - float objectScalingFactor = objectDistance / oldObjectDistance; - Matrix.scaleM(rotationMatrix, 0, objectScalingFactor, objectScalingFactor, objectScalingFactor); - Matrix.multiplyMV(posVec, 0, rotationMatrix, 0, modelCube, 12); - - float angleY = (float) Math.random() * 80 - 40; // Angle in Y plane, between -40 and 40. - angleY = (float) Math.toRadians(angleY); - float newY = (float) Math.tan(angleY) * objectDistance; - - modelPosition[0] = posVec[0]; - modelPosition[1] = newY; - modelPosition[2] = posVec[2]; - - updateModelPosition(); - } - - /** - * Check if user is looking at object by calculating where the object is in eye-space. - * - * @return true if the user is looking at the object. - */ - private boolean isLookingAtObject() { - // Convert object space to camera space. Use the headView from onNewFrame. - Matrix.multiplyMM(modelView, 0, headView, 0, modelCube, 0); - Matrix.multiplyMV(tempPosition, 0, modelView, 0, POS_MATRIX_MULTIPLY_VEC, 0); - - float pitch = (float) Math.atan2(tempPosition[1], -tempPosition[2]); - float yaw = (float) Math.atan2(tempPosition[0], -tempPosition[2]); - - return Math.abs(pitch) < PITCH_LIMIT && Math.abs(yaw) < YAW_LIMIT; - } -} diff --git a/samples/sdk-treasurehunt/src/main/java/com/google/vr/sdk/samples/treasurehunt/WorldLayoutData.java b/samples/sdk-treasurehunt/src/main/java/com/google/vr/sdk/samples/treasurehunt/WorldLayoutData.java deleted file mode 100644 index 401451da..00000000 --- a/samples/sdk-treasurehunt/src/main/java/com/google/vr/sdk/samples/treasurehunt/WorldLayoutData.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright 2017 Google Inc. All Rights Reserved. - - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.vr.sdk.samples.treasurehunt; - -/** - * Contains vertex, normal and color data. - */ -public final class WorldLayoutData { - - public static final float[] CUBE_COORDS = new float[] { - // Front face - -1.0f, 1.0f, 1.0f, - -1.0f, -1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, - -1.0f, -1.0f, 1.0f, - 1.0f, -1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, - - // Right face - 1.0f, 1.0f, 1.0f, - 1.0f, -1.0f, 1.0f, - 1.0f, 1.0f, -1.0f, - 1.0f, -1.0f, 1.0f, - 1.0f, -1.0f, -1.0f, - 1.0f, 1.0f, -1.0f, - - // Back face - 1.0f, 1.0f, -1.0f, - 1.0f, -1.0f, -1.0f, - -1.0f, 1.0f, -1.0f, - 1.0f, -1.0f, -1.0f, - -1.0f, -1.0f, -1.0f, - -1.0f, 1.0f, -1.0f, - - // Left face - -1.0f, 1.0f, -1.0f, - -1.0f, -1.0f, -1.0f, - -1.0f, 1.0f, 1.0f, - -1.0f, -1.0f, -1.0f, - -1.0f, -1.0f, 1.0f, - -1.0f, 1.0f, 1.0f, - - // Top face - -1.0f, 1.0f, -1.0f, - -1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, -1.0f, - -1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, -1.0f, - - // Bottom face - 1.0f, -1.0f, -1.0f, - 1.0f, -1.0f, 1.0f, - -1.0f, -1.0f, -1.0f, - 1.0f, -1.0f, 1.0f, - -1.0f, -1.0f, 1.0f, - -1.0f, -1.0f, -1.0f, - }; - - public static final float[] CUBE_COLORS = new float[] { - // front, green - 0f, 0.5273f, 0.2656f, 1.0f, - 0f, 0.5273f, 0.2656f, 1.0f, - 0f, 0.5273f, 0.2656f, 1.0f, - 0f, 0.5273f, 0.2656f, 1.0f, - 0f, 0.5273f, 0.2656f, 1.0f, - 0f, 0.5273f, 0.2656f, 1.0f, - - // right, blue - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - - // back, also green - 0f, 0.5273f, 0.2656f, 1.0f, - 0f, 0.5273f, 0.2656f, 1.0f, - 0f, 0.5273f, 0.2656f, 1.0f, - 0f, 0.5273f, 0.2656f, 1.0f, - 0f, 0.5273f, 0.2656f, 1.0f, - 0f, 0.5273f, 0.2656f, 1.0f, - - // left, also blue - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - - // top, red - 0.8359375f, 0.17578125f, 0.125f, 1.0f, - 0.8359375f, 0.17578125f, 0.125f, 1.0f, - 0.8359375f, 0.17578125f, 0.125f, 1.0f, - 0.8359375f, 0.17578125f, 0.125f, 1.0f, - 0.8359375f, 0.17578125f, 0.125f, 1.0f, - 0.8359375f, 0.17578125f, 0.125f, 1.0f, - - // bottom, also red - 0.8359375f, 0.17578125f, 0.125f, 1.0f, - 0.8359375f, 0.17578125f, 0.125f, 1.0f, - 0.8359375f, 0.17578125f, 0.125f, 1.0f, - 0.8359375f, 0.17578125f, 0.125f, 1.0f, - 0.8359375f, 0.17578125f, 0.125f, 1.0f, - 0.8359375f, 0.17578125f, 0.125f, 1.0f, - }; - - public static final float[] CUBE_FOUND_COLORS = new float[] { - // front, yellow - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - - // right, yellow - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - - // back, yellow - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - - // left, yellow - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - - // top, yellow - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - - // bottom, yellow - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - 1.0f, 0.6523f, 0.0f, 1.0f, - }; - - public static final float[] CUBE_NORMALS = new float[] { - // Front face - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, - - // Right face - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - - // Back face - 0.0f, 0.0f, -1.0f, - 0.0f, 0.0f, -1.0f, - 0.0f, 0.0f, -1.0f, - 0.0f, 0.0f, -1.0f, - 0.0f, 0.0f, -1.0f, - 0.0f, 0.0f, -1.0f, - - // Left face - -1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, - - // Top face - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - - // Bottom face - 0.0f, -1.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.0f, -1.0f, 0.0f - }; - - // The grid lines on the floor are rendered procedurally and large polygons cause floating point - // precision problems on some architectures. So we split the floor into 4 quadrants. - public static final float[] FLOOR_COORDS = new float[] { - // +X, +Z quadrant - 200, 0, 0, - 0, 0, 0, - 0, 0, 200, - 200, 0, 0, - 0, 0, 200, - 200, 0, 200, - - // -X, +Z quadrant - 0, 0, 0, - -200, 0, 0, - -200, 0, 200, - 0, 0, 0, - -200, 0, 200, - 0, 0, 200, - - // +X, -Z quadrant - 200, 0, -200, - 0, 0, -200, - 0, 0, 0, - 200, 0, -200, - 0, 0, 0, - 200, 0, 0, - - // -X, -Z quadrant - 0, 0, -200, - -200, 0, -200, - -200, 0, 0, - 0, 0, -200, - -200, 0, 0, - 0, 0, 0, - }; - - public static final float[] FLOOR_NORMALS = new float[] { - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - }; - - public static final float[] FLOOR_COLORS = new float[] { - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - 0.0f, 0.3398f, 0.9023f, 1.0f, - }; -} diff --git a/samples/sdk-treasurehunt/src/main/res/drawable-nodpi/vr_icon.png b/samples/sdk-treasurehunt/src/main/res/drawable-nodpi/vr_icon.png deleted file mode 100644 index 06f896db..00000000 Binary files a/samples/sdk-treasurehunt/src/main/res/drawable-nodpi/vr_icon.png and /dev/null differ diff --git a/samples/sdk-treasurehunt/src/main/res/drawable-nodpi/vr_icon_background.png b/samples/sdk-treasurehunt/src/main/res/drawable-nodpi/vr_icon_background.png deleted file mode 100644 index 6b8d8569..00000000 Binary files a/samples/sdk-treasurehunt/src/main/res/drawable-nodpi/vr_icon_background.png and /dev/null differ diff --git a/samples/sdk-treasurehunt/src/main/res/layout/common_ui.xml b/samples/sdk-treasurehunt/src/main/res/layout/common_ui.xml deleted file mode 100644 index 72625985..00000000 --- a/samples/sdk-treasurehunt/src/main/res/layout/common_ui.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - diff --git a/samples/sdk-treasurehunt/src/main/res/raw/grid_fragment.shader b/samples/sdk-treasurehunt/src/main/res/raw/grid_fragment.shader deleted file mode 100644 index 55aa8271..00000000 --- a/samples/sdk-treasurehunt/src/main/res/raw/grid_fragment.shader +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2017 Google Inc. All Rights Reserved. - - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -precision mediump float; -varying vec4 v_Color; -varying vec3 v_Grid; - -void main() { - float depth = gl_FragCoord.z / gl_FragCoord.w; // Calculate world-space distance. - - if ((mod(abs(v_Grid.x), 10.0) < 0.1) || (mod(abs(v_Grid.z), 10.0) < 0.1)) { - gl_FragColor = max(0.0, (90.0-depth) / 90.0) * vec4(1.0, 1.0, 1.0, 1.0) - + min(1.0, depth / 90.0) * v_Color; - } else { - gl_FragColor = v_Color; - } -} diff --git a/samples/sdk-treasurehunt/src/main/res/raw/light_vertex.shader b/samples/sdk-treasurehunt/src/main/res/raw/light_vertex.shader deleted file mode 100644 index 9ef4f5fb..00000000 --- a/samples/sdk-treasurehunt/src/main/res/raw/light_vertex.shader +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2017 Google Inc. All Rights Reserved. - - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -uniform mat4 u_Model; -uniform mat4 u_MVP; -uniform mat4 u_MVMatrix; -uniform vec3 u_LightPos; - -attribute vec4 a_Position; -attribute vec4 a_Color; -attribute vec3 a_Normal; - -varying vec4 v_Color; -varying vec3 v_Grid; - -void main() { - v_Grid = vec3(u_Model * a_Position); - - vec3 modelViewVertex = vec3(u_MVMatrix * a_Position); - vec3 modelViewNormal = vec3(u_MVMatrix * vec4(a_Normal, 0.0)); - - float distance = length(u_LightPos - modelViewVertex); - vec3 lightVector = normalize(u_LightPos - modelViewVertex); - float diffuse = max(dot(modelViewNormal, lightVector), 0.5); - - diffuse = diffuse * (1.0 / (1.0 + (0.00001 * distance * distance))); - v_Color = vec4(a_Color.rgb * diffuse, a_Color.a); - gl_Position = u_MVP * a_Position; -} diff --git a/samples/sdk-treasurehunt/src/main/res/raw/passthrough_fragment.shader b/samples/sdk-treasurehunt/src/main/res/raw/passthrough_fragment.shader deleted file mode 100644 index f087a003..00000000 --- a/samples/sdk-treasurehunt/src/main/res/raw/passthrough_fragment.shader +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2017 Google Inc. All Rights Reserved. - - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -precision mediump float; -varying vec4 v_Color; - -void main() { - gl_FragColor = v_Color; -} diff --git a/samples/sdk-treasurehunt/src/main/res/values/strings.xml b/samples/sdk-treasurehunt/src/main/res/values/strings.xml deleted file mode 100644 index 4c9a5184..00000000 --- a/samples/sdk-treasurehunt/src/main/res/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - TreasureHunt - diff --git a/samples/sdk-video360/build.gradle b/samples/sdk-video360/build.gradle index cc77ef9a..f7499f66 100644 --- a/samples/sdk-video360/build.gradle +++ b/samples/sdk-video360/build.gradle @@ -36,6 +36,6 @@ android { dependencies { compile 'com.android.support:appcompat-v7:26.1.0' - compile 'com.google.vr:sdk-base:1.160.0' - compile 'com.google.vr:sdk-controller:1.160.0' + compile 'com.google.vr:sdk-base:1.170.0' + compile 'com.google.vr:sdk-controller:1.170.0' } diff --git a/samples/sdk-video360/src/main/AndroidManifest.xml b/samples/sdk-video360/src/main/AndroidManifest.xml index dbbffacc..38f38900 100644 --- a/samples/sdk-video360/src/main/AndroidManifest.xml +++ b/samples/sdk-video360/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="180716036" + android:versionName="1.170.0"> diff --git a/samples/sdk-videoplayer/build.gradle b/samples/sdk-videoplayer/build.gradle index ffa28a0e..8bc25628 100644 --- a/samples/sdk-videoplayer/build.gradle +++ b/samples/sdk-videoplayer/build.gradle @@ -38,6 +38,6 @@ dependencies { compile 'com.google.android.exoplayer:exoplayer:2.6.1' compile 'com.google.android.exoplayer:extension-gvr:2.6.1' - compile 'com.google.vr:sdk-base:1.160.0' - compile 'com.google.vr:sdk-common:1.160.0' + compile 'com.google.vr:sdk-base:1.170.0' + compile 'com.google.vr:sdk-common:1.170.0' } diff --git a/samples/sdk-videoplayer/src/main/AndroidManifest.xml b/samples/sdk-videoplayer/src/main/AndroidManifest.xml index 53cccc8a..e82d6174 100644 --- a/samples/sdk-videoplayer/src/main/AndroidManifest.xml +++ b/samples/sdk-videoplayer/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="180716036" + android:versionName="1.170.0"> @@ -42,6 +42,7 @@ + diff --git a/samples/sdk-videoplayer/src/main/java/com/google/vr/sdk/samples/videoplayer/VideoScene.java b/samples/sdk-videoplayer/src/main/java/com/google/vr/sdk/samples/videoplayer/VideoScene.java index 0520f666..328141d9 100644 --- a/samples/sdk-videoplayer/src/main/java/com/google/vr/sdk/samples/videoplayer/VideoScene.java +++ b/samples/sdk-videoplayer/src/main/java/com/google/vr/sdk/samples/videoplayer/VideoScene.java @@ -273,13 +273,13 @@ public void updateVideoFpsFraction( * This needs to be called every time the GL context is re-created. There is no release * counterpart for now, since GL resources are automatically cleaned up when the GL context * is destroyed. - * + * * @param context Android activity context used to load the resources. */ public void prepareGLResources(Context context) { resources.prepare(context); } - + /** * Manages all GL resources used by video scenes. Only one copy of these resources is needed * for all VideoScene instances. @@ -341,7 +341,7 @@ private static final class Resources { if (spriteProgram == 0) { throw new RuntimeException("Could not create sprite program"); } - + // Prepare vertex data. ByteBuffer vertices = ByteBuffer.allocateDirect(VERTEX_DATA.length * FLOAT_SIZE_BYTES) .order(ByteOrder.nativeOrder()); @@ -350,7 +350,7 @@ private static final class Resources { vertexPositions.position(VERTEX_DATA_POS_OFFSET); vertexUVs = vertices.asFloatBuffer(); vertexUVs.position(VERTEX_DATA_UV_OFFSET); - + // Load the texture to be shown instead of the video while the latter is initializing. int[] textureIds = new int[1]; GLES20.glGenTextures(1, textureIds, 0); diff --git a/samples/sdk-videoplayer/src/main/java/com/google/vr/sdk/samples/videoplayer/VideoSceneRenderer.java b/samples/sdk-videoplayer/src/main/java/com/google/vr/sdk/samples/videoplayer/VideoSceneRenderer.java index faf96aa8..24e6abf3 100644 --- a/samples/sdk-videoplayer/src/main/java/com/google/vr/sdk/samples/videoplayer/VideoSceneRenderer.java +++ b/samples/sdk-videoplayer/src/main/java/com/google/vr/sdk/samples/videoplayer/VideoSceneRenderer.java @@ -211,18 +211,19 @@ private void updateHeadAndEyeMatrices() { Matrix.multiplyMM(eyeFromWorld[eye], 0, eyeFromHead, 0, headFromWorld, 0); } if (gvrAudioProcessor != null) { + // Extract orientation quaternion from the head-from-world matrix. float sx = headFromWorld[0]; float sy = headFromWorld[5]; float sz = headFromWorld[10]; - float w = (float) Math.sqrt(Math.max(0.0f, 1.0 + sx + sy + sz)) * 0.5f; + float w = (float) Math.sqrt(Math.max(0.0f, 1.0 + sx + sy + sz)) * -0.5f; float x = (float) Math.sqrt(Math.max(0.0f, 1.0 + sx - sy - sz)) * 0.5f; - float y = (float) Math.sqrt(Math.max(0.0f, 1.0 - sx + sy - sz)) * 0.5f; + float y = (float) Math.sqrt(Math.max(0.0f, 1.0 - sx + sy - sz)) * -0.5f; float z = (float) Math.sqrt(Math.max(0.0f, 1.0 - sx - sy + sz)) * 0.5f; gvrAudioProcessor.updateOrientation( + w, (headFromWorld[6] - headFromWorld[9] < 0) != (x < 0) ? -x : x, (headFromWorld[8] - headFromWorld[2] < 0) != (y < 0) ? -y : y, - (headFromWorld[1] - headFromWorld[4] < 0) != (z < 0) ? -z : z, - w); + (headFromWorld[1] - headFromWorld[4] < 0) != (z < 0) ? -z : z); } } diff --git a/settings.gradle b/settings.gradle index 13b66854..f7c709ee 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,7 +6,6 @@ include ':samples:sdk-controllerclient' include ':samples:sdk-hellovr' include ':samples:sdk-simplepanowidget' include ':samples:sdk-simplevideowidget' -include ':samples:sdk-treasurehunt' include ':samples:sdk-video360' include ':samples:sdk-videoplayer' @@ -15,9 +14,7 @@ include ':samples:sdk-videoplayer' // files by running "./gradlew :extractNdk" which will create a libraries/jni // folder. Then uncomment these lines to enable the NDK samples and synchronize // Android Studio. -//include ':samples:ndk-controllerpaint' //include ':samples:ndk-hellovr' -//include ':samples:ndk-treasurehunt' // Android Studio doesn't preserve nested modules in its Project View. To create // a cleaner layout, we reorganize and rename the modules loaded above.