1/*
2 * Copyright (c) 2009-2010 jMonkeyEngine
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 *   notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 *   notice, this list of conditions and the following disclaimer in the
14 *   documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 *   may be used to endorse or promote products derived from this software
18 *   without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32package com.jme3.math;
33
34import java.util.Random;
35
36/**
37 * <code>FastMath</code> provides 'fast' math approximations and float equivalents of Math
38 * functions.  These are all used as static values and functions.
39 *
40 * @author Various
41 * @version $Id: FastMath.java,v 1.45 2007/08/26 08:44:20 irrisor Exp $
42 */
43final public class FastMath {
44
45    private FastMath() {
46    }
47    /** A "close to zero" double epsilon value for use*/
48    public static final double DBL_EPSILON = 2.220446049250313E-16d;
49    /** A "close to zero" float epsilon value for use*/
50    public static final float FLT_EPSILON = 1.1920928955078125E-7f;
51    /** A "close to zero" float epsilon value for use*/
52    public static final float ZERO_TOLERANCE = 0.0001f;
53    public static final float ONE_THIRD = 1f / 3f;
54    /** The value PI as a float. (180 degrees) */
55    public static final float PI = (float) Math.PI;
56    /** The value 2PI as a float. (360 degrees) */
57    public static final float TWO_PI = 2.0f * PI;
58    /** The value PI/2 as a float. (90 degrees) */
59    public static final float HALF_PI = 0.5f * PI;
60    /** The value PI/4 as a float. (45 degrees) */
61    public static final float QUARTER_PI = 0.25f * PI;
62    /** The value 1/PI as a float. */
63    public static final float INV_PI = 1.0f / PI;
64    /** The value 1/(2PI) as a float. */
65    public static final float INV_TWO_PI = 1.0f / TWO_PI;
66    /** A value to multiply a degree value by, to convert it to radians. */
67    public static final float DEG_TO_RAD = PI / 180.0f;
68    /** A value to multiply a radian value by, to convert it to degrees. */
69    public static final float RAD_TO_DEG = 180.0f / PI;
70    /** A precreated random object for random numbers. */
71    public static final Random rand = new Random(System.currentTimeMillis());
72
73    /**
74     * Returns true if the number is a power of 2 (2,4,8,16...)
75     *
76     * A good implementation found on the Java boards. note: a number is a power
77     * of two if and only if it is the smallest number with that number of
78     * significant bits. Therefore, if you subtract 1, you know that the new
79     * number will have fewer bits, so ANDing the original number with anything
80     * less than it will give 0.
81     *
82     * @param number
83     *            The number to test.
84     * @return True if it is a power of two.
85     */
86    public static boolean isPowerOfTwo(int number) {
87        return (number > 0) && (number & (number - 1)) == 0;
88    }
89
90    public static int nearestPowerOfTwo(int number) {
91        return (int) Math.pow(2, Math.ceil(Math.log(number) / Math.log(2)));
92    }
93
94    /**
95     * Linear interpolation from startValue to endValue by the given percent.
96     * Basically: ((1 - percent) * startValue) + (percent * endValue)
97     *
98     * @param scale
99     *            scale value to use. if 1, use endValue, if 0, use startValue.
100     * @param startValue
101     *            Begining value. 0% of f
102     * @param endValue
103     *            ending value. 100% of f
104     * @return The interpolated value between startValue and endValue.
105     */
106    public static float interpolateLinear(float scale, float startValue, float endValue) {
107        if (startValue == endValue) {
108            return startValue;
109        }
110        if (scale <= 0f) {
111            return startValue;
112        }
113        if (scale >= 1f) {
114            return endValue;
115        }
116        return ((1f - scale) * startValue) + (scale * endValue);
117    }
118
119    /**
120     * Linear interpolation from startValue to endValue by the given percent.
121     * Basically: ((1 - percent) * startValue) + (percent * endValue)
122     *
123     * @param scale
124     *            scale value to use. if 1, use endValue, if 0, use startValue.
125     * @param startValue
126     *            Begining value. 0% of f
127     * @param endValue
128     *            ending value. 100% of f
129     * @param store a vector3f to store the result
130     * @return The interpolated value between startValue and endValue.
131     */
132    public static Vector3f interpolateLinear(float scale, Vector3f startValue, Vector3f endValue, Vector3f store) {
133        if (store == null) {
134            store = new Vector3f();
135        }
136        store.x = interpolateLinear(scale, startValue.x, endValue.x);
137        store.y = interpolateLinear(scale, startValue.y, endValue.y);
138        store.z = interpolateLinear(scale, startValue.z, endValue.z);
139        return store;
140    }
141
142    /**
143     * Linear interpolation from startValue to endValue by the given percent.
144     * Basically: ((1 - percent) * startValue) + (percent * endValue)
145     *
146     * @param scale
147     *            scale value to use. if 1, use endValue, if 0, use startValue.
148     * @param startValue
149     *            Begining value. 0% of f
150     * @param endValue
151     *            ending value. 100% of f
152     * @return The interpolated value between startValue and endValue.
153     */
154    public static Vector3f interpolateLinear(float scale, Vector3f startValue, Vector3f endValue) {
155        return interpolateLinear(scale, startValue, endValue, null);
156    }
157
158    /**
159     * Linear extrapolation from startValue to endValue by the given scale.
160     * if scale is between 0 and 1 this method returns the same result as interpolateLinear
161     * if the scale is over 1 the value is linearly extrapolated.
162     * Note that the end value is the value for a scale of 1.
163     * @param scale the scale for extrapolation
164     * @param startValue the starting value (scale = 0)
165     * @param endValue the end value (scale = 1)
166     * @return an extrapolation for the given parameters
167     */
168    public static float extrapolateLinear(float scale, float startValue, float endValue) {
169//        if (scale <= 0f) {
170//            return startValue;
171//        }
172        return ((1f - scale) * startValue) + (scale * endValue);
173    }
174
175    /**
176     * Linear extrapolation from startValue to endValue by the given scale.
177     * if scale is between 0 and 1 this method returns the same result as interpolateLinear
178     * if the scale is over 1 the value is linearly extrapolated.
179     * Note that the end value is the value for a scale of 1.
180     * @param scale the scale for extrapolation
181     * @param startValue the starting value (scale = 0)
182     * @param endValue the end value (scale = 1)
183     * @param store an initialized vector to store the return value
184     * @return an extrapolation for the given parameters
185     */
186    public static Vector3f extrapolateLinear(float scale, Vector3f startValue, Vector3f endValue, Vector3f store) {
187        if (store == null) {
188            store = new Vector3f();
189        }
190//        if (scale <= 1f) {
191//            return interpolateLinear(scale, startValue, endValue, store);
192//        }
193        store.x = extrapolateLinear(scale, startValue.x, endValue.x);
194        store.y = extrapolateLinear(scale, startValue.y, endValue.y);
195        store.z = extrapolateLinear(scale, startValue.z, endValue.z);
196        return store;
197    }
198
199    /**
200     * Linear extrapolation from startValue to endValue by the given scale.
201     * if scale is between 0 and 1 this method returns the same result as interpolateLinear
202     * if the scale is over 1 the value is linearly extrapolated.
203     * Note that the end value is the value for a scale of 1.
204     * @param scale the scale for extrapolation
205     * @param startValue the starting value (scale = 0)
206     * @param endValue the end value (scale = 1)
207     * @return an extrapolation for the given parameters
208     */
209    public static Vector3f extrapolateLinear(float scale, Vector3f startValue, Vector3f endValue) {
210        return extrapolateLinear(scale, startValue, endValue, null);
211    }
212
213    /**Interpolate a spline between at least 4 control points following the Catmull-Rom equation.
214     * here is the interpolation matrix
215     * m = [ 0.0  1.0  0.0   0.0 ]
216     *     [-T    0.0  T     0.0 ]
217     *     [ 2T   T-3  3-2T  -T  ]
218     *     [-T    2-T  T-2   T   ]
219     * where T is the curve tension
220     * the result is a value between p1 and p2, t=0 for p1, t=1 for p2
221     * @param u value from 0 to 1
222     * @param T The tension of the curve
223     * @param p0 control point 0
224     * @param p1 control point 1
225     * @param p2 control point 2
226     * @param p3 control point 3
227     * @return catmull-Rom interpolation
228     */
229    public static float interpolateCatmullRom(float u, float T, float p0, float p1, float p2, float p3) {
230        float c1, c2, c3, c4;
231        c1 = p1;
232        c2 = -1.0f * T * p0 + T * p2;
233        c3 = 2 * T * p0 + (T - 3) * p1 + (3 - 2 * T) * p2 + -T * p3;
234        c4 = -T * p0 + (2 - T) * p1 + (T - 2) * p2 + T * p3;
235
236        return (float) (((c4 * u + c3) * u + c2) * u + c1);
237    }
238
239    /**Interpolate a spline between at least 4 control points following the Catmull-Rom equation.
240     * here is the interpolation matrix
241     * m = [ 0.0  1.0  0.0   0.0 ]
242     *     [-T    0.0  T     0.0 ]
243     *     [ 2T   T-3  3-2T  -T  ]
244     *     [-T    2-T  T-2   T   ]
245     * where T is the tension of the curve
246     * the result is a value between p1 and p2, t=0 for p1, t=1 for p2
247     * @param u value from 0 to 1
248     * @param T The tension of the curve
249     * @param p0 control point 0
250     * @param p1 control point 1
251     * @param p2 control point 2
252     * @param p3 control point 3
253     * @param store a Vector3f to store the result
254     * @return catmull-Rom interpolation
255     */
256    public static Vector3f interpolateCatmullRom(float u, float T, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3, Vector3f store) {
257        if (store == null) {
258            store = new Vector3f();
259        }
260        store.x = interpolateCatmullRom(u, T, p0.x, p1.x, p2.x, p3.x);
261        store.y = interpolateCatmullRom(u, T, p0.y, p1.y, p2.y, p3.y);
262        store.z = interpolateCatmullRom(u, T, p0.z, p1.z, p2.z, p3.z);
263        return store;
264    }
265
266    /**Interpolate a spline between at least 4 control points following the Catmull-Rom equation.
267     * here is the interpolation matrix
268     * m = [ 0.0  1.0  0.0   0.0 ]
269     *     [-T    0.0  T     0.0 ]
270     *     [ 2T   T-3  3-2T  -T  ]
271     *     [-T    2-T  T-2   T   ]
272     * where T is the tension of the curve
273     * the result is a value between p1 and p2, t=0 for p1, t=1 for p2
274     * @param u value from 0 to 1
275     * @param T The tension of the curve
276     * @param p0 control point 0
277     * @param p1 control point 1
278     * @param p2 control point 2
279     * @param p3 control point 3
280     * @return catmull-Rom interpolation
281     */
282    public static Vector3f interpolateCatmullRom(float u, float T, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) {
283        return interpolateCatmullRom(u, T, p0, p1, p2, p3, null);
284    }
285
286    /**Interpolate a spline between at least 4 control points following the Bezier equation.
287     * here is the interpolation matrix
288     * m = [ -1.0   3.0  -3.0    1.0 ]
289     *     [  3.0  -6.0   3.0    0.0 ]
290     *     [ -3.0   3.0   0.0    0.0 ]
291     *     [  1.0   0.0   0.0    0.0 ]
292     * where T is the curve tension
293     * the result is a value between p1 and p3, t=0 for p1, t=1 for p3
294     * @param u value from 0 to 1
295     * @param p0 control point 0
296     * @param p1 control point 1
297     * @param p2 control point 2
298     * @param p3 control point 3
299     * @return Bezier interpolation
300     */
301    public static float interpolateBezier(float u, float p0, float p1, float p2, float p3) {
302        float oneMinusU = 1.0f - u;
303        float oneMinusU2 = oneMinusU * oneMinusU;
304        float u2 = u * u;
305        return p0 * oneMinusU2 * oneMinusU
306                + 3.0f * p1 * u * oneMinusU2
307                + 3.0f * p2 * u2 * oneMinusU
308                + p3 * u2 * u;
309    }
310
311    /**Interpolate a spline between at least 4 control points following the Bezier equation.
312     * here is the interpolation matrix
313     * m = [ -1.0   3.0  -3.0    1.0 ]
314     *     [  3.0  -6.0   3.0    0.0 ]
315     *     [ -3.0   3.0   0.0    0.0 ]
316     *     [  1.0   0.0   0.0    0.0 ]
317     * where T is the tension of the curve
318     * the result is a value between p1 and p3, t=0 for p1, t=1 for p3
319     * @param u value from 0 to 1
320     * @param p0 control point 0
321     * @param p1 control point 1
322     * @param p2 control point 2
323     * @param p3 control point 3
324     * @param store a Vector3f to store the result
325     * @return Bezier interpolation
326     */
327    public static Vector3f interpolateBezier(float u, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3, Vector3f store) {
328        if (store == null) {
329            store = new Vector3f();
330        }
331        store.x = interpolateBezier(u, p0.x, p1.x, p2.x, p3.x);
332        store.y = interpolateBezier(u, p0.y, p1.y, p2.y, p3.y);
333        store.z = interpolateBezier(u, p0.z, p1.z, p2.z, p3.z);
334        return store;
335    }
336
337    /**Interpolate a spline between at least 4 control points following the Bezier equation.
338     * here is the interpolation matrix
339     * m = [ -1.0   3.0  -3.0    1.0 ]
340     *     [  3.0  -6.0   3.0    0.0 ]
341     *     [ -3.0   3.0   0.0    0.0 ]
342     *     [  1.0   0.0   0.0    0.0 ]
343     * where T is the tension of the curve
344     * the result is a value between p1 and p3, t=0 for p1, t=1 for p3
345     * @param u value from 0 to 1
346     * @param p0 control point 0
347     * @param p1 control point 1
348     * @param p2 control point 2
349     * @param p3 control point 3
350     * @return Bezier interpolation
351     */
352    public static Vector3f interpolateBezier(float u, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) {
353        return interpolateBezier(u, p0, p1, p2, p3, null);
354    }
355
356    /**
357     * Compute the lenght on a catmull rom spline between control point 1 and 2
358     * @param p0 control point 0
359     * @param p1 control point 1
360     * @param p2 control point 2
361     * @param p3 control point 3
362     * @param startRange the starting range on the segment (use 0)
363     * @param endRange the end range on the segment (use 1)
364     * @param curveTension the curve tension
365     * @return the length of the segment
366     */
367    public static float getCatmullRomP1toP2Length(Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3, float startRange, float endRange, float curveTension) {
368
369        float epsilon = 0.001f;
370        float middleValue = (startRange + endRange) * 0.5f;
371        Vector3f start = p1.clone();
372        if (startRange != 0) {
373            FastMath.interpolateCatmullRom(startRange, curveTension, p0, p1, p2, p3, start);
374        }
375        Vector3f end = p2.clone();
376        if (endRange != 1) {
377            FastMath.interpolateCatmullRom(endRange, curveTension, p0, p1, p2, p3, end);
378        }
379        Vector3f middle = FastMath.interpolateCatmullRom(middleValue, curveTension, p0, p1, p2, p3);
380        float l = end.subtract(start).length();
381        float l1 = middle.subtract(start).length();
382        float l2 = end.subtract(middle).length();
383        float len = l1 + l2;
384        if (l + epsilon < len) {
385            l1 = getCatmullRomP1toP2Length(p0, p1, p2, p3, startRange, middleValue, curveTension);
386            l2 = getCatmullRomP1toP2Length(p0, p1, p2, p3, middleValue, endRange, curveTension);
387        }
388        l = l1 + l2;
389        return l;
390    }
391
392    /**
393     * Compute the lenght on a bezier spline between control point 1 and 2
394     * @param p0 control point 0
395     * @param p1 control point 1
396     * @param p2 control point 2
397     * @param p3 control point 3
398     * @return the length of the segment
399     */
400    public static float getBezierP1toP2Length(Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) {
401        float delta = 0.02f, t = 0.0f, result = 0.0f;
402        Vector3f v1 = p0.clone(), v2 = new Vector3f();
403        while (t <= 1.0f) {
404            FastMath.interpolateBezier(t, p0, p1, p2, p3, v2);
405            result += v1.subtractLocal(v2).length();
406            v1.set(v2);
407            t += delta;
408        }
409        return result;
410    }
411
412    /**
413     * Returns the arc cosine of an angle given in radians.<br>
414     * Special cases:
415     * <ul><li>If fValue is smaller than -1, then the result is PI.
416     * <li>If the argument is greater than 1, then the result is 0.</ul>
417     * @param fValue The angle, in radians.
418     * @return fValue's acos
419     * @see java.lang.Math#acos(double)
420     */
421    public static float acos(float fValue) {
422        if (-1.0f < fValue) {
423            if (fValue < 1.0f) {
424                return (float) Math.acos(fValue);
425            }
426
427            return 0.0f;
428        }
429
430        return PI;
431    }
432
433    /**
434     * Returns the arc sine of an angle given in radians.<br>
435     * Special cases:
436     * <ul><li>If fValue is smaller than -1, then the result is -HALF_PI.
437     * <li>If the argument is greater than 1, then the result is HALF_PI.</ul>
438     * @param fValue The angle, in radians.
439     * @return fValue's asin
440     * @see java.lang.Math#asin(double)
441     */
442    public static float asin(float fValue) {
443        if (-1.0f < fValue) {
444            if (fValue < 1.0f) {
445                return (float) Math.asin(fValue);
446            }
447
448            return HALF_PI;
449        }
450
451        return -HALF_PI;
452    }
453
454    /**
455     * Returns the arc tangent of an angle given in radians.<br>
456     * @param fValue The angle, in radians.
457     * @return fValue's atan
458     * @see java.lang.Math#atan(double)
459     */
460    public static float atan(float fValue) {
461        return (float) Math.atan(fValue);
462    }
463
464    /**
465     * A direct call to Math.atan2.
466     * @param fY
467     * @param fX
468     * @return Math.atan2(fY,fX)
469     * @see java.lang.Math#atan2(double, double)
470     */
471    public static float atan2(float fY, float fX) {
472        return (float) Math.atan2(fY, fX);
473    }
474
475    /**
476     * Rounds a fValue up.  A call to Math.ceil
477     * @param fValue The value.
478     * @return The fValue rounded up
479     * @see java.lang.Math#ceil(double)
480     */
481    public static float ceil(float fValue) {
482        return (float) Math.ceil(fValue);
483    }
484
485    /**
486     * Fast Trig functions for x86. This forces the trig functiosn to stay
487     * within the safe area on the x86 processor (-45 degrees to +45 degrees)
488     * The results may be very slightly off from what the Math and StrictMath
489     * trig functions give due to rounding in the angle reduction but it will be
490     * very very close.
491     *
492     * note: code from wiki posting on java.net by jeffpk
493     */
494    public static float reduceSinAngle(float radians) {
495        radians %= TWO_PI; // put us in -2PI to +2PI space
496        if (Math.abs(radians) > PI) { // put us in -PI to +PI space
497            radians = radians - (TWO_PI);
498        }
499        if (Math.abs(radians) > HALF_PI) {// put us in -PI/2 to +PI/2 space
500            radians = PI - radians;
501        }
502
503        return radians;
504    }
505
506    /**
507     * Returns sine of a value.
508     *
509     * note: code from wiki posting on java.net by jeffpk
510     *
511     * @param fValue
512     *            The value to sine, in radians.
513     * @return The sine of fValue.
514     * @see java.lang.Math#sin(double)
515     */
516    public static float sin2(float fValue) {
517        fValue = reduceSinAngle(fValue); // limits angle to between -PI/2 and +PI/2
518        if (Math.abs(fValue) <= Math.PI / 4) {
519            return (float) Math.sin(fValue);
520        }
521
522        return (float) Math.cos(Math.PI / 2 - fValue);
523    }
524
525    /**
526     * Returns cos of a value.
527     *
528     * @param fValue
529     *            The value to cosine, in radians.
530     * @return The cosine of fValue.
531     * @see java.lang.Math#cos(double)
532     */
533    public static float cos2(float fValue) {
534        return sin2(fValue + HALF_PI);
535    }
536
537    public static float cos(float v) {
538        return (float) Math.cos(v);
539    }
540
541    public static float sin(float v) {
542        return (float) Math.sin(v);
543    }
544
545    /**
546     * Returns E^fValue
547     * @param fValue Value to raise to a power.
548     * @return The value E^fValue
549     * @see java.lang.Math#exp(double)
550     */
551    public static float exp(float fValue) {
552        return (float) Math.exp(fValue);
553    }
554
555    /**
556     * Returns Absolute value of a float.
557     * @param fValue The value to abs.
558     * @return The abs of the value.
559     * @see java.lang.Math#abs(float)
560     */
561    public static float abs(float fValue) {
562        if (fValue < 0) {
563            return -fValue;
564        }
565        return fValue;
566    }
567
568    /**
569     * Returns a number rounded down.
570     * @param fValue The value to round
571     * @return The given number rounded down
572     * @see java.lang.Math#floor(double)
573     */
574    public static float floor(float fValue) {
575        return (float) Math.floor(fValue);
576    }
577
578    /**
579     * Returns 1/sqrt(fValue)
580     * @param fValue The value to process.
581     * @return 1/sqrt(fValue)
582     * @see java.lang.Math#sqrt(double)
583     */
584    public static float invSqrt(float fValue) {
585        return (float) (1.0f / Math.sqrt(fValue));
586    }
587
588    public static float fastInvSqrt(float x) {
589        float xhalf = 0.5f * x;
590        int i = Float.floatToIntBits(x); // get bits for floating value
591        i = 0x5f375a86 - (i >> 1); // gives initial guess y0
592        x = Float.intBitsToFloat(i); // convert bits back to float
593        x = x * (1.5f - xhalf * x * x); // Newton step, repeating increases accuracy
594        return x;
595    }
596
597    /**
598     * Returns the log base E of a value.
599     * @param fValue The value to log.
600     * @return The log of fValue base E
601     * @see java.lang.Math#log(double)
602     */
603    public static float log(float fValue) {
604        return (float) Math.log(fValue);
605    }
606
607    /**
608     * Returns the logarithm of value with given base, calculated as log(value)/log(base),
609     * so that pow(base, return)==value (contributed by vear)
610     * @param value The value to log.
611     * @param base Base of logarithm.
612     * @return The logarithm of value with given base
613     */
614    public static float log(float value, float base) {
615        return (float) (Math.log(value) / Math.log(base));
616    }
617
618    /**
619     * Returns a number raised to an exponent power.  fBase^fExponent
620     * @param fBase The base value (IE 2)
621     * @param fExponent The exponent value (IE 3)
622     * @return base raised to exponent (IE 8)
623     * @see java.lang.Math#pow(double, double)
624     */
625    public static float pow(float fBase, float fExponent) {
626        return (float) Math.pow(fBase, fExponent);
627    }
628
629    /**
630     * Returns the value squared.  fValue ^ 2
631     * @param fValue The vaule to square.
632     * @return The square of the given value.
633     */
634    public static float sqr(float fValue) {
635        return fValue * fValue;
636    }
637
638    /**
639     * Returns the square root of a given value.
640     * @param fValue The value to sqrt.
641     * @return The square root of the given value.
642     * @see java.lang.Math#sqrt(double)
643     */
644    public static float sqrt(float fValue) {
645        return (float) Math.sqrt(fValue);
646    }
647
648    /**
649     * Returns the tangent of a value.  If USE_FAST_TRIG is enabled, an approximate value
650     * is returned.  Otherwise, a direct value is used.
651     * @param fValue The value to tangent, in radians.
652     * @return The tangent of fValue.
653     * @see java.lang.Math#tan(double)
654     */
655    public static float tan(float fValue) {
656        return (float) Math.tan(fValue);
657    }
658
659    /**
660     * Returns 1 if the number is positive, -1 if the number is negative, and 0 otherwise
661     * @param iValue The integer to examine.
662     * @return The integer's sign.
663     */
664    public static int sign(int iValue) {
665        if (iValue > 0) {
666            return 1;
667        }
668        if (iValue < 0) {
669            return -1;
670        }
671        return 0;
672    }
673
674    /**
675     * Returns 1 if the number is positive, -1 if the number is negative, and 0 otherwise
676     * @param fValue The float to examine.
677     * @return The float's sign.
678     */
679    public static float sign(float fValue) {
680        return Math.signum(fValue);
681    }
682
683    /**
684     * Given 3 points in a 2d plane, this function computes if the points going from A-B-C
685     * are moving counter clock wise.
686     * @param p0 Point 0.
687     * @param p1 Point 1.
688     * @param p2 Point 2.
689     * @return 1 If they are CCW, -1 if they are not CCW, 0 if p2 is between p0 and p1.
690     */
691    public static int counterClockwise(Vector2f p0, Vector2f p1, Vector2f p2) {
692        float dx1, dx2, dy1, dy2;
693        dx1 = p1.x - p0.x;
694        dy1 = p1.y - p0.y;
695        dx2 = p2.x - p0.x;
696        dy2 = p2.y - p0.y;
697        if (dx1 * dy2 > dy1 * dx2) {
698            return 1;
699        }
700        if (dx1 * dy2 < dy1 * dx2) {
701            return -1;
702        }
703        if ((dx1 * dx2 < 0) || (dy1 * dy2 < 0)) {
704            return -1;
705        }
706        if ((dx1 * dx1 + dy1 * dy1) < (dx2 * dx2 + dy2 * dy2)) {
707            return 1;
708        }
709        return 0;
710    }
711
712    /**
713     * Test if a point is inside a triangle.  1 if the point is on the ccw side,
714     * -1 if the point is on the cw side, and 0 if it is on neither.
715     * @param t0 First point of the triangle.
716     * @param t1 Second point of the triangle.
717     * @param t2 Third point of the triangle.
718     * @param p The point to test.
719     * @return Value 1 or -1 if inside triangle, 0 otherwise.
720     */
721    public static int pointInsideTriangle(Vector2f t0, Vector2f t1, Vector2f t2, Vector2f p) {
722        int val1 = counterClockwise(t0, t1, p);
723        if (val1 == 0) {
724            return 1;
725        }
726        int val2 = counterClockwise(t1, t2, p);
727        if (val2 == 0) {
728            return 1;
729        }
730        if (val2 != val1) {
731            return 0;
732        }
733        int val3 = counterClockwise(t2, t0, p);
734        if (val3 == 0) {
735            return 1;
736        }
737        if (val3 != val1) {
738            return 0;
739        }
740        return val3;
741    }
742
743    /**
744     * A method that computes normal for a triangle defined by three vertices.
745     * @param v1 first vertex
746     * @param v2 second vertex
747     * @param v3 third vertex
748     * @return a normal for the face
749     */
750    public static Vector3f computeNormal(Vector3f v1, Vector3f v2, Vector3f v3) {
751        Vector3f a1 = v1.subtract(v2);
752        Vector3f a2 = v3.subtract(v2);
753        return a2.crossLocal(a1).normalizeLocal();
754    }
755
756    /**
757     * Returns the determinant of a 4x4 matrix.
758     */
759    public static float determinant(double m00, double m01, double m02,
760            double m03, double m10, double m11, double m12, double m13,
761            double m20, double m21, double m22, double m23, double m30,
762            double m31, double m32, double m33) {
763
764        double det01 = m20 * m31 - m21 * m30;
765        double det02 = m20 * m32 - m22 * m30;
766        double det03 = m20 * m33 - m23 * m30;
767        double det12 = m21 * m32 - m22 * m31;
768        double det13 = m21 * m33 - m23 * m31;
769        double det23 = m22 * m33 - m23 * m32;
770        return (float) (m00 * (m11 * det23 - m12 * det13 + m13 * det12) - m01
771                * (m10 * det23 - m12 * det03 + m13 * det02) + m02
772                * (m10 * det13 - m11 * det03 + m13 * det01) - m03
773                * (m10 * det12 - m11 * det02 + m12 * det01));
774    }
775
776    /**
777     * Returns a random float between 0 and 1.
778     *
779     * @return A random float between <tt>0.0f</tt> (inclusive) to
780     *         <tt>1.0f</tt> (exclusive).
781     */
782    public static float nextRandomFloat() {
783        return rand.nextFloat();
784    }
785
786    /**
787     * Returns a random float between min and max.
788     *
789     * @return A random int between <tt>min</tt> (inclusive) to
790     *         <tt>max</tt> (inclusive).
791     */
792    public static int nextRandomInt(int min, int max) {
793        return (int) (nextRandomFloat() * (max - min + 1)) + min;
794    }
795
796    public static int nextRandomInt() {
797        return rand.nextInt();
798    }
799
800    /**
801     * Converts a point from Spherical coordinates to Cartesian (using positive
802     * Y as up) and stores the results in the store var.
803     */
804    public static Vector3f sphericalToCartesian(Vector3f sphereCoords,
805            Vector3f store) {
806        store.y = sphereCoords.x * FastMath.sin(sphereCoords.z);
807        float a = sphereCoords.x * FastMath.cos(sphereCoords.z);
808        store.x = a * FastMath.cos(sphereCoords.y);
809        store.z = a * FastMath.sin(sphereCoords.y);
810
811        return store;
812    }
813
814    /**
815     * Converts a point from Cartesian coordinates (using positive Y as up) to
816     * Spherical and stores the results in the store var. (Radius, Azimuth,
817     * Polar)
818     */
819    public static Vector3f cartesianToSpherical(Vector3f cartCoords,
820            Vector3f store) {
821        float x = cartCoords.x;
822        if (x == 0) {
823            x = FastMath.FLT_EPSILON;
824        }
825        store.x = FastMath.sqrt((x * x)
826                + (cartCoords.y * cartCoords.y)
827                + (cartCoords.z * cartCoords.z));
828        store.y = FastMath.atan(cartCoords.z / x);
829        if (x < 0) {
830            store.y += FastMath.PI;
831        }
832        store.z = FastMath.asin(cartCoords.y / store.x);
833        return store;
834    }
835
836    /**
837     * Converts a point from Spherical coordinates to Cartesian (using positive
838     * Z as up) and stores the results in the store var.
839     */
840    public static Vector3f sphericalToCartesianZ(Vector3f sphereCoords,
841            Vector3f store) {
842        store.z = sphereCoords.x * FastMath.sin(sphereCoords.z);
843        float a = sphereCoords.x * FastMath.cos(sphereCoords.z);
844        store.x = a * FastMath.cos(sphereCoords.y);
845        store.y = a * FastMath.sin(sphereCoords.y);
846
847        return store;
848    }
849
850    /**
851     * Converts a point from Cartesian coordinates (using positive Z as up) to
852     * Spherical and stores the results in the store var. (Radius, Azimuth,
853     * Polar)
854     */
855    public static Vector3f cartesianZToSpherical(Vector3f cartCoords,
856            Vector3f store) {
857        float x = cartCoords.x;
858        if (x == 0) {
859            x = FastMath.FLT_EPSILON;
860        }
861        store.x = FastMath.sqrt((x * x)
862                + (cartCoords.y * cartCoords.y)
863                + (cartCoords.z * cartCoords.z));
864        store.z = FastMath.atan(cartCoords.z / x);
865        if (x < 0) {
866            store.z += FastMath.PI;
867        }
868        store.y = FastMath.asin(cartCoords.y / store.x);
869        return store;
870    }
871
872    /**
873     * Takes an value and expresses it in terms of min to max.
874     *
875     * @param val -
876     *            the angle to normalize (in radians)
877     * @return the normalized angle (also in radians)
878     */
879    public static float normalize(float val, float min, float max) {
880        if (Float.isInfinite(val) || Float.isNaN(val)) {
881            return 0f;
882        }
883        float range = max - min;
884        while (val > max) {
885            val -= range;
886        }
887        while (val < min) {
888            val += range;
889        }
890        return val;
891    }
892
893    /**
894     * @param x
895     *            the value whose sign is to be adjusted.
896     * @param y
897     *            the value whose sign is to be used.
898     * @return x with its sign changed to match the sign of y.
899     */
900    public static float copysign(float x, float y) {
901        if (y >= 0 && x <= -0) {
902            return -x;
903        } else if (y < 0 && x >= 0) {
904            return -x;
905        } else {
906            return x;
907        }
908    }
909
910    /**
911     * Take a float input and clamp it between min and max.
912     *
913     * @param input
914     * @param min
915     * @param max
916     * @return clamped input
917     */
918    public static float clamp(float input, float min, float max) {
919        return (input < min) ? min : (input > max) ? max : input;
920    }
921
922    /**
923     * Clamps the given float to be between 0 and 1.
924     *
925     * @param input
926     * @return input clamped between 0 and 1.
927     */
928    public static float saturate(float input) {
929        return clamp(input, 0f, 1f);
930    }
931
932    /**
933     * Converts a single precision (32 bit) floating point value
934     * into half precision (16 bit).
935     *
936     * <p>Source: <a href="http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf">
937     * http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf</a><br><strong>broken link</strong>
938     *
939     * @param half The half floating point value as a short.
940     * @return floating point value of the half.
941     */
942    public static float convertHalfToFloat(short half) {
943        switch ((int) half) {
944            case 0x0000:
945                return 0f;
946            case 0x8000:
947                return -0f;
948            case 0x7c00:
949                return Float.POSITIVE_INFINITY;
950            case 0xfc00:
951                return Float.NEGATIVE_INFINITY;
952            // TODO: Support for NaN?
953            default:
954                return Float.intBitsToFloat(((half & 0x8000) << 16)
955                        | (((half & 0x7c00) + 0x1C000) << 13)
956                        | ((half & 0x03FF) << 13));
957        }
958    }
959
960    public static short convertFloatToHalf(float flt) {
961        if (Float.isNaN(flt)) {
962            throw new UnsupportedOperationException("NaN to half conversion not supported!");
963        } else if (flt == Float.POSITIVE_INFINITY) {
964            return (short) 0x7c00;
965        } else if (flt == Float.NEGATIVE_INFINITY) {
966            return (short) 0xfc00;
967        } else if (flt == 0f) {
968            return (short) 0x0000;
969        } else if (flt == -0f) {
970            return (short) 0x8000;
971        } else if (flt > 65504f) {
972            // max value supported by half float
973            return 0x7bff;
974        } else if (flt < -65504f) {
975            return (short) (0x7bff | 0x8000);
976        } else if (flt > 0f && flt < 5.96046E-8f) {
977            return 0x0001;
978        } else if (flt < 0f && flt > -5.96046E-8f) {
979            return (short) 0x8001;
980        }
981
982        int f = Float.floatToIntBits(flt);
983        return (short) (((f >> 16) & 0x8000)
984                | ((((f & 0x7f800000) - 0x38000000) >> 13) & 0x7c00)
985                | ((f >> 13) & 0x03ff));
986    }
987}
988