blob: de4945d92bea452be4113eb9e8651eb1a40717ce [file] [log] [blame]
/*
* 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.
*/
package com.google.vr.sdk.samples.hellovr;
import static android.opengl.GLU.gluErrorString;
import android.opengl.GLES20;
import android.opengl.Matrix;
import android.text.TextUtils;
import android.util.Log;
/** Utility functions. */
/* package */ class Util {
private static final String TAG = "Util";
/** Debug builds should fail quickly. Release versions of the app should have this disabled. */
private static final boolean HALT_ON_GL_ERROR = true;
/** Class only contains static methods. */
private Util() {}
/**
* Checks GLES20.glGetError and fails quickly if the state isn't GL_NO_ERROR.
*
* @param label Label to report in case of error.
*/
public static void checkGlError(String label) {
int error = GLES20.glGetError();
int lastError;
if (error != GLES20.GL_NO_ERROR) {
do {
lastError = error;
Log.e(TAG, label + ": glError " + gluErrorString(lastError));
error = GLES20.glGetError();
} while (error != GLES20.GL_NO_ERROR);
if (HALT_ON_GL_ERROR) {
throw new RuntimeException("glError " + gluErrorString(lastError));
}
}
}
/**
* Builds a GL shader program from vertex & fragment shader code. The vertex and fragment shaders
* are passed as arrays of strings in order to make debugging compilation issues easier.
*
* @param vertexCode GLES20 vertex shader program.
* @param fragmentCode GLES20 fragment shader program.
* @return GLES20 program id.
*/
public static int compileProgram(String[] vertexCode, String[] fragmentCode) {
checkGlError("Start of compileProgram");
// prepare shaders and OpenGL program
int vertexShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
GLES20.glShaderSource(vertexShader, TextUtils.join("\n", vertexCode));
GLES20.glCompileShader(vertexShader);
checkGlError("Compile vertex shader");
int fragmentShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
GLES20.glShaderSource(fragmentShader, TextUtils.join("\n", fragmentCode));
GLES20.glCompileShader(fragmentShader);
checkGlError("Compile fragment shader");
int program = GLES20.glCreateProgram();
GLES20.glAttachShader(program, vertexShader);
GLES20.glAttachShader(program, fragmentShader);
// Link and check for errors.
GLES20.glLinkProgram(program);
int[] linkStatus = new int[1];
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] != GLES20.GL_TRUE) {
String errorMsg = "Unable to link shader program: \n" + GLES20.glGetProgramInfoLog(program);
Log.e(TAG, errorMsg);
if (HALT_ON_GL_ERROR) {
throw new RuntimeException(errorMsg);
}
}
checkGlError("End of compileProgram");
return program;
}
/**
* Computes the angle between two vectors; see
* https://en.wikipedia.org/wiki/Vector_projection#Definitions_in_terms_of_a_and_b.
*/
public static float angleBetweenVectors(float[] vec1, float[] vec2) {
float cosOfAngle = dotProduct(vec1, vec2) / (vectorNorm(vec1) * vectorNorm(vec2));
return (float) Math.acos(Math.max(-1.0f, Math.min(1.0f, cosOfAngle)));
}
private static float dotProduct(float[] vec1, float[] vec2) {
return vec1[0] * vec2[0] + vec1[1] * vec2[1] + vec1[2] * vec2[2];
}
private static float vectorNorm(float[] vec) {
return Matrix.length(vec[0], vec[1], vec[2]);
}
}