/* * Copyright (c) 2003-onwards Shaven Puppy Ltd * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of 'Shaven Puppy' nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.shavenpuppy.jglib.util; /** * Fixed-point math routines */ public final class FPMath { private static final float INV = 1.0f/65536.0f; private static final double INVD = 1.0/65536.0; /** Handy constants */ public static final int SIXTEEN = FPMath.fpValue(16); public static final int EIGHT = FPMath.fpValue(8); public static final int FOUR = FPMath.fpValue(4); public static final int TWO = FPMath.fpValue(2); public static final int ONE = FPMath.fpValue(1); public static final int MINUSONE = FPMath.fpValue(-1); public static final int HALF = FPMath.fpValue(0.5); public static final int QUARTER = FPMath.fpValue(0.25); public static final int EIGHTH = FPMath.fpValue(0.125); public static final int SIXTEENTH = FPMath.fpValue(0.0625); public static final int THIRTYTWOTH = FPMath.fpValue(0.03125); public static final int PI = FPMath.fpValue(Math.PI); public static final int PIBY2 = FPMath.fpValue(Math.PI * 0.5); public static final int PITIMES2 = FPMath.fpValue(Math.PI * 2.0); /** * Cosine table */ private static final int[] cos = new int[65536]; static { for (int i = 0; i < 65536; i ++) { cos[i] = fpValue(Math.cos(i * Math.PI / 32768.0)); } } /** No constructor */ private FPMath() {} /** * Parse an FP value from a String. IF the string is terminated with the * characters "fp" then they are ignored. * @param in * @return a fixed-point value * @throws NumberFormatException */ public static int parse(String in) throws NumberFormatException { if (in.endsWith("fp")) { return fpValue(Float.parseFloat(in.substring(0, in.length() - 2))); } else { return fpValue(Float.parseFloat(in)); } } /** * Square root. * @param v A value in 16:16 FP * @return the square root of V in 16:16 FP */ public static final int sqrt(int len) { return FPMath.fpValue(Math.sqrt(FPMath.doubleValue(len))); } /** * Square root. * @param v A value in 16:16 FP stored in a long (top 32 bits ignored!) * @return the square root of V in 16:16 FP */ public static final int sqrt(long len) { return FPMath.fpValue(Math.sqrt(FPMath.doubleValue(len))); } /** * Multiply two fixed point math numbers together * @param a * @param b * @return a fixed point value */ public static int mul(int a, int b) { long aa = a; long bb = b; long cc = aa * bb; return (int)(cc >> 16L); /* long aa = ((long)a) & 0xFFFFL; long bb = ((long)b) & 0xFFFFL; long a8 = ((long)a) >> 8; long b8 = ((long)b) >> 8; return (int) ((a8) * (b8) +((aa * (b8)) >> 8L) +(((a8) * bb) >> 8L) +((aa * bb) >> 16)); // Note: this line can be removed to sacrifice a little accuracy for more speed */ } /** * Multiply two fixed point math numbers together * returning the result in a long * @param a * @param b * @return a fixed point value */ public static long lmul(int a, int b) { long aa = a; long bb = b; long cc = aa * bb; return cc >> 16L; /* long aa = ((long)a) & 0xFFFFL; long bb = ((long)b) & 0xFFFFL; long a8 = ((long)a) >> 8; long b8 = ((long)b) >> 8; return (a8) * (b8) +((aa * (b8)) >> 8L) +(((a8) * bb) >> 8L) +((aa * bb) >> 16); // Note: this line can be removed to sacrifice a little accuracy for more speed */ } /** * Divide a fixed point maths number * @param num The numerator * @param den The denominator * @return a fixed point value */ public static int div(int num, int den) { if (den == 0) { return 0; } else { return (int)((((long)num << 32L) / den) >> 16L); // if (den == 0) // return 0; // else // return (num << 16) / den; //return fpValue(floatValue(num) / floatValue(den)); } } /** * Convert a fixed point number to an int * @param fp * @return int */ public static int intValue(int fp) { return fp >> 16; } /** * Convert a fixed point number to an int * @param fp * @return int */ public static int intValue(long fp) { return (int)(fp >> 16); } /** * Convert a float to a fixed point * @param f * @return fp */ public static int fpValue(float f) { return (int)(f * 65536.0f); } /** * Convert a double to a fixed point * @param f * @return fp */ public static int fpValue(double f) { return (int)(f * 65536.0); } /** * Convert a fixed point number to a float * @param fp * @return int */ public static float floatValue(int fp) { return fp * INV; } /** * Convert a fixed point number to a double * @param fp * @return int */ public static double doubleValue(long fp) { return fp * INVD; } /** * Convert an int to a fixed point value * @param int * @return fp */ public static int fpValue(int i) { return i << 16; } /** * Cosines. This is very approximate cosine. * @param theta The angle, in 16:16 Yakly Degrees * @return cos(theta) in 16:16 */ public static int cos(int theta) { return cos[theta & 0xFFFF]; } /** * Sines. This is very approximate sine. * @param theta The angle, in 16:16 Yakly Degrees * @return sin(theta) in 16:16 */ public static int sin(int theta) { return cos[(theta - 16384) & 0xFFFF]; } /** * Convert an angle in floating point radians to 16:16 Yakly degrees * @param theta The angle, in floating point radians * @return The angle, in 16:16 Yakly degrees */ public static int fpYaklyDegrees(float theta) { int yakTheta = ((int)(theta * 32768.0f / Math.PI)) & 0xFFFF; return yakTheta; } /** * Convert an angle in floating point radians to 16:16 Yakly degrees * @param theta The angle, in floating point radians * @return The angle, in 16:16 Yakly degrees */ public static int fpYaklyDegrees(double theta) { return ((int)(theta * 32768.0 / Math.PI)) & 0xFFFF; } }