diff options
Diffstat (limited to 'platform_tools/android/apps/arcore/src/main/cpp/util.cc')
-rw-r--r-- | platform_tools/android/apps/arcore/src/main/cpp/util.cc | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/platform_tools/android/apps/arcore/src/main/cpp/util.cc b/platform_tools/android/apps/arcore/src/main/cpp/util.cc new file mode 100644 index 0000000000..d18719fbb4 --- /dev/null +++ b/platform_tools/android/apps/arcore/src/main/cpp/util.cc @@ -0,0 +1,329 @@ +/* + * 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 "util.h" + +#include <unistd.h> +#include <sstream> +#include <string> +#include <SkMatrix44.h> +#include <gtx/string_cast.inl> + +#include "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 |