package org.jrenner.fps; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Preferences; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g3d.utils.MeshPartBuilder; import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder; import com.badlogic.gdx.math.GeometryUtils; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Matrix4; import com.badlogic.gdx.math.Quaternion; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.physics.bullet.linearmath.btVector3; import com.badlogic.gdx.utils.Disposable; import com.badlogic.gdx.utils.GdxRuntimeException; import com.badlogic.gdx.utils.NumberUtils; import com.badlogic.gdx.utils.Pool; import com.badlogic.gdx.utils.StringBuilder; import java.util.Arrays; /** a messy junk drawer */ // TODO clean up this junk! public class Tools { public static String fmt(float f, String name) { if (name == null) name = ""; return String.format("%s: %.3f", name, f); } public static String fmt(float f) { return fmt(f, null); } public static void print(float f) { print(f, null); } public static void print(float f, String name) { System.out.println(fmt(f, name)); } public static String fmt(Vector3 vec) { return fmt(vec, null); } public static String fmt(Vector3 vec, String name) { if (name == null) name = ""; return String.format("(V3) %s x: %.3f, y: %.3f, z: %.3f", name, vec.x, vec.y, vec.z); } public static String fmt(Vector3 vec, int precision) { return fmt(vec, "", precision); } public static String fmt(Vector3 vec, String name, int precision) { if (name == null) name = ""; String base = "(V3) %s x: %.PRECf, y: %.PRECf, z: %.PRECf"; String fmtString = base.replaceAll("PREC", Integer.toString(precision)); return String.format(fmtString, name, vec.x, vec.y, vec.z); } public static void print(Vector3 vec) { print(vec, null); } public static void print(Vector3 vec, String name) { System.out.println(Tools.fmt(vec, name)); } public static String fmt(MeshPartBuilder.VertexInfo vi) { return fmt(vi, null); } public static String fmt(MeshPartBuilder.VertexInfo vi, String name) { if (name == null) name = ""; StringBuilder sb = new StringBuilder(); sb.append("VertexInfo: ").append(name).append("\n"); sb.append("\t").append(fmt(vi.position, "position")).append("\n"); sb.append("\t").append(fmt(vi.color)).append("\n"); sb.append("\t").append(fmt(vi.normal, "normal")); return sb.toString(); } public static void print(MeshPartBuilder.VertexInfo vi) { System.out.println(fmt(vi, null)); } public static void print(MeshPartBuilder.VertexInfo vi, String name) { System.out.println(fmt(vi, name)); } public static String fmt(Color color, String name) { if (name == null) name = ""; return String.format("(Color) %s R:%.1f G:%.1f B:%.1f A:%.1f", name, color.r, color.g, color.b, color.a); } public static String fmt(Color color) { return fmt(color, null); } public static void print(Color color, String name) { System.out.println(Tools.fmt(color, name)); } public static void print(Color color) { print(color, null); } public static String fmt(Quaternion q, String name) { if (name == null) name = ""; return String.format("(Q %s) - yaw: %.0f, pitch: %.0f, roll: %.0f -- w: %.2f, x: %.2f, y: %.2f, z: %.2f", name, q.getYaw(), q.getPitch(), q.getRoll(), q.w, q.x, q.y, q.z); } public static String fmt(Quaternion q) { return fmt(q, null); } public static void print(Quaternion q, String name) { System.out.println(fmt(q, name)); } public static void print(Quaternion q) { System.out.println(fmt(q, null)); } private static Matrix4 mtx = new Matrix4(); private static Quaternion q = new Quaternion(); public static void rotateAround(Vector3 position, Vector3 axis, float angle) { q.setFromAxis(axis, angle); mtx.set(q); position.prj(mtx); /*tmp.set(point); tmp.sub(position); position.add(tmp); position.rotate(axis, angle); tmp.rotate(axis, angle); position.add(-tmp.x, -tmp.y, -tmp.z);*/ } public static void sleep(long ms) { try { Thread.sleep(ms); } catch (InterruptedException e) { e.printStackTrace(); } } private static Vector3 crsTmp = new Vector3(); public static Vector3 getDownFromVector(Vector3 vec) { crsTmp.set(vec).nor(); crsTmp.crs(Vector3.Y); // cross by world up to get a right handle angle vector (facing forward) tmp.set(vec).nor(); return tmp.crs(crsTmp).nor(); // get the relative "down" } public static Vector3 getUpFromVector(Vector3 vec) { crsTmp.set(vec).nor(); crsTmp.crs(Vector3.Y); // cross by world up to get a right handle angle vector (facing forward) tmp.set(vec).nor(); return crsTmp.crs(tmp).nor(); // get the relative "down" } public static Vector3 getRightFromVector(Vector3 vec) { crsTmp.set(vec).nor(); crsTmp.crs(Vector3.Y); // cross by world up to get a right handle angle vector //Tools.print(crsTmp, "right"); //Tools.print(vec, "original"); return crsTmp.nor(); } public static Vector3 getLeftFromVector(Vector3 vec) { crsTmp.set(vec).nor(); tmp.set(Vector3.Y).crs(crsTmp); return tmp.nor(); } /** return angle in degrees */ public static float getAngleFromAtoB(Vector2 a, Vector2 b) { float rawAngle = (float) Math.toDegrees(Math.atan2(b.y - a.y, b.x - a.x)); return (rawAngle - 90) % 360; } public static float getAngleFromAtoB(float ax, float ay, float bx, float by) { return (float) Math.toDegrees(Math.atan2(by - ay, bx - ax)); } private static Vector2 va = new Vector2(); private static Vector2 vb = new Vector2(); public static float getAngleFromAtoB(Vector3 a, Vector3 b, Vector3 axis) { if (axis.equals(Vector3.Y)) { va.set(a.x, a.z); vb.set(b.x, b.z); return getAngleFromAtoB(va, vb); } else { throw new IllegalArgumentException("bad argument for vector angle"); } } static Vector3 tmp = new Vector3(); static Vector3 tmp2 = new Vector3(); static Vector3 tmp3 = new Vector3(); /** thanks to lordjone from #libgdx! */ public static void faceDirectionZ(Quaternion q, Vector3 direction) { Vector3 axisZ = tmp.set(direction).nor(); Vector3 axisY = tmp2.set(tmp).crs(Vector3.Y).nor().crs(tmp).nor(); Vector3 axisX = tmp3.set(axisY).crs(axisZ).nor(); q.setFromAxes(false, axisX.x, axisY.x, axisZ.x, axisX.y, axisY.y, axisZ.y, axisX.z, axisY.z, axisZ.z); } public static void faceDirectionY(Quaternion q, Vector3 direction) { throw new GdxRuntimeException("THIS IS NOT WORKING! DONT USE IT!"); /*Vector3 axisZ = tmp.set(direction).nor(); Vector3 axisY = tmp2.set(tmp).crs(Vector3.X).nor().crs(tmp).nor(); Vector3 axisX = tmp3.set(axisY).crs(axisZ).nor(); q.setFromAxes(false, axisX.x, axisY.x, axisZ.x, axisX.y, axisY.y, axisZ.y, axisX.z, axisY.z, axisZ.z);*/ } public static float constrainAngle180(float angle) { while (angle > 180) { angle = angle - 360; } while (angle < -180) { angle = angle + 360; } return angle; } // TODO This algorithm is bad, but it's random enough for now public static Vector3 randomUnitVector() { float x = MathUtils.random(0f, 1f); float y = MathUtils.random(0f, 1f); float z = MathUtils.random(0f, 1f); return tmp.set(x, y, z).nor(); } public static Color randomColor(float lo, float hi) { Color col = new Color(); col.r = MathUtils.random(lo, hi); col.g = MathUtils.random(lo, hi); col.b = MathUtils.random(lo, hi); col.a = 1f; return col; } public static Color randomColor() { return randomColor(0f, 1f); } public static void calculateRectFaceNormal(Vector3 norm, Vector3 a, Vector3 b) { a.nor(); b.nor(); norm.set(b).crs(a).nor(); } public static void arraySwap(Object[] arr, int i1, int i2) { Object tmp = arr[i1]; arr[i1] = arr[i2]; arr[i2] = tmp; } public static void reverseArray(Object[] arr) { for (int i = 0, j = arr.length - 1; i < j; i++, j--) { Object tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } } public static void dispose(Disposable disp) { dispose(disp, ""); } public static void dispose(Disposable disp, String name) { Log.debug("dispose: " + name + " -- " + disp); disp.dispose(); } public static Preferences getPrefs(String name) { return Gdx.app.getPreferences("org.jrenner.fps." + name); } public static float readFloatFromBytes(byte[] bytes, int offset) { int i = 0; int value = bytes[0 + offset] & 0xFF; value |= bytes[1 + offset]<<(8) & 0xFFFF; value |= bytes[2 + offset]<<(16) & 0xFFFFFF; value |= bytes[3 + offset]<<(24) & 0xFFFFFFFF; return NumberUtils.intBitsToFloat(value); } public static int writeFloatToBytes(float f, byte[] bytes, int offset) { int value = NumberUtils.floatToIntBits(f); bytes[0 + offset] = (byte) (value & 0xFF); bytes[1 + offset] = (byte) (value>>8 & 0xFF); bytes[2 + offset] = (byte) (value>>16 & 0xFF); bytes[3 + offset] = (byte) (value>>24 & 0xFF); // return next idx return offset + 4; } }