1 /* 2 * Copyright 2017 Google Inc. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #include "util.h" 17 18 #include <unistd.h> 19 #include <sstream> 20 #include <string> 21 #include <SkMatrix44.h> 22 #include <gtx/string_cast.inl> 23 24 #include "jni_interface.h" 25 26 namespace hello_ar { 27 namespace util { 28 29 void CheckGlError(const char *operation) { 30 bool anyError = false; 31 for (GLint error = glGetError(); error; error = glGetError()) { 32 LOGE("after %s() glError (0x%x)\n", operation, error); 33 anyError = true; 34 } 35 if (anyError) { 36 abort(); 37 } 38 } 39 40 // Convenience function used in CreateProgram below. 41 static GLuint LoadShader(GLenum shader_type, const char *shader_source) { 42 GLuint shader = glCreateShader(shader_type); 43 if (!shader) { 44 return shader; 45 } 46 47 glShaderSource(shader, 1, &shader_source, nullptr); 48 glCompileShader(shader); 49 GLint compiled = 0; 50 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); 51 52 if (!compiled) { 53 GLint info_len = 0; 54 55 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_len); 56 if (!info_len) { 57 return shader; 58 } 59 60 char *buf = reinterpret_cast<char *>(malloc(info_len)); 61 if (!buf) { 62 return shader; 63 } 64 65 glGetShaderInfoLog(shader, info_len, nullptr, buf); 66 LOGE("hello_ar::util::Could not compile shader %d:\n%s\n", shader_type, 67 buf); 68 free(buf); 69 glDeleteShader(shader); 70 shader = 0; 71 } 72 73 return shader; 74 } 75 76 GLuint CreateProgram(const char *vertex_source, const char *fragment_source) { 77 GLuint vertexShader = LoadShader(GL_VERTEX_SHADER, vertex_source); 78 if (!vertexShader) { 79 return 0; 80 } 81 82 GLuint fragment_shader = LoadShader(GL_FRAGMENT_SHADER, fragment_source); 83 if (!fragment_shader) { 84 return 0; 85 } 86 87 GLuint program = glCreateProgram(); 88 if (program) { 89 glAttachShader(program, vertexShader); 90 CheckGlError("hello_ar::util::glAttachShader"); 91 glAttachShader(program, fragment_shader); 92 CheckGlError("hello_ar::util::glAttachShader"); 93 glLinkProgram(program); 94 GLint link_status = GL_FALSE; 95 glGetProgramiv(program, GL_LINK_STATUS, &link_status); 96 if (link_status != GL_TRUE) { 97 GLint buf_length = 0; 98 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &buf_length); 99 if (buf_length) { 100 char *buf = reinterpret_cast<char *>(malloc(buf_length)); 101 if (buf) { 102 glGetProgramInfoLog(program, buf_length, nullptr, buf); 103 LOGE("hello_ar::util::Could not link program:\n%s\n", buf); 104 free(buf); 105 } 106 } 107 glDeleteProgram(program); 108 program = 0; 109 } 110 } 111 return program; 112 } 113 114 bool LoadPngFromAssetManager(int target, const std::string &path) { 115 JNIEnv *env = GetJniEnv(); 116 117 // Put all the JNI values in a structure that is statically initalized on the 118 // first call to this method. This makes it thread safe in the unlikely case 119 // of multiple threads calling this method. 120 static struct JNIData { 121 jclass helper_class; 122 jmethodID load_image_method; 123 jmethodID load_texture_method; 124 } jniIds = [env]() -> JNIData { 125 constexpr char kHelperClassName[] = 126 "org/skia/arcore/JniInterface"; 127 constexpr char kLoadImageMethodName[] = "loadImage"; 128 constexpr char kLoadImageMethodSignature[] = 129 "(Ljava/lang/String;)Landroid/graphics/Bitmap;"; 130 constexpr char kLoadTextureMethodName[] = "loadTexture"; 131 constexpr char kLoadTextureMethodSignature[] = 132 "(ILandroid/graphics/Bitmap;)V"; 133 jclass helper_class = FindClass(kHelperClassName); 134 if (helper_class) { 135 helper_class = static_cast<jclass>(env->NewGlobalRef(helper_class)); 136 jmethodID load_image_method = env->GetStaticMethodID( 137 helper_class, kLoadImageMethodName, kLoadImageMethodSignature); 138 jmethodID load_texture_method = env->GetStaticMethodID( 139 helper_class, kLoadTextureMethodName, kLoadTextureMethodSignature); 140 return {helper_class, load_image_method, load_texture_method}; 141 } 142 LOGE("hello_ar::util::Could not find Java helper class %s", 143 kHelperClassName); 144 return {}; 145 }(); 146 147 if (!jniIds.helper_class) { 148 return false; 149 } 150 151 jstring j_path = env->NewStringUTF(path.c_str()); 152 153 jobject image_obj = env->CallStaticObjectMethod( 154 jniIds.helper_class, jniIds.load_image_method, j_path); 155 156 if (j_path) { 157 env->DeleteLocalRef(j_path); 158 } 159 160 env->CallStaticVoidMethod(jniIds.helper_class, jniIds.load_texture_method, 161 target, image_obj); 162 return true; 163 } 164 165 void GetTransformMatrixFromPose(ArSession *ar_session, 166 const ArPose *ar_pose, 167 glm::mat4 *out_model_mat) { 168 if (out_model_mat == nullptr) { 169 LOGE("util::GetTransformMatrixFromPose model_mat is null."); 170 return; 171 } 172 ArPose_getMatrix(ar_session, ar_pose, 173 glm::value_ptr(*out_model_mat)); 174 } 175 176 glm::vec3 GetPlaneNormal(const ArSession *ar_session, 177 const ArPose &plane_pose) { 178 float plane_pose_raw[7] = {0.f}; 179 ArPose_getPoseRaw(ar_session, &plane_pose, plane_pose_raw); 180 glm::quat plane_quaternion(plane_pose_raw[3], plane_pose_raw[0], 181 plane_pose_raw[1], plane_pose_raw[2]); 182 // Get normal vector, normal is defined to be positive Y-position in local 183 // frame. 184 return glm::rotate(plane_quaternion, glm::vec3(0., 1.f, 0.)); 185 } 186 187 float CalculateDistanceToPlane(const ArSession *ar_session, 188 const ArPose &plane_pose, 189 const ArPose &camera_pose) { 190 float plane_pose_raw[7] = {0.f}; 191 ArPose_getPoseRaw(ar_session, &plane_pose, plane_pose_raw); 192 glm::vec3 plane_position(plane_pose_raw[4], plane_pose_raw[5], 193 plane_pose_raw[6]); 194 glm::vec3 normal = GetPlaneNormal(ar_session, plane_pose); 195 196 float camera_pose_raw[7] = {0.f}; 197 ArPose_getPoseRaw(ar_session, &camera_pose, camera_pose_raw); 198 glm::vec3 camera_P_plane(camera_pose_raw[4] - plane_position.x, 199 camera_pose_raw[5] - plane_position.y, 200 camera_pose_raw[6] - plane_position.z); 201 return glm::dot(normal, camera_P_plane); 202 } 203 204 glm::mat4 GetCameraRotationMatrix(float cameraOutRaw[]) { 205 glm::mat4 cameraRotation(1); 206 glm::quat cameraQuat = glm::quat(cameraOutRaw[0], cameraOutRaw[1], cameraOutRaw[2], 207 cameraOutRaw[3]); 208 cameraRotation = glm::toMat4(cameraQuat); 209 glm::vec4 temp = cameraRotation[0]; 210 cameraRotation[0] = cameraRotation[2]; 211 cameraRotation[2] = temp; 212 return cameraRotation; 213 } 214 215 void GetCameraInfo(ArSession* arSession, ArFrame* arFrame, glm::vec3& cameraPos, glm::mat4& cameraRotation) { 216 //Acquire camera 217 ArCamera *ar_camera; 218 ArFrame_acquireCamera(arSession, arFrame, &ar_camera); 219 220 //Get camera pose 221 ArPose *camera_pose = nullptr; 222 ArPose_create(arSession, nullptr, &camera_pose); 223 ArCamera_getDisplayOrientedPose(arSession, ar_camera, camera_pose); 224 225 //Get camera raw info 226 float outCameraRaw[] = {0, 0, 0, 0, 0, 0, 0}; 227 ArPose_getPoseRaw(arSession, camera_pose, outCameraRaw); 228 ArPose_destroy(camera_pose); 229 230 //Write to out variables 231 cameraPos = glm::vec3(outCameraRaw[4], outCameraRaw[5], outCameraRaw[6]); 232 cameraRotation = util::GetCameraRotationMatrix(outCameraRaw); 233 234 //Release camera 235 ArCamera_release(ar_camera); 236 } 237 238 SkMatrix44 GlmMatToSkMat(const glm::mat4 m) { 239 SkMatrix44 skMat = SkMatrix44::kIdentity_Constructor; 240 for (int i = 0; i < 4; i++) { 241 for (int j = 0; j < 4; j++) { 242 skMat.set(j, i, m[i][j]); 243 } 244 } 245 return skMat; 246 } 247 248 glm::mat4 SkMatToGlmMat(const SkMatrix44 m) { 249 glm::mat4 glmMat(1); 250 for (int i = 0; i < 4; i++) { 251 for (int j = 0; j < 4; j++) { 252 glmMat[i][j] = m.get(j, i); 253 } 254 } 255 return glmMat; 256 } 257 258 void Log4x4Matrix(float raw_matrix[16]) { 259 LOGI( 260 "%f, %f, %f, %f\n" 261 "%f, %f, %f, %f\n" 262 "%f, %f, %f, %f\n" 263 "%f, %f, %f, %f\n", 264 raw_matrix[0], raw_matrix[1], raw_matrix[2], raw_matrix[3], raw_matrix[4], 265 raw_matrix[5], raw_matrix[6], raw_matrix[7], raw_matrix[8], raw_matrix[9], 266 raw_matrix[10], raw_matrix[11], raw_matrix[12], raw_matrix[13], 267 raw_matrix[14], raw_matrix[15]); 268 } 269 270 void LogGlmMat(glm::mat4 m, char *type) { 271 std::string str = glm::to_string(m); 272 LOGE("glm Matrix - %s: %s\n", type, str.c_str()); 273 } 274 275 void LogSkMat44(SkMatrix44 m, char *type) { 276 LOGE("SkMatrix - %s: [%g, %g, %g, %g] || [%g, %g, %g, %g] || [%g, %g, %g, %g] || [%g, %g, %g, %g] \n", 277 type, 278 m.get(0, 0), m.get(1, 0), m.get(2, 0), m.get(3, 0), 279 m.get(0, 1), m.get(1, 1), m.get(2, 1), m.get(3, 1), 280 m.get(0, 2), m.get(1, 2), m.get(2, 2), m.get(3, 2), 281 m.get(0, 3), m.get(1, 3), m.get(2, 3), m.get(3, 3) 282 ); 283 } 284 285 void LogSkMat(SkMatrix m, char *type) { 286 LOGE("SkMatrix - %s: [%g, %g, %g] || [%g, %g, %g] || [%g, %g, %g] \n", type, 287 m.get(0), m.get(3), m.get(6), 288 m.get(1), m.get(4), m.get(7), 289 m.get(2), m.get(5), m.get(8) 290 ); 291 } 292 293 void LogOrientation(float rotationDirection, float angleRad, char *type) { 294 LOGI("Plane orientation: %s", type); 295 LOGI("Cross dotted with zDir:", rotationDirection); 296 if (rotationDirection == -1) { 297 LOGI("Counter Clockwise %.6f degrees rotation: ", glm::degrees(angleRad)); 298 } else { 299 LOGI("Clockwise %.6f degrees rotation: ", glm::degrees(angleRad)); 300 } 301 } 302 303 float Dot(glm::vec3 u, glm::vec3 v) { 304 float result = u.x * v.x + u.y * v.y + u.z * v.z; 305 return result; 306 } 307 308 float Magnitude(glm::vec3 u) { 309 float result = u.x * u.x + u.y * u.y + u.z * u.z; 310 return sqrt(result); 311 } 312 313 float AngleRad(glm::vec3 u, glm::vec3 v) { 314 float dot = util::Dot(u, v); 315 float scale = (util::Magnitude(u) * util::Magnitude(v)); 316 float cosine = dot / scale; 317 float acosine = acos(cosine); 318 return acosine; 319 } 320 321 glm::vec3 ProjectOntoPlane(glm::vec3 in, glm::vec3 normal) { 322 float dot = util::Dot(in, normal); 323 float multiplier = dot / (util::Magnitude(normal) * util::Magnitude(normal)); 324 glm::vec3 out = in - multiplier * normal; 325 return out; 326 } 327 328 } // namespace util 329 } // namespace hello_ar 330