├── .github └── ISSUE_TEMPLATE.md ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── part0_work ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ ├── models │ │ ├── andy.obj │ │ ├── andy.png │ │ └── andy_spec.png │ └── shaders │ │ ├── object.frag │ │ ├── object.vert │ │ ├── screenquad.frag │ │ └── screenquad.vert │ ├── java │ └── com │ │ └── google │ │ └── ar │ │ └── core │ │ └── codelab │ │ ├── common │ │ ├── helpers │ │ │ ├── CameraPermissionHelper.java │ │ │ ├── DisplayRotationHelper.java │ │ │ ├── FullScreenHelper.java │ │ │ ├── SnackbarHelper.java │ │ │ ├── TapHelper.java │ │ │ └── TrackingStateHelper.java │ │ └── rendering │ │ │ ├── BackgroundRenderer.java │ │ │ ├── ObjectRenderer.java │ │ │ └── ShaderUtil.java │ │ └── depth │ │ └── DepthCodelabActivity.java │ └── res │ ├── drawable-xxhdpi │ └── ic_launcher.png │ ├── layout │ └── activity_main.xml │ └── values │ ├── strings.xml │ └── styles.xml ├── part1 ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ ├── models │ │ ├── andy.obj │ │ ├── andy.png │ │ └── andy_spec.png │ └── shaders │ │ ├── object.frag │ │ ├── object.vert │ │ ├── screenquad.frag │ │ └── screenquad.vert │ ├── java │ └── com │ │ └── google │ │ └── ar │ │ └── core │ │ └── codelab │ │ ├── common │ │ ├── helpers │ │ │ ├── CameraPermissionHelper.java │ │ │ ├── DisplayRotationHelper.java │ │ │ ├── FullScreenHelper.java │ │ │ ├── SnackbarHelper.java │ │ │ ├── TapHelper.java │ │ │ └── TrackingStateHelper.java │ │ └── rendering │ │ │ ├── BackgroundRenderer.java │ │ │ ├── ObjectRenderer.java │ │ │ └── ShaderUtil.java │ │ └── depth │ │ └── DepthCodelabActivity.java │ └── res │ ├── drawable-xxhdpi │ └── ic_launcher.png │ ├── layout │ └── activity_main.xml │ └── values │ ├── strings.xml │ └── styles.xml ├── part2 ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ ├── models │ │ ├── andy.obj │ │ ├── andy.png │ │ └── andy_spec.png │ └── shaders │ │ ├── object.frag │ │ ├── object.vert │ │ ├── screenquad.frag │ │ └── screenquad.vert │ ├── java │ └── com │ │ └── google │ │ └── ar │ │ └── core │ │ └── codelab │ │ ├── common │ │ ├── helpers │ │ │ ├── CameraPermissionHelper.java │ │ │ ├── DisplayRotationHelper.java │ │ │ ├── FullScreenHelper.java │ │ │ ├── SnackbarHelper.java │ │ │ ├── TapHelper.java │ │ │ └── TrackingStateHelper.java │ │ └── rendering │ │ │ ├── BackgroundRenderer.java │ │ │ ├── ObjectRenderer.java │ │ │ └── ShaderUtil.java │ │ └── depth │ │ ├── DepthCodelabActivity.java │ │ └── DepthTextureHandler.java │ └── res │ ├── drawable-xxhdpi │ └── ic_launcher.png │ ├── layout │ └── activity_main.xml │ └── values │ ├── strings.xml │ └── styles.xml ├── part3 ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ ├── models │ │ ├── andy.obj │ │ ├── andy.png │ │ └── andy_spec.png │ └── shaders │ │ ├── background_show_depth_map.frag │ │ ├── background_show_depth_map.vert │ │ ├── object.frag │ │ ├── object.vert │ │ ├── screenquad.frag │ │ └── screenquad.vert │ ├── java │ └── com │ │ └── google │ │ └── ar │ │ └── core │ │ └── codelab │ │ ├── common │ │ ├── helpers │ │ │ ├── CameraPermissionHelper.java │ │ │ ├── DisplayRotationHelper.java │ │ │ ├── FullScreenHelper.java │ │ │ ├── SnackbarHelper.java │ │ │ ├── TapHelper.java │ │ │ └── TrackingStateHelper.java │ │ └── rendering │ │ │ ├── BackgroundRenderer.java │ │ │ ├── ObjectRenderer.java │ │ │ └── ShaderUtil.java │ │ └── depth │ │ ├── DepthCodelabActivity.java │ │ └── DepthTextureHandler.java │ └── res │ ├── drawable-xxhdpi │ └── ic_launcher.png │ ├── layout │ └── activity_main.xml │ └── values │ ├── strings.xml │ └── styles.xml ├── part4_completed ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ ├── models │ │ ├── andy.obj │ │ ├── andy.png │ │ └── andy_spec.png │ └── shaders │ │ ├── background_show_depth_map.frag │ │ ├── background_show_depth_map.vert │ │ ├── object.frag │ │ ├── object.vert │ │ ├── occlusion_object.frag │ │ ├── occlusion_object.vert │ │ ├── screenquad.frag │ │ └── screenquad.vert │ ├── java │ └── com │ │ └── google │ │ └── ar │ │ └── core │ │ └── codelab │ │ ├── common │ │ ├── helpers │ │ │ ├── CameraPermissionHelper.java │ │ │ ├── DisplayRotationHelper.java │ │ │ ├── FullScreenHelper.java │ │ │ ├── SnackbarHelper.java │ │ │ ├── TapHelper.java │ │ │ └── TrackingStateHelper.java │ │ └── rendering │ │ │ ├── BackgroundRenderer.java │ │ │ ├── ObjectRenderer.java │ │ │ ├── OcclusionObjectRenderer.java │ │ │ └── ShaderUtil.java │ │ └── depth │ │ ├── DepthCodelabActivity.java │ │ └── DepthTextureHandler.java │ └── res │ ├── drawable-xxhdpi │ └── ic_launcher.png │ ├── layout │ └── activity_main.xml │ └── values │ ├── strings.xml │ └── styles.xml └── settings.gradle /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | ### SPECIFIC ISSUE ENCOUNTERED 14 | 15 | 16 | ### VERSIONS USED 17 | - Android Studio: 18 | - ARCore SDK for Android: 19 | - Device manufacturer, model, and O/S: 20 | - ARCore: 21 | On Windows, use: `adb shell pm dump com.google.ar.core | findstr /i "packages: versionName"` 22 | On macOS, use: `adb shell pm dump com.google.ar.core | egrep -i versionName\|packages:` 23 | - Output of `adb shell getprop ro.build.fingerprint`: 24 | 25 | 26 | ### STEPS TO REPRODUCE THE ISSUE 27 | 1. 28 | 1. 29 | 1. 30 | 31 | 32 | ### WORKAROUNDS (IF ANY) 33 | 34 | 35 | ### ADDITIONAL COMMENTS 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Android Studio configuration. 2 | *.iml 3 | .idea/ 4 | 5 | # Gradle configuration. 6 | .gradle/ 7 | build/ 8 | 9 | # User configuration. 10 | local.properties 11 | 12 | # OS configurations. 13 | .DS_Store 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Contributor License Agreement 7 | 8 | Contributions to this project must be accompanied by a Contributor License 9 | Agreement. You (or your employer) retain the copyright to your contribution; 10 | this simply gives us permission to use and redistribute your contributions as 11 | part of the project. Head over to to see 12 | your current agreements on file or to sign a new one. 13 | 14 | You generally only need to submit a CLA once, so if you've already submitted one 15 | (even if it was for a different project), you probably don't need to do it 16 | again. 17 | 18 | ## Code reviews 19 | 20 | All submissions, including submissions by project members, require review. We 21 | use GitHub pull requests for this purpose. Consult 22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 23 | information on using pull requests. 24 | 25 | ## Community Guidelines 26 | 27 | This project follows [Google's Open Source Community 28 | Guidelines](https://opensource.google/conduct/). 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ARCore Depth API Codelab 2 | ======================== 3 | Copyright 2020 Google LLC. All rights reserved. 4 | 5 | This Codelab provides examples for how developers can use the Depth API in ARCore to expand the realism of their AR applications. 6 | 7 | This codelab provides step-by-step instructions for how to use depth for the following use-cases: 8 | * Depth-based occlusion: Allowing virtual objects to hide behind real-world objects. 9 | * Visual effects: Showing the 3D geometry of the scene with pulsing colors. 10 | 11 | ## Android Studio projects 12 | 13 | This codelab contains the following projects: 14 | * `part0_work`: The starter app. You should make edits to this module when doing this codelab. 15 | * `part1`: Reference code of what your edits should look like when you complete Part 1 (checking depth support). 16 | * `part2`: Reference code when you complete Part 2 (retrieving the depth texture). 17 | * `part3`: Reference code when you complete Part 3 (visualizing the depth texture). 18 | * `part4_completed`: The final version of the app (including depth-based occlusion). Reference code when you complete Part 4 and this codelab. 19 | 20 | ## Related links 21 | 22 | * https://codelabs.developers.google.com/codelabs/arcore-depth/#0 23 | * https://developers.google.com/ar/develop/java/depth/overview 24 | * https://developers.googleblog.com/2020/06/a-new-wave-of-ar-realism-with-arcore-depth-api.html 25 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | google() 6 | jcenter() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.0.1' 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | google() 18 | jcenter() 19 | mavenLocal() 20 | } 21 | } 22 | 23 | task clean(type: Delete) { 24 | delete rootProject.buildDir 25 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | 19 | # Enables Android X. 20 | android.useAndroidX=true 21 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 20 16:28:34 EDT 2022 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip 7 | -------------------------------------------------------------------------------- /part0_work/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | google-services.json 3 | -------------------------------------------------------------------------------- /part0_work/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | def setVersionName = { -> 4 | if (project.hasProperty("androidVersionName")) { 5 | println("Replacing versionName with supplied build parameter: " + 6 | "$androidVersionName") 7 | return androidVersionName 8 | } else { 9 | return "1.0" 10 | } 11 | } 12 | 13 | android { 14 | compileSdkVersion 28 15 | defaultConfig { 16 | applicationId "com.google.ar.core.codelab.depth" 17 | 18 | // AR Optional apps must declare minSdkVersion >= 14. 19 | // AR Required apps must declare minSdkVersion >= 24. 20 | minSdkVersion 24 21 | targetSdkVersion 28 22 | versionCode 1 23 | versionName setVersionName() 24 | } 25 | compileOptions { 26 | sourceCompatibility JavaVersion.VERSION_1_8 27 | targetCompatibility JavaVersion.VERSION_1_8 28 | } 29 | buildTypes { 30 | release { 31 | minifyEnabled false 32 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 33 | } 34 | } 35 | } 36 | 37 | dependencies { 38 | // ARCore library 39 | // Dependency version is rewritten at build time. 40 | implementation 'com.google.ar:core:1.31.0' 41 | 42 | // Obj - a simple Wavefront OBJ file loader 43 | // https://github.com/javagl/Obj 44 | implementation 'de.javagl:obj:0.2.1' 45 | 46 | implementation 'com.android.support:appcompat-v7:28.0.0' 47 | implementation 'com.android.support:design:28.0.0' 48 | } 49 | -------------------------------------------------------------------------------- /part0_work/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /opt/android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /part0_work/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 34 | 35 | 41 | 42 | 43 | 44 | 45 | 46 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /part0_work/src/main/assets/models/andy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part0_work/src/main/assets/models/andy.png -------------------------------------------------------------------------------- /part0_work/src/main/assets/models/andy_spec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part0_work/src/main/assets/models/andy_spec.png -------------------------------------------------------------------------------- /part0_work/src/main/assets/shaders/object.frag: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | precision mediump float; 17 | 18 | uniform sampler2D u_Texture; 19 | 20 | uniform vec4 u_LightingParameters; 21 | uniform vec4 u_MaterialParameters; 22 | uniform vec4 u_ColorCorrectionParameters; 23 | 24 | varying vec3 v_ViewPosition; 25 | varying vec3 v_ViewNormal; 26 | varying vec2 v_TexCoord; 27 | uniform vec4 u_ObjColor; 28 | 29 | void main() { 30 | // We support approximate sRGB gamma. 31 | const float kGamma = 0.4545454; 32 | const float kInverseGamma = 2.2; 33 | const float kMiddleGrayGamma = 0.466; 34 | 35 | // Unpack lighting and material parameters for better naming. 36 | vec3 viewLightDirection = u_LightingParameters.xyz; 37 | vec3 colorShift = u_ColorCorrectionParameters.rgb; 38 | float averagePixelIntensity = u_ColorCorrectionParameters.a; 39 | 40 | float materialAmbient = u_MaterialParameters.x; 41 | float materialDiffuse = u_MaterialParameters.y; 42 | float materialSpecular = u_MaterialParameters.z; 43 | float materialSpecularPower = u_MaterialParameters.w; 44 | 45 | // Normalize varying parameters, because they are linearly interpolated in the vertex shader. 46 | vec3 viewFragmentDirection = normalize(v_ViewPosition); 47 | vec3 viewNormal = normalize(v_ViewNormal); 48 | 49 | // Flip the y-texture coordinate to address the texture from top-left. 50 | vec4 objectColor = texture2D(u_Texture, vec2(v_TexCoord.x, 1.0 - v_TexCoord.y)); 51 | 52 | // Apply color to grayscale image only if the alpha of u_ObjColor is 53 | // greater and equal to 255.0. 54 | if (u_ObjColor.a >= 255.0) { 55 | float intensity = objectColor.r; 56 | objectColor.rgb = u_ObjColor.rgb * intensity / 255.0; 57 | } 58 | 59 | // Apply inverse SRGB gamma to the texture before making lighting calculations. 60 | objectColor.rgb = pow(objectColor.rgb, vec3(kInverseGamma)); 61 | 62 | // Ambient light is unaffected by the light intensity. 63 | float ambient = materialAmbient; 64 | 65 | // Approximate a hemisphere light (not a harsh directional light). 66 | float diffuse = materialDiffuse * 67 | 0.5 * (dot(viewNormal, viewLightDirection) + 1.0); 68 | 69 | // Compute specular light. 70 | vec3 reflectedLightDirection = reflect(viewLightDirection, viewNormal); 71 | float specularStrength = max(0.0, dot(viewFragmentDirection, reflectedLightDirection)); 72 | float specular = materialSpecular * 73 | pow(specularStrength, materialSpecularPower); 74 | 75 | vec3 color = objectColor.rgb * (ambient + diffuse) + specular; 76 | // Apply SRGB gamma before writing the fragment color. 77 | color.rgb = pow(color, vec3(kGamma)); 78 | // Apply average pixel intensity and color shift 79 | color *= colorShift * (averagePixelIntensity / kMiddleGrayGamma); 80 | gl_FragColor.rgb = color; 81 | gl_FragColor.a = objectColor.a; 82 | } 83 | -------------------------------------------------------------------------------- /part0_work/src/main/assets/shaders/object.vert: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | uniform mat4 u_ModelView; 17 | uniform mat4 u_ModelViewProjection; 18 | 19 | attribute vec4 a_Position; 20 | attribute vec3 a_Normal; 21 | attribute vec2 a_TexCoord; 22 | 23 | varying vec3 v_ViewPosition; 24 | varying vec3 v_ViewNormal; 25 | varying vec2 v_TexCoord; 26 | 27 | void main() { 28 | v_ViewPosition = (u_ModelView * a_Position).xyz; 29 | v_ViewNormal = normalize((u_ModelView * vec4(a_Normal, 0.0)).xyz); 30 | v_TexCoord = a_TexCoord; 31 | gl_Position = u_ModelViewProjection * a_Position; 32 | } 33 | -------------------------------------------------------------------------------- /part0_work/src/main/assets/shaders/screenquad.frag: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | #extension GL_OES_EGL_image_external : require 16 | 17 | precision mediump float; 18 | varying vec2 v_TexCoord; 19 | uniform samplerExternalOES sTexture; 20 | 21 | 22 | void main() { 23 | gl_FragColor = texture2D(sTexture, v_TexCoord); 24 | } 25 | -------------------------------------------------------------------------------- /part0_work/src/main/assets/shaders/screenquad.vert: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | attribute vec4 a_Position; 17 | attribute vec2 a_TexCoord; 18 | 19 | varying vec2 v_TexCoord; 20 | 21 | void main() { 22 | gl_Position = a_Position; 23 | v_TexCoord = a_TexCoord; 24 | } 25 | -------------------------------------------------------------------------------- /part0_work/src/main/java/com/google/ar/core/codelab/common/helpers/CameraPermissionHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.Manifest; 18 | import android.app.Activity; 19 | import android.content.Intent; 20 | import android.content.pm.PackageManager; 21 | import android.net.Uri; 22 | import android.provider.Settings; 23 | import android.support.v4.app.ActivityCompat; 24 | import android.support.v4.content.ContextCompat; 25 | 26 | /** Helper to ask camera permission. */ 27 | public final class CameraPermissionHelper { 28 | private static final int CAMERA_PERMISSION_CODE = 0; 29 | private static final String CAMERA_PERMISSION = Manifest.permission.CAMERA; 30 | 31 | /** Check to see we have the necessary permissions for this app. */ 32 | public static boolean hasCameraPermission(Activity activity) { 33 | return ContextCompat.checkSelfPermission(activity, CAMERA_PERMISSION) 34 | == PackageManager.PERMISSION_GRANTED; 35 | } 36 | 37 | /** Check to see we have the necessary permissions for this app, and ask for them if we don't. */ 38 | public static void requestCameraPermission(Activity activity) { 39 | ActivityCompat.requestPermissions( 40 | activity, new String[] {CAMERA_PERMISSION}, CAMERA_PERMISSION_CODE); 41 | } 42 | 43 | /** Check to see if we need to show the rationale for this permission. */ 44 | public static boolean shouldShowRequestPermissionRationale(Activity activity) { 45 | return ActivityCompat.shouldShowRequestPermissionRationale(activity, CAMERA_PERMISSION); 46 | } 47 | 48 | /** Launch Application Setting to grant permission. */ 49 | public static void launchPermissionSettings(Activity activity) { 50 | Intent intent = new Intent(); 51 | intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 52 | intent.setData(Uri.fromParts("package", activity.getPackageName(), null)); 53 | activity.startActivity(intent); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /part0_work/src/main/java/com/google/ar/core/codelab/common/helpers/FullScreenHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.app.Activity; 18 | import android.view.View; 19 | 20 | /** Helper to set up the Android full screen mode. */ 21 | public final class FullScreenHelper { 22 | /** 23 | * Sets the Android fullscreen flags. Expected to be called from {@link 24 | * Activity#onWindowFocusChanged(boolean hasFocus)}. 25 | * 26 | * @param activity the Activity on which the full screen mode will be set. 27 | * @param hasFocus the hasFocus flag passed from the {@link Activity#onWindowFocusChanged(boolean 28 | * hasFocus)} callback. 29 | */ 30 | public static void setFullScreenOnWindowFocusChanged(Activity activity, boolean hasFocus) { 31 | if (hasFocus) { 32 | // https://developer.android.com/training/system-ui/immersive.html#sticky 33 | activity 34 | .getWindow() 35 | .getDecorView() 36 | .setSystemUiVisibility( 37 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE 38 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 39 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 40 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 41 | | View.SYSTEM_UI_FLAG_FULLSCREEN 42 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /part0_work/src/main/java/com/google/ar/core/codelab/common/helpers/SnackbarHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.app.Activity; 18 | import android.support.design.widget.BaseTransientBottomBar; 19 | import android.support.design.widget.Snackbar; 20 | import android.view.View; 21 | import android.widget.TextView; 22 | 23 | /** 24 | * Helper to manage the sample snackbar. Hides the Android boilerplate code, and exposes simpler 25 | * methods. 26 | */ 27 | public final class SnackbarHelper { 28 | private static final int BACKGROUND_COLOR = 0xbf323232; 29 | private Snackbar messageSnackbar; 30 | private enum DismissBehavior { HIDE, SHOW, FINISH }; 31 | private int maxLines = 2; 32 | private String lastMessage = ""; 33 | 34 | public boolean isShowing() { 35 | return messageSnackbar != null; 36 | } 37 | 38 | /** Shows a snackbar with a given message. */ 39 | public void showMessage(Activity activity, String message) { 40 | if (!message.isEmpty() && (!isShowing() || !lastMessage.equals(message))) { 41 | lastMessage = message; 42 | show(activity, message, DismissBehavior.HIDE); 43 | } 44 | } 45 | 46 | /** Shows a snackbar with a given message, and a dismiss button. */ 47 | public void showMessageWithDismiss(Activity activity, String message) { 48 | show(activity, message, DismissBehavior.SHOW); 49 | } 50 | 51 | /** 52 | * Shows a snackbar with a given error message. When dismissed, will finish the activity. Useful 53 | * for notifying errors, where no further interaction with the activity is possible. 54 | */ 55 | public void showError(Activity activity, String errorMessage) { 56 | show(activity, errorMessage, DismissBehavior.FINISH); 57 | } 58 | 59 | /** 60 | * Hides the currently showing snackbar, if there is one. Safe to call from any thread. Safe to 61 | * call even if snackbar is not shown. 62 | */ 63 | public void hide(Activity activity) { 64 | if (!isShowing()) { 65 | return; 66 | } 67 | lastMessage = ""; 68 | Snackbar messageSnackbarToHide = messageSnackbar; 69 | messageSnackbar = null; 70 | activity.runOnUiThread( 71 | new Runnable() { 72 | @Override 73 | public void run() { 74 | messageSnackbarToHide.dismiss(); 75 | } 76 | }); 77 | } 78 | 79 | public void setMaxLines(int lines) { 80 | maxLines = lines; 81 | } 82 | 83 | private void show( 84 | final Activity activity, final String message, final DismissBehavior dismissBehavior) { 85 | activity.runOnUiThread( 86 | new Runnable() { 87 | @Override 88 | public void run() { 89 | messageSnackbar = 90 | Snackbar.make( 91 | activity.findViewById(android.R.id.content), 92 | message, 93 | Snackbar.LENGTH_INDEFINITE); 94 | messageSnackbar.getView().setBackgroundColor(BACKGROUND_COLOR); 95 | if (dismissBehavior != DismissBehavior.HIDE) { 96 | messageSnackbar.setAction( 97 | "Dismiss", 98 | new View.OnClickListener() { 99 | @Override 100 | public void onClick(View v) { 101 | messageSnackbar.dismiss(); 102 | } 103 | }); 104 | if (dismissBehavior == DismissBehavior.FINISH) { 105 | messageSnackbar.addCallback( 106 | new BaseTransientBottomBar.BaseCallback() { 107 | @Override 108 | public void onDismissed(Snackbar transientBottomBar, int event) { 109 | super.onDismissed(transientBottomBar, event); 110 | activity.finish(); 111 | } 112 | }); 113 | } 114 | } 115 | ((TextView) 116 | messageSnackbar 117 | .getView() 118 | .findViewById(android.support.design.R.id.snackbar_text)) 119 | .setMaxLines(maxLines); 120 | messageSnackbar.show(); 121 | } 122 | }); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /part0_work/src/main/java/com/google/ar/core/codelab/common/helpers/TapHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.content.Context; 18 | import android.view.GestureDetector; 19 | import android.view.MotionEvent; 20 | import android.view.View; 21 | import android.view.View.OnTouchListener; 22 | import java.util.concurrent.ArrayBlockingQueue; 23 | import java.util.concurrent.BlockingQueue; 24 | 25 | /** 26 | * Helper to detect taps using Android GestureDetector, and pass the taps between UI thread and 27 | * render thread. 28 | */ 29 | public final class TapHelper implements OnTouchListener { 30 | private final GestureDetector gestureDetector; 31 | private final BlockingQueue queuedSingleTaps = new ArrayBlockingQueue<>(16); 32 | 33 | /** 34 | * Creates the tap helper. 35 | * 36 | * @param context the application's context. 37 | */ 38 | public TapHelper(Context context) { 39 | gestureDetector = 40 | new GestureDetector( 41 | context, 42 | new GestureDetector.SimpleOnGestureListener() { 43 | @Override 44 | public boolean onSingleTapUp(MotionEvent e) { 45 | // Queue tap if there is space. Tap is lost if queue is full. 46 | queuedSingleTaps.offer(e); 47 | return true; 48 | } 49 | 50 | @Override 51 | public boolean onDown(MotionEvent e) { 52 | return true; 53 | } 54 | }); 55 | } 56 | 57 | /** 58 | * Polls for a tap. 59 | * 60 | * @return if a tap was queued, a MotionEvent for the tap. Otherwise null if no taps are queued. 61 | */ 62 | public MotionEvent poll() { 63 | return queuedSingleTaps.poll(); 64 | } 65 | 66 | @Override 67 | public boolean onTouch(View view, MotionEvent motionEvent) { 68 | return gestureDetector.onTouchEvent(motionEvent); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /part0_work/src/main/java/com/google/ar/core/codelab/common/helpers/TrackingStateHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.app.Activity; 18 | import android.view.WindowManager; 19 | import com.google.ar.core.Camera; 20 | import com.google.ar.core.TrackingFailureReason; 21 | import com.google.ar.core.TrackingState; 22 | 23 | /** Gets human readibly tracking failure reasons and suggested actions. */ 24 | public final class TrackingStateHelper { 25 | private static final String INSUFFICIENT_FEATURES_MESSAGE = 26 | "Can't find anything. Aim device at a surface with more texture or color."; 27 | private static final String EXCESSIVE_MOTION_MESSAGE = "Moving too fast. Slow down."; 28 | private static final String INSUFFICIENT_LIGHT_MESSAGE = 29 | "Too dark. Try moving to a well-lit area."; 30 | private static final String BAD_STATE_MESSAGE = 31 | "Tracking lost due to bad internal state. Please try restarting the AR experience."; 32 | private static final String CAMERA_UNAVAILABLE_MESSAGE = 33 | "Another app is using the camera. Tap on this app or try closing the other one."; 34 | 35 | private final Activity activity; 36 | 37 | private TrackingState previousTrackingState; 38 | 39 | public TrackingStateHelper(Activity activity) { 40 | this.activity = activity; 41 | } 42 | 43 | /** Keep the screen unlocked while tracking, but allow it to lock when tracking stops. */ 44 | public void updateKeepScreenOnFlag(TrackingState trackingState) { 45 | if (trackingState == previousTrackingState) { 46 | return; 47 | } 48 | 49 | previousTrackingState = trackingState; 50 | switch (trackingState) { 51 | case PAUSED: 52 | case STOPPED: 53 | activity.runOnUiThread( 54 | () -> activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)); 55 | break; 56 | case TRACKING: 57 | activity.runOnUiThread( 58 | () -> activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)); 59 | break; 60 | } 61 | } 62 | 63 | public static String getTrackingFailureReasonString(Camera camera) { 64 | TrackingFailureReason reason = camera.getTrackingFailureReason(); 65 | switch (reason) { 66 | case NONE: 67 | return ""; 68 | case BAD_STATE: 69 | return BAD_STATE_MESSAGE; 70 | case INSUFFICIENT_LIGHT: 71 | return INSUFFICIENT_LIGHT_MESSAGE; 72 | case EXCESSIVE_MOTION: 73 | return EXCESSIVE_MOTION_MESSAGE; 74 | case INSUFFICIENT_FEATURES: 75 | return INSUFFICIENT_FEATURES_MESSAGE; 76 | case CAMERA_UNAVAILABLE: 77 | return CAMERA_UNAVAILABLE_MESSAGE; 78 | } 79 | return "Unknown tracking failure reason: " + reason; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /part0_work/src/main/java/com/google/ar/core/codelab/common/rendering/ShaderUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.rendering; 16 | 17 | import android.content.Context; 18 | import android.opengl.GLES20; 19 | import android.util.Log; 20 | import java.io.BufferedReader; 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.io.InputStreamReader; 24 | 25 | /** Shader helper functions. */ 26 | public class ShaderUtil { 27 | /** 28 | * Converts a raw text file, saved as a resource, into an OpenGL ES shader. 29 | * 30 | * @param type The type of shader we will be creating. 31 | * @param filename The filename of the asset file about to be turned into a shader. 32 | * @return The shader object handler. 33 | */ 34 | public static int loadGLShader(String tag, Context context, int type, String filename) 35 | throws IOException { 36 | String code = readShaderFileFromAssets(context, filename); 37 | int shader = GLES20.glCreateShader(type); 38 | GLES20.glShaderSource(shader, code); 39 | GLES20.glCompileShader(shader); 40 | 41 | // Get the compilation status. 42 | final int[] compileStatus = new int[1]; 43 | GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0); 44 | 45 | // If the compilation failed, delete the shader. 46 | if (compileStatus[0] == 0) { 47 | Log.e(tag, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shader)); 48 | GLES20.glDeleteShader(shader); 49 | shader = 0; 50 | } 51 | 52 | if (shader == 0) { 53 | throw new RuntimeException("Error creating shader."); 54 | } 55 | 56 | return shader; 57 | } 58 | 59 | /** 60 | * Checks if we've had an error inside of OpenGL ES, and if so what that error is. 61 | * 62 | * @param label Label to report in case of error. 63 | * @throws RuntimeException If an OpenGL error is detected. 64 | */ 65 | public static void checkGLError(String tag, String label) { 66 | int lastError = GLES20.GL_NO_ERROR; 67 | // Drain the queue of all errors. 68 | int error; 69 | while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { 70 | Log.e(tag, label + ": glError " + error); 71 | lastError = error; 72 | } 73 | if (lastError != GLES20.GL_NO_ERROR) { 74 | throw new RuntimeException(label + ": glError " + lastError); 75 | } 76 | } 77 | 78 | /** 79 | * Converts a raw shader file into a string. 80 | * 81 | * @param filename The filename of the shader file about to be turned into a shader. 82 | * @return The context of the text file, or null in case of error. 83 | */ 84 | private static String readShaderFileFromAssets(Context context, String filename) 85 | throws IOException { 86 | try (InputStream inputStream = context.getAssets().open(filename); 87 | BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { 88 | StringBuilder sb = new StringBuilder(); 89 | String line; 90 | while ((line = reader.readLine()) != null) { 91 | String[] tokens = line.split(" ", -1); 92 | if (tokens[0].equals("#include")) { 93 | String includeFilename = tokens[1]; 94 | includeFilename = includeFilename.replace("\"", ""); 95 | if (includeFilename.equals(filename)) { 96 | throw new IOException("Do not include the calling file."); 97 | } 98 | sb.append(readShaderFileFromAssets(context, includeFilename)); 99 | } else { 100 | sb.append(line).append("\n"); 101 | } 102 | } 103 | return sb.toString(); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /part0_work/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part0_work/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /part0_work/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 16 | 21 | 22 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /part0_work/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | Depth Codelab 19 | 20 | -------------------------------------------------------------------------------- /part0_work/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 22 | 29 | 30 | 31 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /part1/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | google-services.json 3 | -------------------------------------------------------------------------------- /part1/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | def setVersionName = { -> 4 | if (project.hasProperty("androidVersionName")) { 5 | println("Replacing versionName with supplied build parameter: " + 6 | "$androidVersionName") 7 | return androidVersionName 8 | } else { 9 | return "1.0" 10 | } 11 | } 12 | 13 | android { 14 | compileSdkVersion 28 15 | defaultConfig { 16 | applicationId "com.google.ar.core.codelab.depth" 17 | 18 | // AR Optional apps must declare minSdkVersion >= 14. 19 | // AR Required apps must declare minSdkVersion >= 24. 20 | minSdkVersion 24 21 | targetSdkVersion 28 22 | versionCode 1 23 | versionName setVersionName() 24 | } 25 | compileOptions { 26 | sourceCompatibility JavaVersion.VERSION_1_8 27 | targetCompatibility JavaVersion.VERSION_1_8 28 | } 29 | buildTypes { 30 | release { 31 | minifyEnabled false 32 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 33 | } 34 | } 35 | } 36 | 37 | dependencies { 38 | // ARCore library 39 | // Dependency version is rewritten at build time. 40 | implementation 'com.google.ar:core:1.31.0' 41 | 42 | // Obj - a simple Wavefront OBJ file loader 43 | // https://github.com/javagl/Obj 44 | implementation 'de.javagl:obj:0.2.1' 45 | 46 | implementation 'com.android.support:appcompat-v7:28.0.0' 47 | implementation 'com.android.support:design:28.0.0' 48 | } 49 | -------------------------------------------------------------------------------- /part1/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /opt/android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /part1/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 34 | 35 | 41 | 42 | 43 | 44 | 45 | 46 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /part1/src/main/assets/models/andy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part1/src/main/assets/models/andy.png -------------------------------------------------------------------------------- /part1/src/main/assets/models/andy_spec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part1/src/main/assets/models/andy_spec.png -------------------------------------------------------------------------------- /part1/src/main/assets/shaders/object.frag: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | precision mediump float; 17 | 18 | uniform sampler2D u_Texture; 19 | 20 | uniform vec4 u_LightingParameters; 21 | uniform vec4 u_MaterialParameters; 22 | uniform vec4 u_ColorCorrectionParameters; 23 | 24 | varying vec3 v_ViewPosition; 25 | varying vec3 v_ViewNormal; 26 | varying vec2 v_TexCoord; 27 | uniform vec4 u_ObjColor; 28 | 29 | void main() { 30 | // We support approximate sRGB gamma. 31 | const float kGamma = 0.4545454; 32 | const float kInverseGamma = 2.2; 33 | const float kMiddleGrayGamma = 0.466; 34 | 35 | // Unpack lighting and material parameters for better naming. 36 | vec3 viewLightDirection = u_LightingParameters.xyz; 37 | vec3 colorShift = u_ColorCorrectionParameters.rgb; 38 | float averagePixelIntensity = u_ColorCorrectionParameters.a; 39 | 40 | float materialAmbient = u_MaterialParameters.x; 41 | float materialDiffuse = u_MaterialParameters.y; 42 | float materialSpecular = u_MaterialParameters.z; 43 | float materialSpecularPower = u_MaterialParameters.w; 44 | 45 | // Normalize varying parameters, because they are linearly interpolated in the vertex shader. 46 | vec3 viewFragmentDirection = normalize(v_ViewPosition); 47 | vec3 viewNormal = normalize(v_ViewNormal); 48 | 49 | // Flip the y-texture coordinate to address the texture from top-left. 50 | vec4 objectColor = texture2D(u_Texture, vec2(v_TexCoord.x, 1.0 - v_TexCoord.y)); 51 | 52 | // Apply color to grayscale image only if the alpha of u_ObjColor is 53 | // greater and equal to 255.0. 54 | if (u_ObjColor.a >= 255.0) { 55 | float intensity = objectColor.r; 56 | objectColor.rgb = u_ObjColor.rgb * intensity / 255.0; 57 | } 58 | 59 | // Apply inverse SRGB gamma to the texture before making lighting calculations. 60 | objectColor.rgb = pow(objectColor.rgb, vec3(kInverseGamma)); 61 | 62 | // Ambient light is unaffected by the light intensity. 63 | float ambient = materialAmbient; 64 | 65 | // Approximate a hemisphere light (not a harsh directional light). 66 | float diffuse = materialDiffuse * 67 | 0.5 * (dot(viewNormal, viewLightDirection) + 1.0); 68 | 69 | // Compute specular light. 70 | vec3 reflectedLightDirection = reflect(viewLightDirection, viewNormal); 71 | float specularStrength = max(0.0, dot(viewFragmentDirection, reflectedLightDirection)); 72 | float specular = materialSpecular * 73 | pow(specularStrength, materialSpecularPower); 74 | 75 | vec3 color = objectColor.rgb * (ambient + diffuse) + specular; 76 | // Apply SRGB gamma before writing the fragment color. 77 | color.rgb = pow(color, vec3(kGamma)); 78 | // Apply average pixel intensity and color shift 79 | color *= colorShift * (averagePixelIntensity / kMiddleGrayGamma); 80 | gl_FragColor.rgb = color; 81 | gl_FragColor.a = objectColor.a; 82 | } 83 | -------------------------------------------------------------------------------- /part1/src/main/assets/shaders/object.vert: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | uniform mat4 u_ModelView; 17 | uniform mat4 u_ModelViewProjection; 18 | 19 | attribute vec4 a_Position; 20 | attribute vec3 a_Normal; 21 | attribute vec2 a_TexCoord; 22 | 23 | varying vec3 v_ViewPosition; 24 | varying vec3 v_ViewNormal; 25 | varying vec2 v_TexCoord; 26 | 27 | void main() { 28 | v_ViewPosition = (u_ModelView * a_Position).xyz; 29 | v_ViewNormal = normalize((u_ModelView * vec4(a_Normal, 0.0)).xyz); 30 | v_TexCoord = a_TexCoord; 31 | gl_Position = u_ModelViewProjection * a_Position; 32 | } 33 | -------------------------------------------------------------------------------- /part1/src/main/assets/shaders/screenquad.frag: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | #extension GL_OES_EGL_image_external : require 16 | 17 | precision mediump float; 18 | varying vec2 v_TexCoord; 19 | uniform samplerExternalOES sTexture; 20 | 21 | 22 | void main() { 23 | gl_FragColor = texture2D(sTexture, v_TexCoord); 24 | } 25 | -------------------------------------------------------------------------------- /part1/src/main/assets/shaders/screenquad.vert: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | attribute vec4 a_Position; 17 | attribute vec2 a_TexCoord; 18 | 19 | varying vec2 v_TexCoord; 20 | 21 | void main() { 22 | gl_Position = a_Position; 23 | v_TexCoord = a_TexCoord; 24 | } 25 | -------------------------------------------------------------------------------- /part1/src/main/java/com/google/ar/core/codelab/common/helpers/CameraPermissionHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.Manifest; 18 | import android.app.Activity; 19 | import android.content.Intent; 20 | import android.content.pm.PackageManager; 21 | import android.net.Uri; 22 | import android.provider.Settings; 23 | import android.support.v4.app.ActivityCompat; 24 | import android.support.v4.content.ContextCompat; 25 | 26 | /** Helper to ask camera permission. */ 27 | public final class CameraPermissionHelper { 28 | private static final int CAMERA_PERMISSION_CODE = 0; 29 | private static final String CAMERA_PERMISSION = Manifest.permission.CAMERA; 30 | 31 | /** Check to see we have the necessary permissions for this app. */ 32 | public static boolean hasCameraPermission(Activity activity) { 33 | return ContextCompat.checkSelfPermission(activity, CAMERA_PERMISSION) 34 | == PackageManager.PERMISSION_GRANTED; 35 | } 36 | 37 | /** Check to see we have the necessary permissions for this app, and ask for them if we don't. */ 38 | public static void requestCameraPermission(Activity activity) { 39 | ActivityCompat.requestPermissions( 40 | activity, new String[] {CAMERA_PERMISSION}, CAMERA_PERMISSION_CODE); 41 | } 42 | 43 | /** Check to see if we need to show the rationale for this permission. */ 44 | public static boolean shouldShowRequestPermissionRationale(Activity activity) { 45 | return ActivityCompat.shouldShowRequestPermissionRationale(activity, CAMERA_PERMISSION); 46 | } 47 | 48 | /** Launch Application Setting to grant permission. */ 49 | public static void launchPermissionSettings(Activity activity) { 50 | Intent intent = new Intent(); 51 | intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 52 | intent.setData(Uri.fromParts("package", activity.getPackageName(), null)); 53 | activity.startActivity(intent); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /part1/src/main/java/com/google/ar/core/codelab/common/helpers/DisplayRotationHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.app.Activity; 18 | import android.content.Context; 19 | import android.hardware.camera2.CameraAccessException; 20 | import android.hardware.camera2.CameraCharacteristics; 21 | import android.hardware.camera2.CameraManager; 22 | import android.hardware.display.DisplayManager; 23 | import android.hardware.display.DisplayManager.DisplayListener; 24 | import android.view.Display; 25 | import android.view.Surface; 26 | import android.view.WindowManager; 27 | import com.google.ar.core.Session; 28 | 29 | /** 30 | * Helper to track the display rotations. In particular, the 180 degree rotations are not notified 31 | * by the onSurfaceChanged() callback, and thus they require listening to the android display 32 | * events. 33 | */ 34 | public final class DisplayRotationHelper implements DisplayListener { 35 | private boolean viewportChanged; 36 | private int viewportWidth; 37 | private int viewportHeight; 38 | private final Display display; 39 | private final DisplayManager displayManager; 40 | private final CameraManager cameraManager; 41 | 42 | /** 43 | * Constructs the DisplayRotationHelper but does not register the listener yet. 44 | * 45 | * @param context the Android {@link Context}. 46 | */ 47 | public DisplayRotationHelper(Context context) { 48 | displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); 49 | cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); 50 | WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 51 | display = windowManager.getDefaultDisplay(); 52 | } 53 | 54 | /** Registers the display listener. Should be called from {@link Activity#onResume()}. */ 55 | public void onResume() { 56 | displayManager.registerDisplayListener(this, null); 57 | } 58 | 59 | /** Unregisters the display listener. Should be called from {@link Activity#onPause()}. */ 60 | public void onPause() { 61 | displayManager.unregisterDisplayListener(this); 62 | } 63 | 64 | /** 65 | * Records a change in surface dimensions. This will be later used by {@link 66 | * #updateSessionIfNeeded(Session)}. Should be called from {@link 67 | * android.opengl.GLSurfaceView.Renderer 68 | * #onSurfaceChanged(javax.microedition.khronos.opengles.GL10, int, int)}. 69 | * 70 | * @param width the updated width of the surface. 71 | * @param height the updated height of the surface. 72 | */ 73 | public void onSurfaceChanged(int width, int height) { 74 | viewportWidth = width; 75 | viewportHeight = height; 76 | viewportChanged = true; 77 | } 78 | 79 | /** 80 | * Updates the session display geometry if a change was posted either by {@link 81 | * #onSurfaceChanged(int, int)} call or by {@link #onDisplayChanged(int)} system callback. This 82 | * function should be called explicitly before each call to {@link Session#update()}. This 83 | * function will also clear the 'pending update' (viewportChanged) flag. 84 | * 85 | * @param session the {@link Session} object to update if display geometry changed. 86 | */ 87 | public void updateSessionIfNeeded(Session session) { 88 | if (viewportChanged) { 89 | int displayRotation = display.getRotation(); 90 | session.setDisplayGeometry(displayRotation, viewportWidth, viewportHeight); 91 | viewportChanged = false; 92 | } 93 | } 94 | 95 | /** 96 | * Returns the aspect ratio of the GL surface viewport while accounting for the display rotation 97 | * relative to the device camera sensor orientation. 98 | */ 99 | public float getCameraSensorRelativeViewportAspectRatio(String cameraId) { 100 | float aspectRatio; 101 | int cameraSensorToDisplayRotation = getCameraSensorToDisplayRotation(cameraId); 102 | switch (cameraSensorToDisplayRotation) { 103 | case 90: 104 | case 270: 105 | aspectRatio = (float) viewportHeight / (float) viewportWidth; 106 | break; 107 | case 0: 108 | case 180: 109 | aspectRatio = (float) viewportWidth / (float) viewportHeight; 110 | break; 111 | default: 112 | throw new RuntimeException("Unhandled rotation: " + cameraSensorToDisplayRotation); 113 | } 114 | return aspectRatio; 115 | } 116 | 117 | /** 118 | * Returns the rotation of the back-facing camera with respect to the display. The value is one of 119 | * 0, 90, 180, 270. 120 | */ 121 | public int getCameraSensorToDisplayRotation(String cameraId) { 122 | CameraCharacteristics characteristics; 123 | try { 124 | characteristics = cameraManager.getCameraCharacteristics(cameraId); 125 | } catch (CameraAccessException e) { 126 | throw new RuntimeException("Unable to determine display orientation", e); 127 | } 128 | 129 | // Camera sensor orientation. 130 | int sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); 131 | 132 | // Current display orientation. 133 | int displayOrientation = toDegrees(display.getRotation()); 134 | 135 | // Make sure we return 0, 90, 180, or 270 degrees. 136 | return (sensorOrientation - displayOrientation + 360) % 360; 137 | } 138 | 139 | private int toDegrees(int rotation) { 140 | switch (rotation) { 141 | case Surface.ROTATION_0: 142 | return 0; 143 | case Surface.ROTATION_90: 144 | return 90; 145 | case Surface.ROTATION_180: 146 | return 180; 147 | case Surface.ROTATION_270: 148 | return 270; 149 | default: 150 | throw new RuntimeException("Unknown rotation " + rotation); 151 | } 152 | } 153 | 154 | @Override 155 | public void onDisplayAdded(int displayId) {} 156 | 157 | @Override 158 | public void onDisplayRemoved(int displayId) {} 159 | 160 | @Override 161 | public void onDisplayChanged(int displayId) { 162 | viewportChanged = true; 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /part1/src/main/java/com/google/ar/core/codelab/common/helpers/FullScreenHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.app.Activity; 18 | import android.view.View; 19 | 20 | /** Helper to set up the Android full screen mode. */ 21 | public final class FullScreenHelper { 22 | /** 23 | * Sets the Android fullscreen flags. Expected to be called from {@link 24 | * Activity#onWindowFocusChanged(boolean hasFocus)}. 25 | * 26 | * @param activity the Activity on which the full screen mode will be set. 27 | * @param hasFocus the hasFocus flag passed from the {@link Activity#onWindowFocusChanged(boolean 28 | * hasFocus)} callback. 29 | */ 30 | public static void setFullScreenOnWindowFocusChanged(Activity activity, boolean hasFocus) { 31 | if (hasFocus) { 32 | // https://developer.android.com/training/system-ui/immersive.html#sticky 33 | activity 34 | .getWindow() 35 | .getDecorView() 36 | .setSystemUiVisibility( 37 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE 38 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 39 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 40 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 41 | | View.SYSTEM_UI_FLAG_FULLSCREEN 42 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /part1/src/main/java/com/google/ar/core/codelab/common/helpers/SnackbarHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.app.Activity; 18 | import android.support.design.widget.BaseTransientBottomBar; 19 | import android.support.design.widget.Snackbar; 20 | import android.view.View; 21 | import android.widget.TextView; 22 | 23 | /** 24 | * Helper to manage the sample snackbar. Hides the Android boilerplate code, and exposes simpler 25 | * methods. 26 | */ 27 | public final class SnackbarHelper { 28 | private static final int BACKGROUND_COLOR = 0xbf323232; 29 | private Snackbar messageSnackbar; 30 | private enum DismissBehavior { HIDE, SHOW, FINISH }; 31 | private int maxLines = 2; 32 | private String lastMessage = ""; 33 | 34 | public boolean isShowing() { 35 | return messageSnackbar != null; 36 | } 37 | 38 | /** Shows a snackbar with a given message. */ 39 | public void showMessage(Activity activity, String message) { 40 | if (!message.isEmpty() && (!isShowing() || !lastMessage.equals(message))) { 41 | lastMessage = message; 42 | show(activity, message, DismissBehavior.HIDE); 43 | } 44 | } 45 | 46 | /** Shows a snackbar with a given message, and a dismiss button. */ 47 | public void showMessageWithDismiss(Activity activity, String message) { 48 | show(activity, message, DismissBehavior.SHOW); 49 | } 50 | 51 | /** 52 | * Shows a snackbar with a given error message. When dismissed, will finish the activity. Useful 53 | * for notifying errors, where no further interaction with the activity is possible. 54 | */ 55 | public void showError(Activity activity, String errorMessage) { 56 | show(activity, errorMessage, DismissBehavior.FINISH); 57 | } 58 | 59 | /** 60 | * Hides the currently showing snackbar, if there is one. Safe to call from any thread. Safe to 61 | * call even if snackbar is not shown. 62 | */ 63 | public void hide(Activity activity) { 64 | if (!isShowing()) { 65 | return; 66 | } 67 | lastMessage = ""; 68 | Snackbar messageSnackbarToHide = messageSnackbar; 69 | messageSnackbar = null; 70 | activity.runOnUiThread( 71 | new Runnable() { 72 | @Override 73 | public void run() { 74 | messageSnackbarToHide.dismiss(); 75 | } 76 | }); 77 | } 78 | 79 | public void setMaxLines(int lines) { 80 | maxLines = lines; 81 | } 82 | 83 | private void show( 84 | final Activity activity, final String message, final DismissBehavior dismissBehavior) { 85 | activity.runOnUiThread( 86 | new Runnable() { 87 | @Override 88 | public void run() { 89 | messageSnackbar = 90 | Snackbar.make( 91 | activity.findViewById(android.R.id.content), 92 | message, 93 | Snackbar.LENGTH_INDEFINITE); 94 | messageSnackbar.getView().setBackgroundColor(BACKGROUND_COLOR); 95 | if (dismissBehavior != DismissBehavior.HIDE) { 96 | messageSnackbar.setAction( 97 | "Dismiss", 98 | new View.OnClickListener() { 99 | @Override 100 | public void onClick(View v) { 101 | messageSnackbar.dismiss(); 102 | } 103 | }); 104 | if (dismissBehavior == DismissBehavior.FINISH) { 105 | messageSnackbar.addCallback( 106 | new BaseTransientBottomBar.BaseCallback() { 107 | @Override 108 | public void onDismissed(Snackbar transientBottomBar, int event) { 109 | super.onDismissed(transientBottomBar, event); 110 | activity.finish(); 111 | } 112 | }); 113 | } 114 | } 115 | ((TextView) 116 | messageSnackbar 117 | .getView() 118 | .findViewById(android.support.design.R.id.snackbar_text)) 119 | .setMaxLines(maxLines); 120 | messageSnackbar.show(); 121 | } 122 | }); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /part1/src/main/java/com/google/ar/core/codelab/common/helpers/TapHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.content.Context; 18 | import android.view.GestureDetector; 19 | import android.view.MotionEvent; 20 | import android.view.View; 21 | import android.view.View.OnTouchListener; 22 | import java.util.concurrent.ArrayBlockingQueue; 23 | import java.util.concurrent.BlockingQueue; 24 | 25 | /** 26 | * Helper to detect taps using Android GestureDetector, and pass the taps between UI thread and 27 | * render thread. 28 | */ 29 | public final class TapHelper implements OnTouchListener { 30 | private final GestureDetector gestureDetector; 31 | private final BlockingQueue queuedSingleTaps = new ArrayBlockingQueue<>(16); 32 | 33 | /** 34 | * Creates the tap helper. 35 | * 36 | * @param context the application's context. 37 | */ 38 | public TapHelper(Context context) { 39 | gestureDetector = 40 | new GestureDetector( 41 | context, 42 | new GestureDetector.SimpleOnGestureListener() { 43 | @Override 44 | public boolean onSingleTapUp(MotionEvent e) { 45 | // Queue tap if there is space. Tap is lost if queue is full. 46 | queuedSingleTaps.offer(e); 47 | return true; 48 | } 49 | 50 | @Override 51 | public boolean onDown(MotionEvent e) { 52 | return true; 53 | } 54 | }); 55 | } 56 | 57 | /** 58 | * Polls for a tap. 59 | * 60 | * @return if a tap was queued, a MotionEvent for the tap. Otherwise null if no taps are queued. 61 | */ 62 | public MotionEvent poll() { 63 | return queuedSingleTaps.poll(); 64 | } 65 | 66 | @Override 67 | public boolean onTouch(View view, MotionEvent motionEvent) { 68 | return gestureDetector.onTouchEvent(motionEvent); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /part1/src/main/java/com/google/ar/core/codelab/common/helpers/TrackingStateHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.app.Activity; 18 | import android.view.WindowManager; 19 | import com.google.ar.core.Camera; 20 | import com.google.ar.core.TrackingFailureReason; 21 | import com.google.ar.core.TrackingState; 22 | 23 | /** Gets human readibly tracking failure reasons and suggested actions. */ 24 | public final class TrackingStateHelper { 25 | private static final String INSUFFICIENT_FEATURES_MESSAGE = 26 | "Can't find anything. Aim device at a surface with more texture or color."; 27 | private static final String EXCESSIVE_MOTION_MESSAGE = "Moving too fast. Slow down."; 28 | private static final String INSUFFICIENT_LIGHT_MESSAGE = 29 | "Too dark. Try moving to a well-lit area."; 30 | private static final String BAD_STATE_MESSAGE = 31 | "Tracking lost due to bad internal state. Please try restarting the AR experience."; 32 | private static final String CAMERA_UNAVAILABLE_MESSAGE = 33 | "Another app is using the camera. Tap on this app or try closing the other one."; 34 | 35 | private final Activity activity; 36 | 37 | private TrackingState previousTrackingState; 38 | 39 | public TrackingStateHelper(Activity activity) { 40 | this.activity = activity; 41 | } 42 | 43 | /** Keep the screen unlocked while tracking, but allow it to lock when tracking stops. */ 44 | public void updateKeepScreenOnFlag(TrackingState trackingState) { 45 | if (trackingState == previousTrackingState) { 46 | return; 47 | } 48 | 49 | previousTrackingState = trackingState; 50 | switch (trackingState) { 51 | case PAUSED: 52 | case STOPPED: 53 | activity.runOnUiThread( 54 | () -> activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)); 55 | break; 56 | case TRACKING: 57 | activity.runOnUiThread( 58 | () -> activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)); 59 | break; 60 | } 61 | } 62 | 63 | public static String getTrackingFailureReasonString(Camera camera) { 64 | TrackingFailureReason reason = camera.getTrackingFailureReason(); 65 | switch (reason) { 66 | case NONE: 67 | return ""; 68 | case BAD_STATE: 69 | return BAD_STATE_MESSAGE; 70 | case INSUFFICIENT_LIGHT: 71 | return INSUFFICIENT_LIGHT_MESSAGE; 72 | case EXCESSIVE_MOTION: 73 | return EXCESSIVE_MOTION_MESSAGE; 74 | case INSUFFICIENT_FEATURES: 75 | return INSUFFICIENT_FEATURES_MESSAGE; 76 | case CAMERA_UNAVAILABLE: 77 | return CAMERA_UNAVAILABLE_MESSAGE; 78 | } 79 | return "Unknown tracking failure reason: " + reason; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /part1/src/main/java/com/google/ar/core/codelab/common/rendering/ShaderUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.rendering; 16 | 17 | import android.content.Context; 18 | import android.opengl.GLES20; 19 | import android.util.Log; 20 | import java.io.BufferedReader; 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.io.InputStreamReader; 24 | 25 | /** Shader helper functions. */ 26 | public class ShaderUtil { 27 | /** 28 | * Converts a raw text file, saved as a resource, into an OpenGL ES shader. 29 | * 30 | * @param type The type of shader we will be creating. 31 | * @param filename The filename of the asset file about to be turned into a shader. 32 | * @return The shader object handler. 33 | */ 34 | public static int loadGLShader(String tag, Context context, int type, String filename) 35 | throws IOException { 36 | String code = readShaderFileFromAssets(context, filename); 37 | int shader = GLES20.glCreateShader(type); 38 | GLES20.glShaderSource(shader, code); 39 | GLES20.glCompileShader(shader); 40 | 41 | // Get the compilation status. 42 | final int[] compileStatus = new int[1]; 43 | GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0); 44 | 45 | // If the compilation failed, delete the shader. 46 | if (compileStatus[0] == 0) { 47 | Log.e(tag, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shader)); 48 | GLES20.glDeleteShader(shader); 49 | shader = 0; 50 | } 51 | 52 | if (shader == 0) { 53 | throw new RuntimeException("Error creating shader."); 54 | } 55 | 56 | return shader; 57 | } 58 | 59 | /** 60 | * Checks if we've had an error inside of OpenGL ES, and if so what that error is. 61 | * 62 | * @param label Label to report in case of error. 63 | * @throws RuntimeException If an OpenGL error is detected. 64 | */ 65 | public static void checkGLError(String tag, String label) { 66 | int lastError = GLES20.GL_NO_ERROR; 67 | // Drain the queue of all errors. 68 | int error; 69 | while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { 70 | Log.e(tag, label + ": glError " + error); 71 | lastError = error; 72 | } 73 | if (lastError != GLES20.GL_NO_ERROR) { 74 | throw new RuntimeException(label + ": glError " + lastError); 75 | } 76 | } 77 | 78 | /** 79 | * Converts a raw shader file into a string. 80 | * 81 | * @param filename The filename of the shader file about to be turned into a shader. 82 | * @return The context of the text file, or null in case of error. 83 | */ 84 | private static String readShaderFileFromAssets(Context context, String filename) 85 | throws IOException { 86 | try (InputStream inputStream = context.getAssets().open(filename); 87 | BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { 88 | StringBuilder sb = new StringBuilder(); 89 | String line; 90 | while ((line = reader.readLine()) != null) { 91 | String[] tokens = line.split(" ", -1); 92 | if (tokens[0].equals("#include")) { 93 | String includeFilename = tokens[1]; 94 | includeFilename = includeFilename.replace("\"", ""); 95 | if (includeFilename.equals(filename)) { 96 | throw new IOException("Do not include the calling file."); 97 | } 98 | sb.append(readShaderFileFromAssets(context, includeFilename)); 99 | } else { 100 | sb.append(line).append("\n"); 101 | } 102 | } 103 | return sb.toString(); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /part1/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part1/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /part1/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 16 | 21 | 22 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /part1/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | Depth Codelab 19 | 20 | -------------------------------------------------------------------------------- /part1/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 22 | 29 | 30 | 31 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /part2/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | google-services.json 3 | -------------------------------------------------------------------------------- /part2/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | def setVersionName = { -> 4 | if (project.hasProperty("androidVersionName")) { 5 | println("Replacing versionName with supplied build parameter: " + 6 | "$androidVersionName") 7 | return androidVersionName 8 | } else { 9 | return "1.0" 10 | } 11 | } 12 | 13 | android { 14 | compileSdkVersion 28 15 | defaultConfig { 16 | applicationId "com.google.ar.core.codelab.depth" 17 | 18 | // AR Optional apps must declare minSdkVersion >= 14. 19 | // AR Required apps must declare minSdkVersion >= 24. 20 | minSdkVersion 24 21 | targetSdkVersion 28 22 | versionCode 1 23 | versionName setVersionName() 24 | } 25 | compileOptions { 26 | sourceCompatibility JavaVersion.VERSION_1_8 27 | targetCompatibility JavaVersion.VERSION_1_8 28 | } 29 | buildTypes { 30 | release { 31 | minifyEnabled false 32 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 33 | } 34 | } 35 | } 36 | 37 | dependencies { 38 | // ARCore library 39 | // Dependency version is rewritten at build time. 40 | implementation 'com.google.ar:core:1.31.0' 41 | 42 | // Obj - a simple Wavefront OBJ file loader 43 | // https://github.com/javagl/Obj 44 | implementation 'de.javagl:obj:0.2.1' 45 | 46 | implementation 'com.android.support:appcompat-v7:28.0.0' 47 | implementation 'com.android.support:design:28.0.0' 48 | } 49 | -------------------------------------------------------------------------------- /part2/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /opt/android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /part2/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 34 | 35 | 41 | 42 | 43 | 44 | 45 | 46 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /part2/src/main/assets/models/andy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part2/src/main/assets/models/andy.png -------------------------------------------------------------------------------- /part2/src/main/assets/models/andy_spec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part2/src/main/assets/models/andy_spec.png -------------------------------------------------------------------------------- /part2/src/main/assets/shaders/object.frag: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | precision mediump float; 17 | 18 | uniform sampler2D u_Texture; 19 | 20 | uniform vec4 u_LightingParameters; 21 | uniform vec4 u_MaterialParameters; 22 | uniform vec4 u_ColorCorrectionParameters; 23 | 24 | varying vec3 v_ViewPosition; 25 | varying vec3 v_ViewNormal; 26 | varying vec2 v_TexCoord; 27 | uniform vec4 u_ObjColor; 28 | 29 | void main() { 30 | // We support approximate sRGB gamma. 31 | const float kGamma = 0.4545454; 32 | const float kInverseGamma = 2.2; 33 | const float kMiddleGrayGamma = 0.466; 34 | 35 | // Unpack lighting and material parameters for better naming. 36 | vec3 viewLightDirection = u_LightingParameters.xyz; 37 | vec3 colorShift = u_ColorCorrectionParameters.rgb; 38 | float averagePixelIntensity = u_ColorCorrectionParameters.a; 39 | 40 | float materialAmbient = u_MaterialParameters.x; 41 | float materialDiffuse = u_MaterialParameters.y; 42 | float materialSpecular = u_MaterialParameters.z; 43 | float materialSpecularPower = u_MaterialParameters.w; 44 | 45 | // Normalize varying parameters, because they are linearly interpolated in the vertex shader. 46 | vec3 viewFragmentDirection = normalize(v_ViewPosition); 47 | vec3 viewNormal = normalize(v_ViewNormal); 48 | 49 | // Flip the y-texture coordinate to address the texture from top-left. 50 | vec4 objectColor = texture2D(u_Texture, vec2(v_TexCoord.x, 1.0 - v_TexCoord.y)); 51 | 52 | // Apply color to grayscale image only if the alpha of u_ObjColor is 53 | // greater and equal to 255.0. 54 | if (u_ObjColor.a >= 255.0) { 55 | float intensity = objectColor.r; 56 | objectColor.rgb = u_ObjColor.rgb * intensity / 255.0; 57 | } 58 | 59 | // Apply inverse SRGB gamma to the texture before making lighting calculations. 60 | objectColor.rgb = pow(objectColor.rgb, vec3(kInverseGamma)); 61 | 62 | // Ambient light is unaffected by the light intensity. 63 | float ambient = materialAmbient; 64 | 65 | // Approximate a hemisphere light (not a harsh directional light). 66 | float diffuse = materialDiffuse * 67 | 0.5 * (dot(viewNormal, viewLightDirection) + 1.0); 68 | 69 | // Compute specular light. 70 | vec3 reflectedLightDirection = reflect(viewLightDirection, viewNormal); 71 | float specularStrength = max(0.0, dot(viewFragmentDirection, reflectedLightDirection)); 72 | float specular = materialSpecular * 73 | pow(specularStrength, materialSpecularPower); 74 | 75 | vec3 color = objectColor.rgb * (ambient + diffuse) + specular; 76 | // Apply SRGB gamma before writing the fragment color. 77 | color.rgb = pow(color, vec3(kGamma)); 78 | // Apply average pixel intensity and color shift 79 | color *= colorShift * (averagePixelIntensity / kMiddleGrayGamma); 80 | gl_FragColor.rgb = color; 81 | gl_FragColor.a = objectColor.a; 82 | } 83 | -------------------------------------------------------------------------------- /part2/src/main/assets/shaders/object.vert: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | uniform mat4 u_ModelView; 17 | uniform mat4 u_ModelViewProjection; 18 | 19 | attribute vec4 a_Position; 20 | attribute vec3 a_Normal; 21 | attribute vec2 a_TexCoord; 22 | 23 | varying vec3 v_ViewPosition; 24 | varying vec3 v_ViewNormal; 25 | varying vec2 v_TexCoord; 26 | 27 | void main() { 28 | v_ViewPosition = (u_ModelView * a_Position).xyz; 29 | v_ViewNormal = normalize((u_ModelView * vec4(a_Normal, 0.0)).xyz); 30 | v_TexCoord = a_TexCoord; 31 | gl_Position = u_ModelViewProjection * a_Position; 32 | } 33 | -------------------------------------------------------------------------------- /part2/src/main/assets/shaders/screenquad.frag: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | #extension GL_OES_EGL_image_external : require 16 | 17 | precision mediump float; 18 | varying vec2 v_TexCoord; 19 | uniform samplerExternalOES sTexture; 20 | 21 | 22 | void main() { 23 | gl_FragColor = texture2D(sTexture, v_TexCoord); 24 | } 25 | -------------------------------------------------------------------------------- /part2/src/main/assets/shaders/screenquad.vert: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | attribute vec4 a_Position; 17 | attribute vec2 a_TexCoord; 18 | 19 | varying vec2 v_TexCoord; 20 | 21 | void main() { 22 | gl_Position = a_Position; 23 | v_TexCoord = a_TexCoord; 24 | } 25 | -------------------------------------------------------------------------------- /part2/src/main/java/com/google/ar/core/codelab/common/helpers/CameraPermissionHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.Manifest; 18 | import android.app.Activity; 19 | import android.content.Intent; 20 | import android.content.pm.PackageManager; 21 | import android.net.Uri; 22 | import android.provider.Settings; 23 | import android.support.v4.app.ActivityCompat; 24 | import android.support.v4.content.ContextCompat; 25 | 26 | /** Helper to ask camera permission. */ 27 | public final class CameraPermissionHelper { 28 | private static final int CAMERA_PERMISSION_CODE = 0; 29 | private static final String CAMERA_PERMISSION = Manifest.permission.CAMERA; 30 | 31 | /** Check to see we have the necessary permissions for this app. */ 32 | public static boolean hasCameraPermission(Activity activity) { 33 | return ContextCompat.checkSelfPermission(activity, CAMERA_PERMISSION) 34 | == PackageManager.PERMISSION_GRANTED; 35 | } 36 | 37 | /** Check to see we have the necessary permissions for this app, and ask for them if we don't. */ 38 | public static void requestCameraPermission(Activity activity) { 39 | ActivityCompat.requestPermissions( 40 | activity, new String[] {CAMERA_PERMISSION}, CAMERA_PERMISSION_CODE); 41 | } 42 | 43 | /** Check to see if we need to show the rationale for this permission. */ 44 | public static boolean shouldShowRequestPermissionRationale(Activity activity) { 45 | return ActivityCompat.shouldShowRequestPermissionRationale(activity, CAMERA_PERMISSION); 46 | } 47 | 48 | /** Launch Application Setting to grant permission. */ 49 | public static void launchPermissionSettings(Activity activity) { 50 | Intent intent = new Intent(); 51 | intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 52 | intent.setData(Uri.fromParts("package", activity.getPackageName(), null)); 53 | activity.startActivity(intent); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /part2/src/main/java/com/google/ar/core/codelab/common/helpers/DisplayRotationHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.app.Activity; 18 | import android.content.Context; 19 | import android.hardware.camera2.CameraAccessException; 20 | import android.hardware.camera2.CameraCharacteristics; 21 | import android.hardware.camera2.CameraManager; 22 | import android.hardware.display.DisplayManager; 23 | import android.hardware.display.DisplayManager.DisplayListener; 24 | import android.view.Display; 25 | import android.view.Surface; 26 | import android.view.WindowManager; 27 | import com.google.ar.core.Session; 28 | 29 | /** 30 | * Helper to track the display rotations. In particular, the 180 degree rotations are not notified 31 | * by the onSurfaceChanged() callback, and thus they require listening to the android display 32 | * events. 33 | */ 34 | public final class DisplayRotationHelper implements DisplayListener { 35 | private boolean viewportChanged; 36 | private int viewportWidth; 37 | private int viewportHeight; 38 | private final Display display; 39 | private final DisplayManager displayManager; 40 | private final CameraManager cameraManager; 41 | 42 | /** 43 | * Constructs the DisplayRotationHelper but does not register the listener yet. 44 | * 45 | * @param context the Android {@link Context}. 46 | */ 47 | public DisplayRotationHelper(Context context) { 48 | displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); 49 | cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); 50 | WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 51 | display = windowManager.getDefaultDisplay(); 52 | } 53 | 54 | /** Registers the display listener. Should be called from {@link Activity#onResume()}. */ 55 | public void onResume() { 56 | displayManager.registerDisplayListener(this, null); 57 | } 58 | 59 | /** Unregisters the display listener. Should be called from {@link Activity#onPause()}. */ 60 | public void onPause() { 61 | displayManager.unregisterDisplayListener(this); 62 | } 63 | 64 | /** 65 | * Records a change in surface dimensions. This will be later used by {@link 66 | * #updateSessionIfNeeded(Session)}. Should be called from {@link 67 | * android.opengl.GLSurfaceView.Renderer 68 | * #onSurfaceChanged(javax.microedition.khronos.opengles.GL10, int, int)}. 69 | * 70 | * @param width the updated width of the surface. 71 | * @param height the updated height of the surface. 72 | */ 73 | public void onSurfaceChanged(int width, int height) { 74 | viewportWidth = width; 75 | viewportHeight = height; 76 | viewportChanged = true; 77 | } 78 | 79 | /** 80 | * Updates the session display geometry if a change was posted either by {@link 81 | * #onSurfaceChanged(int, int)} call or by {@link #onDisplayChanged(int)} system callback. This 82 | * function should be called explicitly before each call to {@link Session#update()}. This 83 | * function will also clear the 'pending update' (viewportChanged) flag. 84 | * 85 | * @param session the {@link Session} object to update if display geometry changed. 86 | */ 87 | public void updateSessionIfNeeded(Session session) { 88 | if (viewportChanged) { 89 | int displayRotation = display.getRotation(); 90 | session.setDisplayGeometry(displayRotation, viewportWidth, viewportHeight); 91 | viewportChanged = false; 92 | } 93 | } 94 | 95 | /** 96 | * Returns the aspect ratio of the GL surface viewport while accounting for the display rotation 97 | * relative to the device camera sensor orientation. 98 | */ 99 | public float getCameraSensorRelativeViewportAspectRatio(String cameraId) { 100 | float aspectRatio; 101 | int cameraSensorToDisplayRotation = getCameraSensorToDisplayRotation(cameraId); 102 | switch (cameraSensorToDisplayRotation) { 103 | case 90: 104 | case 270: 105 | aspectRatio = (float) viewportHeight / (float) viewportWidth; 106 | break; 107 | case 0: 108 | case 180: 109 | aspectRatio = (float) viewportWidth / (float) viewportHeight; 110 | break; 111 | default: 112 | throw new RuntimeException("Unhandled rotation: " + cameraSensorToDisplayRotation); 113 | } 114 | return aspectRatio; 115 | } 116 | 117 | /** 118 | * Returns the rotation of the back-facing camera with respect to the display. The value is one of 119 | * 0, 90, 180, 270. 120 | */ 121 | public int getCameraSensorToDisplayRotation(String cameraId) { 122 | CameraCharacteristics characteristics; 123 | try { 124 | characteristics = cameraManager.getCameraCharacteristics(cameraId); 125 | } catch (CameraAccessException e) { 126 | throw new RuntimeException("Unable to determine display orientation", e); 127 | } 128 | 129 | // Camera sensor orientation. 130 | int sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); 131 | 132 | // Current display orientation. 133 | int displayOrientation = toDegrees(display.getRotation()); 134 | 135 | // Make sure we return 0, 90, 180, or 270 degrees. 136 | return (sensorOrientation - displayOrientation + 360) % 360; 137 | } 138 | 139 | private int toDegrees(int rotation) { 140 | switch (rotation) { 141 | case Surface.ROTATION_0: 142 | return 0; 143 | case Surface.ROTATION_90: 144 | return 90; 145 | case Surface.ROTATION_180: 146 | return 180; 147 | case Surface.ROTATION_270: 148 | return 270; 149 | default: 150 | throw new RuntimeException("Unknown rotation " + rotation); 151 | } 152 | } 153 | 154 | @Override 155 | public void onDisplayAdded(int displayId) {} 156 | 157 | @Override 158 | public void onDisplayRemoved(int displayId) {} 159 | 160 | @Override 161 | public void onDisplayChanged(int displayId) { 162 | viewportChanged = true; 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /part2/src/main/java/com/google/ar/core/codelab/common/helpers/FullScreenHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.app.Activity; 18 | import android.view.View; 19 | 20 | /** Helper to set up the Android full screen mode. */ 21 | public final class FullScreenHelper { 22 | /** 23 | * Sets the Android fullscreen flags. Expected to be called from {@link 24 | * Activity#onWindowFocusChanged(boolean hasFocus)}. 25 | * 26 | * @param activity the Activity on which the full screen mode will be set. 27 | * @param hasFocus the hasFocus flag passed from the {@link Activity#onWindowFocusChanged(boolean 28 | * hasFocus)} callback. 29 | */ 30 | public static void setFullScreenOnWindowFocusChanged(Activity activity, boolean hasFocus) { 31 | if (hasFocus) { 32 | // https://developer.android.com/training/system-ui/immersive.html#sticky 33 | activity 34 | .getWindow() 35 | .getDecorView() 36 | .setSystemUiVisibility( 37 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE 38 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 39 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 40 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 41 | | View.SYSTEM_UI_FLAG_FULLSCREEN 42 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /part2/src/main/java/com/google/ar/core/codelab/common/helpers/SnackbarHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.app.Activity; 18 | import android.support.design.widget.BaseTransientBottomBar; 19 | import android.support.design.widget.Snackbar; 20 | import android.view.View; 21 | import android.widget.TextView; 22 | 23 | /** 24 | * Helper to manage the sample snackbar. Hides the Android boilerplate code, and exposes simpler 25 | * methods. 26 | */ 27 | public final class SnackbarHelper { 28 | private static final int BACKGROUND_COLOR = 0xbf323232; 29 | private Snackbar messageSnackbar; 30 | private enum DismissBehavior { HIDE, SHOW, FINISH }; 31 | private int maxLines = 2; 32 | private String lastMessage = ""; 33 | 34 | public boolean isShowing() { 35 | return messageSnackbar != null; 36 | } 37 | 38 | /** Shows a snackbar with a given message. */ 39 | public void showMessage(Activity activity, String message) { 40 | if (!message.isEmpty() && (!isShowing() || !lastMessage.equals(message))) { 41 | lastMessage = message; 42 | show(activity, message, DismissBehavior.HIDE); 43 | } 44 | } 45 | 46 | /** Shows a snackbar with a given message, and a dismiss button. */ 47 | public void showMessageWithDismiss(Activity activity, String message) { 48 | show(activity, message, DismissBehavior.SHOW); 49 | } 50 | 51 | /** 52 | * Shows a snackbar with a given error message. When dismissed, will finish the activity. Useful 53 | * for notifying errors, where no further interaction with the activity is possible. 54 | */ 55 | public void showError(Activity activity, String errorMessage) { 56 | show(activity, errorMessage, DismissBehavior.FINISH); 57 | } 58 | 59 | /** 60 | * Hides the currently showing snackbar, if there is one. Safe to call from any thread. Safe to 61 | * call even if snackbar is not shown. 62 | */ 63 | public void hide(Activity activity) { 64 | if (!isShowing()) { 65 | return; 66 | } 67 | lastMessage = ""; 68 | Snackbar messageSnackbarToHide = messageSnackbar; 69 | messageSnackbar = null; 70 | activity.runOnUiThread( 71 | new Runnable() { 72 | @Override 73 | public void run() { 74 | messageSnackbarToHide.dismiss(); 75 | } 76 | }); 77 | } 78 | 79 | public void setMaxLines(int lines) { 80 | maxLines = lines; 81 | } 82 | 83 | private void show( 84 | final Activity activity, final String message, final DismissBehavior dismissBehavior) { 85 | activity.runOnUiThread( 86 | new Runnable() { 87 | @Override 88 | public void run() { 89 | messageSnackbar = 90 | Snackbar.make( 91 | activity.findViewById(android.R.id.content), 92 | message, 93 | Snackbar.LENGTH_INDEFINITE); 94 | messageSnackbar.getView().setBackgroundColor(BACKGROUND_COLOR); 95 | if (dismissBehavior != DismissBehavior.HIDE) { 96 | messageSnackbar.setAction( 97 | "Dismiss", 98 | new View.OnClickListener() { 99 | @Override 100 | public void onClick(View v) { 101 | messageSnackbar.dismiss(); 102 | } 103 | }); 104 | if (dismissBehavior == DismissBehavior.FINISH) { 105 | messageSnackbar.addCallback( 106 | new BaseTransientBottomBar.BaseCallback() { 107 | @Override 108 | public void onDismissed(Snackbar transientBottomBar, int event) { 109 | super.onDismissed(transientBottomBar, event); 110 | activity.finish(); 111 | } 112 | }); 113 | } 114 | } 115 | ((TextView) 116 | messageSnackbar 117 | .getView() 118 | .findViewById(android.support.design.R.id.snackbar_text)) 119 | .setMaxLines(maxLines); 120 | messageSnackbar.show(); 121 | } 122 | }); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /part2/src/main/java/com/google/ar/core/codelab/common/helpers/TapHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.content.Context; 18 | import android.view.GestureDetector; 19 | import android.view.MotionEvent; 20 | import android.view.View; 21 | import android.view.View.OnTouchListener; 22 | import java.util.concurrent.ArrayBlockingQueue; 23 | import java.util.concurrent.BlockingQueue; 24 | 25 | /** 26 | * Helper to detect taps using Android GestureDetector, and pass the taps between UI thread and 27 | * render thread. 28 | */ 29 | public final class TapHelper implements OnTouchListener { 30 | private final GestureDetector gestureDetector; 31 | private final BlockingQueue queuedSingleTaps = new ArrayBlockingQueue<>(16); 32 | 33 | /** 34 | * Creates the tap helper. 35 | * 36 | * @param context the application's context. 37 | */ 38 | public TapHelper(Context context) { 39 | gestureDetector = 40 | new GestureDetector( 41 | context, 42 | new GestureDetector.SimpleOnGestureListener() { 43 | @Override 44 | public boolean onSingleTapUp(MotionEvent e) { 45 | // Queue tap if there is space. Tap is lost if queue is full. 46 | queuedSingleTaps.offer(e); 47 | return true; 48 | } 49 | 50 | @Override 51 | public boolean onDown(MotionEvent e) { 52 | return true; 53 | } 54 | }); 55 | } 56 | 57 | /** 58 | * Polls for a tap. 59 | * 60 | * @return if a tap was queued, a MotionEvent for the tap. Otherwise null if no taps are queued. 61 | */ 62 | public MotionEvent poll() { 63 | return queuedSingleTaps.poll(); 64 | } 65 | 66 | @Override 67 | public boolean onTouch(View view, MotionEvent motionEvent) { 68 | return gestureDetector.onTouchEvent(motionEvent); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /part2/src/main/java/com/google/ar/core/codelab/common/helpers/TrackingStateHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.app.Activity; 18 | import android.view.WindowManager; 19 | import com.google.ar.core.Camera; 20 | import com.google.ar.core.TrackingFailureReason; 21 | import com.google.ar.core.TrackingState; 22 | 23 | /** Gets human readibly tracking failure reasons and suggested actions. */ 24 | public final class TrackingStateHelper { 25 | private static final String INSUFFICIENT_FEATURES_MESSAGE = 26 | "Can't find anything. Aim device at a surface with more texture or color."; 27 | private static final String EXCESSIVE_MOTION_MESSAGE = "Moving too fast. Slow down."; 28 | private static final String INSUFFICIENT_LIGHT_MESSAGE = 29 | "Too dark. Try moving to a well-lit area."; 30 | private static final String BAD_STATE_MESSAGE = 31 | "Tracking lost due to bad internal state. Please try restarting the AR experience."; 32 | private static final String CAMERA_UNAVAILABLE_MESSAGE = 33 | "Another app is using the camera. Tap on this app or try closing the other one."; 34 | 35 | private final Activity activity; 36 | 37 | private TrackingState previousTrackingState; 38 | 39 | public TrackingStateHelper(Activity activity) { 40 | this.activity = activity; 41 | } 42 | 43 | /** Keep the screen unlocked while tracking, but allow it to lock when tracking stops. */ 44 | public void updateKeepScreenOnFlag(TrackingState trackingState) { 45 | if (trackingState == previousTrackingState) { 46 | return; 47 | } 48 | 49 | previousTrackingState = trackingState; 50 | switch (trackingState) { 51 | case PAUSED: 52 | case STOPPED: 53 | activity.runOnUiThread( 54 | () -> activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)); 55 | break; 56 | case TRACKING: 57 | activity.runOnUiThread( 58 | () -> activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)); 59 | break; 60 | } 61 | } 62 | 63 | public static String getTrackingFailureReasonString(Camera camera) { 64 | TrackingFailureReason reason = camera.getTrackingFailureReason(); 65 | switch (reason) { 66 | case NONE: 67 | return ""; 68 | case BAD_STATE: 69 | return BAD_STATE_MESSAGE; 70 | case INSUFFICIENT_LIGHT: 71 | return INSUFFICIENT_LIGHT_MESSAGE; 72 | case EXCESSIVE_MOTION: 73 | return EXCESSIVE_MOTION_MESSAGE; 74 | case INSUFFICIENT_FEATURES: 75 | return INSUFFICIENT_FEATURES_MESSAGE; 76 | case CAMERA_UNAVAILABLE: 77 | return CAMERA_UNAVAILABLE_MESSAGE; 78 | } 79 | return "Unknown tracking failure reason: " + reason; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /part2/src/main/java/com/google/ar/core/codelab/common/rendering/ShaderUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.rendering; 16 | 17 | import android.content.Context; 18 | import android.opengl.GLES20; 19 | import android.util.Log; 20 | import java.io.BufferedReader; 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.io.InputStreamReader; 24 | 25 | /** Shader helper functions. */ 26 | public class ShaderUtil { 27 | /** 28 | * Converts a raw text file, saved as a resource, into an OpenGL ES shader. 29 | * 30 | * @param type The type of shader we will be creating. 31 | * @param filename The filename of the asset file about to be turned into a shader. 32 | * @return The shader object handler. 33 | */ 34 | public static int loadGLShader(String tag, Context context, int type, String filename) 35 | throws IOException { 36 | String code = readShaderFileFromAssets(context, filename); 37 | int shader = GLES20.glCreateShader(type); 38 | GLES20.glShaderSource(shader, code); 39 | GLES20.glCompileShader(shader); 40 | 41 | // Get the compilation status. 42 | final int[] compileStatus = new int[1]; 43 | GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0); 44 | 45 | // If the compilation failed, delete the shader. 46 | if (compileStatus[0] == 0) { 47 | Log.e(tag, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shader)); 48 | GLES20.glDeleteShader(shader); 49 | shader = 0; 50 | } 51 | 52 | if (shader == 0) { 53 | throw new RuntimeException("Error creating shader."); 54 | } 55 | 56 | return shader; 57 | } 58 | 59 | /** 60 | * Checks if we've had an error inside of OpenGL ES, and if so what that error is. 61 | * 62 | * @param label Label to report in case of error. 63 | * @throws RuntimeException If an OpenGL error is detected. 64 | */ 65 | public static void checkGLError(String tag, String label) { 66 | int lastError = GLES20.GL_NO_ERROR; 67 | // Drain the queue of all errors. 68 | int error; 69 | while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { 70 | Log.e(tag, label + ": glError " + error); 71 | lastError = error; 72 | } 73 | if (lastError != GLES20.GL_NO_ERROR) { 74 | throw new RuntimeException(label + ": glError " + lastError); 75 | } 76 | } 77 | 78 | /** 79 | * Converts a raw shader file into a string. 80 | * 81 | * @param filename The filename of the shader file about to be turned into a shader. 82 | * @return The context of the text file, or null in case of error. 83 | */ 84 | private static String readShaderFileFromAssets(Context context, String filename) 85 | throws IOException { 86 | try (InputStream inputStream = context.getAssets().open(filename); 87 | BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { 88 | StringBuilder sb = new StringBuilder(); 89 | String line; 90 | while ((line = reader.readLine()) != null) { 91 | String[] tokens = line.split(" ", -1); 92 | if (tokens[0].equals("#include")) { 93 | String includeFilename = tokens[1]; 94 | includeFilename = includeFilename.replace("\"", ""); 95 | if (includeFilename.equals(filename)) { 96 | throw new IOException("Do not include the calling file."); 97 | } 98 | sb.append(readShaderFileFromAssets(context, includeFilename)); 99 | } else { 100 | sb.append(line).append("\n"); 101 | } 102 | } 103 | return sb.toString(); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /part2/src/main/java/com/google/ar/core/codelab/depth/DepthTextureHandler.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package com.google.ar.core.codelab.depth; 16 | 17 | import static android.opengl.GLES20.GL_CLAMP_TO_EDGE; 18 | import static android.opengl.GLES20.GL_TEXTURE_2D; 19 | import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER; 20 | import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER; 21 | import static android.opengl.GLES20.GL_TEXTURE_WRAP_S; 22 | import static android.opengl.GLES20.GL_TEXTURE_WRAP_T; 23 | import static android.opengl.GLES20.GL_UNSIGNED_BYTE; 24 | import static android.opengl.GLES20.glBindTexture; 25 | import static android.opengl.GLES20.glGenTextures; 26 | import static android.opengl.GLES20.glTexImage2D; 27 | import static android.opengl.GLES20.glTexParameteri; 28 | import static android.opengl.GLES30.GL_LINEAR; 29 | import static android.opengl.GLES30.GL_RG; 30 | import static android.opengl.GLES30.GL_RG8; 31 | 32 | import android.media.Image; 33 | import com.google.ar.core.Frame; 34 | import com.google.ar.core.exceptions.NotYetAvailableException; 35 | 36 | /** Handle RG8 GPU texture containing a DEPTH16 depth image. */ 37 | public final class DepthTextureHandler { 38 | 39 | private int depthTextureId = -1; 40 | private int depthTextureWidth = -1; 41 | private int depthTextureHeight = -1; 42 | 43 | /** 44 | * Creates and initializes the depth texture. This method needs to be called on a 45 | * thread with a EGL context attached. 46 | */ 47 | public void createOnGlThread() { 48 | int[] textureId = new int[1]; 49 | glGenTextures(1, textureId, 0); 50 | depthTextureId = textureId[0]; 51 | glBindTexture(GL_TEXTURE_2D, depthTextureId); 52 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 53 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 54 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 55 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 56 | } 57 | 58 | /** 59 | * Updates the depth texture with the content from acquireDepthImage(). 60 | * This method needs to be called on a thread with a EGL context attached. 61 | */ 62 | public void update(final Frame frame) { 63 | try { 64 | Image depthImage = frame.acquireDepthImage16Bits(); 65 | depthTextureWidth = depthImage.getWidth(); 66 | depthTextureHeight = depthImage.getHeight(); 67 | glBindTexture(GL_TEXTURE_2D, depthTextureId); 68 | glTexImage2D( 69 | GL_TEXTURE_2D, 70 | 0, 71 | GL_RG8, 72 | depthTextureWidth, 73 | depthTextureHeight, 74 | 0, 75 | GL_RG, 76 | GL_UNSIGNED_BYTE, 77 | depthImage.getPlanes()[0].getBuffer()); 78 | depthImage.close(); 79 | } catch (NotYetAvailableException e) { 80 | // This normally means that depth data is not available yet. 81 | } 82 | } 83 | 84 | public int getDepthTexture() { 85 | return depthTextureId; 86 | } 87 | 88 | public int getDepthWidth() { 89 | return depthTextureWidth; 90 | } 91 | 92 | public int getDepthHeight() { 93 | return depthTextureHeight; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /part2/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part2/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /part2/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 16 | 21 | 22 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /part2/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | Depth Codelab 19 | 20 | -------------------------------------------------------------------------------- /part2/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 22 | 29 | 30 | 31 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /part3/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | google-services.json 3 | -------------------------------------------------------------------------------- /part3/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | def setVersionName = { -> 4 | if (project.hasProperty("androidVersionName")) { 5 | println("Replacing versionName with supplied build parameter: " + 6 | "$androidVersionName") 7 | return androidVersionName 8 | } else { 9 | return "1.0" 10 | } 11 | } 12 | 13 | android { 14 | compileSdkVersion 28 15 | defaultConfig { 16 | applicationId "com.google.ar.core.codelab.depth" 17 | 18 | // AR Optional apps must declare minSdkVersion >= 14. 19 | // AR Required apps must declare minSdkVersion >= 24. 20 | minSdkVersion 24 21 | targetSdkVersion 28 22 | versionCode 1 23 | versionName setVersionName() 24 | } 25 | compileOptions { 26 | sourceCompatibility JavaVersion.VERSION_1_8 27 | targetCompatibility JavaVersion.VERSION_1_8 28 | } 29 | buildTypes { 30 | release { 31 | minifyEnabled false 32 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 33 | } 34 | } 35 | } 36 | 37 | dependencies { 38 | // ARCore library 39 | // Dependency version is rewritten at build time. 40 | implementation 'com.google.ar:core:1.31.0' 41 | 42 | // Obj - a simple Wavefront OBJ file loader 43 | // https://github.com/javagl/Obj 44 | implementation 'de.javagl:obj:0.2.1' 45 | 46 | implementation 'com.android.support:appcompat-v7:28.0.0' 47 | implementation 'com.android.support:design:28.0.0' 48 | } 49 | -------------------------------------------------------------------------------- /part3/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /opt/android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /part3/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 34 | 35 | 41 | 42 | 43 | 44 | 45 | 46 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /part3/src/main/assets/models/andy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part3/src/main/assets/models/andy.png -------------------------------------------------------------------------------- /part3/src/main/assets/models/andy_spec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part3/src/main/assets/models/andy_spec.png -------------------------------------------------------------------------------- /part3/src/main/assets/shaders/background_show_depth_map.frag: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | precision mediump float; 17 | uniform sampler2D u_Depth; 18 | varying vec2 v_TexCoord; 19 | const highp float kMaxDepth = 20000.0; // In millimeters. 20 | 21 | uniform float u_DepthRangeToRenderMm; 22 | const float kDepthWidthToRenderMm = 350.0; 23 | 24 | float GetDepthMillimeters(vec4 depth_pixel_value) { 25 | return 255.0 * (depth_pixel_value.r + depth_pixel_value.g * 256.0); 26 | } 27 | 28 | // Returns an interpolated color in a 6 degree polynomial interpolation. 29 | vec3 GetPolynomialColor(in float x, 30 | in vec4 kRedVec4, in vec4 kGreenVec4, in vec4 kBlueVec4, 31 | in vec2 kRedVec2, in vec2 kGreenVec2, in vec2 kBlueVec2) { 32 | // Moves the color space a little bit to avoid pure red. 33 | // Removes this line for more contrast. 34 | x = clamp(x * 0.9 + 0.03, 0.0, 1.0); 35 | vec4 v4 = vec4(1.0, x, x * x, x * x * x); 36 | vec2 v2 = v4.zw * v4.z; 37 | return vec3( 38 | dot(v4, kRedVec4) + dot(v2, kRedVec2), 39 | dot(v4, kGreenVec4) + dot(v2, kGreenVec2), 40 | dot(v4, kBlueVec4) + dot(v2, kBlueVec2) 41 | ); 42 | } 43 | 44 | // Returns a smooth Percept colormap based upon the Turbo colormap: 45 | // https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html 46 | vec3 PerceptColormap(in float x) { 47 | const vec4 kRedVec4 = vec4(0.55305649, 3.00913185, -5.46192616, -11.11819092); 48 | const vec4 kGreenVec4 = vec4(0.16207513, 0.17712472, 15.24091500, -36.50657960); 49 | const vec4 kBlueVec4 = vec4(-0.05195877, 5.18000081, -30.94853351, 81.96403246); 50 | const vec2 kRedVec2 = vec2(27.81927491, -14.87899417); 51 | const vec2 kGreenVec2 = vec2(25.95549545, -5.02738237); 52 | const vec2 kBlueVec2 = vec2(-86.53476570, 30.23299484); 53 | const float kInvalidDepthThreshold = 0.01; 54 | return step(kInvalidDepthThreshold, x) * 55 | GetPolynomialColor(x, kRedVec4, kGreenVec4, kBlueVec4, 56 | kRedVec2, kGreenVec2, kBlueVec2); 57 | } 58 | 59 | void main() { 60 | vec4 packed_depth = texture2D(u_Depth, v_TexCoord.xy); 61 | highp float depth_mm = GetDepthMillimeters(packed_depth); 62 | highp float normalized_depth = depth_mm / kMaxDepth; 63 | vec4 depth_color = vec4(PerceptColormap(normalized_depth), 1.0); 64 | gl_FragColor = depth_color; 65 | gl_FragColor.a = clamp(1.0 - abs((depth_mm - u_DepthRangeToRenderMm) / kDepthWidthToRenderMm), 0.0, 1.0); 66 | } 67 | -------------------------------------------------------------------------------- /part3/src/main/assets/shaders/background_show_depth_map.vert: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | attribute vec4 a_Position; 17 | attribute vec2 a_TexCoord; 18 | 19 | varying vec2 v_TexCoord; 20 | 21 | void main() { 22 | gl_Position = a_Position; 23 | v_TexCoord = a_TexCoord; 24 | } -------------------------------------------------------------------------------- /part3/src/main/assets/shaders/object.frag: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | precision mediump float; 17 | 18 | uniform sampler2D u_Texture; 19 | 20 | uniform vec4 u_LightingParameters; 21 | uniform vec4 u_MaterialParameters; 22 | uniform vec4 u_ColorCorrectionParameters; 23 | 24 | varying vec3 v_ViewPosition; 25 | varying vec3 v_ViewNormal; 26 | varying vec2 v_TexCoord; 27 | uniform vec4 u_ObjColor; 28 | 29 | void main() { 30 | // We support approximate sRGB gamma. 31 | const float kGamma = 0.4545454; 32 | const float kInverseGamma = 2.2; 33 | const float kMiddleGrayGamma = 0.466; 34 | 35 | // Unpack lighting and material parameters for better naming. 36 | vec3 viewLightDirection = u_LightingParameters.xyz; 37 | vec3 colorShift = u_ColorCorrectionParameters.rgb; 38 | float averagePixelIntensity = u_ColorCorrectionParameters.a; 39 | 40 | float materialAmbient = u_MaterialParameters.x; 41 | float materialDiffuse = u_MaterialParameters.y; 42 | float materialSpecular = u_MaterialParameters.z; 43 | float materialSpecularPower = u_MaterialParameters.w; 44 | 45 | // Normalize varying parameters, because they are linearly interpolated in the vertex shader. 46 | vec3 viewFragmentDirection = normalize(v_ViewPosition); 47 | vec3 viewNormal = normalize(v_ViewNormal); 48 | 49 | // Flip the y-texture coordinate to address the texture from top-left. 50 | vec4 objectColor = texture2D(u_Texture, vec2(v_TexCoord.x, 1.0 - v_TexCoord.y)); 51 | 52 | // Apply color to grayscale image only if the alpha of u_ObjColor is 53 | // greater and equal to 255.0. 54 | if (u_ObjColor.a >= 255.0) { 55 | float intensity = objectColor.r; 56 | objectColor.rgb = u_ObjColor.rgb * intensity / 255.0; 57 | } 58 | 59 | // Apply inverse SRGB gamma to the texture before making lighting calculations. 60 | objectColor.rgb = pow(objectColor.rgb, vec3(kInverseGamma)); 61 | 62 | // Ambient light is unaffected by the light intensity. 63 | float ambient = materialAmbient; 64 | 65 | // Approximate a hemisphere light (not a harsh directional light). 66 | float diffuse = materialDiffuse * 67 | 0.5 * (dot(viewNormal, viewLightDirection) + 1.0); 68 | 69 | // Compute specular light. 70 | vec3 reflectedLightDirection = reflect(viewLightDirection, viewNormal); 71 | float specularStrength = max(0.0, dot(viewFragmentDirection, reflectedLightDirection)); 72 | float specular = materialSpecular * 73 | pow(specularStrength, materialSpecularPower); 74 | 75 | vec3 color = objectColor.rgb * (ambient + diffuse) + specular; 76 | // Apply SRGB gamma before writing the fragment color. 77 | color.rgb = pow(color, vec3(kGamma)); 78 | // Apply average pixel intensity and color shift 79 | color *= colorShift * (averagePixelIntensity / kMiddleGrayGamma); 80 | gl_FragColor.rgb = color; 81 | gl_FragColor.a = objectColor.a; 82 | } 83 | -------------------------------------------------------------------------------- /part3/src/main/assets/shaders/object.vert: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | uniform mat4 u_ModelView; 17 | uniform mat4 u_ModelViewProjection; 18 | 19 | attribute vec4 a_Position; 20 | attribute vec3 a_Normal; 21 | attribute vec2 a_TexCoord; 22 | 23 | varying vec3 v_ViewPosition; 24 | varying vec3 v_ViewNormal; 25 | varying vec2 v_TexCoord; 26 | 27 | void main() { 28 | v_ViewPosition = (u_ModelView * a_Position).xyz; 29 | v_ViewNormal = normalize((u_ModelView * vec4(a_Normal, 0.0)).xyz); 30 | v_TexCoord = a_TexCoord; 31 | gl_Position = u_ModelViewProjection * a_Position; 32 | } 33 | -------------------------------------------------------------------------------- /part3/src/main/assets/shaders/screenquad.frag: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | #extension GL_OES_EGL_image_external : require 16 | 17 | precision mediump float; 18 | varying vec2 v_TexCoord; 19 | uniform samplerExternalOES sTexture; 20 | 21 | 22 | void main() { 23 | gl_FragColor = texture2D(sTexture, v_TexCoord); 24 | } 25 | -------------------------------------------------------------------------------- /part3/src/main/assets/shaders/screenquad.vert: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | attribute vec4 a_Position; 17 | attribute vec2 a_TexCoord; 18 | 19 | varying vec2 v_TexCoord; 20 | 21 | void main() { 22 | gl_Position = a_Position; 23 | v_TexCoord = a_TexCoord; 24 | } 25 | -------------------------------------------------------------------------------- /part3/src/main/java/com/google/ar/core/codelab/common/helpers/CameraPermissionHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.Manifest; 18 | import android.app.Activity; 19 | import android.content.Intent; 20 | import android.content.pm.PackageManager; 21 | import android.net.Uri; 22 | import android.provider.Settings; 23 | import android.support.v4.app.ActivityCompat; 24 | import android.support.v4.content.ContextCompat; 25 | 26 | /** Helper to ask camera permission. */ 27 | public final class CameraPermissionHelper { 28 | private static final int CAMERA_PERMISSION_CODE = 0; 29 | private static final String CAMERA_PERMISSION = Manifest.permission.CAMERA; 30 | 31 | /** Check to see we have the necessary permissions for this app. */ 32 | public static boolean hasCameraPermission(Activity activity) { 33 | return ContextCompat.checkSelfPermission(activity, CAMERA_PERMISSION) 34 | == PackageManager.PERMISSION_GRANTED; 35 | } 36 | 37 | /** Check to see we have the necessary permissions for this app, and ask for them if we don't. */ 38 | public static void requestCameraPermission(Activity activity) { 39 | ActivityCompat.requestPermissions( 40 | activity, new String[] {CAMERA_PERMISSION}, CAMERA_PERMISSION_CODE); 41 | } 42 | 43 | /** Check to see if we need to show the rationale for this permission. */ 44 | public static boolean shouldShowRequestPermissionRationale(Activity activity) { 45 | return ActivityCompat.shouldShowRequestPermissionRationale(activity, CAMERA_PERMISSION); 46 | } 47 | 48 | /** Launch Application Setting to grant permission. */ 49 | public static void launchPermissionSettings(Activity activity) { 50 | Intent intent = new Intent(); 51 | intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 52 | intent.setData(Uri.fromParts("package", activity.getPackageName(), null)); 53 | activity.startActivity(intent); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /part3/src/main/java/com/google/ar/core/codelab/common/helpers/FullScreenHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.app.Activity; 18 | import android.view.View; 19 | 20 | /** Helper to set up the Android full screen mode. */ 21 | public final class FullScreenHelper { 22 | /** 23 | * Sets the Android fullscreen flags. Expected to be called from {@link 24 | * Activity#onWindowFocusChanged(boolean hasFocus)}. 25 | * 26 | * @param activity the Activity on which the full screen mode will be set. 27 | * @param hasFocus the hasFocus flag passed from the {@link Activity#onWindowFocusChanged(boolean 28 | * hasFocus)} callback. 29 | */ 30 | public static void setFullScreenOnWindowFocusChanged(Activity activity, boolean hasFocus) { 31 | if (hasFocus) { 32 | // https://developer.android.com/training/system-ui/immersive.html#sticky 33 | activity 34 | .getWindow() 35 | .getDecorView() 36 | .setSystemUiVisibility( 37 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE 38 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 39 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 40 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 41 | | View.SYSTEM_UI_FLAG_FULLSCREEN 42 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /part3/src/main/java/com/google/ar/core/codelab/common/helpers/SnackbarHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.app.Activity; 18 | import android.support.design.widget.BaseTransientBottomBar; 19 | import android.support.design.widget.Snackbar; 20 | import android.view.View; 21 | import android.widget.TextView; 22 | 23 | /** 24 | * Helper to manage the sample snackbar. Hides the Android boilerplate code, and exposes simpler 25 | * methods. 26 | */ 27 | public final class SnackbarHelper { 28 | private static final int BACKGROUND_COLOR = 0xbf323232; 29 | private Snackbar messageSnackbar; 30 | private enum DismissBehavior { HIDE, SHOW, FINISH }; 31 | private int maxLines = 2; 32 | private String lastMessage = ""; 33 | 34 | public boolean isShowing() { 35 | return messageSnackbar != null; 36 | } 37 | 38 | /** Shows a snackbar with a given message. */ 39 | public void showMessage(Activity activity, String message) { 40 | if (!message.isEmpty() && (!isShowing() || !lastMessage.equals(message))) { 41 | lastMessage = message; 42 | show(activity, message, DismissBehavior.HIDE); 43 | } 44 | } 45 | 46 | /** Shows a snackbar with a given message, and a dismiss button. */ 47 | public void showMessageWithDismiss(Activity activity, String message) { 48 | show(activity, message, DismissBehavior.SHOW); 49 | } 50 | 51 | /** 52 | * Shows a snackbar with a given error message. When dismissed, will finish the activity. Useful 53 | * for notifying errors, where no further interaction with the activity is possible. 54 | */ 55 | public void showError(Activity activity, String errorMessage) { 56 | show(activity, errorMessage, DismissBehavior.FINISH); 57 | } 58 | 59 | /** 60 | * Hides the currently showing snackbar, if there is one. Safe to call from any thread. Safe to 61 | * call even if snackbar is not shown. 62 | */ 63 | public void hide(Activity activity) { 64 | if (!isShowing()) { 65 | return; 66 | } 67 | lastMessage = ""; 68 | Snackbar messageSnackbarToHide = messageSnackbar; 69 | messageSnackbar = null; 70 | activity.runOnUiThread( 71 | new Runnable() { 72 | @Override 73 | public void run() { 74 | messageSnackbarToHide.dismiss(); 75 | } 76 | }); 77 | } 78 | 79 | public void setMaxLines(int lines) { 80 | maxLines = lines; 81 | } 82 | 83 | private void show( 84 | final Activity activity, final String message, final DismissBehavior dismissBehavior) { 85 | activity.runOnUiThread( 86 | new Runnable() { 87 | @Override 88 | public void run() { 89 | messageSnackbar = 90 | Snackbar.make( 91 | activity.findViewById(android.R.id.content), 92 | message, 93 | Snackbar.LENGTH_INDEFINITE); 94 | messageSnackbar.getView().setBackgroundColor(BACKGROUND_COLOR); 95 | if (dismissBehavior != DismissBehavior.HIDE) { 96 | messageSnackbar.setAction( 97 | "Dismiss", 98 | new View.OnClickListener() { 99 | @Override 100 | public void onClick(View v) { 101 | messageSnackbar.dismiss(); 102 | } 103 | }); 104 | if (dismissBehavior == DismissBehavior.FINISH) { 105 | messageSnackbar.addCallback( 106 | new BaseTransientBottomBar.BaseCallback() { 107 | @Override 108 | public void onDismissed(Snackbar transientBottomBar, int event) { 109 | super.onDismissed(transientBottomBar, event); 110 | activity.finish(); 111 | } 112 | }); 113 | } 114 | } 115 | ((TextView) 116 | messageSnackbar 117 | .getView() 118 | .findViewById(android.support.design.R.id.snackbar_text)) 119 | .setMaxLines(maxLines); 120 | messageSnackbar.show(); 121 | } 122 | }); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /part3/src/main/java/com/google/ar/core/codelab/common/helpers/TapHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.content.Context; 18 | import android.view.GestureDetector; 19 | import android.view.MotionEvent; 20 | import android.view.View; 21 | import android.view.View.OnTouchListener; 22 | import java.util.concurrent.ArrayBlockingQueue; 23 | import java.util.concurrent.BlockingQueue; 24 | 25 | /** 26 | * Helper to detect taps using Android GestureDetector, and pass the taps between UI thread and 27 | * render thread. 28 | */ 29 | public final class TapHelper implements OnTouchListener { 30 | private final GestureDetector gestureDetector; 31 | private final BlockingQueue queuedSingleTaps = new ArrayBlockingQueue<>(16); 32 | 33 | /** 34 | * Creates the tap helper. 35 | * 36 | * @param context the application's context. 37 | */ 38 | public TapHelper(Context context) { 39 | gestureDetector = 40 | new GestureDetector( 41 | context, 42 | new GestureDetector.SimpleOnGestureListener() { 43 | @Override 44 | public boolean onSingleTapUp(MotionEvent e) { 45 | // Queue tap if there is space. Tap is lost if queue is full. 46 | queuedSingleTaps.offer(e); 47 | return true; 48 | } 49 | 50 | @Override 51 | public boolean onDown(MotionEvent e) { 52 | return true; 53 | } 54 | }); 55 | } 56 | 57 | /** 58 | * Polls for a tap. 59 | * 60 | * @return if a tap was queued, a MotionEvent for the tap. Otherwise null if no taps are queued. 61 | */ 62 | public MotionEvent poll() { 63 | return queuedSingleTaps.poll(); 64 | } 65 | 66 | @Override 67 | public boolean onTouch(View view, MotionEvent motionEvent) { 68 | return gestureDetector.onTouchEvent(motionEvent); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /part3/src/main/java/com/google/ar/core/codelab/common/helpers/TrackingStateHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.helpers; 16 | 17 | import android.app.Activity; 18 | import android.view.WindowManager; 19 | import com.google.ar.core.Camera; 20 | import com.google.ar.core.TrackingFailureReason; 21 | import com.google.ar.core.TrackingState; 22 | 23 | /** Gets human readibly tracking failure reasons and suggested actions. */ 24 | public final class TrackingStateHelper { 25 | private static final String INSUFFICIENT_FEATURES_MESSAGE = 26 | "Can't find anything. Aim device at a surface with more texture or color."; 27 | private static final String EXCESSIVE_MOTION_MESSAGE = "Moving too fast. Slow down."; 28 | private static final String INSUFFICIENT_LIGHT_MESSAGE = 29 | "Too dark. Try moving to a well-lit area."; 30 | private static final String BAD_STATE_MESSAGE = 31 | "Tracking lost due to bad internal state. Please try restarting the AR experience."; 32 | private static final String CAMERA_UNAVAILABLE_MESSAGE = 33 | "Another app is using the camera. Tap on this app or try closing the other one."; 34 | 35 | private final Activity activity; 36 | 37 | private TrackingState previousTrackingState; 38 | 39 | public TrackingStateHelper(Activity activity) { 40 | this.activity = activity; 41 | } 42 | 43 | /** Keep the screen unlocked while tracking, but allow it to lock when tracking stops. */ 44 | public void updateKeepScreenOnFlag(TrackingState trackingState) { 45 | if (trackingState == previousTrackingState) { 46 | return; 47 | } 48 | 49 | previousTrackingState = trackingState; 50 | switch (trackingState) { 51 | case PAUSED: 52 | case STOPPED: 53 | activity.runOnUiThread( 54 | () -> activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)); 55 | break; 56 | case TRACKING: 57 | activity.runOnUiThread( 58 | () -> activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)); 59 | break; 60 | } 61 | } 62 | 63 | public static String getTrackingFailureReasonString(Camera camera) { 64 | TrackingFailureReason reason = camera.getTrackingFailureReason(); 65 | switch (reason) { 66 | case NONE: 67 | return ""; 68 | case BAD_STATE: 69 | return BAD_STATE_MESSAGE; 70 | case INSUFFICIENT_LIGHT: 71 | return INSUFFICIENT_LIGHT_MESSAGE; 72 | case EXCESSIVE_MOTION: 73 | return EXCESSIVE_MOTION_MESSAGE; 74 | case INSUFFICIENT_FEATURES: 75 | return INSUFFICIENT_FEATURES_MESSAGE; 76 | case CAMERA_UNAVAILABLE: 77 | return CAMERA_UNAVAILABLE_MESSAGE; 78 | } 79 | return "Unknown tracking failure reason: " + reason; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /part3/src/main/java/com/google/ar/core/codelab/common/rendering/ShaderUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.google.ar.core.codelab.common.rendering; 16 | 17 | import android.content.Context; 18 | import android.opengl.GLES20; 19 | import android.util.Log; 20 | import java.io.BufferedReader; 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.io.InputStreamReader; 24 | 25 | /** Shader helper functions. */ 26 | public class ShaderUtil { 27 | /** 28 | * Converts a raw text file, saved as a resource, into an OpenGL ES shader. 29 | * 30 | * @param type The type of shader we will be creating. 31 | * @param filename The filename of the asset file about to be turned into a shader. 32 | * @return The shader object handler. 33 | */ 34 | public static int loadGLShader(String tag, Context context, int type, String filename) 35 | throws IOException { 36 | String code = readShaderFileFromAssets(context, filename); 37 | int shader = GLES20.glCreateShader(type); 38 | GLES20.glShaderSource(shader, code); 39 | GLES20.glCompileShader(shader); 40 | 41 | // Get the compilation status. 42 | final int[] compileStatus = new int[1]; 43 | GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0); 44 | 45 | // If the compilation failed, delete the shader. 46 | if (compileStatus[0] == 0) { 47 | Log.e(tag, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shader)); 48 | GLES20.glDeleteShader(shader); 49 | shader = 0; 50 | } 51 | 52 | if (shader == 0) { 53 | throw new RuntimeException("Error creating shader."); 54 | } 55 | 56 | return shader; 57 | } 58 | 59 | /** 60 | * Checks if we've had an error inside of OpenGL ES, and if so what that error is. 61 | * 62 | * @param label Label to report in case of error. 63 | * @throws RuntimeException If an OpenGL error is detected. 64 | */ 65 | public static void checkGLError(String tag, String label) { 66 | int lastError = GLES20.GL_NO_ERROR; 67 | // Drain the queue of all errors. 68 | int error; 69 | while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { 70 | Log.e(tag, label + ": glError " + error); 71 | lastError = error; 72 | } 73 | if (lastError != GLES20.GL_NO_ERROR) { 74 | throw new RuntimeException(label + ": glError " + lastError); 75 | } 76 | } 77 | 78 | /** 79 | * Converts a raw shader file into a string. 80 | * 81 | * @param filename The filename of the shader file about to be turned into a shader. 82 | * @return The context of the text file, or null in case of error. 83 | */ 84 | private static String readShaderFileFromAssets(Context context, String filename) 85 | throws IOException { 86 | try (InputStream inputStream = context.getAssets().open(filename); 87 | BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { 88 | StringBuilder sb = new StringBuilder(); 89 | String line; 90 | while ((line = reader.readLine()) != null) { 91 | String[] tokens = line.split(" ", -1); 92 | if (tokens[0].equals("#include")) { 93 | String includeFilename = tokens[1]; 94 | includeFilename = includeFilename.replace("\"", ""); 95 | if (includeFilename.equals(filename)) { 96 | throw new IOException("Do not include the calling file."); 97 | } 98 | sb.append(readShaderFileFromAssets(context, includeFilename)); 99 | } else { 100 | sb.append(line).append("\n"); 101 | } 102 | } 103 | return sb.toString(); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /part3/src/main/java/com/google/ar/core/codelab/depth/DepthTextureHandler.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package com.google.ar.core.codelab.depth; 16 | 17 | import static android.opengl.GLES20.GL_CLAMP_TO_EDGE; 18 | import static android.opengl.GLES20.GL_TEXTURE_2D; 19 | import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER; 20 | import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER; 21 | import static android.opengl.GLES20.GL_TEXTURE_WRAP_S; 22 | import static android.opengl.GLES20.GL_TEXTURE_WRAP_T; 23 | import static android.opengl.GLES20.GL_UNSIGNED_BYTE; 24 | import static android.opengl.GLES20.glBindTexture; 25 | import static android.opengl.GLES20.glGenTextures; 26 | import static android.opengl.GLES20.glTexImage2D; 27 | import static android.opengl.GLES20.glTexParameteri; 28 | import static android.opengl.GLES30.GL_LINEAR; 29 | import static android.opengl.GLES30.GL_RG; 30 | import static android.opengl.GLES30.GL_RG8; 31 | 32 | import android.media.Image; 33 | import com.google.ar.core.Frame; 34 | import com.google.ar.core.exceptions.NotYetAvailableException; 35 | 36 | /** Handle RG8 GPU texture containing a DEPTH16 depth image. */ 37 | public final class DepthTextureHandler { 38 | 39 | private int depthTextureId = -1; 40 | private int depthTextureWidth = -1; 41 | private int depthTextureHeight = -1; 42 | 43 | /** 44 | * Creates and initializes the depth texture. This method needs to be called on a 45 | * thread with a EGL context attached. 46 | */ 47 | public void createOnGlThread() { 48 | int[] textureId = new int[1]; 49 | glGenTextures(1, textureId, 0); 50 | depthTextureId = textureId[0]; 51 | glBindTexture(GL_TEXTURE_2D, depthTextureId); 52 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 53 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 54 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 55 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 56 | } 57 | 58 | /** 59 | * Updates the depth texture with the content from acquireDepthImage(). 60 | * This method needs to be called on a thread with a EGL context attached. 61 | */ 62 | public void update(final Frame frame) { 63 | try { 64 | Image depthImage = frame.acquireDepthImage16Bits(); 65 | depthTextureWidth = depthImage.getWidth(); 66 | depthTextureHeight = depthImage.getHeight(); 67 | glBindTexture(GL_TEXTURE_2D, depthTextureId); 68 | glTexImage2D( 69 | GL_TEXTURE_2D, 70 | 0, 71 | GL_RG8, 72 | depthTextureWidth, 73 | depthTextureHeight, 74 | 0, 75 | GL_RG, 76 | GL_UNSIGNED_BYTE, 77 | depthImage.getPlanes()[0].getBuffer()); 78 | depthImage.close(); 79 | } catch (NotYetAvailableException e) { 80 | // This normally means that depth data is not available yet. 81 | } 82 | } 83 | 84 | public int getDepthTexture() { 85 | return depthTextureId; 86 | } 87 | 88 | public int getDepthWidth() { 89 | return depthTextureWidth; 90 | } 91 | 92 | public int getDepthHeight() { 93 | return depthTextureHeight; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /part3/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part3/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /part3/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 16 | 21 | 22 | 27 | 28 |