/*
* Copyright 2016 MovingBlocks
*
* 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.terasology.rendering.openvrprovider;
import jopenvr.HmdMatrix34_t;
import jopenvr.HmdMatrix44_t;
import jopenvr.VRControllerState_t;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.joml.Vector4f;
/**
* Utility functions that don't interact with the headset (conversions and the like).
*/
public final class OpenVRUtil {
private OpenVRUtil() {
// Not called
}
static void setSteamVRMatrix3ToMatrix4f(HmdMatrix34_t hmdMatrix, Matrix4f matrixToSet) {
matrixToSet.set(
hmdMatrix.m[0], hmdMatrix.m[4], hmdMatrix.m[8], 0,
hmdMatrix.m[1], hmdMatrix.m[5], hmdMatrix.m[9], 0,
hmdMatrix.m[2], hmdMatrix.m[6], hmdMatrix.m[10], 0,
hmdMatrix.m[3], hmdMatrix.m[7], hmdMatrix.m[11], 1f
);
}
static void setSteamVRMatrix44ToMatrix4f(HmdMatrix44_t hmdMatrix, Matrix4f matrixToSet) {
matrixToSet.set(
hmdMatrix.m[0], hmdMatrix.m[4], hmdMatrix.m[8], hmdMatrix.m[12],
hmdMatrix.m[1], hmdMatrix.m[5], hmdMatrix.m[9], hmdMatrix.m[13],
hmdMatrix.m[2], hmdMatrix.m[6], hmdMatrix.m[10], hmdMatrix.m[14],
hmdMatrix.m[3], hmdMatrix.m[7], hmdMatrix.m[11], hmdMatrix.m[15]
);
}
public static VRControllerState_t createZeroControllerState() {
VRControllerState_t state = new VRControllerState_t();
// controller not connected, clear state
state.ulButtonPressed = 0;
for (int i = 0; i < 5; i++) {
if (state.rAxis[i] != null) {
state.rAxis[i].x = 0.0f;
state.rAxis[i].y = 0.0f;
}
}
return state;
}
public static boolean isPressed(long nButton, long uiButtonPressed) {
return ((uiButtonPressed & nButton) > 0);
}
public static boolean switchedDown(long nButton, long stateBefore, long stateAfter) {
return (!isPressed(nButton, stateBefore) && isPressed(nButton, stateAfter));
}
public static boolean switchedUp(long nButton, long stateBefore, long stateAfter) {
return (isPressed(nButton, stateBefore) && !isPressed(nButton, stateAfter));
}
/*
* Takes 3 unit vectors, representing an orthonormal basis, and generates a unit quaternion.
*/
public static Vector4f getQuaternion(boolean normalizeAxes,
float xxInput, float xyInput, float xzInput,
float yxInput, float yyInput, float yzInput,
float zxInput, float zyInput, float zzInput) {
float xx = xxInput;
float xy = xyInput;
float xz = xzInput;
float yx = yxInput;
float yy = yyInput;
float yz = yzInput;
float zx = zxInput;
float zy = zyInput;
float zz = zzInput;
float x;
float y;
float z;
float w;
if (normalizeAxes) {
final float lx = 1f / new Vector3f(xx, xy, xz).length();
final float ly = 1f / new Vector3f(yx, yy, yz).length();
final float lz = 1f / new Vector3f(zx, zy, zz).length();
xx *= lx;
xy *= lx;
xz *= lx;
yx *= ly;
yy *= ly;
yz *= ly;
zx *= lz;
zy *= lz;
zz *= lz;
}
// the trace is the sum of the diagonal elements; see
// http://mathworld.wolfram.com/MatrixTrace.html
final float t = xx + yy + zz;
// we protect the division by s by ensuring that s>=1
if (t >= 0) { // |w| >= .5
float s = (float) Math.sqrt(t + 1); // |s|>=1 ...
w = 0.5f * s;
s = 0.5f / s; // so this division isn't bad
x = (zy - yz) * s;
y = (xz - zx) * s;
z = (yx - xy) * s;
} else if ((xx > yy) && (xx > zz)) {
float s = (float) Math.sqrt(1.0 + xx - yy - zz); // |s|>=1
x = s * 0.5f; // |x| >= .5
s = 0.5f / s;
y = (yx + xy) * s;
z = (xz + zx) * s;
w = (zy - yz) * s;
} else if (yy > zz) {
float s = (float) Math.sqrt(1.0 + yy - xx - zz); // |s|>=1
y = s * 0.5f; // |y| >= .5
s = 0.5f / s;
x = (yx + xy) * s;
z = (zy + yz) * s;
w = (xz - zx) * s;
} else {
float s = (float) Math.sqrt(1.0 + zz - xx - yy); // |s|>=1
z = s * 0.5f; // |z| >= .5
s = 0.5f / s;
x = (xz + zx) * s;
y = (zy + yz) * s;
w = (yx - xy) * s;
}
return new Vector4f(x, y, z, w);
}
/*
* Converts the rotation portion of a 4x4 matrix into a unit quaternion.
*/
public static Vector4f convertToQuaternion(Matrix4f m1) {
return getQuaternion(true,
m1.m00(), m1.m10(), m1.m20(),
m1.m01(), m1.m11(), m1.m21(),
m1.m02(), m1.m12(), m1.m22()
);
}
static Matrix4f createIdentityMatrix4f() {
return new Matrix4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
}