remove arcore from apps project directory
arcore is untouched and impedes builds of other apps in platform-tools Change-Id: I92b603de318b956c116fa0a065a26d2217755b68 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/294736 Commit-Queue: Jorge Betancourt <jmbetancourt@google.com> Reviewed-by: Mike Reed <reed@google.com>
This commit is contained in:
parent
25df1f7f88
commit
6c4b67d13b
@ -41,7 +41,6 @@
|
||||
'../../gn',
|
||||
'../../include',
|
||||
'../../modules',
|
||||
'../../platform_tools/android/apps/arcore/src/main/cpp',
|
||||
'../../platform_tools/android/apps/skottie/src/main/cpp',
|
||||
'../../platform_tools/android/launcher/skia_launcher.cpp',
|
||||
'../../platform_tools/android/vulkan/Skia_Vulkan_Android.h',
|
||||
|
@ -1,75 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
##
|
||||
|
||||
# Sets the minimum version of CMake required to build the native library.
|
||||
cmake_minimum_required(VERSION 3.4.1)
|
||||
|
||||
# Import the ARCore library.
|
||||
add_library(arcore SHARED IMPORTED)
|
||||
set_target_properties(arcore PROPERTIES IMPORTED_LOCATION
|
||||
"${ARCORE_LIBPATH}/${ANDROID_ABI}/libarcore_sdk_c.so")
|
||||
|
||||
add_library(sk_skia SHARED IMPORTED)
|
||||
set_target_properties(sk_skia PROPERTIES IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/src/main/libs/${ANDROID_ABI}/libarcore.so")
|
||||
|
||||
# This is the main app library.
|
||||
add_library(hello_ar_native SHARED
|
||||
"src/main/cpp/hello_ar_application.cc"
|
||||
"src/main/cpp/background_renderer.cc"
|
||||
"src/main/cpp/jni_interface.cc"
|
||||
"src/main/cpp/plane_renderer.cc"
|
||||
"src/main/cpp/point_cloud_renderer.cc"
|
||||
"src/main/cpp/util.cc"
|
||||
"src/main/cpp/pending_anchor.cc"
|
||||
"src/main/cpp/anchor_wrapper.cc"
|
||||
|
||||
"src/main/cpp/SkArCamera.cpp")
|
||||
|
||||
target_include_directories(hello_ar_native PRIVATE
|
||||
#BASIC AR NATIVE CODE
|
||||
"src/main/cpp"
|
||||
|
||||
#ARCORE LIBRARY
|
||||
"${ARCORE_INCLUDE}"
|
||||
|
||||
#GLM
|
||||
"${ANDROID_NDK}/sources/third_party/vulkan/src/libs/glm"
|
||||
|
||||
#SKIA INCLUDE DIRECTORIES
|
||||
"${SKIA_INCLUDE_PATH}/../modules/skshaper/include"
|
||||
"${SKIA_INCLUDE_PATH}/../modules/skottie/include"
|
||||
"${SKIA_INCLUDE_PATH}/../tools"
|
||||
"${SKIA_INCLUDE_PATH}/../gm"
|
||||
"${SKIA_INCLUDE_PATH}/core"
|
||||
"${SKIA_INCLUDE_PATH}/config"
|
||||
"${SKIA_INCLUDE_PATH}/gpu"
|
||||
"${SKIA_INCLUDE_PATH}/android"
|
||||
"${SKIA_INCLUDE_PATH}/c"
|
||||
"${SKIA_INCLUDE_PATH}/codec"
|
||||
"${SKIA_INCLUDE_PATH}/effects"
|
||||
"${SKIA_INCLUDE_PATH}/encode"
|
||||
"${SKIA_INCLUDE_PATH}/pathops"
|
||||
"${SKIA_INCLUDE_PATH}/ports"
|
||||
"${SKIA_INCLUDE_PATH}/private"
|
||||
"${SKIA_INCLUDE_PATH}/svg"
|
||||
"${SKIA_INCLUDE_PATH}/utils"
|
||||
"${SKIA_INCLUDE_PATH}/views")
|
||||
|
||||
target_link_libraries(hello_ar_native
|
||||
android
|
||||
log
|
||||
GLESv2
|
||||
arcore
|
||||
sk_skia)
|
@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
/*
|
||||
The arcore aar library contains the native shared libraries. These are
|
||||
extracted before building to a temporary directory.
|
||||
*/
|
||||
def arcore_libpath = "${buildDir}/arcore-native"
|
||||
|
||||
// Create a configuration to mark which aars to extract .so files from
|
||||
configurations { natives }
|
||||
|
||||
android {
|
||||
sourceSets.main.jni.srcDirs = [] //disable automatic ndk-build call
|
||||
sourceSets.main.jniLibs.srcDir "src/main/libs"
|
||||
productFlavors { arm64 {} }
|
||||
|
||||
setupSkiaLibraryBuild(project, applicationVariants, "libarcore")
|
||||
|
||||
compileSdkVersion 27
|
||||
defaultConfig {
|
||||
applicationId "org.skia.viewer"
|
||||
// 24 is the minimum since ARCore only works with 24 and higher.
|
||||
minSdkVersion 24
|
||||
targetSdkVersion 27
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags "-std=c++11", "-Wall"
|
||||
arguments "-DANDROID_STL=c++_static",
|
||||
"-DARCORE_LIBPATH=${arcore_libpath}/jni",
|
||||
"-DARCORE_INCLUDE=${project.rootDir}/../../libraries/include",
|
||||
"-DSKIA_INCLUDE_PATH=${project.rootDir}/../../../include"
|
||||
}
|
||||
}
|
||||
ndk {
|
||||
abiFilters "arm64-v8a"
|
||||
}
|
||||
}
|
||||
flavorDimensions "base"
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path "CMakeLists.txt"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// ARCore library
|
||||
implementation 'com.google.ar:core:1.2.0'
|
||||
natives 'com.google.ar:core:1.2.0'
|
||||
|
||||
implementation 'com.android.support:appcompat-v7:27.0.2'
|
||||
implementation 'com.android.support:design:27.0.2'
|
||||
}
|
||||
|
||||
// Extracts the shared libraries from aars in the natives configuration.
|
||||
// This is done so that NDK builds can access these libraries.
|
||||
task extractNativeLibraries() {
|
||||
doFirst {
|
||||
configurations.natives.files.each { f ->
|
||||
copy {
|
||||
from zipTree(f)
|
||||
into arcore_libpath
|
||||
include "jni/**/*"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tasks.whenTaskAdded {
|
||||
task-> if (task.name.contains("external") && !task.name.contains("Clean")) {
|
||||
task.dependsOn(extractNativeLibraries)
|
||||
|
||||
//make sure skia lib is built and copied in the correct directory before building arcore
|
||||
tasks.whenTaskAdded {
|
||||
t-> if (t.name.contains("CopySkiaLib")) {
|
||||
task.dependsOn(t)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,35 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.skia.arcore">
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<!-- This tag indicates that this application requires ARCore. This results in the application
|
||||
only being visible in the Google Play Store on devices that support ARCore. -->
|
||||
<uses-feature android:name="android.hardware.camera.ar" android:required="true"/>
|
||||
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
|
||||
android:usesCleartextTraffic="false">
|
||||
<!-- This tag indicates that this application requires ARCore. This results in the Google Play
|
||||
Store downloading and installing ARCore along with the application. -->
|
||||
<meta-data android:name="com.google.ar.core" android:value="required" />
|
||||
|
||||
<activity
|
||||
android:name=".HelloArActivity"
|
||||
android:label="@string/app_name"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.AppCompat.DayNight.NoActionBar"
|
||||
|
||||
android:screenOrientation="locked">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
Binary file not shown.
Before Width: | Height: | Size: 143 KiB |
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Google LLC
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <arcore_c_api.h>
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/SkArCamera.h"
|
||||
#include "SkArUtil.h"
|
||||
|
||||
std::unique_ptr<SkArCamera> SkArCamera::Make(SkArSession* session, SkArFrame* frame) {
|
||||
return std::unique_ptr<SkArCamera>(new SkArCamera(session, frame));
|
||||
}
|
||||
|
||||
SkArCamera::~SkArCamera() {
|
||||
ArCamera_release(fArCamera);
|
||||
}
|
||||
|
||||
SkArCamera::SkArCamera(SkArSession* session, SkArFrame* frame) : fArCamera(nullptr) {
|
||||
ArFrame_acquireCamera(session->getArSession(), frame->getArFrame(), &fArCamera);
|
||||
}
|
||||
|
||||
void SkArCamera::getViewMatrix(const SkArSession* session, float outColMajor[16]) {
|
||||
ArCamera_getViewMatrix(session->getArSession(), fArCamera, outColMajor);
|
||||
}
|
||||
|
||||
void SkArCamera::getProjectionMatrix(const SkArSession* session, float nearClip,
|
||||
float farClip, float outColMajor[16]) {
|
||||
ArCamera_getProjectionMatrix(session->getArSession(), fArCamera, nearClip, farClip,
|
||||
outColMajor);
|
||||
}
|
||||
|
||||
SkArTrackingState SkArCamera::getTrackingState(const SkArSession* session) {
|
||||
ArTrackingState arTrackingState;
|
||||
ArCamera_getTrackingState(session->getArSession(), fArCamera, &arTrackingState);
|
||||
return SkArUtil::MakeSkArTrackingState(arTrackingState);
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Google LLC
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkArCamera_DEFINED
|
||||
#define SkArCamera_DEFINED
|
||||
|
||||
#include <memory>
|
||||
#include "SkArTrackingState.h"
|
||||
|
||||
class ArCamera;
|
||||
class SkArFrame;
|
||||
class SkArSession;
|
||||
|
||||
/**
|
||||
* Provides information about the camera that is used to capture images. Such information
|
||||
* includes projection matrices, pose of camera...
|
||||
*/
|
||||
|
||||
class SkArCamera {
|
||||
|
||||
public:
|
||||
/**
|
||||
* Factory method used to construct an SkArCamera from the current frame, using the current
|
||||
* session
|
||||
* @param session raw pointer to the current SkArSession
|
||||
* @param frame raw pointer to the current SkArFrame
|
||||
* @return unique pointer to an SkArCamera. Never nullptr
|
||||
*/
|
||||
static std::unique_ptr<SkArCamera> Make(SkArSession* session, SkArFrame* frame);
|
||||
|
||||
~SkArCamera();
|
||||
|
||||
/**
|
||||
* Fills outColMajor with the values of the camera's current View matrix in column-major order
|
||||
* @param session current SkArSession
|
||||
* @param outColMajor 16-float array that will contain the View matrix content
|
||||
*/
|
||||
void getViewMatrix(const SkArSession* session, float outColMajor[16]);
|
||||
|
||||
/**
|
||||
* Fills outColMajor with the values of the camera's current Projection matrix in
|
||||
* column-major order
|
||||
* @param session current SkArSession
|
||||
* @param nearClip wanted near clip value for the camera
|
||||
* @param farClip wanted far clip value for the camera
|
||||
* @param outColMajor 16-float array that will contain the Projection matrix content
|
||||
*/
|
||||
void getProjectionMatrix(const SkArSession* session, float nearClip, float farClip,
|
||||
float outColMajor[16]);
|
||||
|
||||
/**
|
||||
* Used to check the current SkArTrackingState of the camera
|
||||
* @param session current SkArSession
|
||||
* @return tracking state of the SkArCamera described by the SkArTrackingState enum
|
||||
*/
|
||||
SkArTrackingState getTrackingState(const SkArSession* session);
|
||||
|
||||
private:
|
||||
SkArCamera(SkArSession* session, SkArFrame* frame);
|
||||
|
||||
// This is a raw pointer. Its lifetime matches that of this class (SkArCamera)
|
||||
ArCamera* fArCamera;
|
||||
};
|
||||
#endif // SkArCamera_DEFINED
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/hello_ar_application.h"
|
||||
#include "arcore_c_api.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/anchor_wrapper.h"
|
||||
|
||||
namespace hello_ar {
|
||||
|
||||
AnchorWrapper::AnchorWrapper(ArAnchor *anchor) : anchor(anchor) {}
|
||||
|
||||
const ArAnchor* AnchorWrapper::GetArAnchor() {
|
||||
return anchor;
|
||||
}
|
||||
DrawableType AnchorWrapper::GetDrawableType() {
|
||||
return drawableType;
|
||||
}
|
||||
|
||||
void AnchorWrapper::SetArAnchor(ArAnchor* anchor) {
|
||||
this->anchor = anchor;
|
||||
}
|
||||
void AnchorWrapper::SetDrawableType(DrawableType drawableType) {
|
||||
this->drawableType = drawableType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace hello_ar
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef C_ARCORE_HELLO_AR_ANCHOR_WRAPPER_H_
|
||||
#define C_ARCORE_HELLO_AR_ANCHOR_WRAPPER_H_
|
||||
#include "arcore_c_api.h"
|
||||
|
||||
namespace hello_ar {
|
||||
enum DrawableType {
|
||||
TEXT = 0, CIRCLE = 1, RECT = 2
|
||||
};
|
||||
|
||||
class AnchorWrapper {
|
||||
public:
|
||||
AnchorWrapper(ArAnchor* anchor);
|
||||
|
||||
const ArAnchor* GetArAnchor();
|
||||
DrawableType GetDrawableType();
|
||||
bool GetInEditMode();
|
||||
|
||||
void SetArAnchor(ArAnchor* anchor);
|
||||
void SetDrawableType(DrawableType drawableType);
|
||||
void SetInEditMode(bool inEditMode);
|
||||
|
||||
private:
|
||||
ArAnchor* anchor;
|
||||
DrawableType drawableType;
|
||||
bool inEditMode = false;
|
||||
};
|
||||
} // namespace hello_ar
|
||||
|
||||
#endif
|
@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// This modules handles drawing the passthrough camera image into the OpenGL
|
||||
// scene.
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/background_renderer.h"
|
||||
|
||||
namespace hello_ar {
|
||||
namespace {
|
||||
// Positions of the quad vertices in clip space (X, Y, Z).
|
||||
const GLfloat kVertices[] = {
|
||||
-1.0f, -1.0f, 0.0f, +1.0f, -1.0f, 0.0f,
|
||||
-1.0f, +1.0f, 0.0f, +1.0f, +1.0f, 0.0f,
|
||||
};
|
||||
|
||||
// UVs of the quad vertices (S, T)
|
||||
const GLfloat kUvs[] = {
|
||||
0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
|
||||
};
|
||||
|
||||
constexpr char kVertexShader[] = R"(
|
||||
attribute vec4 vertex;
|
||||
attribute vec2 textureCoords;
|
||||
varying vec2 v_textureCoords;
|
||||
void main() {
|
||||
v_textureCoords = textureCoords;
|
||||
gl_Position = vertex;
|
||||
})";
|
||||
|
||||
constexpr char kFragmentShader[] = R"(
|
||||
#extension GL_OES_EGL_image_external : require
|
||||
precision mediump float;
|
||||
uniform samplerExternalOES texture;
|
||||
varying vec2 v_textureCoords;
|
||||
void main() {
|
||||
gl_FragColor = texture2D(texture, v_textureCoords);
|
||||
})";
|
||||
|
||||
} // namespace
|
||||
|
||||
void BackgroundRenderer::InitializeGlContent() {
|
||||
shader_program_ = util::CreateProgram(kVertexShader, kFragmentShader);
|
||||
|
||||
if (!shader_program_) {
|
||||
LOGE("Could not create program.");
|
||||
}
|
||||
|
||||
glGenTextures(1, &texture_id_);
|
||||
glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id_);
|
||||
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
uniform_texture_ = glGetUniformLocation(shader_program_, "texture");
|
||||
attribute_vertices_ = glGetAttribLocation(shader_program_, "vertex");
|
||||
attribute_uvs_ = glGetAttribLocation(shader_program_, "textureCoords");
|
||||
}
|
||||
|
||||
void BackgroundRenderer::Draw(const ArSession *session, const ArFrame *frame) {
|
||||
static_assert(std::extent<decltype(kUvs)>::value == kNumVertices * 2,
|
||||
"Incorrect kUvs length");
|
||||
static_assert(std::extent<decltype(kVertices)>::value == kNumVertices * 3,
|
||||
"Incorrect kVertices length");
|
||||
|
||||
// If display rotation changed (also includes view size change), we need to
|
||||
// re-query the uv coordinates for the on-screen portion of the camera image.
|
||||
int32_t geometry_changed = 0;
|
||||
ArFrame_getDisplayGeometryChanged(session, frame, &geometry_changed);
|
||||
if (geometry_changed != 0 || !uvs_initialized_) {
|
||||
ArFrame_transformDisplayUvCoords(session, frame, kNumVertices * 2, kUvs,
|
||||
transformed_uvs_);
|
||||
uvs_initialized_ = true;
|
||||
}
|
||||
glUseProgram(shader_program_);
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
glUniform1i(uniform_texture_, 1);
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id_);
|
||||
|
||||
glEnableVertexAttribArray(attribute_vertices_);
|
||||
glVertexAttribPointer(attribute_vertices_, 3, GL_FLOAT, GL_FALSE, 0,
|
||||
kVertices);
|
||||
|
||||
glEnableVertexAttribArray(attribute_uvs_);
|
||||
glVertexAttribPointer(attribute_uvs_, 2, GL_FLOAT, GL_FALSE, 0,
|
||||
transformed_uvs_);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
glUseProgram(0);
|
||||
glDepthMask(GL_TRUE);
|
||||
util::CheckGlError("BackgroundRenderer::Draw() error");
|
||||
}
|
||||
|
||||
GLuint BackgroundRenderer::GetTextureId() const { return texture_id_; }
|
||||
|
||||
} // namespace hello_ar
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef C_ARCORE_HELLO_AR_BACKGROUND_RENDERER_H_
|
||||
#define C_ARCORE_HELLO_AR_BACKGROUND_RENDERER_H_
|
||||
|
||||
#include <GLES2/gl2.h>
|
||||
#include <GLES2/gl2ext.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "arcore_c_api.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/util.h"
|
||||
|
||||
namespace hello_ar {
|
||||
|
||||
// This class renders the passthrough camera image into the OpenGL frame.
|
||||
class BackgroundRenderer {
|
||||
public:
|
||||
BackgroundRenderer() = default;
|
||||
|
||||
~BackgroundRenderer() = default;
|
||||
|
||||
// Sets up OpenGL state. Must be called on the OpenGL thread and before any
|
||||
// other methods below.
|
||||
void InitializeGlContent();
|
||||
|
||||
// Draws the background image. This methods must be called for every ArFrame
|
||||
// returned by ArSession_update() to catch display geometry change events.
|
||||
void Draw(const ArSession *session, const ArFrame *frame);
|
||||
|
||||
// Returns the generated texture name for the GL_TEXTURE_EXTERNAL_OES target.
|
||||
GLuint GetTextureId() const;
|
||||
|
||||
private:
|
||||
static constexpr int kNumVertices = 4;
|
||||
|
||||
GLuint shader_program_;
|
||||
GLuint texture_id_;
|
||||
|
||||
GLuint attribute_vertices_;
|
||||
GLuint attribute_uvs_;
|
||||
GLuint uniform_texture_;
|
||||
|
||||
float transformed_uvs_[kNumVertices * 2];
|
||||
bool uvs_initialized_ = false;
|
||||
};
|
||||
} // namespace hello_ar
|
||||
#endif // C_ARCORE_HELLO_AR_BACKGROUND_RENDERER_H_
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef C_ARCORE_HELLOE_AR_GLM_H_
|
||||
#define C_ARCORE_HELLOE_AR_GLM_H_
|
||||
|
||||
#define GLM_FORCE_RADIANS 1
|
||||
#include "glm.hpp"
|
||||
#include "gtc/matrix_transform.hpp"
|
||||
#include "gtc/type_ptr.hpp"
|
||||
#include "gtx/quaternion.hpp"
|
||||
|
||||
#endif
|
@ -1,986 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/hello_ar_application.h"
|
||||
#include <gtx/string_cast.hpp>
|
||||
|
||||
#include <math.h> /* acos */
|
||||
#include "include/core/SkCanvas.h"
|
||||
#include "include/core/SkFontStyle.h"
|
||||
#include "include/core/SkMatrix.h"
|
||||
#include "include/core/SkMatrix44.h"
|
||||
#include "include/core/SkPoint3.h"
|
||||
#include "include/core/SkStream.h"
|
||||
#include "include/core/SkSurface.h"
|
||||
#include "include/core/SkTextBlob.h"
|
||||
#include "include/core/SkTypeface.h"
|
||||
#include "include/gpu/GrBackendSurface.h"
|
||||
#include "include/gpu/GrContext.h"
|
||||
#include "include/gpu/gl/GrGLTypes.h"
|
||||
#include "include/utils/Sk3D.h"
|
||||
#include "modules/skottie/include/Skottie.h"
|
||||
#include "modules/skshaper/include/SkShaper.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/anchor_wrapper.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/glm.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/pending_anchor.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/plane_renderer.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/util.h"
|
||||
#include "tools/Resources.h"
|
||||
|
||||
namespace hello_ar {
|
||||
namespace {
|
||||
constexpr size_t kMaxNumberOfAndroidsToRender = 1;
|
||||
constexpr int32_t kPlaneColorRgbaSize = 16;
|
||||
|
||||
const glm::vec3 kWhite = {255, 255, 255};
|
||||
|
||||
constexpr std::array<uint32_t, kPlaneColorRgbaSize> kPlaneColorRgba = {
|
||||
{0xFFFFFFFF, 0xF44336FF, 0xE91E63FF, 0x9C27B0FF, 0x673AB7FF, 0x3F51B5FF,
|
||||
0x2196F3FF, 0x03A9F4FF, 0x00BCD4FF, 0x009688FF, 0x4CAF50FF, 0x8BC34AFF,
|
||||
0xCDDC39FF, 0xFFEB3BFF, 0xFFC107FF, 0xFF9800FF}};
|
||||
|
||||
inline glm::vec3 GetRandomPlaneColor() {
|
||||
const int32_t colorRgba = kPlaneColorRgba[std::rand() % kPlaneColorRgbaSize];
|
||||
return glm::vec3(((colorRgba >> 24) & 0xff) / 255.0f,
|
||||
((colorRgba >> 16) & 0xff) / 255.0f,
|
||||
((colorRgba >> 8) & 0xff) / 255.0f);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
HelloArApplication::HelloArApplication(AAssetManager *asset_manager)
|
||||
: asset_manager_(asset_manager) {
|
||||
LOGI("OnCreate()");
|
||||
}
|
||||
|
||||
HelloArApplication::~HelloArApplication() {
|
||||
if (ar_session_ != nullptr) {
|
||||
ArSession_destroy(ar_session_);
|
||||
ArFrame_destroy(ar_frame_);
|
||||
}
|
||||
}
|
||||
|
||||
void HelloArApplication::OnPause() {
|
||||
LOGI("OnPause()");
|
||||
if (ar_session_ != nullptr) {
|
||||
ArSession_pause(ar_session_);
|
||||
}
|
||||
}
|
||||
|
||||
void HelloArApplication::OnResume(void *env, void *context, void *activity) {
|
||||
LOGI("OnResume()");
|
||||
|
||||
if (ar_session_ == nullptr) {
|
||||
ArInstallStatus install_status;
|
||||
// If install was not yet requested, that means that we are resuming the
|
||||
// activity first time because of explicit user interaction (such as
|
||||
// launching the application)
|
||||
bool user_requested_install = !install_requested_;
|
||||
|
||||
// === ATTENTION! ATTENTION! ATTENTION! ===
|
||||
// This method can and will fail in user-facing situations. Your
|
||||
// application must handle these cases at least somewhat gracefully. See
|
||||
// HelloAR Java sample code for reasonable behavior.
|
||||
CHECK(ArCoreApk_requestInstall(env, activity, user_requested_install,
|
||||
&install_status) == AR_SUCCESS);
|
||||
|
||||
switch (install_status) {
|
||||
case AR_INSTALL_STATUS_INSTALLED:
|
||||
break;
|
||||
case AR_INSTALL_STATUS_INSTALL_REQUESTED:
|
||||
install_requested_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// === ATTENTION! ATTENTION! ATTENTION! ===
|
||||
// This method can and will fail in user-facing situations. Your
|
||||
// application must handle these cases at least somewhat gracefully. See
|
||||
// HelloAR Java sample code for reasonable behavior.
|
||||
CHECK(ArSession_create(env, context, &ar_session_) == AR_SUCCESS);
|
||||
CHECK(ar_session_);
|
||||
|
||||
ArFrame_create(ar_session_, &ar_frame_);
|
||||
CHECK(ar_frame_);
|
||||
|
||||
ArSession_setDisplayGeometry(ar_session_, display_rotation_, width_,
|
||||
height_);
|
||||
}
|
||||
|
||||
const ArStatus status = ArSession_resume(ar_session_);
|
||||
CHECK(status == AR_SUCCESS);
|
||||
}
|
||||
|
||||
void HelloArApplication::OnSurfaceCreated() {
|
||||
LOGI("OnSurfaceCreated()");
|
||||
|
||||
background_renderer_.InitializeGlContent();
|
||||
point_cloud_renderer_.InitializeGlContent();
|
||||
plane_renderer_.InitializeGlContent(asset_manager_);
|
||||
}
|
||||
|
||||
void HelloArApplication::OnDisplayGeometryChanged(int display_rotation,
|
||||
int width, int height) {
|
||||
LOGI("OnSurfaceChanged(%d, %d)", width, height);
|
||||
glViewport(0, 0, width, height);
|
||||
display_rotation_ = display_rotation;
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
|
||||
if (ar_session_ != nullptr) {
|
||||
ArSession_setDisplayGeometry(ar_session_, display_rotation, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void HelloArApplication::OnObjectRotationChanged(int rotation) {
|
||||
LOGI("OnObjectRotationChanged(%d)", rotation);
|
||||
currentObjectRotation = rotation;
|
||||
}
|
||||
|
||||
void HelloArApplication::OnAction(float value) {
|
||||
LOGI("OnAction(%.6f)", value);
|
||||
currentValue = value;
|
||||
}
|
||||
|
||||
void DrawText(SkCanvas *canvas, SkPaint *paint, const char text[]) {
|
||||
float spacing = 0.05;
|
||||
for (int i = 0; i < sizeof(text) / sizeof(text[0]); i++) {
|
||||
const char letter[] = {text[i]};
|
||||
size_t byteLength = strlen(static_cast<const char *>(letter));
|
||||
canvas->drawText(letter, byteLength, spacing * i, 0, *paint);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawAxes(SkCanvas *canvas, SkMatrix44 m) {
|
||||
SkPaint p;
|
||||
p.setStrokeWidth(10);
|
||||
SkPoint3 src[4] = {
|
||||
{0, 0, 0},
|
||||
{0.2, 0, 0},
|
||||
{0, 0.2, 0},
|
||||
{0, 0, 0.2},
|
||||
};
|
||||
SkPoint dst[4];
|
||||
Sk3MapPts(dst, m, src, 4);
|
||||
|
||||
const char str[] = "XYZ";
|
||||
p.setColor(SK_ColorRED);
|
||||
canvas->drawLine(dst[0], dst[1], p);
|
||||
|
||||
p.setColor(SK_ColorGREEN);
|
||||
canvas->drawLine(dst[0], dst[2], p);
|
||||
|
||||
p.setColor(SK_ColorBLUE);
|
||||
canvas->drawLine(dst[0], dst[3], p);
|
||||
}
|
||||
|
||||
void DrawVector(SkCanvas *canvas, SkMatrix44 m, glm::vec3 begin, glm::vec3 end, SkColor c) {
|
||||
SkPaint p;
|
||||
p.setStrokeWidth(15);
|
||||
SkPoint3 src[2] = {
|
||||
{begin.x, begin.y, begin.z},
|
||||
{end.x, end.y, end.z}
|
||||
};
|
||||
SkPoint dst[2];
|
||||
Sk3MapPts(dst, m, src, 2);
|
||||
|
||||
const char str[] = "XYZ";
|
||||
p.setColor(c);
|
||||
canvas->drawLine(dst[0], dst[1], p);
|
||||
}
|
||||
|
||||
void DrawBoundingBox(SkCanvas* canvas) {
|
||||
SkPaint paint;
|
||||
paint.setColor(SK_ColorYELLOW);
|
||||
SkIRect bounds = canvas->getDeviceClipBounds();
|
||||
SkRect b = SkRect::Make(bounds);
|
||||
|
||||
canvas->drawRect(b, paint);
|
||||
}
|
||||
|
||||
void HelloArApplication::OnDrawFrame() {
|
||||
grContext = GrContext::MakeGL();
|
||||
|
||||
GrBackendRenderTarget target;
|
||||
sk_sp<SkSurface> surface = nullptr;
|
||||
GrGLFramebufferInfo framebuffer_info;
|
||||
framebuffer_info.fFBOID = 0;
|
||||
framebuffer_info.fFormat = 0x8058;
|
||||
|
||||
|
||||
glClearColor(0.9f, 0.9f, 0.9f, 1.0f);
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
if (ar_session_ == nullptr) return;
|
||||
|
||||
ArSession_setCameraTextureName(ar_session_,
|
||||
background_renderer_.GetTextureId());
|
||||
|
||||
// Update session to get current frame and render camera background.
|
||||
if (ArSession_update(ar_session_, ar_frame_) != AR_SUCCESS) {
|
||||
LOGE("HelloArApplication::OnDrawFrame ArSession_update error");
|
||||
}
|
||||
|
||||
// GET CAMERA INFO
|
||||
ArCamera *ar_camera;
|
||||
ArFrame_acquireCamera(ar_session_, ar_frame_, &ar_camera);
|
||||
|
||||
glm::mat4 view_mat;
|
||||
glm::mat4 projection_mat;
|
||||
ArCamera_getViewMatrix(ar_session_, ar_camera, glm::value_ptr(view_mat));
|
||||
ArCamera_getProjectionMatrix(ar_session_, ar_camera,
|
||||
/*near=*/0.1f, /*far=*/100.f,
|
||||
glm::value_ptr(projection_mat));
|
||||
|
||||
ArTrackingState camera_tracking_state;
|
||||
ArCamera_getTrackingState(ar_session_, ar_camera, &camera_tracking_state);
|
||||
ArCamera_release(ar_camera);
|
||||
|
||||
background_renderer_.Draw(ar_session_, ar_frame_);
|
||||
|
||||
// If the camera isn't tracking don't bother rendering other objects.
|
||||
if (camera_tracking_state != AR_TRACKING_STATE_TRACKING) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get light estimation value.
|
||||
ArLightEstimate *ar_light_estimate;
|
||||
ArLightEstimateState ar_light_estimate_state;
|
||||
ArLightEstimate_create(ar_session_, &ar_light_estimate);
|
||||
|
||||
ArFrame_getLightEstimate(ar_session_, ar_frame_, ar_light_estimate);
|
||||
ArLightEstimate_getState(ar_session_, ar_light_estimate,
|
||||
&ar_light_estimate_state);
|
||||
|
||||
// Set light intensity to default. Intensity value ranges from 0.0f to 1.0f.
|
||||
// The first three components are color scaling factors.
|
||||
// The last one is the average pixel intensity in gamma space.
|
||||
float color_correction[4] = {1.f, 1.f, 1.f, 1.f};
|
||||
if (ar_light_estimate_state == AR_LIGHT_ESTIMATE_STATE_VALID) {
|
||||
ArLightEstimate_getColorCorrection(ar_session_, ar_light_estimate,
|
||||
color_correction);
|
||||
}
|
||||
|
||||
ArLightEstimate_destroy(ar_light_estimate);
|
||||
ar_light_estimate = nullptr;
|
||||
SkMatrix44 skProj;
|
||||
SkMatrix44 skView;
|
||||
SkMatrix skViewport;
|
||||
|
||||
skProj = util::GlmMatToSkMat(projection_mat);
|
||||
skView = util::GlmMatToSkMat(view_mat);
|
||||
skViewport.setScale(width_ / 2, -height_ / 2);
|
||||
skViewport.postTranslate(width_ / 2, height_ / 2);
|
||||
target = GrBackendRenderTarget(width_, height_, 0, 0, framebuffer_info);
|
||||
surface = SkSurface::MakeFromBackendRenderTarget(grContext.get(),
|
||||
target,
|
||||
kBottomLeft_GrSurfaceOrigin,
|
||||
kRGBA_8888_SkColorType,
|
||||
nullptr, nullptr);
|
||||
|
||||
// Render Andy objects.
|
||||
std::vector<SkMatrix44> models;
|
||||
//glm::mat4 model_mat(1.0f);
|
||||
for (const auto &obj_iter : tracked_obj_set_) {
|
||||
ArTrackingState tracking_state = AR_TRACKING_STATE_STOPPED;
|
||||
ArAnchor_getTrackingState(ar_session_, obj_iter, &tracking_state);
|
||||
if (tracking_state == AR_TRACKING_STATE_TRACKING) {
|
||||
// Render object only if the tracking state is AR_TRACKING_STATE_TRACKING.
|
||||
//util::GetTransformMatrixFromAnchor(ar_session_, obj_iter, &model_mat);
|
||||
//DRAW ANDY
|
||||
//andy_renderer_.Draw(glm::mat4(1), glm::mat4(1), model_mat, color_correction);
|
||||
|
||||
//PREPARE SKIA MATS
|
||||
|
||||
SkMatrix44 skModel;
|
||||
|
||||
switch (currentObjectRotation) {
|
||||
case 0: {
|
||||
auto iter = anchor_skmat4_axis_aligned_map_.find(obj_iter);
|
||||
if (iter != anchor_skmat4_axis_aligned_map_.end()) {
|
||||
skModel = iter->second;
|
||||
models.push_back(skModel);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1: {
|
||||
auto iter = anchor_skmat4_camera_aligned_map_.find(obj_iter);
|
||||
if (iter != anchor_skmat4_camera_aligned_map_.end()) {
|
||||
skModel = iter->second;
|
||||
models.push_back(skModel);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2: {
|
||||
auto iter = anchor_skmat4_snap_aligned_map_.find(obj_iter);
|
||||
if (iter != anchor_skmat4_snap_aligned_map_.end()) {
|
||||
skModel = iter->second;
|
||||
models.push_back(skModel);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
auto iter = anchor_skmat4_axis_aligned_map_.find(obj_iter);
|
||||
if (iter != anchor_skmat4_axis_aligned_map_.end()) {
|
||||
skModel = iter->second;
|
||||
models.push_back(skModel);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Update and render planes.
|
||||
ArTrackableList *plane_list = nullptr;
|
||||
ArTrackableList_create(ar_session_, &plane_list);
|
||||
CHECK(plane_list != nullptr);
|
||||
|
||||
ArTrackableType plane_tracked_type = AR_TRACKABLE_PLANE;
|
||||
ArSession_getAllTrackables(ar_session_, plane_tracked_type, plane_list);
|
||||
|
||||
int32_t plane_list_size = 0;
|
||||
ArTrackableList_getSize(ar_session_, plane_list, &plane_list_size);
|
||||
plane_count_ = plane_list_size;
|
||||
|
||||
for (int i = 0; i < plane_list_size; ++i) {
|
||||
ArTrackable *ar_trackable = nullptr;
|
||||
ArTrackableList_acquireItem(ar_session_, plane_list, i, &ar_trackable);
|
||||
ArPlane *ar_plane = ArAsPlane(ar_trackable);
|
||||
ArTrackingState out_tracking_state;
|
||||
ArTrackable_getTrackingState(ar_session_, ar_trackable,
|
||||
&out_tracking_state);
|
||||
|
||||
ArPlane *subsume_plane;
|
||||
ArPlane_acquireSubsumedBy(ar_session_, ar_plane, &subsume_plane);
|
||||
if (subsume_plane != nullptr) {
|
||||
ArTrackable_release(ArAsTrackable(subsume_plane));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ArTrackingState::AR_TRACKING_STATE_TRACKING != out_tracking_state) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ArTrackingState plane_tracking_state;
|
||||
ArTrackable_getTrackingState(ar_session_, ArAsTrackable(ar_plane),
|
||||
&plane_tracking_state);
|
||||
if (plane_tracking_state == AR_TRACKING_STATE_TRACKING) {
|
||||
const auto iter = plane_color_map_.find(ar_plane);
|
||||
glm::vec3 color;
|
||||
if (iter != plane_color_map_.end()) {
|
||||
color = iter->second;
|
||||
|
||||
// If this is an already observed trackable release it so it doesn't
|
||||
// leave aof placing objects on surfaces (n additional reference dangling.
|
||||
ArTrackable_release(ar_trackable);
|
||||
} else {
|
||||
// The first plane is always white.
|
||||
if (!first_plane_has_been_found_) {
|
||||
first_plane_has_been_found_ = true;
|
||||
color = kWhite;
|
||||
} else {
|
||||
color = GetRandomPlaneColor();
|
||||
}
|
||||
plane_color_map_.insert({ar_plane, color});
|
||||
}
|
||||
|
||||
plane_renderer_.Draw(projection_mat, view_mat, ar_session_, ar_plane,
|
||||
color);
|
||||
}
|
||||
}
|
||||
|
||||
ArTrackableList_destroy(plane_list);
|
||||
plane_list = nullptr;
|
||||
|
||||
// Update and render point cloud.
|
||||
ArPointCloud *ar_point_cloud = nullptr;
|
||||
ArStatus point_cloud_status =
|
||||
ArFrame_acquirePointCloud(ar_session_, ar_frame_, &ar_point_cloud);
|
||||
if (point_cloud_status == AR_SUCCESS) {
|
||||
point_cloud_renderer_.Draw(projection_mat * view_mat, ar_session_,
|
||||
ar_point_cloud);
|
||||
ArPointCloud_release(ar_point_cloud);
|
||||
}
|
||||
SkMatrix44 i = SkMatrix44::kIdentity_Constructor;
|
||||
|
||||
if (surface != nullptr) {
|
||||
SkCanvas *canvas = surface->getCanvas();
|
||||
SkAutoCanvasRestore acr(canvas, true);
|
||||
SkMatrix44 vpv = skViewport * skProj * skView;
|
||||
for(SkMatrix44 skModel: models) {
|
||||
SkMatrix44 i = SkMatrix44::kIdentity_Constructor;
|
||||
canvas->setMatrix(i);
|
||||
SkMatrix44 mvpv = skViewport * skProj * skView * skModel;
|
||||
|
||||
//Draw XYZ axes
|
||||
DrawAxes(canvas, mvpv);
|
||||
//Drawing camera orientation
|
||||
/* DrawVector(canvas, vpv, begins[0], ends[0], SK_ColorMAGENTA);
|
||||
DrawVector(canvas, vpv, begins[0], ends[1], SK_ColorYELLOW);
|
||||
DrawVector(canvas, vpv, begins[0], ends[2], SK_ColorCYAN);*/
|
||||
|
||||
canvas->concat(mvpv);
|
||||
SkPaint paint;
|
||||
|
||||
//Draw Circle
|
||||
paint.setColor(0x80700000);
|
||||
canvas->drawCircle(0, 0, 0.1, paint);
|
||||
|
||||
//Draw Text
|
||||
paint.setColor(SK_ColorBLUE);
|
||||
if (currentValue != 0) {
|
||||
paint.setTextSize(currentValue);
|
||||
} else {
|
||||
paint.setTextSize(0.1);
|
||||
}
|
||||
|
||||
paint.setAntiAlias(true);
|
||||
const char text[] = "SkAR";
|
||||
size_t byteLength = strlen(static_cast<const char *>(text));
|
||||
SkShaper shaper(nullptr);
|
||||
SkTextBlobBuilder builder;
|
||||
SkPoint p = SkPoint::Make(0, 0);
|
||||
shaper.shape(&builder, paint, text, byteLength, true, p, 10);
|
||||
canvas->drawTextBlob(builder.make(), 0, 0, paint);
|
||||
|
||||
//DrawBoundingBox(canvas);
|
||||
}
|
||||
canvas->flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool HelloArApplication::OnTouchedFirst(float x, float y, int drawMode) {
|
||||
LOGI("Entered OnTouchedFirst");
|
||||
if (pendingAnchor != nullptr) {
|
||||
delete pendingAnchor;
|
||||
}
|
||||
SkPoint p = SkPoint::Make(x,y);
|
||||
pendingAnchor = new PendingAnchor(p);
|
||||
bool editAnchor = false;
|
||||
|
||||
if (ar_frame_ != nullptr && ar_session_ != nullptr) {
|
||||
ArHitResultList *hit_result_list = nullptr;
|
||||
ArHitResultList_create(ar_session_, &hit_result_list);
|
||||
CHECK(hit_result_list);
|
||||
ArFrame_hitTest(ar_session_, ar_frame_, x, y, hit_result_list);
|
||||
|
||||
int32_t hit_result_list_size = 0;
|
||||
ArHitResultList_getSize(ar_session_, hit_result_list, &hit_result_list_size);
|
||||
ArHitResult *ar_hit_result = nullptr;
|
||||
ArPose *out_pose = nullptr;
|
||||
ArPlane* hitPlane = nullptr;
|
||||
for (int32_t i = 0; i < hit_result_list_size; ++i) {
|
||||
ArHitResult *ar_hit = nullptr;
|
||||
ArPose *created_out_pose = nullptr;
|
||||
ArHitResult_create(ar_session_, &ar_hit);
|
||||
ArHitResultList_getItem(ar_session_, hit_result_list, i, ar_hit);
|
||||
|
||||
if (ar_hit == nullptr) {
|
||||
LOGE("HelloArApplication::OnTouched ArHitResultList_getItem error");
|
||||
return editAnchor;
|
||||
}
|
||||
|
||||
ArTrackable *ar_trackable = nullptr;
|
||||
ArHitResult_acquireTrackable(ar_session_, ar_hit, &ar_trackable);
|
||||
ArTrackableType ar_trackable_type = AR_TRACKABLE_NOT_VALID;
|
||||
ArTrackable_getType(ar_session_, ar_trackable, &ar_trackable_type);
|
||||
// Creates an anchor if a plane or an oriented point was hit.
|
||||
if (AR_TRACKABLE_PLANE == ar_trackable_type) {
|
||||
ArPose *hit_pose = nullptr;
|
||||
ArPose_create(ar_session_, nullptr, &hit_pose);
|
||||
ArHitResult_getHitPose(ar_session_, ar_hit, hit_pose);
|
||||
int32_t in_polygon = 0;
|
||||
ArPlane *ar_plane = ArAsPlane(ar_trackable);
|
||||
ArPlane_isPoseInPolygon(ar_session_, ar_plane, hit_pose, &in_polygon);
|
||||
|
||||
{
|
||||
// Use hit pose and camera pose to check if hittest is from the
|
||||
// back of the plane, if it is, no need to create the anchor.
|
||||
ArPose *camera_pose = nullptr;
|
||||
ArPose_create(ar_session_, nullptr, &camera_pose);
|
||||
ArCamera *ar_camera;
|
||||
ArFrame_acquireCamera(ar_session_, ar_frame_, &ar_camera);
|
||||
ArCamera_getPose(ar_session_, ar_camera, camera_pose);
|
||||
float normal_distance_to_plane = util::CalculateDistanceToPlane(
|
||||
ar_session_, *hit_pose, *camera_pose);
|
||||
|
||||
if (!in_polygon || normal_distance_to_plane < 0) {
|
||||
ArPose_destroy(camera_pose);
|
||||
continue;
|
||||
}
|
||||
ArPose_destroy(camera_pose);
|
||||
ArCamera_release(ar_camera);
|
||||
}
|
||||
|
||||
//Raw pose of hit location
|
||||
float out_hit_raw[] = {0, 0, 0, 0, 0, 0, 0};
|
||||
ArPose_getPoseRaw(ar_session_, hit_pose, out_hit_raw);
|
||||
ArPose_destroy(hit_pose);
|
||||
|
||||
//Position of anchor
|
||||
glm::vec4 pendingAnchorPos(out_hit_raw[4], out_hit_raw[5], out_hit_raw[6], 1);
|
||||
pendingAnchor->SetContainingPlane(ar_plane);
|
||||
|
||||
//Check if plane contains approx the same anchor
|
||||
auto planeAnchors = plane_anchors_map_.find(ar_plane);
|
||||
if (planeAnchors != plane_anchors_map_.end()) {
|
||||
//other anchors existed on this plane
|
||||
std::vector<ArAnchor*> anchors = planeAnchors->second;
|
||||
int i = 0;
|
||||
LOGI("Size of anchor list: %d", (int) anchors.size());
|
||||
for(ArAnchor* const& anchor: anchors) {
|
||||
//Get anchor's pose
|
||||
i++;
|
||||
LOGI("CHECKING: Anchor #%d", i);
|
||||
ArPose *anchor_pose = nullptr;
|
||||
ArPose_create(ar_session_, nullptr, &anchor_pose);
|
||||
ArAnchor_getPose(ar_session_, anchor, anchor_pose);
|
||||
float out_anchor_raw[] = {0, 0, 0, 0, 0, 0, 0};
|
||||
ArPose_getPoseRaw(ar_session_, anchor_pose, out_anchor_raw);
|
||||
ArPose_destroy(anchor_pose);
|
||||
glm::vec4 oldAnchorPos(out_anchor_raw[4], out_anchor_raw[5], out_anchor_raw[6], 1);
|
||||
oldAnchorPos = oldAnchorPos - pendingAnchorPos;
|
||||
float distance = util::Magnitude(glm::vec3(oldAnchorPos));
|
||||
if (distance < 0.1f) {
|
||||
LOGI("TouchFirst: Editing old anchor!");
|
||||
editAnchor = true;
|
||||
pendingAnchor->SetArAnchor(anchor);
|
||||
pendingAnchor->SetEditMode(true);
|
||||
|
||||
ArHitResult_destroy(ar_hit);
|
||||
ArHitResultList_destroy(hit_result_list);
|
||||
LOGI("TouchFirst: Edit %d", editAnchor);
|
||||
return editAnchor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//actual hit result, and containing plane
|
||||
ar_hit_result = ar_hit;
|
||||
hitPlane = ar_plane;
|
||||
|
||||
//new anchor pos
|
||||
float wanted_raw_pose[] = {0, 0, 0, 0, out_hit_raw[4], out_hit_raw[5], out_hit_raw[6]};
|
||||
ArPose_create(ar_session_, wanted_raw_pose, &created_out_pose);
|
||||
out_pose = created_out_pose;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (ar_hit_result) {
|
||||
LOGI("TouchFirst: Adding new anchor!");
|
||||
ArAnchor *anchor = nullptr;
|
||||
pendingAnchor->SetEditMode(false);
|
||||
|
||||
if (ArSession_acquireNewAnchor(ar_session_, out_pose, &anchor) != AR_SUCCESS) {
|
||||
LOGE("HelloArApplication::OnTouched ArHitResult_acquireNewAnchor error");
|
||||
LOGI("TouchFirst: Failed to acquire new anchor");
|
||||
delete hitPlane;
|
||||
delete pendingAnchor;
|
||||
pendingAnchor = nullptr;
|
||||
LOGI("TouchFirst: Edit %d", editAnchor);
|
||||
return editAnchor;
|
||||
}
|
||||
pendingAnchor->SetArAnchor(anchor);
|
||||
|
||||
ArHitResult_destroy(ar_hit_result);
|
||||
ArHitResultList_destroy(hit_result_list);
|
||||
ArPose_destroy(out_pose);
|
||||
hit_result_list = nullptr;
|
||||
LOGI("TouchFirst: Edit %d", editAnchor);
|
||||
return editAnchor;
|
||||
}
|
||||
|
||||
LOGI("TouchFirst: didn't hit anything");
|
||||
delete hitPlane;
|
||||
delete pendingAnchor;
|
||||
pendingAnchor = nullptr;
|
||||
LOGI("TouchFirst: Edit %d", editAnchor);
|
||||
return editAnchor;
|
||||
}
|
||||
}
|
||||
|
||||
void HelloArApplication::AddAnchor(ArAnchor* anchor, ArPlane* containingPlane) {
|
||||
//delete anchor from matrices maps
|
||||
//releasing the anchor if it is not tracking anymore
|
||||
ArTrackingState tracking_state = AR_TRACKING_STATE_STOPPED;
|
||||
ArAnchor_getTrackingState(ar_session_, anchor, &tracking_state);
|
||||
if (tracking_state != AR_TRACKING_STATE_TRACKING) {
|
||||
RemoveAnchor(anchor);
|
||||
return;
|
||||
}
|
||||
|
||||
//releasing the first anchor if we exceeded maximum number of objects to be rendered
|
||||
if (tracked_obj_set_.size() >= kMaxNumberOfAndroidsToRender) {
|
||||
RemoveAnchor(tracked_obj_set_[0]);
|
||||
}
|
||||
|
||||
//updating the containing plane with a new anchor
|
||||
auto planeAnchors = plane_anchors_map_.find(containingPlane);
|
||||
if (planeAnchors != plane_anchors_map_.end()) {
|
||||
//other anchors existed on this plane
|
||||
LOGI("TouchFinal: ADDING TO OLD ANCHORS");
|
||||
std::vector<ArAnchor*> anchors = planeAnchors->second;
|
||||
anchors.push_back(anchor);
|
||||
plane_anchors_map_[containingPlane] = anchors;
|
||||
anchor_plane_map_.insert({anchor, containingPlane});
|
||||
} else {
|
||||
LOGI("TouchFinal: NEW SET OF ANCHORS");
|
||||
std::vector<ArAnchor*> anchors;
|
||||
anchors.push_back(anchor);
|
||||
plane_anchors_map_.insert({containingPlane, anchors});
|
||||
anchor_plane_map_.insert({anchor, containingPlane});
|
||||
}
|
||||
|
||||
tracked_obj_set_.push_back(anchor);
|
||||
}
|
||||
|
||||
void HelloArApplication::OnTouchTranslate(float x, float y) {
|
||||
LOGI("Entered On Edit Touched");
|
||||
ArAnchor *anchor = pendingAnchor->GetArAnchor();
|
||||
glm::mat4 matrix = util::SkMatToGlmMat(
|
||||
anchor_skmat4_axis_aligned_map_.find(anchor)->second);
|
||||
|
||||
if (ar_frame_ != nullptr && ar_session_ != nullptr) {
|
||||
ArHitResultList *hit_result_list = nullptr;
|
||||
ArHitResultList_create(ar_session_, &hit_result_list);
|
||||
CHECK(hit_result_list);
|
||||
ArFrame_hitTest(ar_session_, ar_frame_, x, y, hit_result_list);
|
||||
|
||||
int32_t hit_result_list_size = 0;
|
||||
ArHitResultList_getSize(ar_session_, hit_result_list, &hit_result_list_size);
|
||||
ArHitResult *ar_hit_result = nullptr;
|
||||
ArPose *out_pose = nullptr;
|
||||
ArPlane *hitPlane = nullptr;
|
||||
for (int32_t i = 0; i < hit_result_list_size; ++i) {
|
||||
ArHitResult *ar_hit = nullptr;
|
||||
ArPose *created_out_pose = nullptr;
|
||||
ArHitResult_create(ar_session_, &ar_hit);
|
||||
ArHitResultList_getItem(ar_session_, hit_result_list, i, ar_hit);
|
||||
|
||||
if (ar_hit == nullptr) {
|
||||
LOGE("HelloArApplication::OnTouched ArHitResultList_getItem error");
|
||||
return;
|
||||
}
|
||||
|
||||
ArTrackable *ar_trackable = nullptr;
|
||||
ArHitResult_acquireTrackable(ar_session_, ar_hit, &ar_trackable);
|
||||
ArTrackableType ar_trackable_type = AR_TRACKABLE_NOT_VALID;
|
||||
ArTrackable_getType(ar_session_, ar_trackable, &ar_trackable_type);
|
||||
// Creates an anchor if a plane or an oriented point was hit.
|
||||
if (AR_TRACKABLE_PLANE == ar_trackable_type) {
|
||||
ArPose *hit_pose = nullptr;
|
||||
ArPose_create(ar_session_, nullptr, &hit_pose);
|
||||
ArHitResult_getHitPose(ar_session_, ar_hit, hit_pose);
|
||||
int32_t in_polygon = 0;
|
||||
ArPlane *ar_plane = ArAsPlane(ar_trackable);
|
||||
ArPlane_isPoseInPolygon(ar_session_, ar_plane, hit_pose, &in_polygon);
|
||||
|
||||
{
|
||||
// Use hit pose and camera pose to check if hittest is from the
|
||||
// back of the plane, if it is, no need to create the anchor.
|
||||
ArPose *camera_pose = nullptr;
|
||||
ArPose_create(ar_session_, nullptr, &camera_pose);
|
||||
ArCamera *ar_camera;
|
||||
ArFrame_acquireCamera(ar_session_, ar_frame_, &ar_camera);
|
||||
ArCamera_getPose(ar_session_, ar_camera, camera_pose);
|
||||
float normal_distance_to_plane = util::CalculateDistanceToPlane(
|
||||
ar_session_, *hit_pose, *camera_pose);
|
||||
|
||||
if (!in_polygon || normal_distance_to_plane < 0) {
|
||||
ArPose_destroy(camera_pose);
|
||||
continue;
|
||||
}
|
||||
ArPose_destroy(camera_pose);
|
||||
ArCamera_release(ar_camera);
|
||||
}
|
||||
|
||||
//Raw pose of hit location
|
||||
float out_hit_raw[] = {0, 0, 0, 0, 0, 0, 0};
|
||||
ArPose_getPoseRaw(ar_session_, hit_pose, out_hit_raw);
|
||||
ArPose_destroy(hit_pose);
|
||||
|
||||
//Translate by new amount
|
||||
glm::vec4 newPos(out_hit_raw[4], out_hit_raw[5], out_hit_raw[6], 1);
|
||||
glm::vec4 oldPos = pendingAnchor->GetAnchorPos(ar_session_);
|
||||
glm::vec3 movement = glm::vec3(newPos - oldPos);
|
||||
|
||||
|
||||
//CAMERA SETTINGS
|
||||
glm::mat4 backToOrigin(1);
|
||||
backToOrigin = glm::translate(backToOrigin, -glm::vec3(oldPos));
|
||||
glm::mat4 backToPlane(1);
|
||||
backToPlane = glm::translate(backToPlane, glm::vec3(oldPos));
|
||||
|
||||
//Axes of Skia object: start with XYZ, totate to get X(-Z)Y, paste on plane, go back to origin --> plane orientation but on origin
|
||||
glm::vec3 objX = glm::normalize(glm::vec3(
|
||||
backToOrigin * matrix *
|
||||
glm::vec4(1, 0, 0, 1))); //X still X
|
||||
glm::vec3 objY = glm::normalize(glm::vec3(
|
||||
backToOrigin * matrix *
|
||||
glm::vec4(0, 1, 0, 1))); //Y is now Z
|
||||
glm::vec3 objZ = glm::normalize(glm::vec3(
|
||||
backToOrigin * matrix *
|
||||
glm::vec4(0, 0, 1, 1))); //Z is now Y
|
||||
|
||||
|
||||
glm::mat4 translate(1);
|
||||
translate = glm::translate(translate, movement);
|
||||
matrix = translate * matrix;
|
||||
RemoveAnchor(anchor);
|
||||
|
||||
|
||||
|
||||
//new anchor pos
|
||||
float wanted_raw_pose[] = {0, 0, 0, 0, out_hit_raw[4], out_hit_raw[5],
|
||||
out_hit_raw[6]};
|
||||
ArPose_create(ar_session_, wanted_raw_pose, &created_out_pose);
|
||||
out_pose = created_out_pose;
|
||||
ar_hit_result = ar_hit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ar_hit_result) {
|
||||
LOGI("TouchFirst: Adding new anchor!");
|
||||
ArAnchor *anchor = nullptr;
|
||||
pendingAnchor->SetEditMode(false);
|
||||
|
||||
if (ArSession_acquireNewAnchor(ar_session_, out_pose, &anchor) != AR_SUCCESS) {
|
||||
LOGE("HelloArApplication::OnTouched ArHitResult_acquireNewAnchor error");
|
||||
LOGI("TouchFirst: Failed to acquire new anchor");
|
||||
delete hitPlane;
|
||||
delete pendingAnchor;
|
||||
pendingAnchor = nullptr;
|
||||
return;
|
||||
}
|
||||
pendingAnchor->SetArAnchor(anchor);
|
||||
anchor_skmat4_axis_aligned_map_[anchor] = util::GlmMatToSkMat(matrix);
|
||||
|
||||
//Add anchor
|
||||
AddAnchor(anchor, pendingAnchor->GetContainingPlane());
|
||||
|
||||
|
||||
ArHitResult_destroy(ar_hit_result);
|
||||
ArHitResultList_destroy(hit_result_list);
|
||||
ArPose_destroy(out_pose);
|
||||
hit_result_list = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HelloArApplication::RemoveAnchor(ArAnchor* anchor) {
|
||||
//delete anchor from matrices maps
|
||||
anchor_skmat4_axis_aligned_map_.erase(anchor);
|
||||
anchor_skmat4_camera_aligned_map_.erase(anchor);
|
||||
anchor_skmat4_snap_aligned_map_.erase(anchor);
|
||||
|
||||
auto containingPlaneIter = anchor_plane_map_.find(anchor);
|
||||
if (containingPlaneIter != anchor_plane_map_.end()) {
|
||||
ArPlane* containingPlane = containingPlaneIter->second;
|
||||
auto planeAnchors = plane_anchors_map_.find(containingPlane);
|
||||
if (planeAnchors != plane_anchors_map_.end()) {
|
||||
//delete this anchor from the list of anchors associated with its plane
|
||||
std::vector<ArAnchor*> anchors = planeAnchors->second;
|
||||
anchors.erase(std::remove(anchors.begin(), anchors.end(), anchor), anchors.end());
|
||||
plane_anchors_map_[planeAnchors->first] = anchors;
|
||||
|
||||
//delete anchor from map of anchor to plane
|
||||
anchor_plane_map_.erase(anchor);
|
||||
}
|
||||
}
|
||||
//delete anchor from list of tracked objects
|
||||
tracked_obj_set_.erase(std::remove(tracked_obj_set_.begin(), tracked_obj_set_.end(), anchor), tracked_obj_set_.end());
|
||||
ArAnchor_release(anchor);
|
||||
}
|
||||
|
||||
void HelloArApplication::UpdateMatrixMaps(ArAnchor* anchorKey, glm::mat4 aaMat, glm::mat4 caMat, glm::mat4 snapMat) {
|
||||
anchor_skmat4_axis_aligned_map_.insert({anchorKey, util::GlmMatToSkMat(aaMat)});
|
||||
anchor_skmat4_camera_aligned_map_.insert({anchorKey, util::GlmMatToSkMat(caMat)});
|
||||
anchor_skmat4_snap_aligned_map_.insert({anchorKey, util::GlmMatToSkMat(snapMat)});
|
||||
}
|
||||
|
||||
void SetSkiaInitialRotation(glm::mat4& initRotation) {
|
||||
initRotation = glm::rotate(initRotation, SK_ScalarPI / 2, glm::vec3(1, 0, 0));
|
||||
}
|
||||
|
||||
void SetSkiaObjectAxes(glm::vec3& x, glm::vec3& y, glm::vec3& z, glm::mat4 transform) {
|
||||
x = glm::normalize(glm::vec3(transform * glm::vec4(1, 0, 0, 1))); //X still X
|
||||
y = glm::normalize(glm::vec3(transform * glm::vec4(0, 1, 0, 1))); //Y is now Z
|
||||
z = glm::normalize(glm::vec3(transform * glm::vec4(0, 0, 1, 1))); //Z is now Y
|
||||
}
|
||||
|
||||
void SetCameraAlignedRotation(glm::mat4& rotateTowardsCamera, float& rotationDirection, const glm::vec3& toProject, const glm::vec3& skiaY, const glm::vec3& skiaZ) {
|
||||
glm::vec3 hitLookProj = -util::ProjectOntoPlane(toProject, skiaZ);
|
||||
float angleRad = util::AngleRad(skiaY, hitLookProj);
|
||||
glm::vec3 cross = glm::normalize(glm::cross(skiaY, hitLookProj));
|
||||
|
||||
//outs
|
||||
rotationDirection = util::Dot(cross, skiaZ);
|
||||
rotateTowardsCamera = glm::rotate(rotateTowardsCamera, angleRad, rotationDirection * skiaZ);
|
||||
}
|
||||
|
||||
struct CameraAlignmentInfo {
|
||||
glm::vec3& skiaY, skiaZ;
|
||||
glm::mat4& preRot, postRot;
|
||||
|
||||
CameraAlignmentInfo(glm::vec3& skiaY, glm::vec3& skiaZ, glm::mat4 preRot, glm::mat4 postRot)
|
||||
: skiaY(skiaY), skiaZ(skiaZ), preRot(preRot), postRot(postRot) {}
|
||||
};
|
||||
|
||||
void SetCameraAlignedVertical(glm::mat4& caMat, const glm::mat4& camRot, const CameraAlignmentInfo& camAlignInfo) {
|
||||
//Camera axes
|
||||
glm::vec3 xCamera = glm::vec3(glm::vec4(1, 0, 0, 1) * camRot);
|
||||
glm::vec3 yCamera = glm::vec3(glm::vec4(0, 1, 0, 1) * camRot);
|
||||
glm::vec3 zCamera = glm::vec3(glm::vec4(0, 0, -1, 1) * camRot);
|
||||
|
||||
//Get matrix that rotates object from plane towards the wanted angle
|
||||
glm::mat4 rotateTowardsCamera(1);
|
||||
float rotationDirection = 1;
|
||||
SetCameraAlignedRotation(rotateTowardsCamera, rotationDirection, yCamera, camAlignInfo.skiaY, camAlignInfo.skiaZ);
|
||||
|
||||
//LogOrientation(dot, angleRad, "Vertical/Wall");
|
||||
glm::mat4 flip(1);
|
||||
flip = glm::rotate(flip, SK_ScalarPI, rotationDirection * camAlignInfo.skiaZ);
|
||||
caMat = camAlignInfo.postRot * flip * rotateTowardsCamera * camAlignInfo.preRot;
|
||||
}
|
||||
|
||||
void SetCameraAlignedHorizontal(glm::mat4& caMat, ArPlaneType planeType, const glm::vec3 hitLook, const CameraAlignmentInfo& camAlignInfo) {
|
||||
//Ceiling or Floor: follow hit location
|
||||
//Get matrix that rotates object from plane towards the wanted angle
|
||||
glm::mat4 rotateTowardsCamera(1);
|
||||
float rotationDirection = 1;
|
||||
SetCameraAlignedRotation(rotateTowardsCamera, rotationDirection, hitLook, camAlignInfo.skiaY, camAlignInfo.skiaZ);
|
||||
|
||||
if (planeType == ArPlaneType::AR_PLANE_HORIZONTAL_DOWNWARD_FACING) {
|
||||
//ceiling
|
||||
//LogOrientation(dot, angleRad, "Ceiling");
|
||||
glm::mat4 flip(1);
|
||||
flip = glm::rotate(flip, SK_ScalarPI, rotationDirection * camAlignInfo.skiaZ);
|
||||
caMat = camAlignInfo.postRot * flip * rotateTowardsCamera * camAlignInfo.preRot;
|
||||
} else {
|
||||
//floor or tabletop
|
||||
//LogOrientation(dot, angleRad, "Floor");
|
||||
caMat = camAlignInfo.postRot * rotateTowardsCamera * camAlignInfo.preRot;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HelloArApplication::SetCameraAlignedMatrix(glm::mat4& caMat, glm::vec3 hitPos, glm::mat4& planeModel, const glm::mat4& initRotation) {
|
||||
//Translation matrices: from plane to origin, and from origin to plane
|
||||
glm::mat4 backToOrigin(1);
|
||||
backToOrigin = glm::translate(backToOrigin, -hitPos);
|
||||
glm::mat4 backToPlane(1);
|
||||
backToPlane = glm::translate(backToPlane, hitPos);
|
||||
|
||||
//Axes of Skia object: start with XYZ, totate to get X(-Z)Y, paste on plane, go back to origin --> plane orientation but on origin
|
||||
glm::vec3 skiaX, skiaY, skiaZ;
|
||||
SetSkiaObjectAxes(skiaX, skiaY, skiaZ, backToOrigin * planeModel * initRotation);
|
||||
|
||||
//Get camera position & rotation
|
||||
glm::vec3 cameraPos;
|
||||
glm::mat4 cameraRotationMatrix;
|
||||
util::GetCameraInfo(ar_session_, ar_frame_, cameraPos, cameraRotationMatrix);
|
||||
|
||||
//Set matrix depending on type of surface
|
||||
ArPlaneType planeType = AR_PLANE_VERTICAL;
|
||||
ArPlane_getType(ar_session_, pendingAnchor->GetContainingPlane(), &planeType);
|
||||
|
||||
//Set CamerAlignmentInfo
|
||||
CameraAlignmentInfo camAlignInfo(skiaY, skiaZ, backToOrigin * planeModel * initRotation, backToPlane);
|
||||
|
||||
if (planeType == ArPlaneType::AR_PLANE_VERTICAL) {
|
||||
//Wall: follow phone orientation
|
||||
SetCameraAlignedVertical(caMat, cameraRotationMatrix, camAlignInfo);
|
||||
} else {
|
||||
//Ceiling or Floor: follow hit location
|
||||
glm::vec3 hitLook(hitPos - cameraPos);
|
||||
SetCameraAlignedHorizontal(caMat, planeType, hitLook, camAlignInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HelloArApplication::SetModelMatrices(glm::mat4& aaMat, glm::mat4& caMat, glm::mat4& snapMat, const glm::mat4& planeModel) {
|
||||
//Brings Skia world to ARCore world
|
||||
glm::mat4 initRotation(1);
|
||||
SetSkiaInitialRotation(initRotation);
|
||||
|
||||
//Copy plane model for editing
|
||||
glm::mat4 copyPlaneModel(planeModel);
|
||||
|
||||
//Set snap matrix
|
||||
//snapMat = copyPlaneModel * initRotation;
|
||||
|
||||
//Set axis-aligned matrix
|
||||
glm::vec4 anchorPos = pendingAnchor->GetAnchorPos(ar_session_);
|
||||
copyPlaneModel[3] = anchorPos;
|
||||
aaMat = planeModel * initRotation;
|
||||
|
||||
//Set camera-aligned matrix
|
||||
//SetCameraAlignedMatrix(caMat, glm::vec3(anchorPos), copyPlaneModel, initRotation);
|
||||
}
|
||||
|
||||
void GetPlaneModelMatrix(glm::mat4& planeModel, ArSession* arSession, ArPlane* arPlane) {
|
||||
ArPose *plane_pose = nullptr;
|
||||
ArPose_create(arSession, nullptr, &plane_pose);
|
||||
ArPlane_getCenterPose(arSession, arPlane, plane_pose);
|
||||
util::GetTransformMatrixFromPose(arSession, plane_pose, &planeModel);
|
||||
ArPose_destroy(plane_pose);
|
||||
}
|
||||
|
||||
void HelloArApplication::OnTouchedFinal(int type) {
|
||||
LOGI("Entered OnTouchedFinal");
|
||||
if (pendingAnchor == nullptr) {
|
||||
LOGI("WARNING: Entered OnTouchedFinal but no pending anchor..");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pendingAnchor->GetEditMode()) {
|
||||
LOGI("WARNING: Editing old anchor in OnTouchedFinal!");
|
||||
}
|
||||
|
||||
//Get necessary pending anchor info
|
||||
ArPlane* containingPlane = pendingAnchor->GetContainingPlane();
|
||||
glm::vec4 pendingAnchorPos = pendingAnchor->GetAnchorPos(ar_session_);
|
||||
ArAnchor* actualAnchor = pendingAnchor->GetArAnchor();
|
||||
|
||||
//Plane model matrix
|
||||
glm::mat4 planeModel(1);
|
||||
GetPlaneModelMatrix(planeModel, ar_session_, containingPlane);
|
||||
|
||||
//Setup skia object model matrices
|
||||
glm::mat4 matrixAxisAligned(1);
|
||||
glm::mat4 matrixCameraAligned(1);
|
||||
glm::mat4 matrixSnapAligned(1);
|
||||
SetModelMatrices(matrixAxisAligned, matrixCameraAligned, matrixSnapAligned, planeModel);
|
||||
|
||||
//Update anchor -> model matrix datastructures
|
||||
UpdateMatrixMaps(actualAnchor, matrixAxisAligned, matrixCameraAligned, matrixSnapAligned);
|
||||
|
||||
//Add anchor to aux datastructures
|
||||
AddAnchor(actualAnchor, containingPlane);
|
||||
}
|
||||
|
||||
} // namespace hello_ar
|
@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef C_ARCORE_HELLOE_AR_HELLO_AR_APPLICATION_H_
|
||||
#define C_ARCORE_HELLOE_AR_HELLO_AR_APPLICATION_H_
|
||||
|
||||
#include "include/core/SkSurface.h"
|
||||
#include "include/gpu/GrBackendSurface.h"
|
||||
#include "include/gpu/GrContext.h"
|
||||
#include "include/gpu/gl/GrGLTypes.h"
|
||||
#include "modules/skottie/include/Skottie.h"
|
||||
#include <GLES2/gl2.h>
|
||||
#include <GLES2/gl2ext.h>
|
||||
#include <android/asset_manager.h>
|
||||
#include <jni.h>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "arcore_c_api.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/background_renderer.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/glm.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/pending_anchor.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/plane_renderer.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/point_cloud_renderer.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/util.h"
|
||||
|
||||
namespace hello_ar {
|
||||
|
||||
// HelloArApplication handles all application logics.
|
||||
class HelloArApplication {
|
||||
public:
|
||||
// Constructor and deconstructor.
|
||||
HelloArApplication() = default;
|
||||
|
||||
HelloArApplication(AAssetManager *asset_manager);
|
||||
|
||||
~HelloArApplication();
|
||||
|
||||
SkMatrix SkiaRenderer(const glm::mat4 &proj, const glm::mat4 &view, const glm::mat4 &model);
|
||||
|
||||
// OnPause is called on the UI thread from the Activity's onPause method.
|
||||
void OnPause();
|
||||
|
||||
// OnResume is called on the UI thread from the Activity's onResume method.
|
||||
void OnResume(void *env, void *context, void *activity);
|
||||
|
||||
// OnSurfaceCreated is called on the OpenGL thread when GLSurfaceView
|
||||
// is created.
|
||||
void OnSurfaceCreated();
|
||||
|
||||
// OnDisplayGeometryChanged is called on the OpenGL thread when the
|
||||
// render surface size or display rotation changes.
|
||||
//
|
||||
// @param display_rotation: current display rotation.
|
||||
// @param width: width of the changed surface view.
|
||||
// @param height: height of the changed surface view.
|
||||
void OnDisplayGeometryChanged(int display_rotation, int width, int height);
|
||||
|
||||
void OnObjectRotationChanged(int rotation);
|
||||
|
||||
void OnAction(float value);
|
||||
|
||||
// OnDrawFrame is called on the OpenGL thread to render the next frame.
|
||||
void OnDrawFrame();
|
||||
|
||||
bool OnTouchedFirst(float x, float y, int drawMode);
|
||||
|
||||
void OnTouchTranslate(float x, float y);
|
||||
|
||||
void OnEditTouched(float x, float y);
|
||||
|
||||
void OnTouchedFinal(int type);
|
||||
|
||||
void RemoveAnchor(ArAnchor* anchor);
|
||||
|
||||
void AddAnchor(ArAnchor* anchor, ArPlane* containingPlane);
|
||||
|
||||
void UpdateMatrixMaps(ArAnchor* anchorKey, glm::mat4 aaMat, glm::mat4 caMat, glm::mat4 snapMat);
|
||||
|
||||
void SetModelMatrices(glm::mat4& aaMat, glm::mat4& caMat, glm::mat4& snapMat, const glm::mat4& planeModel);
|
||||
|
||||
void SetCameraAlignedMatrix(glm::mat4& caMat, glm::vec3 hitPos, glm::mat4& planeModel, const glm::mat4& initRotation);
|
||||
|
||||
// Returns true if any planes have been detected. Used for hiding the
|
||||
// "searching for planes" snackbar.
|
||||
bool HasDetectedPlanes() const { return plane_count_ > 0; }
|
||||
|
||||
glm::mat4
|
||||
ComputeCameraAlignedMatrix(ArPlane *arPlane, glm::mat4 planeModel, glm::mat4 initRotation,
|
||||
glm::vec4 anchorPos,
|
||||
glm::vec3 cameraPos, glm::vec3 hitPos,
|
||||
float cameraDisplayOutRaw[]);
|
||||
|
||||
private:
|
||||
ArSession *ar_session_ = nullptr;
|
||||
ArFrame *ar_frame_ = nullptr;
|
||||
|
||||
PendingAnchor* pendingAnchor = nullptr;
|
||||
|
||||
//SKIA VARS
|
||||
sk_sp<GrContext> grContext;
|
||||
sk_sp<skottie::Animation> fAnim;
|
||||
SkScalar fAnimT = 0;
|
||||
|
||||
bool install_requested_ = false;
|
||||
int width_ = 1;
|
||||
int height_ = 1;
|
||||
int display_rotation_ = 0;
|
||||
|
||||
int currentObjectRotation = 0;
|
||||
float currentValue = 0;
|
||||
|
||||
std::vector<glm::vec3> begins;
|
||||
std::vector<glm::vec3> ends;
|
||||
|
||||
AAssetManager *const asset_manager_;
|
||||
|
||||
// The anchors at which we are drawing android models
|
||||
std::vector<ArAnchor *> tracked_obj_set_;
|
||||
|
||||
// Stores the randomly-selected color each plane is drawn with
|
||||
std::unordered_map<ArPlane *, glm::vec3> plane_color_map_;
|
||||
|
||||
std::unordered_map<ArAnchor *, SkMatrix44> anchor_skmat4_axis_aligned_map_;
|
||||
std::unordered_map<ArAnchor *, SkMatrix44> anchor_skmat4_camera_aligned_map_;
|
||||
std::unordered_map<ArAnchor *, SkMatrix44> anchor_skmat4_snap_aligned_map_;
|
||||
|
||||
std::unordered_map<ArPlane *, std::vector<ArAnchor*>> plane_anchors_map_;
|
||||
std::unordered_map<ArAnchor *, ArPlane*> anchor_plane_map_;
|
||||
|
||||
// The first plane is always rendered in white, if this is true then a plane
|
||||
// at some point has been found.
|
||||
bool first_plane_has_been_found_ = false;
|
||||
|
||||
PointCloudRenderer point_cloud_renderer_;
|
||||
BackgroundRenderer background_renderer_;
|
||||
PlaneRenderer plane_renderer_;
|
||||
|
||||
int32_t plane_count_ = 0;
|
||||
};
|
||||
} // namespace hello_ar
|
||||
|
||||
#endif // C_ARCORE_HELLOE_AR_HELLO_AR_APPLICATION_H_
|
@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <android/asset_manager.h>
|
||||
#include <android/asset_manager_jni.h>
|
||||
#include <jni.h>
|
||||
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/hello_ar_application.h"
|
||||
|
||||
#define JNI_METHOD(return_type, method_name) \
|
||||
JNIEXPORT return_type JNICALL \
|
||||
Java_org_skia_arcore_JniInterface_##method_name
|
||||
|
||||
extern "C" {
|
||||
|
||||
namespace {
|
||||
// maintain a reference to the JVM so we can use it later.
|
||||
static JavaVM *g_vm = nullptr;
|
||||
|
||||
inline jlong jptr(hello_ar::HelloArApplication *native_hello_ar_application) {
|
||||
return reinterpret_cast<intptr_t>(native_hello_ar_application);
|
||||
}
|
||||
|
||||
inline hello_ar::HelloArApplication *native(jlong ptr) {
|
||||
return reinterpret_cast<hello_ar::HelloArApplication *>(ptr);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
jint JNI_OnLoad(JavaVM *vm, void *) {
|
||||
g_vm = vm;
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
JNI_METHOD(jlong, createNativeApplication)
|
||||
(JNIEnv *env, jclass, jobject j_asset_manager) {
|
||||
AAssetManager *asset_manager = AAssetManager_fromJava(env, j_asset_manager);
|
||||
return jptr(new hello_ar::HelloArApplication(asset_manager));
|
||||
}
|
||||
|
||||
JNI_METHOD(void, destroyNativeApplication)
|
||||
(JNIEnv *, jclass, jlong native_application) {
|
||||
delete native(native_application);
|
||||
}
|
||||
|
||||
JNI_METHOD(void, onPause)
|
||||
(JNIEnv *, jclass, jlong native_application) {
|
||||
native(native_application)->OnPause();
|
||||
}
|
||||
|
||||
JNI_METHOD(void, onResume)
|
||||
(JNIEnv *env, jclass, jlong native_application, jobject context,
|
||||
jobject activity) {
|
||||
native(native_application)->OnResume(env, context, activity);
|
||||
}
|
||||
|
||||
JNI_METHOD(void, onGlSurfaceCreated)
|
||||
(JNIEnv *, jclass, jlong native_application) {
|
||||
native(native_application)->OnSurfaceCreated();
|
||||
}
|
||||
|
||||
JNI_METHOD(void, onDisplayGeometryChanged)
|
||||
(JNIEnv *, jobject, jlong native_application, int display_rotation, int width,
|
||||
int height) {
|
||||
native(native_application)
|
||||
->OnDisplayGeometryChanged(display_rotation, width, height);
|
||||
}
|
||||
|
||||
JNI_METHOD(void, onObjectRotationChanged)
|
||||
(JNIEnv *, jobject, jlong native_application, int rotation) {
|
||||
native(native_application)
|
||||
->OnObjectRotationChanged(rotation);
|
||||
}
|
||||
|
||||
JNI_METHOD(void, onAction)
|
||||
(JNIEnv *, jobject, jlong native_application, jfloat value) {
|
||||
native(native_application)->OnAction(value);
|
||||
}
|
||||
|
||||
JNI_METHOD(void, onGlSurfaceDrawFrame)
|
||||
(JNIEnv *, jclass, jlong native_application) {
|
||||
native(native_application)->OnDrawFrame();
|
||||
}
|
||||
|
||||
JNI_METHOD(void, onTouchTranslate)
|
||||
(JNIEnv *, jclass, jlong native_application, jfloat x, jfloat y) {
|
||||
return native(native_application)->OnTouchTranslate(x, y);
|
||||
}
|
||||
|
||||
JNI_METHOD(bool, onTouchedFirst)
|
||||
(JNIEnv *, jclass, jlong native_application, jfloat x, jfloat y, int drawMode) {
|
||||
return native(native_application)->OnTouchedFirst(x, y, drawMode);
|
||||
}
|
||||
|
||||
JNI_METHOD(void, onTouchedFinal)
|
||||
(JNIEnv *, jclass, jlong native_application, int type) {
|
||||
native(native_application)->OnTouchedFinal(type);
|
||||
}
|
||||
|
||||
JNI_METHOD(jboolean, hasDetectedPlanes)
|
||||
(JNIEnv *, jclass, jlong native_application) {
|
||||
return static_cast<jboolean>(
|
||||
native(native_application)->HasDetectedPlanes() ? JNI_TRUE : JNI_FALSE);
|
||||
}
|
||||
|
||||
JNIEnv *GetJniEnv() {
|
||||
JNIEnv *env;
|
||||
jint result = g_vm->AttachCurrentThread(&env, nullptr);
|
||||
return result == JNI_OK ? env : nullptr;
|
||||
}
|
||||
|
||||
jclass FindClass(const char *classname) {
|
||||
JNIEnv *env = GetJniEnv();
|
||||
return env->FindClass(classname);
|
||||
}
|
||||
|
||||
} // extern "C"
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef C_ARCORE_HELLOE_AR_JNI_INTERFACE_H_
|
||||
#define C_ARCORE_HELLOE_AR_JNI_INTERFACE_H_
|
||||
|
||||
#include <jni.h>
|
||||
/**
|
||||
* Helper functions to provide access to Java from C via JNI.
|
||||
*/
|
||||
extern "C" {
|
||||
|
||||
// Helper function used to access the jni environment on the current thread.
|
||||
// In this sample, no consideration is made for detaching the thread when the
|
||||
// thread exits. This can cause memory leaks, so production applications should
|
||||
// detach when the thread no longer needs access to the JVM.
|
||||
JNIEnv *GetJniEnv();
|
||||
|
||||
jclass FindClass(const char *classname);
|
||||
} // extern "C"
|
||||
#endif
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "include/core/SkCanvas.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/hello_ar_application.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/plane_renderer.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/util.h"
|
||||
|
||||
namespace hello_ar {
|
||||
PendingAnchor::PendingAnchor(SkPoint touchLocation) : touchLocation(touchLocation) {}
|
||||
|
||||
PendingAnchor::~PendingAnchor() {}
|
||||
|
||||
SkPoint PendingAnchor::GetTouchLocation() {
|
||||
return touchLocation;
|
||||
}
|
||||
|
||||
bool PendingAnchor::GetEditMode() {
|
||||
return editMode;
|
||||
}
|
||||
|
||||
ArPlane* PendingAnchor::GetContainingPlane() {
|
||||
return containingPlane;
|
||||
}
|
||||
|
||||
glm::vec4 PendingAnchor::GetAnchorPos(ArSession* arSession) {
|
||||
float poseRaw[] = {0, 0, 0, 0, 0, 0, 0};
|
||||
ArPose* anchorPose = nullptr;
|
||||
ArPose_create(arSession, poseRaw, &anchorPose);
|
||||
ArAnchor_getPose(arSession, this->anchor, anchorPose);
|
||||
ArPose_getPoseRaw(arSession, anchorPose, poseRaw);
|
||||
ArPose_destroy(anchorPose);
|
||||
glm::vec4 anchorPos = glm::vec4(poseRaw[4], poseRaw[5], poseRaw[6], 1);
|
||||
return anchorPos;
|
||||
}
|
||||
|
||||
ArAnchor* PendingAnchor::GetArAnchor() {
|
||||
return anchor;
|
||||
}
|
||||
|
||||
void PendingAnchor::SetArAnchor(ArAnchor* anchor) {
|
||||
this->anchor = anchor;
|
||||
}
|
||||
|
||||
void PendingAnchor::SetEditMode(bool editMode) {
|
||||
this->editMode = editMode;
|
||||
}
|
||||
|
||||
void PendingAnchor::SetContainingPlane(ArPlane* plane) {
|
||||
this->containingPlane = plane;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace hello_ar
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef C_ARCORE_HELLO_AR_PENDING_ANCHOR_H_
|
||||
#define C_ARCORE_HELLO_AR_PENDING_ANCHOR_H_
|
||||
|
||||
#include "include/gpu/GrBackendSurface.h"
|
||||
#include "include/gpu/gl/GrGLTypes.h"
|
||||
|
||||
#include "arcore_c_api.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/glm.h"
|
||||
|
||||
namespace hello_ar {
|
||||
class PendingAnchor {
|
||||
public:
|
||||
PendingAnchor(SkPoint touchLocation);
|
||||
~PendingAnchor();
|
||||
|
||||
SkPoint GetTouchLocation();
|
||||
bool GetEditMode();
|
||||
ArPlane* GetContainingPlane();
|
||||
glm::vec4 GetAnchorPos(ArSession* arSession);
|
||||
ArAnchor* GetArAnchor();
|
||||
|
||||
void SetArAnchor(ArAnchor* anchor);
|
||||
void SetEditMode(bool editMode);
|
||||
void SetContainingPlane(ArPlane* plane);
|
||||
|
||||
private:
|
||||
SkPoint touchLocation;
|
||||
bool editMode = false;
|
||||
ArAnchor* anchor;
|
||||
ArPlane* containingPlane;
|
||||
};
|
||||
} // namespace hello_ar
|
||||
|
||||
#endif
|
@ -1,220 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/plane_renderer.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/util.h"
|
||||
|
||||
namespace hello_ar {
|
||||
namespace {
|
||||
constexpr char kVertexShader[] = R"(
|
||||
precision highp float;
|
||||
precision highp int;
|
||||
attribute vec3 vertex;
|
||||
varying vec2 v_textureCoords;
|
||||
varying float v_alpha;
|
||||
|
||||
uniform mat4 mvp;
|
||||
uniform mat4 model_mat;
|
||||
uniform vec3 normal;
|
||||
|
||||
void main() {
|
||||
// Vertex Z value is used as the alpha in this shader.
|
||||
v_alpha = vertex.z;
|
||||
|
||||
vec4 local_pos = vec4(vertex.x, 0.0, vertex.y, 1.0);
|
||||
gl_Position = mvp * local_pos;
|
||||
vec4 world_pos = model_mat * local_pos;
|
||||
|
||||
// Construct two vectors that are orthogonal to the normal.
|
||||
// This arbitrary choice is not co-linear with either horizontal
|
||||
// or vertical plane normals.
|
||||
const vec3 arbitrary = vec3(1.0, 1.0, 0.0);
|
||||
vec3 vec_u = normalize(cross(normal, arbitrary));
|
||||
vec3 vec_v = normalize(cross(normal, vec_u));
|
||||
|
||||
// Project vertices in world frame onto vec_u and vec_v.
|
||||
v_textureCoords = vec2(
|
||||
dot(world_pos.xyz, vec_u), dot(world_pos.xyz, vec_v));
|
||||
})";
|
||||
|
||||
constexpr char kFragmentShader[] = R"(
|
||||
precision highp float;
|
||||
precision highp int;
|
||||
uniform sampler2D texture;
|
||||
uniform vec3 color;
|
||||
varying vec2 v_textureCoords;
|
||||
varying float v_alpha;
|
||||
void main() {
|
||||
float r = texture2D(texture, v_textureCoords).r;
|
||||
gl_FragColor = vec4(color.xyz, r * v_alpha);
|
||||
})";
|
||||
} // namespace
|
||||
|
||||
void PlaneRenderer::InitializeGlContent(AAssetManager *asset_manager) {
|
||||
shader_program_ = util::CreateProgram(kVertexShader, kFragmentShader);
|
||||
|
||||
if (!shader_program_) {
|
||||
LOGE("Could not create program.");
|
||||
}
|
||||
|
||||
uniform_mvp_mat_ = glGetUniformLocation(shader_program_, "mvp");
|
||||
uniform_texture_ = glGetUniformLocation(shader_program_, "texture");
|
||||
uniform_model_mat_ = glGetUniformLocation(shader_program_, "model_mat");
|
||||
uniform_normal_vec_ = glGetUniformLocation(shader_program_, "normal");
|
||||
uniform_color_ = glGetUniformLocation(shader_program_, "color");
|
||||
attri_vertices_ = glGetAttribLocation(shader_program_, "vertex");
|
||||
|
||||
glGenTextures(1, &texture_id_);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_id_);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
if (!util::LoadPngFromAssetManager(GL_TEXTURE_2D, "models/trigrid.png")) {
|
||||
LOGE("Could not load png texture for planes.");
|
||||
}
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
util::CheckGlError("plane_renderer::InitializeGlContent()");
|
||||
}
|
||||
|
||||
void PlaneRenderer::Draw(const glm::mat4 &projection_mat,
|
||||
const glm::mat4 &view_mat, const ArSession *ar_session,
|
||||
const ArPlane *ar_plane, const glm::vec3 &color) {
|
||||
if (!shader_program_) {
|
||||
LOGE("shader_program is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateForPlane(ar_session, ar_plane);
|
||||
|
||||
glUseProgram(shader_program_);
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glUniform1i(uniform_texture_, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_id_);
|
||||
|
||||
// Compose final mvp matrix for this plane renderer.
|
||||
glUniformMatrix4fv(uniform_mvp_mat_, 1, GL_FALSE,
|
||||
glm::value_ptr(projection_mat * view_mat * model_mat_));
|
||||
|
||||
glUniformMatrix4fv(uniform_model_mat_, 1, GL_FALSE,
|
||||
glm::value_ptr(model_mat_));
|
||||
glUniform3f(uniform_normal_vec_, normal_vec_.x, normal_vec_.y, normal_vec_.z);
|
||||
glUniform3f(uniform_color_, color.x, color.y, color.z);
|
||||
|
||||
glEnableVertexAttribArray(attri_vertices_);
|
||||
glVertexAttribPointer(attri_vertices_, 3, GL_FLOAT, GL_FALSE, 0,
|
||||
vertices_.data());
|
||||
|
||||
glDrawElements(GL_TRIANGLES, triangles_.size(), GL_UNSIGNED_SHORT,
|
||||
triangles_.data());
|
||||
|
||||
glUseProgram(0);
|
||||
glDepthMask(GL_TRUE);
|
||||
util::CheckGlError("plane_renderer::Draw()");
|
||||
}
|
||||
|
||||
void PlaneRenderer::UpdateForPlane(const ArSession *ar_session,
|
||||
const ArPlane *ar_plane) {
|
||||
// The following code generates a triangle mesh filling a convex polygon,
|
||||
// including a feathered edge for blending.
|
||||
//
|
||||
// The indices shown in the diagram are used in comments below.
|
||||
// _______________ 0_______________1
|
||||
// | | |4___________5|
|
||||
// | | | | | |
|
||||
// | | => | | | |
|
||||
// | | | | | |
|
||||
// | | |7-----------6|
|
||||
// --------------- 3---------------2
|
||||
|
||||
vertices_.clear();
|
||||
triangles_.clear();
|
||||
|
||||
int32_t polygon_length;
|
||||
ArPlane_getPolygonSize(ar_session, ar_plane, &polygon_length);
|
||||
|
||||
if (polygon_length == 0) {
|
||||
LOGE("PlaneRenderer::UpdatePlane, no valid plane polygon is found");
|
||||
return;
|
||||
}
|
||||
|
||||
const int32_t vertices_size = polygon_length / 2;
|
||||
std::vector<glm::vec2> raw_vertices(vertices_size);
|
||||
ArPlane_getPolygon(ar_session, ar_plane,
|
||||
glm::value_ptr(raw_vertices.front()));
|
||||
|
||||
// Fill vertex 0 to 3. Note that the vertex.xy are used for x and z
|
||||
// position. vertex.z is used for alpha. The outter polygon's alpha
|
||||
// is 0.
|
||||
for (int32_t i = 0; i < vertices_size; ++i) {
|
||||
vertices_.push_back(glm::vec3(raw_vertices[i].x, raw_vertices[i].y, 0.0f));
|
||||
}
|
||||
|
||||
util::ScopedArPose scopedArPose(ar_session);
|
||||
ArPlane_getCenterPose(ar_session, ar_plane, scopedArPose.GetArPose());
|
||||
ArPose_getMatrix(ar_session, scopedArPose.GetArPose(),
|
||||
glm::value_ptr(model_mat_));
|
||||
normal_vec_ = util::GetPlaneNormal(ar_session, *scopedArPose.GetArPose());
|
||||
|
||||
// Feather distance 0.2 meters.
|
||||
const float kFeatherLength = 0.2f;
|
||||
// Feather scale over the distance between plane center and vertices.
|
||||
const float kFeatherScale = 0.2f;
|
||||
|
||||
// Fill vertex 4 to 7, with alpha set to 1.
|
||||
for (int32_t i = 0; i < vertices_size; ++i) {
|
||||
// Vector from plane center to current point.
|
||||
glm::vec2 v = raw_vertices[i];
|
||||
const float scale =
|
||||
1.0f - std::min((kFeatherLength / glm::length(v)), kFeatherScale);
|
||||
const glm::vec2 result_v = scale * v;
|
||||
|
||||
vertices_.push_back(glm::vec3(result_v.x, result_v.y, 1.0f));
|
||||
}
|
||||
|
||||
const int32_t vertices_length = vertices_.size();
|
||||
const int32_t half_vertices_length = vertices_length / 2;
|
||||
|
||||
// Generate triangle (4, 5, 6) and (4, 6, 7).
|
||||
for (int i = half_vertices_length + 1; i < vertices_length - 1; ++i) {
|
||||
triangles_.push_back(half_vertices_length);
|
||||
triangles_.push_back(i);
|
||||
triangles_.push_back(i + 1);
|
||||
}
|
||||
|
||||
// Generate triangle (0, 1, 4), (4, 1, 5), (5, 1, 2), (5, 2, 6),
|
||||
// (6, 2, 3), (6, 3, 7), (7, 3, 0), (7, 0, 4)
|
||||
for (int i = 0; i < half_vertices_length; ++i) {
|
||||
triangles_.push_back(i);
|
||||
triangles_.push_back((i + 1) % half_vertices_length);
|
||||
triangles_.push_back(i + half_vertices_length);
|
||||
|
||||
triangles_.push_back(i + half_vertices_length);
|
||||
triangles_.push_back((i + 1) % half_vertices_length);
|
||||
triangles_.push_back((i + half_vertices_length + 1) % half_vertices_length +
|
||||
half_vertices_length);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace hello_ar
|
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef C_ARCORE_HELLOE_AR_PLANE_RENDERER_H_
|
||||
#define C_ARCORE_HELLOE_AR_PLANE_RENDERER_H_
|
||||
|
||||
#include <GLES2/gl2.h>
|
||||
#include <GLES2/gl2ext.h>
|
||||
#include <android/asset_manager.h>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "arcore_c_api.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/glm.h"
|
||||
|
||||
namespace hello_ar {
|
||||
|
||||
// PlaneRenderer renders ARCore plane type.
|
||||
class PlaneRenderer {
|
||||
public:
|
||||
PlaneRenderer() = default;
|
||||
|
||||
~PlaneRenderer() = default;
|
||||
|
||||
// Sets up OpenGL state used by the plane renderer. Must be called on the
|
||||
// OpenGL thread.
|
||||
void InitializeGlContent(AAssetManager *asset_manager);
|
||||
|
||||
// Draws the provided plane.
|
||||
void Draw(const glm::mat4 &projection_mat, const glm::mat4 &view_mat,
|
||||
const ArSession *ar_session, const ArPlane *ar_plane,
|
||||
const glm::vec3 &color);
|
||||
|
||||
private:
|
||||
void UpdateForPlane(const ArSession *ar_session, const ArPlane *ar_plane);
|
||||
|
||||
std::vector<glm::vec3> vertices_;
|
||||
std::vector<GLushort> triangles_;
|
||||
glm::mat4 model_mat_ = glm::mat4(1.0f);
|
||||
glm::vec3 normal_vec_ = glm::vec3(0.0f);
|
||||
|
||||
GLuint texture_id_;
|
||||
|
||||
GLuint shader_program_;
|
||||
GLint attri_vertices_;
|
||||
GLint uniform_mvp_mat_;
|
||||
GLint uniform_texture_;
|
||||
GLint uniform_model_mat_;
|
||||
GLint uniform_normal_vec_;
|
||||
GLint uniform_color_;
|
||||
};
|
||||
} // namespace hello_ar
|
||||
|
||||
#endif // C_ARCORE_HELLOE_AR_PLANE_RENDERER_H_
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/point_cloud_renderer.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/util.h"
|
||||
|
||||
namespace hello_ar {
|
||||
namespace {
|
||||
constexpr char kVertexShader[] = R"(
|
||||
attribute vec4 vertex;
|
||||
uniform mat4 mvp;
|
||||
void main() {
|
||||
gl_PointSize = 5.0;
|
||||
// Pointcloud vertex's w component is confidence value.
|
||||
// Not used in renderer.
|
||||
gl_Position = mvp * vec4(vertex.xyz, 1.0);
|
||||
})";
|
||||
|
||||
constexpr char kFragmentShader[] = R"(
|
||||
precision lowp float;
|
||||
void main() {
|
||||
gl_FragColor = vec4(0.1215, 0.7372, 0.8235, 1.0);
|
||||
})";
|
||||
} // namespace
|
||||
|
||||
void PointCloudRenderer::InitializeGlContent() {
|
||||
shader_program_ = util::CreateProgram(kVertexShader, kFragmentShader);
|
||||
|
||||
CHECK(shader_program_);
|
||||
|
||||
attribute_vertices_ = glGetAttribLocation(shader_program_, "vertex");
|
||||
uniform_mvp_mat_ = glGetUniformLocation(shader_program_, "mvp");
|
||||
|
||||
util::CheckGlError("point_cloud_renderer::InitializeGlContent()");
|
||||
}
|
||||
|
||||
void PointCloudRenderer::Draw(glm::mat4 mvp_matrix, ArSession *ar_session,
|
||||
ArPointCloud *ar_point_cloud) const {
|
||||
CHECK(shader_program_);
|
||||
|
||||
glUseProgram(shader_program_);
|
||||
|
||||
int32_t number_of_points = 0;
|
||||
ArPointCloud_getNumberOfPoints(ar_session, ar_point_cloud, &number_of_points);
|
||||
if (number_of_points <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float *point_cloud_data;
|
||||
ArPointCloud_getData(ar_session, ar_point_cloud, &point_cloud_data);
|
||||
|
||||
glUniformMatrix4fv(uniform_mvp_mat_, 1, GL_FALSE, glm::value_ptr(mvp_matrix));
|
||||
|
||||
glEnableVertexAttribArray(attribute_vertices_);
|
||||
glVertexAttribPointer(attribute_vertices_, 4, GL_FLOAT, GL_FALSE, 0,
|
||||
point_cloud_data);
|
||||
|
||||
glDrawArrays(GL_POINTS, 0, number_of_points);
|
||||
|
||||
glUseProgram(0);
|
||||
util::CheckGlError("PointCloudRenderer::Draw");
|
||||
}
|
||||
|
||||
} // namespace hello_ar
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef C_ARCORE_HELLOE_AR_POINT_CLOUD_RENDERER_H_
|
||||
#define C_ARCORE_HELLOE_AR_POINT_CLOUD_RENDERER_H_
|
||||
|
||||
#include <GLES2/gl2.h>
|
||||
#include <GLES2/gl2ext.h>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
#include "arcore_c_api.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/glm.h"
|
||||
|
||||
namespace hello_ar {
|
||||
|
||||
class PointCloudRenderer {
|
||||
public:
|
||||
// Default constructor of PointCloudRenderer.
|
||||
PointCloudRenderer() = default;
|
||||
|
||||
// Default deconstructor of PointCloudRenderer.
|
||||
~PointCloudRenderer() = default;
|
||||
|
||||
// Initialize the GL content, needs to be called on GL thread.
|
||||
void InitializeGlContent();
|
||||
|
||||
// Render the AR point cloud.
|
||||
//
|
||||
// @param mvp_matrix, the model view projection matrix of point cloud.
|
||||
// @param ar_session, the session that is used to query point cloud points
|
||||
// from ar_point_cloud.
|
||||
// @param ar_point_cloud, point cloud data to for rendering.
|
||||
void Draw(glm::mat4 mvp_matrix, ArSession *ar_session,
|
||||
ArPointCloud *ar_point_cloud) const;
|
||||
|
||||
private:
|
||||
GLuint shader_program_;
|
||||
GLint attribute_vertices_;
|
||||
GLint uniform_mvp_mat_;
|
||||
};
|
||||
} // namespace hello_ar
|
||||
|
||||
#endif // C_ARCORE_HELLOE_AR_POINT_CLOUD_RENDERER_H_
|
@ -1,329 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/util.h"
|
||||
|
||||
#include "include/core/SkMatrix44.h"
|
||||
#include <gtx/string_cast.inl>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/jni_interface.h"
|
||||
|
||||
namespace hello_ar {
|
||||
namespace util {
|
||||
|
||||
void CheckGlError(const char *operation) {
|
||||
bool anyError = false;
|
||||
for (GLint error = glGetError(); error; error = glGetError()) {
|
||||
LOGE("after %s() glError (0x%x)\n", operation, error);
|
||||
anyError = true;
|
||||
}
|
||||
if (anyError) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience function used in CreateProgram below.
|
||||
static GLuint LoadShader(GLenum shader_type, const char *shader_source) {
|
||||
GLuint shader = glCreateShader(shader_type);
|
||||
if (!shader) {
|
||||
return shader;
|
||||
}
|
||||
|
||||
glShaderSource(shader, 1, &shader_source, nullptr);
|
||||
glCompileShader(shader);
|
||||
GLint compiled = 0;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
|
||||
|
||||
if (!compiled) {
|
||||
GLint info_len = 0;
|
||||
|
||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_len);
|
||||
if (!info_len) {
|
||||
return shader;
|
||||
}
|
||||
|
||||
char *buf = reinterpret_cast<char *>(malloc(info_len));
|
||||
if (!buf) {
|
||||
return shader;
|
||||
}
|
||||
|
||||
glGetShaderInfoLog(shader, info_len, nullptr, buf);
|
||||
LOGE("hello_ar::util::Could not compile shader %d:\n%s\n", shader_type,
|
||||
buf);
|
||||
free(buf);
|
||||
glDeleteShader(shader);
|
||||
shader = 0;
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
GLuint CreateProgram(const char *vertex_source, const char *fragment_source) {
|
||||
GLuint vertexShader = LoadShader(GL_VERTEX_SHADER, vertex_source);
|
||||
if (!vertexShader) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLuint fragment_shader = LoadShader(GL_FRAGMENT_SHADER, fragment_source);
|
||||
if (!fragment_shader) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLuint program = glCreateProgram();
|
||||
if (program) {
|
||||
glAttachShader(program, vertexShader);
|
||||
CheckGlError("hello_ar::util::glAttachShader");
|
||||
glAttachShader(program, fragment_shader);
|
||||
CheckGlError("hello_ar::util::glAttachShader");
|
||||
glLinkProgram(program);
|
||||
GLint link_status = GL_FALSE;
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &link_status);
|
||||
if (link_status != GL_TRUE) {
|
||||
GLint buf_length = 0;
|
||||
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &buf_length);
|
||||
if (buf_length) {
|
||||
char *buf = reinterpret_cast<char *>(malloc(buf_length));
|
||||
if (buf) {
|
||||
glGetProgramInfoLog(program, buf_length, nullptr, buf);
|
||||
LOGE("hello_ar::util::Could not link program:\n%s\n", buf);
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
glDeleteProgram(program);
|
||||
program = 0;
|
||||
}
|
||||
}
|
||||
return program;
|
||||
}
|
||||
|
||||
bool LoadPngFromAssetManager(int target, const std::string &path) {
|
||||
JNIEnv *env = GetJniEnv();
|
||||
|
||||
// Put all the JNI values in a structure that is statically initalized on the
|
||||
// first call to this method. This makes it thread safe in the unlikely case
|
||||
// of multiple threads calling this method.
|
||||
static struct JNIData {
|
||||
jclass helper_class;
|
||||
jmethodID load_image_method;
|
||||
jmethodID load_texture_method;
|
||||
} jniIds = [env]() -> JNIData {
|
||||
constexpr char kHelperClassName[] =
|
||||
"org/skia/arcore/JniInterface";
|
||||
constexpr char kLoadImageMethodName[] = "loadImage";
|
||||
constexpr char kLoadImageMethodSignature[] =
|
||||
"(Ljava/lang/String;)Landroid/graphics/Bitmap;";
|
||||
constexpr char kLoadTextureMethodName[] = "loadTexture";
|
||||
constexpr char kLoadTextureMethodSignature[] =
|
||||
"(ILandroid/graphics/Bitmap;)V";
|
||||
jclass helper_class = FindClass(kHelperClassName);
|
||||
if (helper_class) {
|
||||
helper_class = static_cast<jclass>(env->NewGlobalRef(helper_class));
|
||||
jmethodID load_image_method = env->GetStaticMethodID(
|
||||
helper_class, kLoadImageMethodName, kLoadImageMethodSignature);
|
||||
jmethodID load_texture_method = env->GetStaticMethodID(
|
||||
helper_class, kLoadTextureMethodName, kLoadTextureMethodSignature);
|
||||
return {helper_class, load_image_method, load_texture_method};
|
||||
}
|
||||
LOGE("hello_ar::util::Could not find Java helper class %s",
|
||||
kHelperClassName);
|
||||
return {};
|
||||
}();
|
||||
|
||||
if (!jniIds.helper_class) {
|
||||
return false;
|
||||
}
|
||||
|
||||
jstring j_path = env->NewStringUTF(path.c_str());
|
||||
|
||||
jobject image_obj = env->CallStaticObjectMethod(
|
||||
jniIds.helper_class, jniIds.load_image_method, j_path);
|
||||
|
||||
if (j_path) {
|
||||
env->DeleteLocalRef(j_path);
|
||||
}
|
||||
|
||||
env->CallStaticVoidMethod(jniIds.helper_class, jniIds.load_texture_method,
|
||||
target, image_obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GetTransformMatrixFromPose(ArSession *ar_session,
|
||||
const ArPose *ar_pose,
|
||||
glm::mat4 *out_model_mat) {
|
||||
if (out_model_mat == nullptr) {
|
||||
LOGE("util::GetTransformMatrixFromPose model_mat is null.");
|
||||
return;
|
||||
}
|
||||
ArPose_getMatrix(ar_session, ar_pose,
|
||||
glm::value_ptr(*out_model_mat));
|
||||
}
|
||||
|
||||
glm::vec3 GetPlaneNormal(const ArSession *ar_session,
|
||||
const ArPose &plane_pose) {
|
||||
float plane_pose_raw[7] = {0.f};
|
||||
ArPose_getPoseRaw(ar_session, &plane_pose, plane_pose_raw);
|
||||
glm::quat plane_quaternion(plane_pose_raw[3], plane_pose_raw[0],
|
||||
plane_pose_raw[1], plane_pose_raw[2]);
|
||||
// Get normal vector, normal is defined to be positive Y-position in local
|
||||
// frame.
|
||||
return glm::rotate(plane_quaternion, glm::vec3(0., 1.f, 0.));
|
||||
}
|
||||
|
||||
float CalculateDistanceToPlane(const ArSession *ar_session,
|
||||
const ArPose &plane_pose,
|
||||
const ArPose &camera_pose) {
|
||||
float plane_pose_raw[7] = {0.f};
|
||||
ArPose_getPoseRaw(ar_session, &plane_pose, plane_pose_raw);
|
||||
glm::vec3 plane_position(plane_pose_raw[4], plane_pose_raw[5],
|
||||
plane_pose_raw[6]);
|
||||
glm::vec3 normal = GetPlaneNormal(ar_session, plane_pose);
|
||||
|
||||
float camera_pose_raw[7] = {0.f};
|
||||
ArPose_getPoseRaw(ar_session, &camera_pose, camera_pose_raw);
|
||||
glm::vec3 camera_P_plane(camera_pose_raw[4] - plane_position.x,
|
||||
camera_pose_raw[5] - plane_position.y,
|
||||
camera_pose_raw[6] - plane_position.z);
|
||||
return glm::dot(normal, camera_P_plane);
|
||||
}
|
||||
|
||||
glm::mat4 GetCameraRotationMatrix(float cameraOutRaw[]) {
|
||||
glm::mat4 cameraRotation(1);
|
||||
glm::quat cameraQuat = glm::quat(cameraOutRaw[0], cameraOutRaw[1], cameraOutRaw[2],
|
||||
cameraOutRaw[3]);
|
||||
cameraRotation = glm::toMat4(cameraQuat);
|
||||
glm::vec4 temp = cameraRotation[0];
|
||||
cameraRotation[0] = cameraRotation[2];
|
||||
cameraRotation[2] = temp;
|
||||
return cameraRotation;
|
||||
}
|
||||
|
||||
void GetCameraInfo(ArSession* arSession, ArFrame* arFrame, glm::vec3& cameraPos, glm::mat4& cameraRotation) {
|
||||
//Acquire camera
|
||||
ArCamera *ar_camera;
|
||||
ArFrame_acquireCamera(arSession, arFrame, &ar_camera);
|
||||
|
||||
//Get camera pose
|
||||
ArPose *camera_pose = nullptr;
|
||||
ArPose_create(arSession, nullptr, &camera_pose);
|
||||
ArCamera_getDisplayOrientedPose(arSession, ar_camera, camera_pose);
|
||||
|
||||
//Get camera raw info
|
||||
float outCameraRaw[] = {0, 0, 0, 0, 0, 0, 0};
|
||||
ArPose_getPoseRaw(arSession, camera_pose, outCameraRaw);
|
||||
ArPose_destroy(camera_pose);
|
||||
|
||||
//Write to out variables
|
||||
cameraPos = glm::vec3(outCameraRaw[4], outCameraRaw[5], outCameraRaw[6]);
|
||||
cameraRotation = util::GetCameraRotationMatrix(outCameraRaw);
|
||||
|
||||
//Release camera
|
||||
ArCamera_release(ar_camera);
|
||||
}
|
||||
|
||||
SkMatrix44 GlmMatToSkMat(const glm::mat4 m) {
|
||||
SkMatrix44 skMat = SkMatrix44::kIdentity_Constructor;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
skMat.set(j, i, m[i][j]);
|
||||
}
|
||||
}
|
||||
return skMat;
|
||||
}
|
||||
|
||||
glm::mat4 SkMatToGlmMat(const SkMatrix44 m) {
|
||||
glm::mat4 glmMat(1);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
glmMat[i][j] = m.get(j, i);
|
||||
}
|
||||
}
|
||||
return glmMat;
|
||||
}
|
||||
|
||||
void Log4x4Matrix(float raw_matrix[16]) {
|
||||
LOGI(
|
||||
"%f, %f, %f, %f\n"
|
||||
"%f, %f, %f, %f\n"
|
||||
"%f, %f, %f, %f\n"
|
||||
"%f, %f, %f, %f\n",
|
||||
raw_matrix[0], raw_matrix[1], raw_matrix[2], raw_matrix[3], raw_matrix[4],
|
||||
raw_matrix[5], raw_matrix[6], raw_matrix[7], raw_matrix[8], raw_matrix[9],
|
||||
raw_matrix[10], raw_matrix[11], raw_matrix[12], raw_matrix[13],
|
||||
raw_matrix[14], raw_matrix[15]);
|
||||
}
|
||||
|
||||
void LogGlmMat(glm::mat4 m, char *type) {
|
||||
std::string str = glm::to_string(m);
|
||||
LOGE("glm Matrix - %s: %s\n", type, str.c_str());
|
||||
}
|
||||
|
||||
void LogSkMat44(SkMatrix44 m, char *type) {
|
||||
LOGE("SkMatrix - %s: [%g, %g, %g, %g] || [%g, %g, %g, %g] || [%g, %g, %g, %g] || [%g, %g, %g, %g] \n",
|
||||
type,
|
||||
m.get(0, 0), m.get(1, 0), m.get(2, 0), m.get(3, 0),
|
||||
m.get(0, 1), m.get(1, 1), m.get(2, 1), m.get(3, 1),
|
||||
m.get(0, 2), m.get(1, 2), m.get(2, 2), m.get(3, 2),
|
||||
m.get(0, 3), m.get(1, 3), m.get(2, 3), m.get(3, 3)
|
||||
);
|
||||
}
|
||||
|
||||
void LogSkMat(SkMatrix m, char *type) {
|
||||
LOGE("SkMatrix - %s: [%g, %g, %g] || [%g, %g, %g] || [%g, %g, %g] \n", type,
|
||||
m.get(0), m.get(3), m.get(6),
|
||||
m.get(1), m.get(4), m.get(7),
|
||||
m.get(2), m.get(5), m.get(8)
|
||||
);
|
||||
}
|
||||
|
||||
void LogOrientation(float rotationDirection, float angleRad, char *type) {
|
||||
LOGI("Plane orientation: %s", type);
|
||||
LOGI("Cross dotted with zDir:", rotationDirection);
|
||||
if (rotationDirection == -1) {
|
||||
LOGI("Counter Clockwise %.6f degrees rotation: ", glm::degrees(angleRad));
|
||||
} else {
|
||||
LOGI("Clockwise %.6f degrees rotation: ", glm::degrees(angleRad));
|
||||
}
|
||||
}
|
||||
|
||||
float Dot(glm::vec3 u, glm::vec3 v) {
|
||||
float result = u.x * v.x + u.y * v.y + u.z * v.z;
|
||||
return result;
|
||||
}
|
||||
|
||||
float Magnitude(glm::vec3 u) {
|
||||
float result = u.x * u.x + u.y * u.y + u.z * u.z;
|
||||
return sqrt(result);
|
||||
}
|
||||
|
||||
float AngleRad(glm::vec3 u, glm::vec3 v) {
|
||||
float dot = util::Dot(u, v);
|
||||
float scale = (util::Magnitude(u) * util::Magnitude(v));
|
||||
float cosine = dot / scale;
|
||||
float acosine = acos(cosine);
|
||||
return acosine;
|
||||
}
|
||||
|
||||
glm::vec3 ProjectOntoPlane(glm::vec3 in, glm::vec3 normal) {
|
||||
float dot = util::Dot(in, normal);
|
||||
float multiplier = dot / (util::Magnitude(normal) * util::Magnitude(normal));
|
||||
glm::vec3 out = in - multiplier * normal;
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
} // namespace hello_ar
|
@ -1,139 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef C_ARCORE_HELLOE_AR_UTIL_H_
|
||||
#define C_ARCORE_HELLOE_AR_UTIL_H_
|
||||
|
||||
#include "include/core/SkMatrix44.h"
|
||||
#include <GLES2/gl2.h>
|
||||
#include <GLES2/gl2ext.h>
|
||||
#include <android/asset_manager.h>
|
||||
#include <android/log.h>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <errno.h>
|
||||
#include <jni.h>
|
||||
#include <vector>
|
||||
|
||||
#include "arcore_c_api.h"
|
||||
#include "platform_tools/android/apps/arcore/src/main/cpp/glm.h"
|
||||
|
||||
#ifndef LOGI
|
||||
#define LOGI(...) \
|
||||
__android_log_print(ANDROID_LOG_INFO, "hello_ar_example_c", __VA_ARGS__)
|
||||
#endif // LOGI
|
||||
|
||||
#ifndef LOGE
|
||||
#define LOGE(...) \
|
||||
__android_log_print(ANDROID_LOG_ERROR, "hello_ar_example_c", __VA_ARGS__)
|
||||
#endif // LOGE
|
||||
|
||||
#ifndef CHECK
|
||||
#define CHECK(condition) \
|
||||
if (!(condition)) { \
|
||||
LOGE("*** CHECK FAILED at %s:%d: %s", __FILE__, __LINE__, #condition); \
|
||||
abort(); \
|
||||
}
|
||||
#endif // CHECK
|
||||
|
||||
namespace hello_ar {
|
||||
// Utilities
|
||||
namespace util {
|
||||
|
||||
// Provides a scoped allocated instance of Anchor.
|
||||
// Can be treated as an ArAnchor*.
|
||||
class ScopedArPose {
|
||||
public:
|
||||
explicit ScopedArPose(const ArSession *session) {
|
||||
ArPose_create(session, nullptr, &pose_);
|
||||
}
|
||||
|
||||
~ScopedArPose() { ArPose_destroy(pose_); }
|
||||
|
||||
ArPose *GetArPose() { return pose_; }
|
||||
|
||||
// Delete copy constructors.
|
||||
ScopedArPose(const ScopedArPose &) = delete;
|
||||
|
||||
void operator=(const ScopedArPose &) = delete;
|
||||
|
||||
private:
|
||||
ArPose *pose_;
|
||||
};
|
||||
|
||||
/* GL Utils */
|
||||
// Check GL error, and abort if an error is encountered.
|
||||
//
|
||||
// @param operation, the name of the GL function call.
|
||||
void CheckGlError(const char *operation);
|
||||
|
||||
// Create a shader program ID.
|
||||
//
|
||||
// @param vertex_source, the vertex shader source.
|
||||
// @param fragment_source, the fragment shader source.
|
||||
// @return
|
||||
GLuint CreateProgram(const char *vertex_source, const char *fragment_source);
|
||||
|
||||
// Load png file from assets folder and then assign it to the OpenGL target.
|
||||
// This method must be called from the renderer thread since it will result in
|
||||
// OpenGL calls to assign the image to the texture target.
|
||||
//
|
||||
// @param target, openGL texture target to load the image into.
|
||||
// @param path, path to the file, relative to the assets folder.
|
||||
// @return true if png is loaded correctly, otherwise false.
|
||||
bool LoadPngFromAssetManager(int target, const std::string &path);
|
||||
|
||||
|
||||
/* ARCore utils */
|
||||
void GetTransformMatrixFromPose(ArSession *ar_session, const ArPose *ar_pose, glm::mat4 *out_model_mat);
|
||||
|
||||
// Get the plane's normal from center pose.
|
||||
glm::vec3 GetPlaneNormal(const ArSession *ar_session, const ArPose &plane_pose);
|
||||
|
||||
// Calculate the normal distance to plane from cameraPose, the given planePose
|
||||
// should have y axis parallel to plane's normal, for example plane's center
|
||||
// pose or hit test pose.
|
||||
float CalculateDistanceToPlane(const ArSession *ar_session, const ArPose &plane_pose, const ArPose &camera_pose);
|
||||
|
||||
// Outputs the camera rotation using display orientation
|
||||
glm::mat4 GetCameraRotationMatrix(float cameraOutRaw[]);
|
||||
|
||||
// Computes camera position and orientation (using GetCameraRotationMatrix)
|
||||
void GetCameraInfo(ArSession* arSession, ArFrame* arFrame, glm::vec3& cameraPos, glm::mat4& cameraRotation);
|
||||
|
||||
/* Matrix conversion */
|
||||
SkMatrix44 GlmMatToSkMat(const glm::mat4 m);
|
||||
glm::mat4 SkMatToGlmMat(const SkMatrix44 m);
|
||||
|
||||
/* Logging utils */
|
||||
//Row major output
|
||||
void Log4x4Matrix(float raw_matrix[16]);
|
||||
|
||||
//Column major output
|
||||
void LogGlmMat(glm::mat4 m, char *type);
|
||||
void LogSkMat44(SkMatrix44 m, char *type);
|
||||
void LogSkMat(SkMatrix m, char *type);
|
||||
void LogOrientation(float rotationDirection, float angleRad, char *type);
|
||||
|
||||
/* Vector ops */
|
||||
float Dot(glm::vec3 u, glm::vec3 v);
|
||||
float Magnitude(glm::vec3 u);
|
||||
float AngleRad(glm::vec3 u, glm::vec3 v);
|
||||
glm::vec3 ProjectOntoPlane(glm::vec3 in, glm::vec3 normal);
|
||||
} // namespace util
|
||||
} // namespace hello_ar
|
||||
|
||||
#endif // C_ARCORE_HELLOE_AR_UTIL_H_
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.skia.arcore;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.provider.Settings;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
|
||||
/**
|
||||
* Helper to ask camera permission.
|
||||
*/
|
||||
public class CameraPermissionHelper {
|
||||
private static final String CAMERA_PERMISSION = Manifest.permission.CAMERA;
|
||||
private static final int CAMERA_PERMISSION_CODE = 0;
|
||||
|
||||
/**
|
||||
* Check to see we have the necessary permissions for this app.
|
||||
*/
|
||||
public static boolean hasCameraPermission(Activity activity) {
|
||||
return ContextCompat.checkSelfPermission(activity, CAMERA_PERMISSION)
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see we have the necessary permissions for this app, and ask for them if we don't.
|
||||
*/
|
||||
public static void requestCameraPermission(Activity activity) {
|
||||
ActivityCompat.requestPermissions(
|
||||
activity, new String[]{CAMERA_PERMISSION}, CAMERA_PERMISSION_CODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if we need to show the rationale for this permission.
|
||||
*/
|
||||
public static boolean shouldShowRequestPermissionRationale(Activity activity) {
|
||||
return ActivityCompat.shouldShowRequestPermissionRationale(activity, CAMERA_PERMISSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch Application Setting to grant permission.
|
||||
*/
|
||||
public static void launchPermissionSettings(Activity activity) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
intent.setData(Uri.fromParts("package", activity.getPackageName(), null));
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
}
|
@ -1,364 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.skia.arcore;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.opengl.GLES20;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
import android.view.ActionMode;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.Gravity;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.EditText;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.Toast;
|
||||
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
/**
|
||||
* This is a simple example that shows how to create an augmented reality (AR) application using the
|
||||
* ARCore C API.
|
||||
*/
|
||||
public class HelloArActivity extends AppCompatActivity
|
||||
implements GLSurfaceView.Renderer, DisplayManager.DisplayListener {
|
||||
private static final String TAG = HelloArActivity.class.getSimpleName();
|
||||
private static final int SNACKBAR_UPDATE_INTERVAL_MILLIS = 1000; // In milliseconds.
|
||||
|
||||
private GLSurfaceView mSurfaceView;
|
||||
private Activity activity = null;
|
||||
private boolean mViewportChanged = false;
|
||||
private int mViewportWidth;
|
||||
private int mViewportHeight;
|
||||
private View contextView = null;
|
||||
private int mCurrentObjectRotation = 0;
|
||||
private float mCurrentValue = 0;
|
||||
private float X = 0;
|
||||
private float Y = 0;
|
||||
|
||||
private boolean toEdit = false;
|
||||
|
||||
// Opaque native pointer to the native application instance.
|
||||
private long mNativeApplication;
|
||||
private GestureDetector mGestureDetector;
|
||||
|
||||
private Snackbar mLoadingMessageSnackbar;
|
||||
private Handler mPlaneStatusCheckingHandler;
|
||||
private final Runnable mPlaneStatusCheckingRunnable =
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// The runnable is executed on main UI thread.
|
||||
try {
|
||||
if (JniInterface.hasDetectedPlanes(mNativeApplication)) {
|
||||
if (mLoadingMessageSnackbar != null) {
|
||||
mLoadingMessageSnackbar.dismiss();
|
||||
}
|
||||
mLoadingMessageSnackbar = null;
|
||||
} else {
|
||||
mPlaneStatusCheckingHandler.postDelayed(
|
||||
mPlaneStatusCheckingRunnable, SNACKBAR_UPDATE_INTERVAL_MILLIS);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
}
|
||||
}
|
||||
};
|
||||
private int mDrawMode = -1;
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
|
||||
setSupportActionBar(myToolbar);
|
||||
|
||||
activity = this;
|
||||
|
||||
//hide notifications bar
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
|
||||
mSurfaceView = (GLSurfaceView) findViewById(R.id.surfaceview);
|
||||
|
||||
mGestureDetector =
|
||||
new GestureDetector(
|
||||
this,
|
||||
new GestureDetector.SimpleOnGestureListener() {
|
||||
@Override
|
||||
public boolean onSingleTapUp(final MotionEvent e) {
|
||||
toEdit = JniInterface.onTouchedFirst(mNativeApplication, e.getX(), e.getY(), mDrawMode);
|
||||
|
||||
Log.i(TAG, "toEdit: " + toEdit);
|
||||
X = e.getX();
|
||||
Y = e.getY();
|
||||
contextView.showContextMenu(e.getX(), e.getY());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
||||
Log.i(TAG, "Scrolling!");
|
||||
JniInterface.onTouchTranslate(mNativeApplication, e2.getX(), e2.getY());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDown(MotionEvent e) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
mSurfaceView.setOnTouchListener(
|
||||
new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
return mGestureDetector.onTouchEvent(event);
|
||||
}
|
||||
});
|
||||
|
||||
// Set up renderer.
|
||||
mSurfaceView.setPreserveEGLContextOnPause(true);
|
||||
mSurfaceView.setEGLContextClientVersion(2);
|
||||
mSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0); // Alpha used for plane blending.
|
||||
mSurfaceView.setRenderer(this);
|
||||
mSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
|
||||
|
||||
JniInterface.assetManager = getAssets();
|
||||
mNativeApplication = JniInterface.createNativeApplication(getAssets());
|
||||
|
||||
mPlaneStatusCheckingHandler = new Handler();
|
||||
|
||||
//Floating context menu
|
||||
contextView = findViewById(R.id.menuView);
|
||||
this.registerForContextMenu(contextView);
|
||||
View.OnLongClickListener listener = new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
activity.closeContextMenu();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
contextView.setOnLongClickListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo)
|
||||
{
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
|
||||
if (!toEdit) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.draw_menu, menu);
|
||||
menu.setHeaderTitle("Draw Options");
|
||||
}
|
||||
|
||||
v.setClickable(false);
|
||||
v.setFocusable(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
|
||||
switch (item.getItemId()) {
|
||||
case R.id.draw_text:
|
||||
JniInterface.onTouchedFinal(mNativeApplication, 0);
|
||||
return true;
|
||||
case R.id.draw_circle:
|
||||
JniInterface.onTouchedFinal(mNativeApplication, 1);
|
||||
return true;
|
||||
case R.id.draw_rect:
|
||||
JniInterface.onTouchedFinal(mNativeApplication, 2);
|
||||
return true;
|
||||
case R.id.edit_size:
|
||||
return true;
|
||||
case R.id.edit_text:
|
||||
return true;
|
||||
default:
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.rotation_mode, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.rotation_axis_aligned:
|
||||
mCurrentObjectRotation = 0;
|
||||
break;
|
||||
case R.id.rotation_camera_aligned:
|
||||
mCurrentObjectRotation = 1;
|
||||
break;
|
||||
case R.id.rotation_snap_aligned:
|
||||
mCurrentObjectRotation = 2;
|
||||
break;
|
||||
case R.id.action:
|
||||
mCurrentValue = 180;
|
||||
JniInterface.onAction(mNativeApplication, mCurrentValue);
|
||||
return true;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
JniInterface.onObjectRotationChanged(mNativeApplication, mCurrentObjectRotation);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
// ARCore requires camera permissions to operate. If we did not yet obtain runtime
|
||||
// permission on Android M and above, now is a good time to ask the user for it.
|
||||
if (!CameraPermissionHelper.hasCameraPermission(this)) {
|
||||
CameraPermissionHelper.requestCameraPermission(this);
|
||||
return;
|
||||
}
|
||||
|
||||
JniInterface.onResume(mNativeApplication, getApplicationContext(), this);
|
||||
mSurfaceView.onResume();
|
||||
|
||||
mLoadingMessageSnackbar =
|
||||
Snackbar.make(
|
||||
HelloArActivity.this.findViewById(android.R.id.content),
|
||||
"Searching for surfaces...",
|
||||
Snackbar.LENGTH_INDEFINITE);
|
||||
// Set the snackbar background to light transparent black color.
|
||||
mLoadingMessageSnackbar.getView().setBackgroundColor(0xbf323232);
|
||||
mLoadingMessageSnackbar.show();
|
||||
mPlaneStatusCheckingHandler.postDelayed(
|
||||
mPlaneStatusCheckingRunnable, SNACKBAR_UPDATE_INTERVAL_MILLIS);
|
||||
|
||||
// Listen to display changed events to detect 180° rotation, which does not cause a config
|
||||
// change or view resize.
|
||||
getSystemService(DisplayManager.class).registerDisplayListener(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
mSurfaceView.onPause();
|
||||
JniInterface.onPause(mNativeApplication);
|
||||
|
||||
mPlaneStatusCheckingHandler.removeCallbacks(mPlaneStatusCheckingRunnable);
|
||||
|
||||
getSystemService(DisplayManager.class).unregisterDisplayListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
// Synchronized to avoid racing onDrawFrame.
|
||||
synchronized (this) {
|
||||
JniInterface.destroyNativeApplication(mNativeApplication);
|
||||
mNativeApplication = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
if (hasFocus) {
|
||||
// Standard Android full-screen functionality.
|
||||
getWindow()
|
||||
.getDecorView()
|
||||
.setSystemUiVisibility(
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
|
||||
GLES20.glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
|
||||
JniInterface.onGlSurfaceCreated(mNativeApplication);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceChanged(GL10 gl, int width, int height) {
|
||||
mViewportWidth = width;
|
||||
mViewportHeight = height;
|
||||
mViewportChanged = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrawFrame(GL10 gl) {
|
||||
// Synchronized to avoid racing onDestroy.
|
||||
synchronized (this) {
|
||||
if (mNativeApplication == 0) {
|
||||
return;
|
||||
}
|
||||
if (mViewportChanged) {
|
||||
int displayRotation = getWindowManager().getDefaultDisplay().getRotation();
|
||||
JniInterface.onDisplayGeometryChanged(
|
||||
mNativeApplication, displayRotation, mViewportWidth, mViewportHeight);
|
||||
mViewportChanged = false;
|
||||
}
|
||||
JniInterface.onGlSurfaceDrawFrame(mNativeApplication);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] results) {
|
||||
if (!CameraPermissionHelper.hasCameraPermission(this)) {
|
||||
Toast.makeText(this, "Camera permission is needed to run this application", Toast.LENGTH_LONG)
|
||||
.show();
|
||||
if (!CameraPermissionHelper.shouldShowRequestPermissionRationale(this)) {
|
||||
// Permission denied with checking "Do not ask again".
|
||||
CameraPermissionHelper.launchPermissionSettings(this);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
// DisplayListener methods
|
||||
@Override
|
||||
public void onDisplayAdded(int displayId) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayRemoved(int displayId) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayChanged(int displayId) {
|
||||
mViewportChanged = true;
|
||||
}
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
package org.skia.arcore;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.opengl.GLUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* JNI interface to native layer.
|
||||
*/
|
||||
public class JniInterface {
|
||||
static {
|
||||
System.loadLibrary("hello_ar_native");
|
||||
}
|
||||
|
||||
private static final String TAG = "JniInterface";
|
||||
static AssetManager assetManager;
|
||||
|
||||
public static native long createNativeApplication(AssetManager assetManager);
|
||||
|
||||
public static native void destroyNativeApplication(long nativeApplication);
|
||||
|
||||
public static native void onPause(long nativeApplication);
|
||||
|
||||
public static native void onResume(long nativeApplication, Context context, Activity activity);
|
||||
|
||||
/**
|
||||
* Allocate OpenGL resources for rendering.
|
||||
*/
|
||||
public static native void onGlSurfaceCreated(long nativeApplication);
|
||||
|
||||
/**
|
||||
* Called on the OpenGL thread before onGlSurfaceDrawFrame when the view port width, height, or
|
||||
* display rotation may have changed.
|
||||
*/
|
||||
public static native void onDisplayGeometryChanged(
|
||||
long nativeApplication, int displayRotation, int width, int height);
|
||||
|
||||
public static native void onObjectRotationChanged(long nativeApplication, int rotation);
|
||||
|
||||
public static native void onAction(long nativeApplication, float value);
|
||||
|
||||
/**
|
||||
* Main render loop, called on the OpenGL thread.
|
||||
*/
|
||||
public static native void onGlSurfaceDrawFrame(long nativeApplication);
|
||||
|
||||
/**
|
||||
* OnTouch event, called on the OpenGL thread.
|
||||
*/
|
||||
|
||||
public static native void onTouchTranslate(long nativeApplication, float x, float y);
|
||||
|
||||
public static native boolean onTouchedFirst(long nativeApplication, float x, float y, int drawMode);
|
||||
|
||||
public static native void onTouchedFinal(long nativeApplication, int type);
|
||||
|
||||
|
||||
/**
|
||||
* Get plane count in current session. Used to disable the "searching for surfaces" snackbar.
|
||||
*/
|
||||
public static native boolean hasDetectedPlanes(long nativeApplication);
|
||||
|
||||
public static Bitmap loadImage(String imageName) {
|
||||
|
||||
try {
|
||||
return BitmapFactory.decodeStream(assetManager.open(imageName));
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Cannot open image " + imageName);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadTexture(int target, Bitmap bitmap) {
|
||||
GLUtils.texImage2D(target, 0, bitmap, 0);
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 21 KiB |
@ -1,41 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:background="@android:color/darker_gray"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<!-- The navigation drawer that's always open -->
|
||||
<ListView android:id="@+id/leftDrawer"
|
||||
android:layout_width="240dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
android:choiceMode="singleChoice"
|
||||
android:divider="@android:color/transparent"
|
||||
android:dividerHeight="0dp"
|
||||
android:layout_marginRight="5dp"
|
||||
android:background="@android:color/background_light"/>
|
||||
|
||||
<!-- The main content view -->
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<!-- We use mainLayout for recreating SurfaceView -->
|
||||
<LinearLayout
|
||||
android:id="@+id/mainLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<SurfaceView
|
||||
android:id="@+id/surfaceView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_centerHorizontal="true" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -1,50 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/drawerLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<!-- The main content view -->
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<View
|
||||
android:layout_gravity="center"
|
||||
android:id="@+id/menuView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/my_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:elevation="4dp"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
|
||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
|
||||
<EditText
|
||||
android:id="@+id/text_box"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:focusable="false"
|
||||
android:clickable="false"
|
||||
android:visibility="gone"/>
|
||||
<android.opengl.GLSurfaceView
|
||||
android:id="@+id/surfaceview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="bottom" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</android.support.v4.widget.DrawerLayout>
|
||||
|
@ -1,35 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:weightSum="1">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginBottom="0dp"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:text="Name:"
|
||||
android:id="@+id/nameText" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginTop="0dp"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="Value"
|
||||
android:id="@+id/valueText" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/optionSpinner"
|
||||
android:paddingTop="0dp"
|
||||
android:paddingBottom="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
</Spinner>
|
||||
|
||||
</LinearLayout>
|
@ -1,15 +0,0 @@
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/draw_text"
|
||||
android:title="Draw Text" />
|
||||
<item
|
||||
android:id="@+id/draw_shape"
|
||||
android:title="Draw Shape" >
|
||||
<menu>
|
||||
<item android:id="@+id/draw_circle"
|
||||
android:title="Circle" />
|
||||
<item android:id="@+id/draw_rect"
|
||||
android:title="Rectangle" />
|
||||
</menu>
|
||||
</item>
|
||||
</menu>
|
@ -1,8 +0,0 @@
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/edit_size"
|
||||
android:title="Size" />
|
||||
<item
|
||||
android:id="@+id/edit_text"
|
||||
android:title="Text" />
|
||||
</menu>
|
@ -1,11 +0,0 @@
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/rotation_axis_aligned"
|
||||
android:title="Plane Axis-Aligned"/>
|
||||
<item android:id="@+id/rotation_camera_aligned"
|
||||
android:title="Camera-Aligned"/>
|
||||
<item android:id="@+id/rotation_snap_aligned"
|
||||
android:title="Snap-Aligned"/>
|
||||
|
||||
<item android:id="@+id/action"
|
||||
android:title="Do Action"/>
|
||||
</menu>
|
@ -1,12 +0,0 @@
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
|
||||
<item
|
||||
android:id="@+id/action_left"
|
||||
android:icon="@android:drawable/ic_media_previous"
|
||||
android:showAsAction="always"/>
|
||||
|
||||
<item android:id="@+id/action_right"
|
||||
android:icon="@android:drawable/ic_media_next"
|
||||
android:showAsAction="always"/>
|
||||
|
||||
</menu>
|
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<integer name="value_tag_key">1</integer>
|
||||
</resources>
|
@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2017 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<string name="app_name">HelloAR C</string>
|
||||
</resources>
|
@ -1,35 +0,0 @@
|
||||
<!--
|
||||
Copyright 2017 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!--
|
||||
Base application theme, dependent on API level. This theme is replaced
|
||||
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Light">
|
||||
<!--
|
||||
Theme customizations available in newer API levels can go in
|
||||
res/values-vXX/styles.xml, while customizations related to
|
||||
backward-compatibility can go here.
|
||||
-->
|
||||
</style>
|
||||
|
||||
<!-- Application theme. -->
|
||||
<style name="AppTheme" parent="AppBaseTheme">
|
||||
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
@ -1,5 +1,4 @@
|
||||
include ':viewer'
|
||||
include ':skqp'
|
||||
include ':arcore' //must build out directory first: bin/gn gen out/arm64 --args='ndk="NDKPATH" target_cpu="ABI" is_component_build=true'
|
||||
include ':skar_java'
|
||||
include ':skottie'
|
||||
include ':skottie'
|
||||
|
Loading…
Reference in New Issue
Block a user