Browse Source

correct core comments and standardize line endings as discussed at http://hub.jmonkeyengine.org/forum/topic/typos-in-com-jme3-mathrendererpost/

[email protected] 11 years ago
parent
commit
98ffe52c77

+ 595 - 595
jme3-core/src/main/java/com/jme3/math/ColorRGBA.java

@@ -1,595 +1,595 @@
-/*
- * Copyright (c) 2009-2012 jMonkeyEngine 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 'jMonkeyEngine' 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.jme3.math;
-
-import com.jme3.export.*;
-import java.io.IOException;
-
-/**
- * <code>ColorRGBA</code> defines a color made from a collection of red, green
- * and blue values. An alpha value determines is transparency. All values must
- * be between 0 and 1. If any value is set higher or lower than these
- * constraints they are clamped to the min or max. That is, if a value smaller
- * than zero is set the value clamps to zero. If a value higher than 1 is
- * passed, that value is clamped to 1. However, because the attributes r, g, b,
- * a are public for efficiency reasons, they can be directly modified with
- * invalid values. The client should take care when directly addressing the
- * values. A call to clamp will assure that the values are within the
- * constraints.
- *
- * @author Mark Powell
- * @version $Id: ColorRGBA.java,v 1.29 2007/09/09 18:25:14 irrisor Exp $
- */
-public final class ColorRGBA implements Savable, Cloneable, java.io.Serializable {
-
-    static final long serialVersionUID = 1;
-    /**
-     * The color black (0,0,0).
-     */
-    public static final ColorRGBA Black = new ColorRGBA(0f, 0f, 0f, 1f);
-    /**
-     * The color white (1,1,1).
-     */
-    public static final ColorRGBA White = new ColorRGBA(1f, 1f, 1f, 1f);
-    /**
-     * The color gray (.2,.2,.2).
-     */
-    public static final ColorRGBA DarkGray = new ColorRGBA(0.2f, 0.2f, 0.2f, 1.0f);
-    /**
-     * The color gray (.5,.5,.5).
-     */
-    public static final ColorRGBA Gray = new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f);
-    /**
-     * The color gray (.8,.8,.8).
-     */
-    public static final ColorRGBA LightGray = new ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f);
-    /**
-     * The color red (1,0,0).
-     */
-    public static final ColorRGBA Red = new ColorRGBA(1f, 0f, 0f, 1f);
-    /**
-     * The color green (0,1,0).
-     */
-    public static final ColorRGBA Green = new ColorRGBA(0f, 1f, 0f, 1f);
-    /**
-     * The color blue (0,0,1).
-     */
-    public static final ColorRGBA Blue = new ColorRGBA(0f, 0f, 1f, 1f);
-    /**
-     * The color yellow (1,1,0).
-     */
-    public static final ColorRGBA Yellow = new ColorRGBA(1f, 1f, 0f, 1f);
-    /**
-     * The color magenta (1,0,1).
-     */
-    public static final ColorRGBA Magenta = new ColorRGBA(1f, 0f, 1f, 1f);
-    /**
-     * The color cyan (0,1,1).
-     */
-    public static final ColorRGBA Cyan = new ColorRGBA(0f, 1f, 1f, 1f);
-    /**
-     * The color orange (251/255, 130/255,0).
-     */
-    public static final ColorRGBA Orange = new ColorRGBA(251f / 255f, 130f / 255f, 0f, 1f);
-    /**
-     * The color brown (65/255, 40/255, 25/255).
-     */
-    public static final ColorRGBA Brown = new ColorRGBA(65f / 255f, 40f / 255f, 25f / 255f, 1f);
-    /**
-     * The color pink (1, 0.68, 0.68).
-     */
-    public static final ColorRGBA Pink = new ColorRGBA(1f, 0.68f, 0.68f, 1f);
-    /**
-     * The black color with no alpha (0, 0, 0, 0).
-     */
-    public static final ColorRGBA BlackNoAlpha = new ColorRGBA(0f, 0f, 0f, 0f);
-    /**
-     * The red component of the color. 0 is none and 1 is maximum red.
-     */
-    public float r;
-    /**
-     * The green component of the color. 0 is none and 1 is maximum green.
-     */
-    public float g;
-    /**
-     * The blue component of the color. 0 is none and 1 is maximum blue.
-     */
-    public float b;
-    /**
-     * The alpha component of the color. 0 is transparent and 1 is opaque.
-     */
-    public float a;
-
-    /**
-     * Constructor instantiates a new <code>ColorRGBA</code> object. This
-     * color is the default "white" with all values 1.
-     */
-    public ColorRGBA() {
-        r = g = b = a = 1.0f;
-    }
-
-    /**
-     * Constructor instantiates a new <code>ColorRGBA</code> object. The
-     * values are defined as passed parameters. These values are then clamped
-     * to insure that they are between 0 and 1.
-     * @param r The red component of this color.
-     * @param g The green component of this <code>ColorRGBA</code>.
-     * @param b The blue component of this <code>ColorRGBA</code>.
-     * @param a The alpha component of this <code>ColorRGBA</code>.
-     */
-    public ColorRGBA(float r, float g, float b, float a) {
-        this.r = r;
-        this.g = g;
-        this.b = b;
-        this.a = a;
-    }
-
-    /**
-     * Copy constructor creates a new <code>ColorRGBA</code> object, based on
-     * a provided color.
-     * @param rgba The <code>ColorRGBA</code> object to copy.
-     */
-    public ColorRGBA(ColorRGBA rgba) {
-        this.a = rgba.a;
-        this.r = rgba.r;
-        this.g = rgba.g;
-        this.b = rgba.b;
-    }
-
-    /**
-     * <code>set</code> sets the RGBA values of this <code>ColorRGBA</code>. The 
-     * values are then clamped to insure that they are between 0 and 1.
-     *
-     * @param r The red component of this color.
-     * @param g The green component of this color.
-     * @param b The blue component of this color.
-     * @param a The alpha component of this color.
-     * @return this
-     */
-    public ColorRGBA set(float r, float g, float b, float a) {
-        this.r = r;
-        this.g = g;
-        this.b = b;
-        this.a = a;
-        return this;
-    }
-
-    /**
-     * <code>set</code> sets the values of this <code>ColorRGBA</code> to those 
-     * set by a parameter color.
-     *
-     * @param rgba The color to set this <code>ColorRGBA</code> to.
-     * @return this
-     */
-    public ColorRGBA set(ColorRGBA rgba) {
-        if (rgba == null) {
-            r = 0;
-            g = 0;
-            b = 0;
-            a = 0;
-        } else {
-            r = rgba.r;
-            g = rgba.g;
-            b = rgba.b;
-            a = rgba.a;
-        }
-        return this;
-    }
-
-    /**
-     * <code>clamp</code> insures that all values are between 0 and 1. If any
-     * are less than 0 they are set to zero. If any are more than 1 they are
-     * set to one.
-     */
-    public void clamp() {
-        if (r < 0) {
-            r = 0;
-        } else if (r > 1) {
-            r = 1;
-        }
-
-        if (g < 0) {
-            g = 0;
-        } else if (g > 1) {
-            g = 1;
-        }
-
-        if (b < 0) {
-            b = 0;
-        } else if (b > 1) {
-            b = 1;
-        }
-
-        if (a < 0) {
-            a = 0;
-        } else if (a > 1) {
-            a = 1;
-        }
-    }
-
-    /**
-     * <code>getColorArray</code> retrieves the color values of this 
-     * <code>ColorRGBA</code> as a four element <code>float</code> array in the 
-     * order: r,g,b,a.
-     * @return The <code>float</code> array that contains the color components.
-     */
-    public float[] getColorArray() {
-        return new float[]{r, g, b, a};
-    }
-
-    /**
-     * Stores the current r,g,b,a values into the given array.  The given array must have a
-     * length of 4 or greater, or an array index out of bounds exception will be thrown.
-     * @param store The <code>float</code> array to store the values into.
-     * @return The <code>float</code> array after storage.
-     */
-    public float[] getColorArray(float[] store) {
-        store[0] = r;
-        store[1] = g;
-        store[2] = b;
-        store[3] = a;
-        return store;
-    }
-
-    /**
-     * Retrieves the alpha component value of this <code>ColorRGBA</code>.
-     * @return The alpha component value.
-     */
-    public float getAlpha() {
-        return a;
-    }
-
-    /**
-     * Retrieves the red component value of this <code>ColorRGBA</code>.
-     * @return The red component value.
-     */
-    public float getRed() {
-        return r;
-    }
-
-    /**
-     * Retrieves the blue component value of this <code>ColorRGBA</code>.
-     * @return The blue component value.
-     */
-    public float getBlue() {
-        return b;
-    }
-
-    /**
-     * Retrieves the green component value of this <code>ColorRGBA</code>.
-     * @return The green component value.
-     */
-    public float getGreen() {
-        return g;
-    }
-
-    /**
-     * Sets this <code>ColorRGBA</code> to the interpolation by changeAmnt from 
-     * this to the finalColor:
-     * this=(1-changeAmnt)*this + changeAmnt * finalColor
-     * @param finalColor The final color to interpolate towards.
-     * @param changeAmnt An amount between 0.0 - 1.0 representing a percentage
-     *  change from this towards finalColor.
-     */
-    public void interpolate(ColorRGBA finalColor, float changeAmnt) {
-        this.r = (1 - changeAmnt) * this.r + changeAmnt * finalColor.r;
-        this.g = (1 - changeAmnt) * this.g + changeAmnt * finalColor.g;
-        this.b = (1 - changeAmnt) * this.b + changeAmnt * finalColor.b;
-        this.a = (1 - changeAmnt) * this.a + changeAmnt * finalColor.a;
-    }
-
-    /**
-     * Sets this <code>ColorRGBA</code> to the interpolation by changeAmnt from 
-     * beginColor to finalColor:
-     * this=(1-changeAmnt)*beginColor + changeAmnt * finalColor
-     * @param beginColor The begining color (changeAmnt=0).
-     * @param finalColor The final color to interpolate towards (changeAmnt=1).
-     * @param changeAmnt An amount between 0.0 - 1.0 representing a precentage
-     *  change from beginColor towards finalColor.
-     */
-    public void interpolate(ColorRGBA beginColor, ColorRGBA finalColor, float changeAmnt) {
-        this.r = (1 - changeAmnt) * beginColor.r + changeAmnt * finalColor.r;
-        this.g = (1 - changeAmnt) * beginColor.g + changeAmnt * finalColor.g;
-        this.b = (1 - changeAmnt) * beginColor.b + changeAmnt * finalColor.b;
-        this.a = (1 - changeAmnt) * beginColor.a + changeAmnt * finalColor.a;
-    }
-
-    /**
-     * <code>randomColor</code> is a utility method that generates a random
-     * opaque color.
-     * @return a random <code>ColorRGBA</code> with an alpha set to 1.
-     */
-    public static ColorRGBA randomColor() {
-        ColorRGBA rVal = new ColorRGBA(0, 0, 0, 1);
-        rVal.r = FastMath.nextRandomFloat();
-        rVal.g = FastMath.nextRandomFloat();
-        rVal.b = FastMath.nextRandomFloat();
-        return rVal;
-    }
-
-    /**
-     * Multiplies each r,g,b,a of this <code>ColorRGBA</code> by the corresponding 
-     * r,g,b,a of the given color and returns the result as a new <code>ColorRGBA</code>.  
-     * Used as a way of combining colors and lights.
-     * @param c The color to multiply by.
-     * @return The new <code>ColorRGBA</code>.  this*c
-     */
-    public ColorRGBA mult(ColorRGBA c) {
-        return new ColorRGBA(c.r * r, c.g * g, c.b * b, c.a * a);
-    }
-
-    /**
-     * Multiplies each r,g,b,a of this <code>ColorRGBA</code> by the given scalar and
-     * returns the result as a new <code>ColorRGBA</code>.  
-     * Used as a way of making colors dimmer or brighter.
-     * @param scalar The scalar to multiply by.
-     * @return The new <code>ColorRGBA</code>.  this*scalar
-     */
-    public ColorRGBA mult(float scalar) {
-        return new ColorRGBA(scalar * r, scalar * g, scalar * b, scalar * a);
-    }
-
-    /**
-     * Multiplies each r,g,b,a of this <code>ColorRGBA</code> by the given scalar and
-     * returns the result (this).  
-     * Used as a way of making colors dimmer or brighter.
-     * @param scalar The scalar to multiply by.
-     * @return this*c
-     */
-    public ColorRGBA multLocal(float scalar) {
-        this.r *= scalar;
-        this.g *= scalar;
-        this.b *= scalar;
-        this.a *= scalar;
-        return this;
-    }
-
-    /**
-     * Adds each r,g,b,a of this <code>ColorRGBA</code> by the corresponding 
-     * r,g,b,a of the given color and returns the result as a new <code>ColorRGBA</code>.
-     * Used as a way of combining colors and lights.
-     * @param c The color to add.
-     * @return The new <code>ColorRGBA</code>.  this+c
-     */
-    public ColorRGBA add(ColorRGBA c) {
-        return new ColorRGBA(c.r + r, c.g + g, c.b + b, c.a + a);
-    }
-
-    /**
-     * Adds each r,g,b,a of this <code>ColorRGBA</code> by the r,g,b,a the given 
-     * color and returns the result (this).  
-     * Used as a way of combining colors and lights.
-     * @param c The color to add.
-     * @return this+c
-     */
-    public ColorRGBA addLocal(ColorRGBA c) {
-        set(c.r + r, c.g + g, c.b + b, c.a + a);
-        return this;
-    }
-
-    /**
-     * <code>toString</code> returns the string representation of this <code>ColorRGBA</code>.
-     * The format of the string is:<br>
-     * <Class Name>: [R=RR.RRRR, G=GG.GGGG, B=BB.BBBB, A=AA.AAAA]
-     * @return The string representation of this <code>ColorRGBA</code>.
-     */
-    @Override
-    public String toString() {
-        return "Color[" + r + ", " + g + ", " + b + ", " + a + "]";
-    }
-
-    @Override
-    public ColorRGBA clone() {
-        try {
-            return (ColorRGBA) super.clone();
-        } catch (CloneNotSupportedException e) {
-            throw new AssertionError(); // can not happen
-        }
-    }
-
-    /**
-     * Saves this <code>ColorRGBA</code> into the given <code>float</code> array.
-     * @param floats The <code>float</code> array to take this <code>ColorRGBA</code>. 
-     * If null, a new <code>float[4]</code> is created.
-     * @return The array, with r,g,b,a float values in that order.
-     */
-    public float[] toArray(float[] floats) {
-        if (floats == null) {
-            floats = new float[4];
-        }
-        floats[0] = r;
-        floats[1] = g;
-        floats[2] = b;
-        floats[3] = a;
-        return floats;
-    }
-
-    /**
-     * <code>equals</code> returns true if this <code>ColorRGBA</code> is logically equivalent
-     * to a given color. That is, if all the components of the two colors are the same.
-     * False is returned otherwise.
-     * @param o The object to compare against.
-     * @return true if the colors are equal, false otherwise.
-     */
-    @Override
-    public boolean equals(Object o) {
-        if (!(o instanceof ColorRGBA)) {
-            return false;
-        }
-
-        if (this == o) {
-            return true;
-        }
-
-        ColorRGBA comp = (ColorRGBA) o;
-        if (Float.compare(r, comp.r) != 0) {
-            return false;
-        }
-        if (Float.compare(g, comp.g) != 0) {
-            return false;
-        }
-        if (Float.compare(b, comp.b) != 0) {
-            return false;
-        }
-        if (Float.compare(a, comp.a) != 0) {
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * <code>hashCode</code> returns a unique code for this <code>ColorRGBA</code> based
-     * on its values. If two colors are logically equivalent, they will return
-     * the same hash code value.
-     * @return The hash code value of this <code>ColorRGBA</code>.
-     */
-    @Override
-    public int hashCode() {
-        int hash = 37;
-        hash += 37 * hash + Float.floatToIntBits(r);
-        hash += 37 * hash + Float.floatToIntBits(g);
-        hash += 37 * hash + Float.floatToIntBits(b);
-        hash += 37 * hash + Float.floatToIntBits(a);
-        return hash;
-    }
-
-    public void write(JmeExporter e) throws IOException {
-        OutputCapsule capsule = e.getCapsule(this);
-        capsule.write(r, "r", 0);
-        capsule.write(g, "g", 0);
-        capsule.write(b, "b", 0);
-        capsule.write(a, "a", 0);
-    }
-
-    public void read(JmeImporter e) throws IOException {
-        InputCapsule capsule = e.getCapsule(this);
-        r = capsule.readFloat("r", 0);
-        g = capsule.readFloat("g", 0);
-        b = capsule.readFloat("b", 0);
-        a = capsule.readFloat("a", 0);
-    }
-    /**
-     * Retrieves the component values of this <code>ColorRGBA</code> as
-     * a four element <code>byte</code> array in the order: r,g,b,a.
-     * @return the <code>byte</code> array that contains the color components.
-     */
-    public byte[] asBytesRGBA() {
-        byte[] store = new byte[4];
-        store[0] = (byte) ((int) (r * 255) & 0xFF);
-        store[1] = (byte) ((int) (g * 255) & 0xFF);
-        store[2] = (byte) ((int) (b * 255) & 0xFF);
-        store[3] = (byte) ((int) (a * 255) & 0xFF);
-        return store;
-    }
-
-    /**
-     * Retrieves the component values of this <code>ColorRGBA</code> as an 
-     * <code>int</code> in a,r,g,b order. 
-     * Bits 24-31 are alpha, 16-23 are red, 8-15 are green, 0-7 are blue.
-     * @return The integer representation of this <code>ColorRGBA</code> in a,r,g,b order.
-     */
-    public int asIntARGB() {
-        int argb = (((int) (a * 255) & 0xFF) << 24)
-                | (((int) (r * 255) & 0xFF) << 16)
-                | (((int) (g * 255) & 0xFF) << 8)
-                | (((int) (b * 255) & 0xFF));
-        return argb;
-    }
-
-    /**
-     * Retrieves the component values of this <code>ColorRGBA</code> as an 
-     * <code>int</code> in r,g,b,a order.
-     * Bits 24-31 are red, 16-23 are green, 8-15 are blue, 0-7 are alpha.
-     * @return The integer representation of this <code>ColorRGBA</code> in r,g,b,a order.
-     */
-    public int asIntRGBA() {
-        int rgba = (((int) (r * 255) & 0xFF) << 24)
-                | (((int) (g * 255) & 0xFF) << 16)
-                | (((int) (b * 255) & 0xFF) << 8)
-                | (((int) (a * 255) & 0xFF));
-        return rgba;
-    }
-    /**
-     * Retrieves the component values of this <code>ColorRGBA</code> as an 
-     * <code>int</code> in a,b,g,r order.
-     * Bits 24-31 are alpha, 16-23 are blue, 8-15 are green, 0-7 are red.
-     * @return The integer representation of this <code>ColorRGBA</code> in a,b,g,r order.
-     */
-    public int asIntABGR() {
-        int abgr = (((int) (a * 255) & 0xFF) << 24)
-                | (((int) (b * 255) & 0xFF) << 16)
-                | (((int) (g * 255) & 0xFF) << 8)
-                | (((int) (r * 255) & 0xFF));
-        return abgr;
-    }
-    /**
-     * Sets the component values of this <code>ColorRGBA</code> with the given  
-     * combined ARGB <code>int</code>.
-     * Bits 24-31 are alpha, bits 16-23 are red, bits 8-15 are green, bits 0-7 are blue.
-     * @param color The integer ARGB value used to set this <code>ColorRGBA</code>.
-     */
-    public void fromIntARGB(int color) {
-        a = ((byte) (color >> 24) & 0xFF) / 255f;
-        r = ((byte) (color >> 16) & 0xFF) / 255f;
-        g = ((byte) (color >> 8) & 0xFF) / 255f;
-        b = ((byte) (color) & 0xFF) / 255f;
-    }
-    /**
-     * Sets the RGBA values of this <code>ColorRGBA</code> with the given combined RGBA value 
-     * Bits 24-31 are red, bits 16-23 are green, bits 8-15 are blue, bits 0-7 are alpha.
-     * @param color The integer RGBA value used to set this object.
-     */
-    public void fromIntRGBA(int color) {
-        r = ((byte) (color >> 24) & 0xFF) / 255f;
-        g = ((byte) (color >> 16) & 0xFF) / 255f;
-        b = ((byte) (color >> 8) & 0xFF) / 255f;
-        a = ((byte) (color) & 0xFF) / 255f;
-    }
-
-    /**
-     * Transform this <code>ColorRGBA</code> to a <code>Vector3f</code> using
-     * x = r, y = g, z = b. The Alpha value is not used.
-     * This method is useful to use for shaders assignment.
-     * @return A <code>Vector3f</code> containing the RGB value of this <code>ColorRGBA</code>.
-     */
-    public Vector3f toVector3f() {
-        return new Vector3f(r, g, b);
-    }
-
-    /**
-     * Transform this <code>ColorRGBA</code> to a <code>Vector4f</code> using
-     * x = r, y = g, z = b, w = a.
-     * This method is useful to use for shaders assignment.
-     * @return A <code>Vector4f</code> containing the RGBA value of this <code>ColorRGBA</code>.
-     */
-    public Vector4f toVector4f() {
-        return new Vector4f(r, g, b, a);
-    }
-}
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine 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 'jMonkeyEngine' 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.jme3.math;
+
+import com.jme3.export.*;
+import java.io.IOException;
+
+/**
+ * <code>ColorRGBA</code> defines a color made from a collection of red, green
+ * and blue values. An alpha value determines is transparency. All values must
+ * be between 0 and 1. If any value is set higher or lower than these
+ * constraints they are clamped to the min or max. That is, if a value smaller
+ * than zero is set the value clamps to zero. If a value higher than 1 is
+ * passed, that value is clamped to 1. However, because the attributes r, g, b,
+ * a are public for efficiency reasons, they can be directly modified with
+ * invalid values. The client should take care when directly addressing the
+ * values. A call to clamp will assure that the values are within the
+ * constraints.
+ *
+ * @author Mark Powell
+ * @version $Id: ColorRGBA.java,v 1.29 2007/09/09 18:25:14 irrisor Exp $
+ */
+public final class ColorRGBA implements Savable, Cloneable, java.io.Serializable {
+
+    static final long serialVersionUID = 1;
+    /**
+     * The color black (0,0,0).
+     */
+    public static final ColorRGBA Black = new ColorRGBA(0f, 0f, 0f, 1f);
+    /**
+     * The color white (1,1,1).
+     */
+    public static final ColorRGBA White = new ColorRGBA(1f, 1f, 1f, 1f);
+    /**
+     * The color gray (.2,.2,.2).
+     */
+    public static final ColorRGBA DarkGray = new ColorRGBA(0.2f, 0.2f, 0.2f, 1.0f);
+    /**
+     * The color gray (.5,.5,.5).
+     */
+    public static final ColorRGBA Gray = new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f);
+    /**
+     * The color gray (.8,.8,.8).
+     */
+    public static final ColorRGBA LightGray = new ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f);
+    /**
+     * The color red (1,0,0).
+     */
+    public static final ColorRGBA Red = new ColorRGBA(1f, 0f, 0f, 1f);
+    /**
+     * The color green (0,1,0).
+     */
+    public static final ColorRGBA Green = new ColorRGBA(0f, 1f, 0f, 1f);
+    /**
+     * The color blue (0,0,1).
+     */
+    public static final ColorRGBA Blue = new ColorRGBA(0f, 0f, 1f, 1f);
+    /**
+     * The color yellow (1,1,0).
+     */
+    public static final ColorRGBA Yellow = new ColorRGBA(1f, 1f, 0f, 1f);
+    /**
+     * The color magenta (1,0,1).
+     */
+    public static final ColorRGBA Magenta = new ColorRGBA(1f, 0f, 1f, 1f);
+    /**
+     * The color cyan (0,1,1).
+     */
+    public static final ColorRGBA Cyan = new ColorRGBA(0f, 1f, 1f, 1f);
+    /**
+     * The color orange (251/255, 130/255,0).
+     */
+    public static final ColorRGBA Orange = new ColorRGBA(251f / 255f, 130f / 255f, 0f, 1f);
+    /**
+     * The color brown (65/255, 40/255, 25/255).
+     */
+    public static final ColorRGBA Brown = new ColorRGBA(65f / 255f, 40f / 255f, 25f / 255f, 1f);
+    /**
+     * The color pink (1, 0.68, 0.68).
+     */
+    public static final ColorRGBA Pink = new ColorRGBA(1f, 0.68f, 0.68f, 1f);
+    /**
+     * The black color with no alpha (0, 0, 0, 0).
+     */
+    public static final ColorRGBA BlackNoAlpha = new ColorRGBA(0f, 0f, 0f, 0f);
+    /**
+     * The red component of the color. 0 is none and 1 is maximum red.
+     */
+    public float r;
+    /**
+     * The green component of the color. 0 is none and 1 is maximum green.
+     */
+    public float g;
+    /**
+     * The blue component of the color. 0 is none and 1 is maximum blue.
+     */
+    public float b;
+    /**
+     * The alpha component of the color. 0 is transparent and 1 is opaque.
+     */
+    public float a;
+
+    /**
+     * Constructor instantiates a new <code>ColorRGBA</code> object. This
+     * color is the default "white" with all values 1.
+     */
+    public ColorRGBA() {
+        r = g = b = a = 1.0f;
+    }
+
+    /**
+     * Constructor instantiates a new <code>ColorRGBA</code> object. The
+     * values are defined as passed parameters. These values are then clamped
+     * to insure that they are between 0 and 1.
+     * @param r The red component of this color.
+     * @param g The green component of this <code>ColorRGBA</code>.
+     * @param b The blue component of this <code>ColorRGBA</code>.
+     * @param a The alpha component of this <code>ColorRGBA</code>.
+     */
+    public ColorRGBA(float r, float g, float b, float a) {
+        this.r = r;
+        this.g = g;
+        this.b = b;
+        this.a = a;
+    }
+
+    /**
+     * Copy constructor creates a new <code>ColorRGBA</code> object, based on
+     * a provided color.
+     * @param rgba The <code>ColorRGBA</code> object to copy.
+     */
+    public ColorRGBA(ColorRGBA rgba) {
+        this.a = rgba.a;
+        this.r = rgba.r;
+        this.g = rgba.g;
+        this.b = rgba.b;
+    }
+
+    /**
+     * <code>set</code> sets the RGBA values of this <code>ColorRGBA</code>. The 
+     * values are then clamped to insure that they are between 0 and 1.
+     *
+     * @param r The red component of this color.
+     * @param g The green component of this color.
+     * @param b The blue component of this color.
+     * @param a The alpha component of this color.
+     * @return this
+     */
+    public ColorRGBA set(float r, float g, float b, float a) {
+        this.r = r;
+        this.g = g;
+        this.b = b;
+        this.a = a;
+        return this;
+    }
+
+    /**
+     * <code>set</code> sets the values of this <code>ColorRGBA</code> to those 
+     * set by a parameter color.
+     *
+     * @param rgba The color to set this <code>ColorRGBA</code> to.
+     * @return this
+     */
+    public ColorRGBA set(ColorRGBA rgba) {
+        if (rgba == null) {
+            r = 0;
+            g = 0;
+            b = 0;
+            a = 0;
+        } else {
+            r = rgba.r;
+            g = rgba.g;
+            b = rgba.b;
+            a = rgba.a;
+        }
+        return this;
+    }
+
+    /**
+     * <code>clamp</code> insures that all values are between 0 and 1. If any
+     * are less than 0 they are set to zero. If any are more than 1 they are
+     * set to one.
+     */
+    public void clamp() {
+        if (r < 0) {
+            r = 0;
+        } else if (r > 1) {
+            r = 1;
+        }
+
+        if (g < 0) {
+            g = 0;
+        } else if (g > 1) {
+            g = 1;
+        }
+
+        if (b < 0) {
+            b = 0;
+        } else if (b > 1) {
+            b = 1;
+        }
+
+        if (a < 0) {
+            a = 0;
+        } else if (a > 1) {
+            a = 1;
+        }
+    }
+
+    /**
+     * <code>getColorArray</code> retrieves the color values of this 
+     * <code>ColorRGBA</code> as a four element <code>float</code> array in the 
+     * order: r,g,b,a.
+     * @return The <code>float</code> array that contains the color components.
+     */
+    public float[] getColorArray() {
+        return new float[]{r, g, b, a};
+    }
+
+    /**
+     * Stores the current r,g,b,a values into the given array.  The given array must have a
+     * length of 4 or greater, or an array index out of bounds exception will be thrown.
+     * @param store The <code>float</code> array to store the values into.
+     * @return The <code>float</code> array after storage.
+     */
+    public float[] getColorArray(float[] store) {
+        store[0] = r;
+        store[1] = g;
+        store[2] = b;
+        store[3] = a;
+        return store;
+    }
+
+    /**
+     * Retrieves the alpha component value of this <code>ColorRGBA</code>.
+     * @return The alpha component value.
+     */
+    public float getAlpha() {
+        return a;
+    }
+
+    /**
+     * Retrieves the red component value of this <code>ColorRGBA</code>.
+     * @return The red component value.
+     */
+    public float getRed() {
+        return r;
+    }
+
+    /**
+     * Retrieves the blue component value of this <code>ColorRGBA</code>.
+     * @return The blue component value.
+     */
+    public float getBlue() {
+        return b;
+    }
+
+    /**
+     * Retrieves the green component value of this <code>ColorRGBA</code>.
+     * @return The green component value.
+     */
+    public float getGreen() {
+        return g;
+    }
+
+    /**
+     * Sets this <code>ColorRGBA</code> to the interpolation by changeAmnt from 
+     * this to the finalColor:
+     * this=(1-changeAmnt)*this + changeAmnt * finalColor
+     * @param finalColor The final color to interpolate towards.
+     * @param changeAmnt An amount between 0.0 - 1.0 representing a percentage
+     *  change from this towards finalColor.
+     */
+    public void interpolate(ColorRGBA finalColor, float changeAmnt) {
+        this.r = (1 - changeAmnt) * this.r + changeAmnt * finalColor.r;
+        this.g = (1 - changeAmnt) * this.g + changeAmnt * finalColor.g;
+        this.b = (1 - changeAmnt) * this.b + changeAmnt * finalColor.b;
+        this.a = (1 - changeAmnt) * this.a + changeAmnt * finalColor.a;
+    }
+
+    /**
+     * Sets this <code>ColorRGBA</code> to the interpolation by changeAmnt from 
+     * beginColor to finalColor:
+     * this=(1-changeAmnt)*beginColor + changeAmnt * finalColor
+     * @param beginColor The beginning color (changeAmnt=0).
+     * @param finalColor The final color to interpolate towards (changeAmnt=1).
+     * @param changeAmnt An amount between 0.0 - 1.0 representing a percentage
+     *  change from beginColor towards finalColor.
+     */
+    public void interpolate(ColorRGBA beginColor, ColorRGBA finalColor, float changeAmnt) {
+        this.r = (1 - changeAmnt) * beginColor.r + changeAmnt * finalColor.r;
+        this.g = (1 - changeAmnt) * beginColor.g + changeAmnt * finalColor.g;
+        this.b = (1 - changeAmnt) * beginColor.b + changeAmnt * finalColor.b;
+        this.a = (1 - changeAmnt) * beginColor.a + changeAmnt * finalColor.a;
+    }
+
+    /**
+     * <code>randomColor</code> is a utility method that generates a random
+     * opaque color.
+     * @return a random <code>ColorRGBA</code> with an alpha set to 1.
+     */
+    public static ColorRGBA randomColor() {
+        ColorRGBA rVal = new ColorRGBA(0, 0, 0, 1);
+        rVal.r = FastMath.nextRandomFloat();
+        rVal.g = FastMath.nextRandomFloat();
+        rVal.b = FastMath.nextRandomFloat();
+        return rVal;
+    }
+
+    /**
+     * Multiplies each r,g,b,a of this <code>ColorRGBA</code> by the corresponding 
+     * r,g,b,a of the given color and returns the result as a new <code>ColorRGBA</code>.  
+     * Used as a way of combining colors and lights.
+     * @param c The color to multiply by.
+     * @return The new <code>ColorRGBA</code>.  this*c
+     */
+    public ColorRGBA mult(ColorRGBA c) {
+        return new ColorRGBA(c.r * r, c.g * g, c.b * b, c.a * a);
+    }
+
+    /**
+     * Multiplies each r,g,b,a of this <code>ColorRGBA</code> by the given scalar and
+     * returns the result as a new <code>ColorRGBA</code>.  
+     * Used as a way of making colors dimmer or brighter.
+     * @param scalar The scalar to multiply by.
+     * @return The new <code>ColorRGBA</code>.  this*scalar
+     */
+    public ColorRGBA mult(float scalar) {
+        return new ColorRGBA(scalar * r, scalar * g, scalar * b, scalar * a);
+    }
+
+    /**
+     * Multiplies each r,g,b,a of this <code>ColorRGBA</code> by the given scalar and
+     * returns the result (this).  
+     * Used as a way of making colors dimmer or brighter.
+     * @param scalar The scalar to multiply by.
+     * @return this*c
+     */
+    public ColorRGBA multLocal(float scalar) {
+        this.r *= scalar;
+        this.g *= scalar;
+        this.b *= scalar;
+        this.a *= scalar;
+        return this;
+    }
+
+    /**
+     * Adds each r,g,b,a of this <code>ColorRGBA</code> by the corresponding 
+     * r,g,b,a of the given color and returns the result as a new <code>ColorRGBA</code>.
+     * Used as a way of combining colors and lights.
+     * @param c The color to add.
+     * @return The new <code>ColorRGBA</code>.  this+c
+     */
+    public ColorRGBA add(ColorRGBA c) {
+        return new ColorRGBA(c.r + r, c.g + g, c.b + b, c.a + a);
+    }
+
+    /**
+     * Adds each r,g,b,a of this <code>ColorRGBA</code> by the r,g,b,a the given 
+     * color and returns the result (this).  
+     * Used as a way of combining colors and lights.
+     * @param c The color to add.
+     * @return this+c
+     */
+    public ColorRGBA addLocal(ColorRGBA c) {
+        set(c.r + r, c.g + g, c.b + b, c.a + a);
+        return this;
+    }
+
+    /**
+     * <code>toString</code> returns the string representation of this <code>ColorRGBA</code>.
+     * The format of the string is:<br>
+     * <Class Name>: [R=RR.RRRR, G=GG.GGGG, B=BB.BBBB, A=AA.AAAA]
+     * @return The string representation of this <code>ColorRGBA</code>.
+     */
+    @Override
+    public String toString() {
+        return "Color[" + r + ", " + g + ", " + b + ", " + a + "]";
+    }
+
+    @Override
+    public ColorRGBA clone() {
+        try {
+            return (ColorRGBA) super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError(); // can not happen
+        }
+    }
+
+    /**
+     * Saves this <code>ColorRGBA</code> into the given <code>float</code> array.
+     * @param floats The <code>float</code> array to take this <code>ColorRGBA</code>. 
+     * If null, a new <code>float[4]</code> is created.
+     * @return The array, with r,g,b,a float values in that order.
+     */
+    public float[] toArray(float[] floats) {
+        if (floats == null) {
+            floats = new float[4];
+        }
+        floats[0] = r;
+        floats[1] = g;
+        floats[2] = b;
+        floats[3] = a;
+        return floats;
+    }
+
+    /**
+     * <code>equals</code> returns true if this <code>ColorRGBA</code> is logically equivalent
+     * to a given color. That is, if all the components of the two colors are the same.
+     * False is returned otherwise.
+     * @param o The object to compare against.
+     * @return true if the colors are equal, false otherwise.
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof ColorRGBA)) {
+            return false;
+        }
+
+        if (this == o) {
+            return true;
+        }
+
+        ColorRGBA comp = (ColorRGBA) o;
+        if (Float.compare(r, comp.r) != 0) {
+            return false;
+        }
+        if (Float.compare(g, comp.g) != 0) {
+            return false;
+        }
+        if (Float.compare(b, comp.b) != 0) {
+            return false;
+        }
+        if (Float.compare(a, comp.a) != 0) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * <code>hashCode</code> returns a unique code for this <code>ColorRGBA</code> based
+     * on its values. If two colors are logically equivalent, they will return
+     * the same hash code value.
+     * @return The hash code value of this <code>ColorRGBA</code>.
+     */
+    @Override
+    public int hashCode() {
+        int hash = 37;
+        hash += 37 * hash + Float.floatToIntBits(r);
+        hash += 37 * hash + Float.floatToIntBits(g);
+        hash += 37 * hash + Float.floatToIntBits(b);
+        hash += 37 * hash + Float.floatToIntBits(a);
+        return hash;
+    }
+
+    public void write(JmeExporter e) throws IOException {
+        OutputCapsule capsule = e.getCapsule(this);
+        capsule.write(r, "r", 0);
+        capsule.write(g, "g", 0);
+        capsule.write(b, "b", 0);
+        capsule.write(a, "a", 0);
+    }
+
+    public void read(JmeImporter e) throws IOException {
+        InputCapsule capsule = e.getCapsule(this);
+        r = capsule.readFloat("r", 0);
+        g = capsule.readFloat("g", 0);
+        b = capsule.readFloat("b", 0);
+        a = capsule.readFloat("a", 0);
+    }
+    /**
+     * Retrieves the component values of this <code>ColorRGBA</code> as
+     * a four element <code>byte</code> array in the order: r,g,b,a.
+     * @return the <code>byte</code> array that contains the color components.
+     */
+    public byte[] asBytesRGBA() {
+        byte[] store = new byte[4];
+        store[0] = (byte) ((int) (r * 255) & 0xFF);
+        store[1] = (byte) ((int) (g * 255) & 0xFF);
+        store[2] = (byte) ((int) (b * 255) & 0xFF);
+        store[3] = (byte) ((int) (a * 255) & 0xFF);
+        return store;
+    }
+
+    /**
+     * Retrieves the component values of this <code>ColorRGBA</code> as an 
+     * <code>int</code> in a,r,g,b order. 
+     * Bits 24-31 are alpha, 16-23 are red, 8-15 are green, 0-7 are blue.
+     * @return The integer representation of this <code>ColorRGBA</code> in a,r,g,b order.
+     */
+    public int asIntARGB() {
+        int argb = (((int) (a * 255) & 0xFF) << 24)
+                | (((int) (r * 255) & 0xFF) << 16)
+                | (((int) (g * 255) & 0xFF) << 8)
+                | (((int) (b * 255) & 0xFF));
+        return argb;
+    }
+
+    /**
+     * Retrieves the component values of this <code>ColorRGBA</code> as an 
+     * <code>int</code> in r,g,b,a order.
+     * Bits 24-31 are red, 16-23 are green, 8-15 are blue, 0-7 are alpha.
+     * @return The integer representation of this <code>ColorRGBA</code> in r,g,b,a order.
+     */
+    public int asIntRGBA() {
+        int rgba = (((int) (r * 255) & 0xFF) << 24)
+                | (((int) (g * 255) & 0xFF) << 16)
+                | (((int) (b * 255) & 0xFF) << 8)
+                | (((int) (a * 255) & 0xFF));
+        return rgba;
+    }
+    /**
+     * Retrieves the component values of this <code>ColorRGBA</code> as an 
+     * <code>int</code> in a,b,g,r order.
+     * Bits 24-31 are alpha, 16-23 are blue, 8-15 are green, 0-7 are red.
+     * @return The integer representation of this <code>ColorRGBA</code> in a,b,g,r order.
+     */
+    public int asIntABGR() {
+        int abgr = (((int) (a * 255) & 0xFF) << 24)
+                | (((int) (b * 255) & 0xFF) << 16)
+                | (((int) (g * 255) & 0xFF) << 8)
+                | (((int) (r * 255) & 0xFF));
+        return abgr;
+    }
+    /**
+     * Sets the component values of this <code>ColorRGBA</code> with the given  
+     * combined ARGB <code>int</code>.
+     * Bits 24-31 are alpha, bits 16-23 are red, bits 8-15 are green, bits 0-7 are blue.
+     * @param color The integer ARGB value used to set this <code>ColorRGBA</code>.
+     */
+    public void fromIntARGB(int color) {
+        a = ((byte) (color >> 24) & 0xFF) / 255f;
+        r = ((byte) (color >> 16) & 0xFF) / 255f;
+        g = ((byte) (color >> 8) & 0xFF) / 255f;
+        b = ((byte) (color) & 0xFF) / 255f;
+    }
+    /**
+     * Sets the RGBA values of this <code>ColorRGBA</code> with the given combined RGBA value 
+     * Bits 24-31 are red, bits 16-23 are green, bits 8-15 are blue, bits 0-7 are alpha.
+     * @param color The integer RGBA value used to set this object.
+     */
+    public void fromIntRGBA(int color) {
+        r = ((byte) (color >> 24) & 0xFF) / 255f;
+        g = ((byte) (color >> 16) & 0xFF) / 255f;
+        b = ((byte) (color >> 8) & 0xFF) / 255f;
+        a = ((byte) (color) & 0xFF) / 255f;
+    }
+
+    /**
+     * Transform this <code>ColorRGBA</code> to a <code>Vector3f</code> using
+     * x = r, y = g, z = b. The Alpha value is not used.
+     * This method is useful to use for shaders assignment.
+     * @return A <code>Vector3f</code> containing the RGB value of this <code>ColorRGBA</code>.
+     */
+    public Vector3f toVector3f() {
+        return new Vector3f(r, g, b);
+    }
+
+    /**
+     * Transform this <code>ColorRGBA</code> to a <code>Vector4f</code> using
+     * x = r, y = g, z = b, w = a.
+     * This method is useful to use for shaders assignment.
+     * @return A <code>Vector4f</code> containing the RGBA value of this <code>ColorRGBA</code>.
+     */
+    public Vector4f toVector4f() {
+        return new Vector4f(r, g, b, a);
+    }
+}

+ 165 - 164
jme3-core/src/main/java/com/jme3/math/CurveAndSurfaceMath.java

@@ -1,164 +1,165 @@
-/*
- * Copyright (c) 2009-2012 jMonkeyEngine
- * 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 'jMonkeyEngine' 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.jme3.math;
-
-import com.jme3.math.Spline.SplineType;
-import java.util.List;
-
-/**
- * This class offers methods to help with curves and surfaces calculations.
- * @author Marcin Roguski (Kealthas)
- */
-public class CurveAndSurfaceMath {
-	private static final float KNOTS_MINIMUM_DELTA = 0.0001f;
-
-	/**
-	 * A private constructor is defined to avoid instatiation of this class.
-	 */
-	private CurveAndSurfaceMath() {}
-	
-	/**
-	 * This method interpolates tha data for the nurbs curve.
-	 * @param u
-	 *            the u value
-	 * @param nurbSpline
-	 *            the nurbs spline definition
-	 * @param store
-	 *            the resulting point in 3D space
-	 */
-	public static void interpolateNurbs(float u, Spline nurbSpline, Vector3f store) {
-		if (nurbSpline.getType() != SplineType.Nurb) {
-			throw new IllegalArgumentException("Given spline is not of a NURB type!");
-		}
-		List<Vector3f> controlPoints = nurbSpline.getControlPoints();
-		float[] weights = nurbSpline.getWeights();
-		List<Float> knots = nurbSpline.getKnots();
-		int controlPointAmount = controlPoints.size();
-
-		store.set(Vector3f.ZERO);
-		float delimeter = 0;
-		for (int i = 0; i < controlPointAmount; ++i) {
-			float val = weights[i] * CurveAndSurfaceMath.computeBaseFunctionValue(i, nurbSpline.getBasisFunctionDegree(), u, knots);
-			store.addLocal(nurbSpline.getControlPoints().get(i)
-					.mult(val));
-			delimeter += val;
-		}
-		store.divideLocal(delimeter);
-	}
-
-	/**
-	 * This method interpolates tha data for the nurbs surface.
-	 * 
-	 * @param u
-	 *            the u value
-	 * @param v
-	 *            the v value
-	 * @param controlPoints
-	 *            the nurbs' control points
-	 * @param knots
-	 *            the nurbs' knots
-	 * @param basisUFunctionDegree
-	 *            the degree of basis U function
-	 * @param basisVFunctionDegree
-	 *            the degree of basis V function
-	 * @param store
-	 *            the resulting point in 3D space
-	 */
-	public static void interpolate(float u, float v, List<List<Vector4f>> controlPoints, List<Float>[] knots, 
-			int basisUFunctionDegree, int basisVFunctionDegree, Vector3f store) {
-		store.set(Vector3f.ZERO);
-		float delimeter = 0;
-		int vControlPointsAmount = controlPoints.size();
-		int uControlPointsAmount = controlPoints.get(0).size();
-		for (int i = 0; i < vControlPointsAmount; ++i) {
-			for (int j = 0; j < uControlPointsAmount; ++j) {
-				Vector4f controlPoint = controlPoints.get(i).get(j);
-				float val = controlPoint.w
-								* CurveAndSurfaceMath.computeBaseFunctionValue(i, basisVFunctionDegree, v, knots[1])
-								* CurveAndSurfaceMath.computeBaseFunctionValue(j, basisUFunctionDegree, u, knots[0]);
-				store.addLocal(controlPoint.x * val, controlPoint.y * val, controlPoint.z * val);
-				delimeter += val;
-			}
-		}
-		store.divideLocal(delimeter);
-	}
-
-	/**
-	 * This method prepares the knots to be used. If the knots represent non-uniform B-splines (first and last knot values are being
-	 * repeated) it leads to NaN results during calculations. This method adds a small number to each of such knots to avoid NaN's.
-	 * @param knots
-	 *            the knots to be prepared to use
-	 * @param basisFunctionDegree
-	 *            the degree of basis function
-	 */
-	// TODO: improve this; constant delta may lead to errors if the difference between tha last repeated
-	// point and the following one is lower than it
-	public static void prepareNurbsKnots(List<Float> knots, int basisFunctionDegree) {
-		float delta = KNOTS_MINIMUM_DELTA;
-		float prevValue = knots.get(0).floatValue();
-		for(int i=1;i<knots.size();++i) {
-			float value = knots.get(i).floatValue();
-			if(value<=prevValue) {
-				value += delta;
-				knots.set(i, Float.valueOf(value));
-				delta += KNOTS_MINIMUM_DELTA;
-			} else {
-				delta = KNOTS_MINIMUM_DELTA;//reset the delta's value
-			}
-			
-			prevValue = value;
-		}
-	}
-
-	/**
-	 * This method computes the base function value for the NURB curve.
-	 * @param i
-	 *            the knot index
-	 * @param k
-	 *            the base function degree
-	 * @param t
-	 *            the knot value
-	 * @param knots
-	 *            the knots' values
-	 * @return the base function value
-	 */
-	private static float computeBaseFunctionValue(int i, int k, float t, List<Float> knots) {
-		if (k == 1) {
-			return knots.get(i) <= t && t < knots.get(i + 1) ? 1.0f : 0.0f;
-		} else {
-			return (t - knots.get(i)) / (knots.get(i + k - 1) - knots.get(i)) * 
-					CurveAndSurfaceMath.computeBaseFunctionValue(i, k - 1, t, knots)
-					+ (knots.get(i + k) - t) / (knots.get(i + k) - knots.get(i + 1)) * 
-					CurveAndSurfaceMath.computeBaseFunctionValue(i + 1, k - 1, t, knots);
-		}
-	}
-}
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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.jme3.math;
+
+import com.jme3.math.Spline.SplineType;
+import java.util.List;
+
+/**
+ * This class offers methods to help with curves and surfaces calculations.
+ * @author Marcin Roguski (Kealthas)
+ */
+public class CurveAndSurfaceMath {
+	private static final float KNOTS_MINIMUM_DELTA = 0.0001f;
+
+	/**
+         * A private constructor is defined to avoid instantiation of this 
+	 * class.
+   	 */
+	private CurveAndSurfaceMath() {}
+	
+	/**
+	 * This method interpolates the data for the nurbs curve.
+	 * @param u
+	 *            the u value
+	 * @param nurbSpline
+	 *            the nurbs spline definition
+	 * @param store
+	 *            the resulting point in 3D space
+	 */
+	public static void interpolateNurbs(float u, Spline nurbSpline, Vector3f store) {
+		if (nurbSpline.getType() != SplineType.Nurb) {
+			throw new IllegalArgumentException("Given spline is not of a NURB type!");
+		}
+		List<Vector3f> controlPoints = nurbSpline.getControlPoints();
+		float[] weights = nurbSpline.getWeights();
+		List<Float> knots = nurbSpline.getKnots();
+		int controlPointAmount = controlPoints.size();
+
+		store.set(Vector3f.ZERO);
+		float delimeter = 0;
+		for (int i = 0; i < controlPointAmount; ++i) {
+			float val = weights[i] * CurveAndSurfaceMath.computeBaseFunctionValue(i, nurbSpline.getBasisFunctionDegree(), u, knots);
+			store.addLocal(nurbSpline.getControlPoints().get(i)
+					.mult(val));
+			delimeter += val;
+		}
+		store.divideLocal(delimeter);
+	}
+
+	/**
+	 * This method interpolates the data for the nurbs surface.
+	 * 
+	 * @param u
+	 *            the u value
+	 * @param v
+	 *            the v value
+	 * @param controlPoints
+	 *            the nurbs' control points
+	 * @param knots
+	 *            the nurbs' knots
+	 * @param basisUFunctionDegree
+	 *            the degree of basis U function
+	 * @param basisVFunctionDegree
+	 *            the degree of basis V function
+	 * @param store
+	 *            the resulting point in 3D space
+	 */
+	public static void interpolate(float u, float v, List<List<Vector4f>> controlPoints, List<Float>[] knots, 
+			int basisUFunctionDegree, int basisVFunctionDegree, Vector3f store) {
+		store.set(Vector3f.ZERO);
+		float delimeter = 0;
+		int vControlPointsAmount = controlPoints.size();
+		int uControlPointsAmount = controlPoints.get(0).size();
+		for (int i = 0; i < vControlPointsAmount; ++i) {
+			for (int j = 0; j < uControlPointsAmount; ++j) {
+				Vector4f controlPoint = controlPoints.get(i).get(j);
+				float val = controlPoint.w
+								* CurveAndSurfaceMath.computeBaseFunctionValue(i, basisVFunctionDegree, v, knots[1])
+								* CurveAndSurfaceMath.computeBaseFunctionValue(j, basisUFunctionDegree, u, knots[0]);
+				store.addLocal(controlPoint.x * val, controlPoint.y * val, controlPoint.z * val);
+				delimeter += val;
+			}
+		}
+		store.divideLocal(delimeter);
+	}
+
+	/**
+	 * This method prepares the knots to be used. If the knots represent non-uniform B-splines (first and last knot values are being
+	 * repeated) it leads to NaN results during calculations. This method adds a small number to each of such knots to avoid NaN's.
+	 * @param knots
+	 *            the knots to be prepared to use
+	 * @param basisFunctionDegree
+	 *            the degree of basis function
+	 */
+	// TODO: improve this; constant delta may lead to errors if the difference between tha last repeated
+	// point and the following one is lower than it
+	public static void prepareNurbsKnots(List<Float> knots, int basisFunctionDegree) {
+		float delta = KNOTS_MINIMUM_DELTA;
+		float prevValue = knots.get(0).floatValue();
+		for(int i=1;i<knots.size();++i) {
+			float value = knots.get(i).floatValue();
+			if(value<=prevValue) {
+				value += delta;
+				knots.set(i, Float.valueOf(value));
+				delta += KNOTS_MINIMUM_DELTA;
+			} else {
+				delta = KNOTS_MINIMUM_DELTA;//reset the delta's value
+			}
+			
+			prevValue = value;
+		}
+	}
+
+	/**
+	 * This method computes the base function value for the NURB curve.
+	 * @param i
+	 *            the knot index
+	 * @param k
+	 *            the base function degree
+	 * @param t
+	 *            the knot value
+	 * @param knots
+	 *            the knots' values
+	 * @return the base function value
+	 */
+	private static float computeBaseFunctionValue(int i, int k, float t, List<Float> knots) {
+		if (k == 1) {
+			return knots.get(i) <= t && t < knots.get(i + 1) ? 1.0f : 0.0f;
+		} else {
+			return (t - knots.get(i)) / (knots.get(i + k - 1) - knots.get(i)) * 
+					CurveAndSurfaceMath.computeBaseFunctionValue(i, k - 1, t, knots)
+					+ (knots.get(i + k) - t) / (knots.get(i + k) - knots.get(i + 1)) * 
+					CurveAndSurfaceMath.computeBaseFunctionValue(i + 1, k - 1, t, knots);
+		}
+	}
+}

+ 960 - 959
jme3-core/src/main/java/com/jme3/math/FastMath.java

@@ -1,959 +1,960 @@
-/*
- * Copyright (c) 2009-2012 jMonkeyEngine
- * 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 'jMonkeyEngine' 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.jme3.math;
-
-import java.util.Random;
-
-/**
- * <code>FastMath</code> provides 'fast' math approximations and float equivalents of Math
- * functions.  These are all used as static values and functions.
- *
- * @author Various
- * @version $Id: FastMath.java,v 1.45 2007/08/26 08:44:20 irrisor Exp $
- */
-final public class FastMath {
-
-    private FastMath() {
-    }
-    /** A "close to zero" double epsilon value for use*/
-    public static final double DBL_EPSILON = 2.220446049250313E-16d;
-    /** A "close to zero" float epsilon value for use*/
-    public static final float FLT_EPSILON = 1.1920928955078125E-7f;
-    /** A "close to zero" float epsilon value for use*/
-    public static final float ZERO_TOLERANCE = 0.0001f;
-    public static final float ONE_THIRD = 1f / 3f;
-    /** The value PI as a float. (180 degrees) */
-    public static final float PI = (float) Math.PI;
-    /** The value 2PI as a float. (360 degrees) */
-    public static final float TWO_PI = 2.0f * PI;
-    /** The value PI/2 as a float. (90 degrees) */
-    public static final float HALF_PI = 0.5f * PI;
-    /** The value PI/4 as a float. (45 degrees) */
-    public static final float QUARTER_PI = 0.25f * PI;
-    /** The value 1/PI as a float. */
-    public static final float INV_PI = 1.0f / PI;
-    /** The value 1/(2PI) as a float. */
-    public static final float INV_TWO_PI = 1.0f / TWO_PI;
-    /** A value to multiply a degree value by, to convert it to radians. */
-    public static final float DEG_TO_RAD = PI / 180.0f;
-    /** A value to multiply a radian value by, to convert it to degrees. */
-    public static final float RAD_TO_DEG = 180.0f / PI;
-    /** A precreated random object for random numbers. */
-    public static final Random rand = new Random(System.currentTimeMillis());
-
-    /**
-     * Returns true if the number is a power of 2 (2,4,8,16...)
-     * 
-     * A good implementation found on the Java boards. note: a number is a power
-     * of two if and only if it is the smallest number with that number of
-     * significant bits. Therefore, if you subtract 1, you know that the new
-     * number will have fewer bits, so ANDing the original number with anything
-     * less than it will give 0.
-     * 
-     * @param number
-     *            The number to test.
-     * @return True if it is a power of two.
-     */
-    public static boolean isPowerOfTwo(int number) {
-        return (number > 0) && (number & (number - 1)) == 0;
-    }
-
-    public static int nearestPowerOfTwo(int number) {
-        return (int) Math.pow(2, Math.ceil(Math.log(number) / Math.log(2)));
-    }
-
-    /**
-     * Linear interpolation from startValue to endValue by the given percent.
-     * Basically: ((1 - percent) * startValue) + (percent * endValue)
-     * 
-     * @param scale
-     *            scale value to use. if 1, use endValue, if 0, use startValue.
-     * @param startValue
-     *            Begining value. 0% of f
-     * @param endValue
-     *            ending value. 100% of f
-     * @return The interpolated value between startValue and endValue.
-     */
-    public static float interpolateLinear(float scale, float startValue, float endValue) {
-        if (startValue == endValue) {
-            return startValue;
-        }
-        if (scale <= 0f) {
-            return startValue;
-        }
-        if (scale >= 1f) {
-            return endValue;
-        }
-        return ((1f - scale) * startValue) + (scale * endValue);
-    }
-
-    /**
-     * Linear interpolation from startValue to endValue by the given percent.
-     * Basically: ((1 - percent) * startValue) + (percent * endValue)
-     *
-     * @param scale
-     *            scale value to use. if 1, use endValue, if 0, use startValue.
-     * @param startValue
-     *            Begining value. 0% of f
-     * @param endValue
-     *            ending value. 100% of f
-     * @param store a vector3f to store the result
-     * @return The interpolated value between startValue and endValue.
-     */
-    public static Vector3f interpolateLinear(float scale, Vector3f startValue, Vector3f endValue, Vector3f store) {
-        if (store == null) {
-            store = new Vector3f();
-        }
-        store.x = interpolateLinear(scale, startValue.x, endValue.x);
-        store.y = interpolateLinear(scale, startValue.y, endValue.y);
-        store.z = interpolateLinear(scale, startValue.z, endValue.z);
-        return store;
-    }
-
-    /**
-     * Linear interpolation from startValue to endValue by the given percent.
-     * Basically: ((1 - percent) * startValue) + (percent * endValue)
-     *
-     * @param scale
-     *            scale value to use. if 1, use endValue, if 0, use startValue.
-     * @param startValue
-     *            Begining value. 0% of f
-     * @param endValue
-     *            ending value. 100% of f
-     * @return The interpolated value between startValue and endValue.
-     */
-    public static Vector3f interpolateLinear(float scale, Vector3f startValue, Vector3f endValue) {
-        return interpolateLinear(scale, startValue, endValue, null);
-    }
-
-    /**
-     * Linear extrapolation from startValue to endValue by the given scale.
-     * if scale is between 0 and 1 this method returns the same result as interpolateLinear
-     * if the scale is over 1 the value is linearly extrapolated.
-     * Note that the end value is the value for a scale of 1.
-     * @param scale the scale for extrapolation
-     * @param startValue the starting value (scale = 0)
-     * @param endValue the end value (scale = 1)
-     * @return an extrapolation for the given parameters
-     */
-    public static float extrapolateLinear(float scale, float startValue, float endValue) {
-//        if (scale <= 0f) {
-//            return startValue;
-//        }
-        return ((1f - scale) * startValue) + (scale * endValue);
-    }
-
-    /**
-     * Linear extrapolation from startValue to endValue by the given scale.
-     * if scale is between 0 and 1 this method returns the same result as interpolateLinear
-     * if the scale is over 1 the value is linearly extrapolated.
-     * Note that the end value is the value for a scale of 1. 
-     * @param scale the scale for extrapolation
-     * @param startValue the starting value (scale = 0)
-     * @param endValue the end value (scale = 1)
-     * @param store an initialized vector to store the return value
-     * @return an extrapolation for the given parameters
-     */
-    public static Vector3f extrapolateLinear(float scale, Vector3f startValue, Vector3f endValue, Vector3f store) {
-        if (store == null) {
-            store = new Vector3f();
-        }
-//        if (scale <= 1f) {
-//            return interpolateLinear(scale, startValue, endValue, store);
-//        }
-        store.x = extrapolateLinear(scale, startValue.x, endValue.x);
-        store.y = extrapolateLinear(scale, startValue.y, endValue.y);
-        store.z = extrapolateLinear(scale, startValue.z, endValue.z);
-        return store;
-    }
-
-    /**
-     * Linear extrapolation from startValue to endValue by the given scale.
-     * if scale is between 0 and 1 this method returns the same result as interpolateLinear
-     * if the scale is over 1 the value is linearly extrapolated.
-     * Note that the end value is the value for a scale of 1.
-     * @param scale the scale for extrapolation
-     * @param startValue the starting value (scale = 0)
-     * @param endValue the end value (scale = 1)
-     * @return an extrapolation for the given parameters
-     */
-    public static Vector3f extrapolateLinear(float scale, Vector3f startValue, Vector3f endValue) {
-        return extrapolateLinear(scale, startValue, endValue, null);
-    }
-
-    /**Interpolate a spline between at least 4 control points following the Catmull-Rom equation.
-     * here is the interpolation matrix
-     * m = [ 0.0  1.0  0.0   0.0 ]
-     *     [-T    0.0  T     0.0 ]
-     *     [ 2T   T-3  3-2T  -T  ]
-     *     [-T    2-T  T-2   T   ]
-     * where T is the curve tension
-     * the result is a value between p1 and p2, t=0 for p1, t=1 for p2
-     * @param u value from 0 to 1
-     * @param T The tension of the curve
-     * @param p0 control point 0
-     * @param p1 control point 1
-     * @param p2 control point 2
-     * @param p3 control point 3
-     * @return catmull-Rom interpolation
-     */
-    public static float interpolateCatmullRom(float u, float T, float p0, float p1, float p2, float p3) {
-        float c1, c2, c3, c4;
-        c1 = p1;
-        c2 = -1.0f * T * p0 + T * p2;
-        c3 = 2 * T * p0 + (T - 3) * p1 + (3 - 2 * T) * p2 + -T * p3;
-        c4 = -T * p0 + (2 - T) * p1 + (T - 2) * p2 + T * p3;
-
-        return (float) (((c4 * u + c3) * u + c2) * u + c1);
-    }
-
-    /**Interpolate a spline between at least 4 control points following the Catmull-Rom equation.
-     * here is the interpolation matrix
-     * m = [ 0.0  1.0  0.0   0.0 ]
-     *     [-T    0.0  T     0.0 ]
-     *     [ 2T   T-3  3-2T  -T  ]
-     *     [-T    2-T  T-2   T   ]
-     * where T is the tension of the curve
-     * the result is a value between p1 and p2, t=0 for p1, t=1 for p2
-     * @param u value from 0 to 1
-     * @param T The tension of the curve
-     * @param p0 control point 0
-     * @param p1 control point 1
-     * @param p2 control point 2
-     * @param p3 control point 3
-     * @param store a Vector3f to store the result
-     * @return catmull-Rom interpolation
-     */
-    public static Vector3f interpolateCatmullRom(float u, float T, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3, Vector3f store) {
-        if (store == null) {
-            store = new Vector3f();
-        }
-        store.x = interpolateCatmullRom(u, T, p0.x, p1.x, p2.x, p3.x);
-        store.y = interpolateCatmullRom(u, T, p0.y, p1.y, p2.y, p3.y);
-        store.z = interpolateCatmullRom(u, T, p0.z, p1.z, p2.z, p3.z);
-        return store;
-    }
-
-    /**Interpolate a spline between at least 4 control points following the Catmull-Rom equation.
-     * here is the interpolation matrix
-     * m = [ 0.0  1.0  0.0   0.0 ]
-     *     [-T    0.0  T     0.0 ]
-     *     [ 2T   T-3  3-2T  -T  ]
-     *     [-T    2-T  T-2   T   ]
-     * where T is the tension of the curve
-     * the result is a value between p1 and p2, t=0 for p1, t=1 for p2
-     * @param u value from 0 to 1
-     * @param T The tension of the curve
-     * @param p0 control point 0
-     * @param p1 control point 1
-     * @param p2 control point 2
-     * @param p3 control point 3
-     * @return catmull-Rom interpolation
-     */
-    public static Vector3f interpolateCatmullRom(float u, float T, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) {
-        return interpolateCatmullRom(u, T, p0, p1, p2, p3, null);
-    }
-
-    /**Interpolate a spline between at least 4 control points following the Bezier equation.
-     * here is the interpolation matrix
-     * m = [ -1.0   3.0  -3.0    1.0 ]
-     *     [  3.0  -6.0   3.0    0.0 ]
-     *     [ -3.0   3.0   0.0    0.0 ]
-     *     [  1.0   0.0   0.0    0.0 ]
-     * where T is the curve tension
-     * the result is a value between p1 and p3, t=0 for p1, t=1 for p3
-     * @param u value from 0 to 1
-     * @param p0 control point 0
-     * @param p1 control point 1
-     * @param p2 control point 2
-     * @param p3 control point 3
-     * @return Bezier interpolation
-     */
-    public static float interpolateBezier(float u, float p0, float p1, float p2, float p3) {
-        float oneMinusU = 1.0f - u;
-        float oneMinusU2 = oneMinusU * oneMinusU;
-        float u2 = u * u;
-        return p0 * oneMinusU2 * oneMinusU
-                + 3.0f * p1 * u * oneMinusU2
-                + 3.0f * p2 * u2 * oneMinusU
-                + p3 * u2 * u;
-    }
-
-    /**Interpolate a spline between at least 4 control points following the Bezier equation.
-     * here is the interpolation matrix
-     * m = [ -1.0   3.0  -3.0    1.0 ]
-     *     [  3.0  -6.0   3.0    0.0 ]
-     *     [ -3.0   3.0   0.0    0.0 ]
-     *     [  1.0   0.0   0.0    0.0 ]
-     * where T is the tension of the curve
-     * the result is a value between p1 and p3, t=0 for p1, t=1 for p3
-     * @param u value from 0 to 1
-     * @param p0 control point 0
-     * @param p1 control point 1
-     * @param p2 control point 2
-     * @param p3 control point 3
-     * @param store a Vector3f to store the result
-     * @return Bezier interpolation
-     */
-    public static Vector3f interpolateBezier(float u, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3, Vector3f store) {
-        if (store == null) {
-            store = new Vector3f();
-        }
-        store.x = interpolateBezier(u, p0.x, p1.x, p2.x, p3.x);
-        store.y = interpolateBezier(u, p0.y, p1.y, p2.y, p3.y);
-        store.z = interpolateBezier(u, p0.z, p1.z, p2.z, p3.z);
-        return store;
-    }
-
-    /**Interpolate a spline between at least 4 control points following the Bezier equation.
-     * here is the interpolation matrix
-     * m = [ -1.0   3.0  -3.0    1.0 ]
-     *     [  3.0  -6.0   3.0    0.0 ]
-     *     [ -3.0   3.0   0.0    0.0 ]
-     *     [  1.0   0.0   0.0    0.0 ]
-     * where T is the tension of the curve
-     * the result is a value between p1 and p3, t=0 for p1, t=1 for p3
-     * @param u value from 0 to 1
-     * @param p0 control point 0
-     * @param p1 control point 1
-     * @param p2 control point 2
-     * @param p3 control point 3
-     * @return Bezier interpolation
-     */
-    public static Vector3f interpolateBezier(float u, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) {
-        return interpolateBezier(u, p0, p1, p2, p3, null);
-    }
-
-    /**
-     * Compute the lenght on a catmull rom spline between control point 1 and 2
-     * @param p0 control point 0
-     * @param p1 control point 1
-     * @param p2 control point 2
-     * @param p3 control point 3
-     * @param startRange the starting range on the segment (use 0)
-     * @param endRange the end range on the segment (use 1)
-     * @param curveTension the curve tension
-     * @return the length of the segment
-     */
-    public static float getCatmullRomP1toP2Length(Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3, float startRange, float endRange, float curveTension) {
-
-        float epsilon = 0.001f;
-        float middleValue = (startRange + endRange) * 0.5f;
-        Vector3f start = p1.clone();
-        if (startRange != 0) {
-            FastMath.interpolateCatmullRom(startRange, curveTension, p0, p1, p2, p3, start);
-        }
-        Vector3f end = p2.clone();
-        if (endRange != 1) {
-            FastMath.interpolateCatmullRom(endRange, curveTension, p0, p1, p2, p3, end);
-        }
-        Vector3f middle = FastMath.interpolateCatmullRom(middleValue, curveTension, p0, p1, p2, p3);
-        float l = end.subtract(start).length();
-        float l1 = middle.subtract(start).length();
-        float l2 = end.subtract(middle).length();
-        float len = l1 + l2;
-        if (l + epsilon < len) {
-            l1 = getCatmullRomP1toP2Length(p0, p1, p2, p3, startRange, middleValue, curveTension);
-            l2 = getCatmullRomP1toP2Length(p0, p1, p2, p3, middleValue, endRange, curveTension);
-        }
-        l = l1 + l2;
-        return l;
-    }
-
-    /**
-     * Compute the lenght on a bezier spline between control point 1 and 2
-     * @param p0 control point 0
-     * @param p1 control point 1
-     * @param p2 control point 2
-     * @param p3 control point 3
-     * @return the length of the segment
-     */
-    public static float getBezierP1toP2Length(Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) {
-        float delta = 0.02f, t = 0.0f, result = 0.0f;
-        Vector3f v1 = p0.clone(), v2 = new Vector3f();
-        while (t <= 1.0f) {
-            FastMath.interpolateBezier(t, p0, p1, p2, p3, v2);
-            result += v1.subtractLocal(v2).length();
-            v1.set(v2);
-            t += delta;
-        }
-        return result;
-    }
-
-    /**
-     * Returns the arc cosine of a value.<br>
-     * Special cases:
-     * <ul><li>If fValue is smaller than -1, then the result is PI.
-     * <li>If the argument is greater than 1, then the result is 0.</ul>
-     * @param fValue The value to arc cosine.
-     * @return The angle, in radians.
-     * @see java.lang.Math#acos(double)
-     */
-    public static float acos(float fValue) {
-        if (-1.0f < fValue) {
-            if (fValue < 1.0f) {
-                return (float) Math.acos(fValue);
-            }
-
-            return 0.0f;
-        }
-
-        return PI;
-    }
-
-    /**
-     * Returns the arc sine of a value.<br>
-     * Special cases:
-     * <ul><li>If fValue is smaller than -1, then the result is -HALF_PI.
-     * <li>If the argument is greater than 1, then the result is HALF_PI.</ul>
-     * @param fValue The value to arc sine.
-     * @return the angle in radians.
-     * @see java.lang.Math#asin(double)
-     */
-    public static float asin(float fValue) {
-        if (-1.0f < fValue) {
-            if (fValue < 1.0f) {
-                return (float) Math.asin(fValue);
-            }
-
-            return HALF_PI;
-        }
-
-        return -HALF_PI;
-    }
-
-    /**
-     * Returns the arc tangent of an angle given in radians.<br>
-     * @param fValue The angle, in radians.
-     * @return fValue's atan
-     * @see java.lang.Math#atan(double)
-     */
-    public static float atan(float fValue) {
-        return (float) Math.atan(fValue);
-    }
-
-    /**
-     * A direct call to Math.atan2.
-     * @param fY
-     * @param fX
-     * @return Math.atan2(fY,fX)
-     * @see java.lang.Math#atan2(double, double)
-     */
-    public static float atan2(float fY, float fX) {
-        return (float) Math.atan2(fY, fX);
-    }
-
-    /**
-     * Rounds a fValue up.  A call to Math.ceil
-     * @param fValue The value.
-     * @return The fValue rounded up
-     * @see java.lang.Math#ceil(double)
-     */
-    public static float ceil(float fValue) {
-        return (float) Math.ceil(fValue);
-    }
-
-    /**
-     * Returns cosine of an angle. Direct call to java.lang.Math
-     * @see Math#cos(double) 
-     * @param v The angle to cosine.
-     * @return  the cosine of the angle.
-     */
-    public static float cos(float v) {
-        return (float) Math.cos(v);
-    }
-
-    /**
-     * Returns the sine of an angle. Direct call to java.lang.Math
-     * @see Math#sin(double) 
-     * @param v The angle to sine.
-     * @return the sine of the angle.
-     */
-    public static float sin(float v) {
-        return (float) Math.sin(v);
-    }
-
-    /**
-     * Returns E^fValue
-     * @param fValue Value to raise to a power.
-     * @return The value E^fValue
-     * @see java.lang.Math#exp(double)
-     */
-    public static float exp(float fValue) {
-        return (float) Math.exp(fValue);
-    }
-
-    /**
-     * Returns Absolute value of a float.
-     * @param fValue The value to abs.
-     * @return The abs of the value.
-     * @see java.lang.Math#abs(float)
-     */
-    public static float abs(float fValue) {
-        if (fValue < 0) {
-            return -fValue;
-        }
-        return fValue;
-    }
-
-    /**
-     * Returns a number rounded down.
-     * @param fValue The value to round
-     * @return The given number rounded down
-     * @see java.lang.Math#floor(double)
-     */
-    public static float floor(float fValue) {
-        return (float) Math.floor(fValue);
-    }
-
-    /**
-     * Returns 1/sqrt(fValue)
-     * @param fValue The value to process.
-     * @return 1/sqrt(fValue)
-     * @see java.lang.Math#sqrt(double)
-     */
-    public static float invSqrt(float fValue) {
-        return (float) (1.0f / Math.sqrt(fValue));
-    }
-
-    public static float fastInvSqrt(float x) {
-        float xhalf = 0.5f * x;
-        int i = Float.floatToIntBits(x); // get bits for floating value
-        i = 0x5f375a86 - (i >> 1); // gives initial guess y0
-        x = Float.intBitsToFloat(i); // convert bits back to float
-        x = x * (1.5f - xhalf * x * x); // Newton step, repeating increases accuracy
-        return x;
-    }
-
-    /**
-     * Returns the log base E of a value.
-     * @param fValue The value to log.
-     * @return The log of fValue base E
-     * @see java.lang.Math#log(double)
-     */
-    public static float log(float fValue) {
-        return (float) Math.log(fValue);
-    }
-
-    /**
-     * Returns the logarithm of value with given base, calculated as log(value)/log(base), 
-     * so that pow(base, return)==value (contributed by vear)
-     * @param value The value to log.
-     * @param base Base of logarithm.
-     * @return The logarithm of value with given base
-     */
-    public static float log(float value, float base) {
-        return (float) (Math.log(value) / Math.log(base));
-    }
-
-    /**
-     * Returns a number raised to an exponent power.  fBase^fExponent
-     * @param fBase The base value (IE 2)
-     * @param fExponent The exponent value (IE 3)
-     * @return base raised to exponent (IE 8)
-     * @see java.lang.Math#pow(double, double)
-     */
-    public static float pow(float fBase, float fExponent) {
-        return (float) Math.pow(fBase, fExponent);
-    }
-
-    /**
-     * Returns the value squared.  fValue ^ 2
-     * @param fValue The vaule to square.
-     * @return The square of the given value.
-     */
-    public static float sqr(float fValue) {
-        return fValue * fValue;
-    }
-
-    /**
-     * Returns the square root of a given value.
-     * @param fValue The value to sqrt.
-     * @return The square root of the given value.
-     * @see java.lang.Math#sqrt(double)
-     */
-    public static float sqrt(float fValue) {
-        return (float) Math.sqrt(fValue);
-    }
-
-    /**
-     * Returns the tangent of a value.  If USE_FAST_TRIG is enabled, an approximate value
-     * is returned.  Otherwise, a direct value is used.
-     * @param fValue The value to tangent, in radians.
-     * @return The tangent of fValue.
-     * @see java.lang.Math#tan(double)
-     */
-    public static float tan(float fValue) {
-        return (float) Math.tan(fValue);
-    }
-
-    /**
-     * Returns 1 if the number is positive, -1 if the number is negative, and 0 otherwise
-     * @param iValue The integer to examine.
-     * @return The integer's sign.
-     */
-    public static int sign(int iValue) {
-        if (iValue > 0) {
-            return 1;
-        }
-        if (iValue < 0) {
-            return -1;
-        }
-        return 0;
-    }
-
-    /**
-     * Returns 1 if the number is positive, -1 if the number is negative, and 0 otherwise
-     * @param fValue The float to examine.
-     * @return The float's sign.
-     */
-    public static float sign(float fValue) {
-        return Math.signum(fValue);
-    }
-
-    /**
-     * Given 3 points in a 2d plane, this function computes if the points going from A-B-C
-     * are moving counter clock wise.
-     * @param p0 Point 0.
-     * @param p1 Point 1.
-     * @param p2 Point 2.
-     * @return 1 If they are CCW, -1 if they are not CCW, 0 if p2 is between p0 and p1.
-     */
-    public static int counterClockwise(Vector2f p0, Vector2f p1, Vector2f p2) {
-        float dx1, dx2, dy1, dy2;
-        dx1 = p1.x - p0.x;
-        dy1 = p1.y - p0.y;
-        dx2 = p2.x - p0.x;
-        dy2 = p2.y - p0.y;
-        if (dx1 * dy2 > dy1 * dx2) {
-            return 1;
-        }
-        if (dx1 * dy2 < dy1 * dx2) {
-            return -1;
-        }
-        if ((dx1 * dx2 < 0) || (dy1 * dy2 < 0)) {
-            return -1;
-        }
-        if ((dx1 * dx1 + dy1 * dy1) < (dx2 * dx2 + dy2 * dy2)) {
-            return 1;
-        }
-        return 0;
-    }
-
-    /**
-     * Test if a point is inside a triangle.  1 if the point is on the ccw side,
-     * -1 if the point is on the cw side, and 0 if it is on neither.
-     * @param t0 First point of the triangle.
-     * @param t1 Second point of the triangle.
-     * @param t2 Third point of the triangle.
-     * @param p The point to test.
-     * @return Value 1 or -1 if inside triangle, 0 otherwise.
-     */
-    public static int pointInsideTriangle(Vector2f t0, Vector2f t1, Vector2f t2, Vector2f p) {
-        int val1 = counterClockwise(t0, t1, p);
-        if (val1 == 0) {
-            return 1;
-        }
-        int val2 = counterClockwise(t1, t2, p);
-        if (val2 == 0) {
-            return 1;
-        }
-        if (val2 != val1) {
-            return 0;
-        }
-        int val3 = counterClockwise(t2, t0, p);
-        if (val3 == 0) {
-            return 1;
-        }
-        if (val3 != val1) {
-            return 0;
-        }
-        return val3;
-    }
-
-    /**
-     * A method that computes normal for a triangle defined by three vertices.
-     * @param v1 first vertex
-     * @param v2 second vertex
-     * @param v3 third vertex
-     * @return a normal for the face
-     */
-    public static Vector3f computeNormal(Vector3f v1, Vector3f v2, Vector3f v3) {
-        Vector3f a1 = v1.subtract(v2);
-        Vector3f a2 = v3.subtract(v2);
-        return a2.crossLocal(a1).normalizeLocal();
-    }
-
-    /**
-     * Returns the determinant of a 4x4 matrix.
-     */
-    public static float determinant(double m00, double m01, double m02,
-            double m03, double m10, double m11, double m12, double m13,
-            double m20, double m21, double m22, double m23, double m30,
-            double m31, double m32, double m33) {
-
-        double det01 = m20 * m31 - m21 * m30;
-        double det02 = m20 * m32 - m22 * m30;
-        double det03 = m20 * m33 - m23 * m30;
-        double det12 = m21 * m32 - m22 * m31;
-        double det13 = m21 * m33 - m23 * m31;
-        double det23 = m22 * m33 - m23 * m32;
-        return (float) (m00 * (m11 * det23 - m12 * det13 + m13 * det12) - m01
-                * (m10 * det23 - m12 * det03 + m13 * det02) + m02
-                * (m10 * det13 - m11 * det03 + m13 * det01) - m03
-                * (m10 * det12 - m11 * det02 + m12 * det01));
-    }
-
-    /**
-     * Returns a random float between 0 and 1.
-     * 
-     * @return A random float between <tt>0.0f</tt> (inclusive) to
-     *         <tt>1.0f</tt> (exclusive).
-     */
-    public static float nextRandomFloat() {
-        return rand.nextFloat();
-    }
-
-    /**
-     * Returns a random integer between min and max.
-     * 
-     * @return A random int between <tt>min</tt> (inclusive) to
-     *         <tt>max</tt> (inclusive).
-     */
-    public static int nextRandomInt(int min, int max) {
-        return (int) (nextRandomFloat() * (max - min + 1)) + min;
-    }
-
-    public static int nextRandomInt() {
-        return rand.nextInt();
-    }
-
-    /**
-     * Converts a point from Spherical coordinates to Cartesian (using positive
-     * Y as up) and stores the results in the store var.
-     */
-    public static Vector3f sphericalToCartesian(Vector3f sphereCoords,
-            Vector3f store) {
-        if (store == null) {
-            store = new Vector3f();
-        }
-        store.y = sphereCoords.x * FastMath.sin(sphereCoords.z);
-        float a = sphereCoords.x * FastMath.cos(sphereCoords.z);
-        store.x = a * FastMath.cos(sphereCoords.y);
-        store.z = a * FastMath.sin(sphereCoords.y);
-
-        return store;
-    }
-
-    /**
-     * Converts a point from Cartesian coordinates (using positive Y as up) to
-     * Spherical and stores the results in the store var. (Radius, Azimuth,
-     * Polar)
-     */
-    public static Vector3f cartesianToSpherical(Vector3f cartCoords,
-            Vector3f store) {
-        if (store == null) {
-            store = new Vector3f();
-        }
-        float x = cartCoords.x;
-        if (x == 0) {
-            x = FastMath.FLT_EPSILON;
-        }
-        store.x = FastMath.sqrt((x * x)
-                + (cartCoords.y * cartCoords.y)
-                + (cartCoords.z * cartCoords.z));
-        store.y = FastMath.atan(cartCoords.z / x);
-        if (x < 0) {
-            store.y += FastMath.PI;
-        }
-        store.z = FastMath.asin(cartCoords.y / store.x);
-        return store;
-    }
-
-    /**
-     * Converts a point from Spherical coordinates to Cartesian (using positive
-     * Z as up) and stores the results in the store var.
-     */
-    public static Vector3f sphericalToCartesianZ(Vector3f sphereCoords,
-            Vector3f store) {
-        if (store == null) {
-            store = new Vector3f();
-        }
-        store.z = sphereCoords.x * FastMath.sin(sphereCoords.z);
-        float a = sphereCoords.x * FastMath.cos(sphereCoords.z);
-        store.x = a * FastMath.cos(sphereCoords.y);
-        store.y = a * FastMath.sin(sphereCoords.y);
-
-        return store;
-    }
-
-    /**
-     * Converts a point from Cartesian coordinates (using positive Z as up) to
-     * Spherical and stores the results in the store var. (Radius, Azimuth,
-     * Polar)
-     */
-    public static Vector3f cartesianZToSpherical(Vector3f cartCoords,
-            Vector3f store) {
-        if (store == null) {
-            store = new Vector3f();
-        }
-        float x = cartCoords.x;
-        if (x == 0) {
-            x = FastMath.FLT_EPSILON;
-        }
-        store.x = FastMath.sqrt((x * x)
-                + (cartCoords.y * cartCoords.y)
-                + (cartCoords.z * cartCoords.z));
-        store.z = FastMath.atan(cartCoords.z / x);
-        if (x < 0) {
-            store.z += FastMath.PI;
-        }
-        store.y = FastMath.asin(cartCoords.y / store.x);
-        return store;
-    }
-
-    /**
-     * Takes an value and expresses it in terms of min to max.
-     * 
-     * @param val -
-     *            the angle to normalize (in radians)
-     * @return the normalized angle (also in radians)
-     */
-    public static float normalize(float val, float min, float max) {
-        if (Float.isInfinite(val) || Float.isNaN(val)) {
-            return 0f;
-        }
-        float range = max - min;
-        while (val > max) {
-            val -= range;
-        }
-        while (val < min) {
-            val += range;
-        }
-        return val;
-    }
-
-    /**
-     * @param x
-     *            the value whose sign is to be adjusted.
-     * @param y
-     *            the value whose sign is to be used.
-     * @return x with its sign changed to match the sign of y.
-     */
-    public static float copysign(float x, float y) {
-        if (y >= 0 && x <= -0) {
-            return -x;
-        } else if (y < 0 && x >= 0) {
-            return -x;
-        } else {
-            return x;
-        }
-    }
-
-    /**
-     * Take a float input and clamp it between min and max.
-     * 
-     * @param input
-     * @param min
-     * @param max
-     * @return clamped input
-     */
-    public static float clamp(float input, float min, float max) {
-        return (input < min) ? min : (input > max) ? max : input;
-    }
-
-    /**
-     * Clamps the given float to be between 0 and 1.
-     *
-     * @param input
-     * @return input clamped between 0 and 1.
-     */
-    public static float saturate(float input) {
-        return clamp(input, 0f, 1f);
-    }
-
-    /**
-     * Converts a single precision (32 bit) floating point value
-     * into half precision (16 bit).
-     *
-     * <p>Source: <a href="http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf">
-     * http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf</a><br><strong>broken link</strong>
-     *
-     * @param half The half floating point value as a short.
-     * @return floating point value of the half.
-     */
-    public static float convertHalfToFloat(short half) {
-        switch ((int) half) {
-            case 0x0000:
-                return 0f;
-            case 0x8000:
-                return -0f;
-            case 0x7c00:
-                return Float.POSITIVE_INFINITY;
-            case 0xfc00:
-                return Float.NEGATIVE_INFINITY;
-            // TODO: Support for NaN?
-            default:
-                return Float.intBitsToFloat(((half & 0x8000) << 16)
-                        | (((half & 0x7c00) + 0x1C000) << 13)
-                        | ((half & 0x03FF) << 13));
-        }
-    }
-
-    public static short convertFloatToHalf(float flt) {
-        if (Float.isNaN(flt)) {
-            throw new UnsupportedOperationException("NaN to half conversion not supported!");
-        } else if (flt == Float.POSITIVE_INFINITY) {
-            return (short) 0x7c00;
-        } else if (flt == Float.NEGATIVE_INFINITY) {
-            return (short) 0xfc00;
-        } else if (flt == 0f) {
-            return (short) 0x0000;
-        } else if (flt == -0f) {
-            return (short) 0x8000;
-        } else if (flt > 65504f) {
-            // max value supported by half float
-            return 0x7bff;
-        } else if (flt < -65504f) {
-            return (short) (0x7bff | 0x8000);
-        } else if (flt > 0f && flt < 5.96046E-8f) {
-            return 0x0001;
-        } else if (flt < 0f && flt > -5.96046E-8f) {
-            return (short) 0x8001;
-        }
-
-        int f = Float.floatToIntBits(flt);
-        return (short) (((f >> 16) & 0x8000)
-                | ((((f & 0x7f800000) - 0x38000000) >> 13) & 0x7c00)
-                | ((f >> 13) & 0x03ff));
-    }
-}
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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.jme3.math;
+
+import java.util.Random;
+
+/**
+ * <code>FastMath</code> provides 'fast' math approximations and float equivalents of Math
+ * functions.  These are all used as static values and functions.
+ *
+ * @author Various
+ * @version $Id: FastMath.java,v 1.45 2007/08/26 08:44:20 irrisor Exp $
+ */
+final public class FastMath {
+
+    private FastMath() {
+    }
+    /** A "close to zero" double epsilon value for use*/
+    public static final double DBL_EPSILON = 2.220446049250313E-16d;
+    /** A "close to zero" float epsilon value for use*/
+    public static final float FLT_EPSILON = 1.1920928955078125E-7f;
+    /** A "close to zero" float epsilon value for use*/
+    public static final float ZERO_TOLERANCE = 0.0001f;
+    public static final float ONE_THIRD = 1f / 3f;
+    /** The value PI as a float. (180 degrees) */
+    public static final float PI = (float) Math.PI;
+    /** The value 2PI as a float. (360 degrees) */
+    public static final float TWO_PI = 2.0f * PI;
+    /** The value PI/2 as a float. (90 degrees) */
+    public static final float HALF_PI = 0.5f * PI;
+    /** The value PI/4 as a float. (45 degrees) */
+    public static final float QUARTER_PI = 0.25f * PI;
+    /** The value 1/PI as a float. */
+    public static final float INV_PI = 1.0f / PI;
+    /** The value 1/(2PI) as a float. */
+    public static final float INV_TWO_PI = 1.0f / TWO_PI;
+    /** A value to multiply a degree value by, to convert it to radians. */
+    public static final float DEG_TO_RAD = PI / 180.0f;
+    /** A value to multiply a radian value by, to convert it to degrees. */
+    public static final float RAD_TO_DEG = 180.0f / PI;
+    /** A precreated random object for random numbers. */
+    public static final Random rand = new Random(System.currentTimeMillis());
+
+    /**
+     * Returns true if the number is a power of 2 (2,4,8,16...)
+     * 
+     * A good implementation found on the Java boards. note: a number is a power
+     * of two if and only if it is the smallest number with that number of
+     * significant bits. Therefore, if you subtract 1, you know that the new
+     * number will have fewer bits, so ANDing the original number with anything
+     * less than it will give 0.
+     * 
+     * @param number
+     *            The number to test.
+     * @return True if it is a power of two.
+     */
+    public static boolean isPowerOfTwo(int number) {
+        return (number > 0) && (number & (number - 1)) == 0;
+    }
+
+    public static int nearestPowerOfTwo(int number) {
+        return (int) Math.pow(2, Math.ceil(Math.log(number) / Math.log(2)));
+    }
+
+    /**
+     * Linear interpolation from startValue to endValue by the given percent.
+     * Basically: ((1 - percent) * startValue) + (percent * endValue)
+     * 
+     * @param scale
+     *            scale value to use. if 1, use endValue, if 0, use startValue.
+     * @param startValue
+     *            Beginning value. 0% of f
+     * @param endValue
+     *            ending value. 100% of f
+     * @return The interpolated value between startValue and endValue.
+     */
+    public static float interpolateLinear(float scale, float startValue, float endValue) {
+        if (startValue == endValue) {
+            return startValue;
+        }
+        if (scale <= 0f) {
+            return startValue;
+        }
+        if (scale >= 1f) {
+            return endValue;
+        }
+        return ((1f - scale) * startValue) + (scale * endValue);
+    }
+
+    /**
+     * Linear interpolation from startValue to endValue by the given percent.
+     * Basically: ((1 - percent) * startValue) + (percent * endValue)
+     *
+     * @param scale
+     *            scale value to use. if 1, use endValue, if 0, use startValue.
+     * @param startValue
+     *            Beginning value. 0% of f
+     * @param endValue
+     *            ending value. 100% of f
+     * @param store a vector3f to store the result
+     * @return The interpolated value between startValue and endValue.
+     */
+    public static Vector3f interpolateLinear(float scale, Vector3f startValue, Vector3f endValue, Vector3f store) {
+        if (store == null) {
+            store = new Vector3f();
+        }
+        store.x = interpolateLinear(scale, startValue.x, endValue.x);
+        store.y = interpolateLinear(scale, startValue.y, endValue.y);
+        store.z = interpolateLinear(scale, startValue.z, endValue.z);
+        return store;
+    }
+
+    /**
+     * Linear interpolation from startValue to endValue by the given percent.
+     * Basically: ((1 - percent) * startValue) + (percent * endValue)
+     *
+     * @param scale
+     *            scale value to use. if 1, use endValue, if 0, use startValue.
+     * @param startValue
+     *            Beginning value. 0% of f
+     * @param endValue
+     *            ending value. 100% of f
+     * @return The interpolated value between startValue and endValue.
+     */
+    public static Vector3f interpolateLinear(float scale, Vector3f startValue, Vector3f endValue) {
+        return interpolateLinear(scale, startValue, endValue, null);
+    }
+
+    /**
+     * Linear extrapolation from startValue to endValue by the given scale.
+     * if scale is between 0 and 1 this method returns the same result as interpolateLinear
+     * if the scale is over 1 the value is linearly extrapolated.
+     * Note that the end value is the value for a scale of 1.
+     * @param scale the scale for extrapolation
+     * @param startValue the starting value (scale = 0)
+     * @param endValue the end value (scale = 1)
+     * @return an extrapolation for the given parameters
+     */
+    public static float extrapolateLinear(float scale, float startValue, float endValue) {
+//        if (scale <= 0f) {
+//            return startValue;
+//        }
+        return ((1f - scale) * startValue) + (scale * endValue);
+    }
+
+    /**
+     * Linear extrapolation from startValue to endValue by the given scale.
+     * if scale is between 0 and 1 this method returns the same result as interpolateLinear
+     * if the scale is over 1 the value is linearly extrapolated.
+     * Note that the end value is the value for a scale of 1. 
+     * @param scale the scale for extrapolation
+     * @param startValue the starting value (scale = 0)
+     * @param endValue the end value (scale = 1)
+     * @param store an initialized vector to store the return value
+     * @return an extrapolation for the given parameters
+     */
+    public static Vector3f extrapolateLinear(float scale, Vector3f startValue, Vector3f endValue, Vector3f store) {
+        if (store == null) {
+            store = new Vector3f();
+        }
+//        if (scale <= 1f) {
+//            return interpolateLinear(scale, startValue, endValue, store);
+//        }
+        store.x = extrapolateLinear(scale, startValue.x, endValue.x);
+        store.y = extrapolateLinear(scale, startValue.y, endValue.y);
+        store.z = extrapolateLinear(scale, startValue.z, endValue.z);
+        return store;
+    }
+
+    /**
+     * Linear extrapolation from startValue to endValue by the given scale.
+     * if scale is between 0 and 1 this method returns the same result as interpolateLinear
+     * if the scale is over 1 the value is linearly extrapolated.
+     * Note that the end value is the value for a scale of 1.
+     * @param scale the scale for extrapolation
+     * @param startValue the starting value (scale = 0)
+     * @param endValue the end value (scale = 1)
+     * @return an extrapolation for the given parameters
+     */
+    public static Vector3f extrapolateLinear(float scale, Vector3f startValue, Vector3f endValue) {
+        return extrapolateLinear(scale, startValue, endValue, null);
+    }
+
+    /**Interpolate a spline between at least 4 control points following the Catmull-Rom equation.
+     * here is the interpolation matrix
+     * m = [ 0.0  1.0  0.0   0.0 ]
+     *     [-T    0.0  T     0.0 ]
+     *     [ 2T   T-3  3-2T  -T  ]
+     *     [-T    2-T  T-2   T   ]
+     * where T is the curve tension
+     * the result is a value between p1 and p2, t=0 for p1, t=1 for p2
+     * @param u value from 0 to 1
+     * @param T The tension of the curve
+     * @param p0 control point 0
+     * @param p1 control point 1
+     * @param p2 control point 2
+     * @param p3 control point 3
+     * @return Catmull–Rom interpolation
+     */
+    public static float interpolateCatmullRom(float u, float T, float p0, float p1, float p2, float p3) {
+        float c1, c2, c3, c4;
+        c1 = p1;
+        c2 = -1.0f * T * p0 + T * p2;
+        c3 = 2 * T * p0 + (T - 3) * p1 + (3 - 2 * T) * p2 + -T * p3;
+        c4 = -T * p0 + (2 - T) * p1 + (T - 2) * p2 + T * p3;
+
+        return (float) (((c4 * u + c3) * u + c2) * u + c1);
+    }
+
+    /**Interpolate a spline between at least 4 control points following the Catmull-Rom equation.
+     * here is the interpolation matrix
+     * m = [ 0.0  1.0  0.0   0.0 ]
+     *     [-T    0.0  T     0.0 ]
+     *     [ 2T   T-3  3-2T  -T  ]
+     *     [-T    2-T  T-2   T   ]
+     * where T is the tension of the curve
+     * the result is a value between p1 and p2, t=0 for p1, t=1 for p2
+     * @param u value from 0 to 1
+     * @param T The tension of the curve
+     * @param p0 control point 0
+     * @param p1 control point 1
+     * @param p2 control point 2
+     * @param p3 control point 3
+     * @param store a Vector3f to store the result
+     * @return Catmull–Rom interpolation
+     */
+    public static Vector3f interpolateCatmullRom(float u, float T, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3, Vector3f store) {
+        if (store == null) {
+            store = new Vector3f();
+        }
+        store.x = interpolateCatmullRom(u, T, p0.x, p1.x, p2.x, p3.x);
+        store.y = interpolateCatmullRom(u, T, p0.y, p1.y, p2.y, p3.y);
+        store.z = interpolateCatmullRom(u, T, p0.z, p1.z, p2.z, p3.z);
+        return store;
+    }
+
+    /**
+     * Interpolate a spline between at least 4 control points using the
+     * Catmull-Rom equation. Here is the interpolation matrix:     
+     * m = [ 0.0  1.0  0.0   0.0 ]
+     *     [-T    0.0  T     0.0 ]
+     *     [ 2T   T-3  3-2T  -T  ]
+     *     [-T    2-T  T-2   T   ]
+     * where T is the tension of the curve
+     * the result is a value between p1 and p2, t=0 for p1, t=1 for p2
+     * @param u value from 0 to 1
+     * @param T The tension of the curve
+     * @param p0 control point 0
+     * @param p1 control point 1
+     * @param p2 control point 2
+     * @param p3 control point 3
+     * @return Catmull–Rom interpolation
+     */
+    public static Vector3f interpolateCatmullRom(float u, float T, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) {
+        return interpolateCatmullRom(u, T, p0, p1, p2, p3, null);
+    }
+
+    /**Interpolate a spline between at least 4 control points following the Bezier equation.
+     * here is the interpolation matrix
+     * m = [ -1.0   3.0  -3.0    1.0 ]
+     *     [  3.0  -6.0   3.0    0.0 ]
+     *     [ -3.0   3.0   0.0    0.0 ]
+     *     [  1.0   0.0   0.0    0.0 ]
+     * where T is the curve tension
+     * the result is a value between p1 and p3, t=0 for p1, t=1 for p3
+     * @param u value from 0 to 1
+     * @param p0 control point 0
+     * @param p1 control point 1
+     * @param p2 control point 2
+     * @param p3 control point 3
+     * @return Bezier interpolation
+     */
+    public static float interpolateBezier(float u, float p0, float p1, float p2, float p3) {
+        float oneMinusU = 1.0f - u;
+        float oneMinusU2 = oneMinusU * oneMinusU;
+        float u2 = u * u;
+        return p0 * oneMinusU2 * oneMinusU
+                + 3.0f * p1 * u * oneMinusU2
+                + 3.0f * p2 * u2 * oneMinusU
+                + p3 * u2 * u;
+    }
+
+    /**Interpolate a spline between at least 4 control points following the Bezier equation.
+     * here is the interpolation matrix
+     * m = [ -1.0   3.0  -3.0    1.0 ]
+     *     [  3.0  -6.0   3.0    0.0 ]
+     *     [ -3.0   3.0   0.0    0.0 ]
+     *     [  1.0   0.0   0.0    0.0 ]
+     * where T is the tension of the curve
+     * the result is a value between p1 and p3, t=0 for p1, t=1 for p3
+     * @param u value from 0 to 1
+     * @param p0 control point 0
+     * @param p1 control point 1
+     * @param p2 control point 2
+     * @param p3 control point 3
+     * @param store a Vector3f to store the result
+     * @return Bezier interpolation
+     */
+    public static Vector3f interpolateBezier(float u, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3, Vector3f store) {
+        if (store == null) {
+            store = new Vector3f();
+        }
+        store.x = interpolateBezier(u, p0.x, p1.x, p2.x, p3.x);
+        store.y = interpolateBezier(u, p0.y, p1.y, p2.y, p3.y);
+        store.z = interpolateBezier(u, p0.z, p1.z, p2.z, p3.z);
+        return store;
+    }
+
+    /**Interpolate a spline between at least 4 control points following the Bezier equation.
+     * here is the interpolation matrix
+     * m = [ -1.0   3.0  -3.0    1.0 ]
+     *     [  3.0  -6.0   3.0    0.0 ]
+     *     [ -3.0   3.0   0.0    0.0 ]
+     *     [  1.0   0.0   0.0    0.0 ]
+     * where T is the tension of the curve
+     * the result is a value between p1 and p3, t=0 for p1, t=1 for p3
+     * @param u value from 0 to 1
+     * @param p0 control point 0
+     * @param p1 control point 1
+     * @param p2 control point 2
+     * @param p3 control point 3
+     * @return Bezier interpolation
+     */
+    public static Vector3f interpolateBezier(float u, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) {
+        return interpolateBezier(u, p0, p1, p2, p3, null);
+    }
+
+    /**
+     * Compute the length of a Catmull–Rom spline between control points 1 and 2
+     * @param p0 control point 0
+     * @param p1 control point 1
+     * @param p2 control point 2
+     * @param p3 control point 3
+     * @param startRange the starting range on the segment (use 0)
+     * @param endRange the end range on the segment (use 1)
+     * @param curveTension the curve tension
+     * @return the length of the segment
+     */
+    public static float getCatmullRomP1toP2Length(Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3, float startRange, float endRange, float curveTension) {
+
+        float epsilon = 0.001f;
+        float middleValue = (startRange + endRange) * 0.5f;
+        Vector3f start = p1.clone();
+        if (startRange != 0) {
+            FastMath.interpolateCatmullRom(startRange, curveTension, p0, p1, p2, p3, start);
+        }
+        Vector3f end = p2.clone();
+        if (endRange != 1) {
+            FastMath.interpolateCatmullRom(endRange, curveTension, p0, p1, p2, p3, end);
+        }
+        Vector3f middle = FastMath.interpolateCatmullRom(middleValue, curveTension, p0, p1, p2, p3);
+        float l = end.subtract(start).length();
+        float l1 = middle.subtract(start).length();
+        float l2 = end.subtract(middle).length();
+        float len = l1 + l2;
+        if (l + epsilon < len) {
+            l1 = getCatmullRomP1toP2Length(p0, p1, p2, p3, startRange, middleValue, curveTension);
+            l2 = getCatmullRomP1toP2Length(p0, p1, p2, p3, middleValue, endRange, curveTension);
+        }
+        l = l1 + l2;
+        return l;
+    }
+
+    /**
+     * Compute the length on a Bezier spline between control points 1 and 2.
+     * @param p0 control point 0
+     * @param p1 control point 1
+     * @param p2 control point 2
+     * @param p3 control point 3
+     * @return the length of the segment
+     */
+    public static float getBezierP1toP2Length(Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) {
+        float delta = 0.02f, t = 0.0f, result = 0.0f;
+        Vector3f v1 = p0.clone(), v2 = new Vector3f();
+        while (t <= 1.0f) {
+            FastMath.interpolateBezier(t, p0, p1, p2, p3, v2);
+            result += v1.subtractLocal(v2).length();
+            v1.set(v2);
+            t += delta;
+        }
+        return result;
+    }
+
+    /**
+     * Returns the arc cosine of a value.<br>
+     * Special cases:
+     * <ul><li>If fValue is smaller than -1, then the result is PI.
+     * <li>If the argument is greater than 1, then the result is 0.</ul>
+     * @param fValue The value to arc cosine.
+     * @return The angle, in radians.
+     * @see java.lang.Math#acos(double)
+     */
+    public static float acos(float fValue) {
+        if (-1.0f < fValue) {
+            if (fValue < 1.0f) {
+                return (float) Math.acos(fValue);
+            }
+
+            return 0.0f;
+        }
+
+        return PI;
+    }
+
+    /**
+     * Returns the arc sine of a value.<br>
+     * Special cases:
+     * <ul><li>If fValue is smaller than -1, then the result is -HALF_PI.
+     * <li>If the argument is greater than 1, then the result is HALF_PI.</ul>
+     * @param fValue The value to arc sine.
+     * @return the angle in radians.
+     * @see java.lang.Math#asin(double)
+     */
+    public static float asin(float fValue) {
+        if (-1.0f < fValue) {
+            if (fValue < 1.0f) {
+                return (float) Math.asin(fValue);
+            }
+
+            return HALF_PI;
+        }
+
+        return -HALF_PI;
+    }
+
+    /**
+     * Returns the arc tangent of an angle given in radians.<br>
+     * @param fValue The angle, in radians.
+     * @return fValue's atan
+     * @see java.lang.Math#atan(double)
+     */
+    public static float atan(float fValue) {
+        return (float) Math.atan(fValue);
+    }
+
+    /**
+     * A direct call to Math.atan2.
+     * @param fY
+     * @param fX
+     * @return Math.atan2(fY,fX)
+     * @see java.lang.Math#atan2(double, double)
+     */
+    public static float atan2(float fY, float fX) {
+        return (float) Math.atan2(fY, fX);
+    }
+
+    /**
+     * Rounds a fValue up.  A call to Math.ceil
+     * @param fValue The value.
+     * @return The fValue rounded up
+     * @see java.lang.Math#ceil(double)
+     */
+    public static float ceil(float fValue) {
+        return (float) Math.ceil(fValue);
+    }
+
+    /**
+     * Returns cosine of an angle. Direct call to java.lang.Math
+     * @see Math#cos(double) 
+     * @param v The angle to cosine.
+     * @return  the cosine of the angle.
+     */
+    public static float cos(float v) {
+        return (float) Math.cos(v);
+    }
+
+    /**
+     * Returns the sine of an angle. Direct call to java.lang.Math
+     * @see Math#sin(double) 
+     * @param v The angle to sine.
+     * @return the sine of the angle.
+     */
+    public static float sin(float v) {
+        return (float) Math.sin(v);
+    }
+
+    /**
+     * Returns E^fValue
+     * @param fValue Value to raise to a power.
+     * @return The value E^fValue
+     * @see java.lang.Math#exp(double)
+     */
+    public static float exp(float fValue) {
+        return (float) Math.exp(fValue);
+    }
+
+    /**
+     * Returns Absolute value of a float.
+     * @param fValue The value to abs.
+     * @return The abs of the value.
+     * @see java.lang.Math#abs(float)
+     */
+    public static float abs(float fValue) {
+        if (fValue < 0) {
+            return -fValue;
+        }
+        return fValue;
+    }
+
+    /**
+     * Returns a number rounded down.
+     * @param fValue The value to round
+     * @return The given number rounded down
+     * @see java.lang.Math#floor(double)
+     */
+    public static float floor(float fValue) {
+        return (float) Math.floor(fValue);
+    }
+
+    /**
+     * Returns 1/sqrt(fValue)
+     * @param fValue The value to process.
+     * @return 1/sqrt(fValue)
+     * @see java.lang.Math#sqrt(double)
+     */
+    public static float invSqrt(float fValue) {
+        return (float) (1.0f / Math.sqrt(fValue));
+    }
+
+    public static float fastInvSqrt(float x) {
+        float xhalf = 0.5f * x;
+        int i = Float.floatToIntBits(x); // get bits for floating value
+        i = 0x5f375a86 - (i >> 1); // gives initial guess y0
+        x = Float.intBitsToFloat(i); // convert bits back to float
+        x = x * (1.5f - xhalf * x * x); // Newton step, repeating increases accuracy
+        return x;
+    }
+
+    /**
+     * Returns the log base E of a value.
+     * @param fValue The value to log.
+     * @return The log of fValue base E
+     * @see java.lang.Math#log(double)
+     */
+    public static float log(float fValue) {
+        return (float) Math.log(fValue);
+    }
+
+    /**
+     * Returns the logarithm of value with given base, calculated as log(value)/log(base), 
+     * so that pow(base, return)==value (contributed by vear)
+     * @param value The value to log.
+     * @param base Base of logarithm.
+     * @return The logarithm of value with given base
+     */
+    public static float log(float value, float base) {
+        return (float) (Math.log(value) / Math.log(base));
+    }
+
+    /**
+     * Returns a number raised to an exponent power.  fBase^fExponent
+     * @param fBase The base value (IE 2)
+     * @param fExponent The exponent value (IE 3)
+     * @return base raised to exponent (IE 8)
+     * @see java.lang.Math#pow(double, double)
+     */
+    public static float pow(float fBase, float fExponent) {
+        return (float) Math.pow(fBase, fExponent);
+    }
+
+    /**
+     * Returns the value squared.  fValue ^ 2
+     * @param fValue The value to square.
+     * @return The square of the given value.
+     */
+    public static float sqr(float fValue) {
+        return fValue * fValue;
+    }
+
+    /**
+     * Returns the square root of a given value.
+     * @param fValue The value to sqrt.
+     * @return The square root of the given value.
+     * @see java.lang.Math#sqrt(double)
+     */
+    public static float sqrt(float fValue) {
+        return (float) Math.sqrt(fValue);
+    }
+
+    /**
+     * Returns the tangent of a value.  If USE_FAST_TRIG is enabled, an approximate value
+     * is returned.  Otherwise, a direct value is used.
+     * @param fValue The value to tangent, in radians.
+     * @return The tangent of fValue.
+     * @see java.lang.Math#tan(double)
+     */
+    public static float tan(float fValue) {
+        return (float) Math.tan(fValue);
+    }
+
+    /**
+     * Returns 1 if the number is positive, -1 if the number is negative, and 0 otherwise
+     * @param iValue The integer to examine.
+     * @return The integer's sign.
+     */
+    public static int sign(int iValue) {
+        if (iValue > 0) {
+            return 1;
+        }
+        if (iValue < 0) {
+            return -1;
+        }
+        return 0;
+    }
+
+    /**
+     * Returns 1 if the number is positive, -1 if the number is negative, and 0 otherwise
+     * @param fValue The float to examine.
+     * @return The float's sign.
+     */
+    public static float sign(float fValue) {
+        return Math.signum(fValue);
+    }
+
+    /**
+     * Given 3 points in a 2d plane, this function computes if the points going from A-B-C
+     * are moving counter clock wise.
+     * @param p0 Point 0.
+     * @param p1 Point 1.
+     * @param p2 Point 2.
+     * @return 1 If they are CCW, -1 if they are not CCW, 0 if p2 is between p0 and p1.
+     */
+    public static int counterClockwise(Vector2f p0, Vector2f p1, Vector2f p2) {
+        float dx1, dx2, dy1, dy2;
+        dx1 = p1.x - p0.x;
+        dy1 = p1.y - p0.y;
+        dx2 = p2.x - p0.x;
+        dy2 = p2.y - p0.y;
+        if (dx1 * dy2 > dy1 * dx2) {
+            return 1;
+        }
+        if (dx1 * dy2 < dy1 * dx2) {
+            return -1;
+        }
+        if ((dx1 * dx2 < 0) || (dy1 * dy2 < 0)) {
+            return -1;
+        }
+        if ((dx1 * dx1 + dy1 * dy1) < (dx2 * dx2 + dy2 * dy2)) {
+            return 1;
+        }
+        return 0;
+    }
+
+    /**
+     * Test if a point is inside a triangle.  1 if the point is on the ccw side,
+     * -1 if the point is on the cw side, and 0 if it is on neither.
+     * @param t0 First point of the triangle.
+     * @param t1 Second point of the triangle.
+     * @param t2 Third point of the triangle.
+     * @param p The point to test.
+     * @return Value 1 or -1 if inside triangle, 0 otherwise.
+     */
+    public static int pointInsideTriangle(Vector2f t0, Vector2f t1, Vector2f t2, Vector2f p) {
+        int val1 = counterClockwise(t0, t1, p);
+        if (val1 == 0) {
+            return 1;
+        }
+        int val2 = counterClockwise(t1, t2, p);
+        if (val2 == 0) {
+            return 1;
+        }
+        if (val2 != val1) {
+            return 0;
+        }
+        int val3 = counterClockwise(t2, t0, p);
+        if (val3 == 0) {
+            return 1;
+        }
+        if (val3 != val1) {
+            return 0;
+        }
+        return val3;
+    }
+
+    /**
+     * A method that computes normal for a triangle defined by three vertices.
+     * @param v1 first vertex
+     * @param v2 second vertex
+     * @param v3 third vertex
+     * @return a normal for the face
+     */
+    public static Vector3f computeNormal(Vector3f v1, Vector3f v2, Vector3f v3) {
+        Vector3f a1 = v1.subtract(v2);
+        Vector3f a2 = v3.subtract(v2);
+        return a2.crossLocal(a1).normalizeLocal();
+    }
+
+    /**
+     * Returns the determinant of a 4x4 matrix.
+     */
+    public static float determinant(double m00, double m01, double m02,
+            double m03, double m10, double m11, double m12, double m13,
+            double m20, double m21, double m22, double m23, double m30,
+            double m31, double m32, double m33) {
+
+        double det01 = m20 * m31 - m21 * m30;
+        double det02 = m20 * m32 - m22 * m30;
+        double det03 = m20 * m33 - m23 * m30;
+        double det12 = m21 * m32 - m22 * m31;
+        double det13 = m21 * m33 - m23 * m31;
+        double det23 = m22 * m33 - m23 * m32;
+        return (float) (m00 * (m11 * det23 - m12 * det13 + m13 * det12) - m01
+                * (m10 * det23 - m12 * det03 + m13 * det02) + m02
+                * (m10 * det13 - m11 * det03 + m13 * det01) - m03
+                * (m10 * det12 - m11 * det02 + m12 * det01));
+    }
+
+    /**
+     * Returns a random float between 0 and 1.
+     * 
+     * @return A random float between <tt>0.0f</tt> (inclusive) to
+     *         <tt>1.0f</tt> (exclusive).
+     */
+    public static float nextRandomFloat() {
+        return rand.nextFloat();
+    }
+
+    /**
+     * Returns a random integer between min and max.
+     * 
+     * @return A random int between <tt>min</tt> (inclusive) to
+     *         <tt>max</tt> (inclusive).
+     */
+    public static int nextRandomInt(int min, int max) {
+        return (int) (nextRandomFloat() * (max - min + 1)) + min;
+    }
+
+    public static int nextRandomInt() {
+        return rand.nextInt();
+    }
+
+    /**
+     * Converts a point from Spherical coordinates to Cartesian (using positive
+     * Y as up) and stores the results in the store var.
+     */
+    public static Vector3f sphericalToCartesian(Vector3f sphereCoords,
+            Vector3f store) {
+        if (store == null) {
+            store = new Vector3f();
+        }
+        store.y = sphereCoords.x * FastMath.sin(sphereCoords.z);
+        float a = sphereCoords.x * FastMath.cos(sphereCoords.z);
+        store.x = a * FastMath.cos(sphereCoords.y);
+        store.z = a * FastMath.sin(sphereCoords.y);
+
+        return store;
+    }
+
+    /**
+     * Converts a point from Cartesian coordinates (using positive Y as up) to
+     * Spherical and stores the results in the store var. (Radius, Azimuth,
+     * Polar)
+     */
+    public static Vector3f cartesianToSpherical(Vector3f cartCoords,
+            Vector3f store) {
+        if (store == null) {
+            store = new Vector3f();
+        }
+        float x = cartCoords.x;
+        if (x == 0) {
+            x = FastMath.FLT_EPSILON;
+        }
+        store.x = FastMath.sqrt((x * x)
+                + (cartCoords.y * cartCoords.y)
+                + (cartCoords.z * cartCoords.z));
+        store.y = FastMath.atan(cartCoords.z / x);
+        if (x < 0) {
+            store.y += FastMath.PI;
+        }
+        store.z = FastMath.asin(cartCoords.y / store.x);
+        return store;
+    }
+
+    /**
+     * Converts a point from Spherical coordinates to Cartesian (using positive
+     * Z as up) and stores the results in the store var.
+     */
+    public static Vector3f sphericalToCartesianZ(Vector3f sphereCoords,
+            Vector3f store) {
+        if (store == null) {
+            store = new Vector3f();
+        }
+        store.z = sphereCoords.x * FastMath.sin(sphereCoords.z);
+        float a = sphereCoords.x * FastMath.cos(sphereCoords.z);
+        store.x = a * FastMath.cos(sphereCoords.y);
+        store.y = a * FastMath.sin(sphereCoords.y);
+
+        return store;
+    }
+
+    /**
+     * Converts a point from Cartesian coordinates (using positive Z as up) to
+     * Spherical and stores the results in the store var. (Radius, Azimuth,
+     * Polar)
+     */
+    public static Vector3f cartesianZToSpherical(Vector3f cartCoords,
+            Vector3f store) {
+        if (store == null) {
+            store = new Vector3f();
+        }
+        float x = cartCoords.x;
+        if (x == 0) {
+            x = FastMath.FLT_EPSILON;
+        }
+        store.x = FastMath.sqrt((x * x)
+                + (cartCoords.y * cartCoords.y)
+                + (cartCoords.z * cartCoords.z));
+        store.z = FastMath.atan(cartCoords.z / x);
+        if (x < 0) {
+            store.z += FastMath.PI;
+        }
+        store.y = FastMath.asin(cartCoords.y / store.x);
+        return store;
+    }
+
+    /**
+     * Takes an value and expresses it in terms of min to max.
+     * 
+     * @param val -
+     *            the angle to normalize (in radians)
+     * @return the normalized angle (also in radians)
+     */
+    public static float normalize(float val, float min, float max) {
+        if (Float.isInfinite(val) || Float.isNaN(val)) {
+            return 0f;
+        }
+        float range = max - min;
+        while (val > max) {
+            val -= range;
+        }
+        while (val < min) {
+            val += range;
+        }
+        return val;
+    }
+
+    /**
+     * @param x
+     *            the value whose sign is to be adjusted.
+     * @param y
+     *            the value whose sign is to be used.
+     * @return x with its sign changed to match the sign of y.
+     */
+    public static float copysign(float x, float y) {
+        if (y >= 0 && x <= -0) {
+            return -x;
+        } else if (y < 0 && x >= 0) {
+            return -x;
+        } else {
+            return x;
+        }
+    }
+
+    /**
+     * Take a float input and clamp it between min and max.
+     * 
+     * @param input
+     * @param min
+     * @param max
+     * @return clamped input
+     */
+    public static float clamp(float input, float min, float max) {
+        return (input < min) ? min : (input > max) ? max : input;
+    }
+
+    /**
+     * Clamps the given float to be between 0 and 1.
+     *
+     * @param input
+     * @return input clamped between 0 and 1.
+     */
+    public static float saturate(float input) {
+        return clamp(input, 0f, 1f);
+    }
+
+    /**
+     * Converts a single precision (32 bit) floating point value
+     * into half precision (16 bit).
+     *
+     * <p>Source: <a href="http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf">
+     * http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf</a><br><strong>broken link</strong>
+     *
+     * @param half The half floating point value as a short.
+     * @return floating point value of the half.
+     */
+    public static float convertHalfToFloat(short half) {
+        switch ((int) half) {
+            case 0x0000:
+                return 0f;
+            case 0x8000:
+                return -0f;
+            case 0x7c00:
+                return Float.POSITIVE_INFINITY;
+            case 0xfc00:
+                return Float.NEGATIVE_INFINITY;
+            // TODO: Support for NaN?
+            default:
+                return Float.intBitsToFloat(((half & 0x8000) << 16)
+                        | (((half & 0x7c00) + 0x1C000) << 13)
+                        | ((half & 0x03FF) << 13));
+        }
+    }
+
+    public static short convertFloatToHalf(float flt) {
+        if (Float.isNaN(flt)) {
+            throw new UnsupportedOperationException("NaN to half conversion not supported!");
+        } else if (flt == Float.POSITIVE_INFINITY) {
+            return (short) 0x7c00;
+        } else if (flt == Float.NEGATIVE_INFINITY) {
+            return (short) 0xfc00;
+        } else if (flt == 0f) {
+            return (short) 0x0000;
+        } else if (flt == -0f) {
+            return (short) 0x8000;
+        } else if (flt > 65504f) {
+            // max value supported by half float
+            return 0x7bff;
+        } else if (flt < -65504f) {
+            return (short) (0x7bff | 0x8000);
+        } else if (flt > 0f && flt < 5.96046E-8f) {
+            return 0x0001;
+        } else if (flt < 0f && flt > -5.96046E-8f) {
+            return (short) 0x8001;
+        }
+
+        int f = Float.floatToIntBits(flt);
+        return (short) (((f >> 16) & 0x8000)
+                | ((((f & 0x7f800000) - 0x38000000) >> 13) & 0x7c00)
+                | ((f >> 13) & 0x03ff));
+    }
+}

+ 456 - 456
jme3-core/src/main/java/com/jme3/post/Filter.java

@@ -1,456 +1,456 @@
-/*
- * Copyright (c) 2009-2012 jMonkeyEngine
- * 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 'jMonkeyEngine' 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.jme3.post;
-
-import com.jme3.asset.AssetManager;
-import com.jme3.export.*;
-import com.jme3.material.Material;
-import com.jme3.renderer.Caps;
-import com.jme3.renderer.RenderManager;
-import com.jme3.renderer.Renderer;
-import com.jme3.renderer.ViewPort;
-import com.jme3.renderer.queue.RenderQueue;
-import com.jme3.texture.FrameBuffer;
-import com.jme3.texture.Image.Format;
-import com.jme3.texture.Texture;
-import com.jme3.texture.Texture2D;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Filters are 2D effects applied to the rendered scene.<br>
- * The filter is fed with the rendered scene image rendered in an offscreen frame buffer.<br>
- * This texture is applied on a fullscreen quad, with a special material.<br>
- * This material uses a shader that aplly the desired effect to the scene texture.<br>
- * <br>
- * This class is abstract, any Filter must extend it.<br>
- * Any filter holds a frameBuffer and a texture<br>
- * The getMaterial must return a Material that use a GLSL shader immplementing the desired effect<br>
- *
- * @author Rémy Bouquet aka Nehon
- */
-public abstract class Filter implements Savable {
-
-
-    private String name;
-    protected Pass defaultPass;
-    protected List<Pass> postRenderPasses;
-    protected Material material;
-    protected boolean enabled = true;
-    protected FilterPostProcessor processor;
-
-    public Filter(String name) {
-        this.name = name;
-    }
-
-    /**
-     * Inner class Pass
-     * Pass are like filters in filters.
-     * Some filters will need multiple passes before the final render
-     */
-    public class Pass {
-
-        protected FrameBuffer renderFrameBuffer;
-        protected Texture2D renderedTexture;
-        protected Texture2D depthTexture;
-        protected Material passMaterial;
-
-        /**
-         * init the pass called internally
-         * @param renderer
-         * @param width
-         * @param height
-         * @param textureFormat
-         * @param depthBufferFormat
-         * @param numSamples
-         */
-        public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat, int numSamples, boolean renderDepth) {
-            Collection<Caps> caps = renderer.getCaps();
-            if (numSamples > 1 && caps.contains(Caps.FrameBufferMultisample) && caps.contains(Caps.OpenGL31)) {
-                renderFrameBuffer = new FrameBuffer(width, height, numSamples);                
-                renderedTexture = new Texture2D(width, height, numSamples, textureFormat);
-                renderFrameBuffer.setDepthBuffer(depthBufferFormat);
-                if (renderDepth) {
-                    depthTexture = new Texture2D(width, height, numSamples, depthBufferFormat);
-                    renderFrameBuffer.setDepthTexture(depthTexture);
-                }
-            } else {
-                renderFrameBuffer = new FrameBuffer(width, height, 1);
-                renderedTexture = new Texture2D(width, height, textureFormat);
-                renderFrameBuffer.setDepthBuffer(depthBufferFormat);
-                if (renderDepth) {
-                    depthTexture = new Texture2D(width, height, depthBufferFormat);
-                    renderFrameBuffer.setDepthTexture(depthTexture);
-                }
-            }
-
-            renderFrameBuffer.setColorTexture(renderedTexture);
-
-
-        }
-
-        /**
-         *  init the pass called internally
-         * @param renderer
-         * @param width
-         * @param height
-         * @param textureFormat
-         * @param depthBufferFormat
-         */
-        public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat) {
-            init(renderer, width, height, textureFormat, depthBufferFormat, 1);
-        }
-
-        public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat, int numSamples) {
-            init(renderer, width, height, textureFormat, depthBufferFormat, numSamples, false);
-        }
-
-        /**
-         *  init the pass called internally
-         * @param renderer
-         * @param width
-         * @param height
-         * @param textureFormat
-         * @param depthBufferFormat
-         * @param numSample
-         * @param material
-         */
-        public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat, int numSample, Material material) {
-            init(renderer, width, height, textureFormat, depthBufferFormat, numSample);
-            passMaterial = material;
-        }
-
-        public boolean requiresSceneAsTexture() {
-            return false;
-        }
-
-        public boolean requiresDepthAsTexture() {
-            return false;
-        }
-
-        public void beforeRender() {
-        }
-
-        public FrameBuffer getRenderFrameBuffer() {
-            return renderFrameBuffer;
-        }
-
-        public void setRenderFrameBuffer(FrameBuffer renderFrameBuffer) {
-            this.renderFrameBuffer = renderFrameBuffer;
-        }
-
-        public Texture2D getDepthTexture() {
-            return depthTexture;
-        }
-
-        public Texture2D getRenderedTexture() {
-            return renderedTexture;
-        }
-
-        public void setRenderedTexture(Texture2D renderedTexture) {
-            this.renderedTexture = renderedTexture;
-        }
-
-        public Material getPassMaterial() {
-            return passMaterial;
-        }
-
-        public void setPassMaterial(Material passMaterial) {
-            this.passMaterial = passMaterial;
-        }
-
-        public void cleanup(Renderer r) {
-            renderFrameBuffer.dispose();
-            renderedTexture.getImage().dispose();
-            if(depthTexture!=null){
-                depthTexture.getImage().dispose();
-            }  
-        }
-    }
-
-    /**
-     * returns the default pass texture format
-     * @return
-     */
-    protected Format getDefaultPassTextureFormat() {
-        return Format.RGBA8;
-    }
-
-    /**
-     * returns the default pass depth format
-     * @return
-     */
-    protected Format getDefaultPassDepthFormat() {
-        return Format.Depth;
-    }
-
-    /**
-     * contruct a Filter
-     */
-    protected Filter() {
-        this("filter");
-    }
-
-    /**
-     *
-     * initialize this filter
-     * use InitFilter for overriding filter initialization
-     * @param manager the assetManager
-     * @param renderManager the renderManager
-     * @param vp the viewport
-     * @param w the width
-     * @param h the height
-     */
-    protected final void init(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
-        //  cleanup(renderManager.getRenderer());
-        defaultPass = new Pass();
-        defaultPass.init(renderManager.getRenderer(), w, h, getDefaultPassTextureFormat(), getDefaultPassDepthFormat());
-        initFilter(manager, renderManager, vp, w, h);
-    }
-
-    /**
-     * cleanup this filter
-     * @param r
-     */
-    protected final void cleanup(Renderer r) {   
-        processor = null;
-        if (defaultPass != null) {
-            defaultPass.cleanup(r);
-        }
-        if (postRenderPasses != null) {
-            for (Iterator<Pass> it = postRenderPasses.iterator(); it.hasNext();) {
-                Pass pass = it.next();
-                pass.cleanup(r);
-            }
-        }
-        cleanUpFilter(r);
-    }
-
-    /**
-     * Initialization of sub classes filters
-     * This method is called once when the filter is added to the FilterPostProcessor
-     * It should contain Material initializations and extra passes initialization
-     * @param manager the assetManager
-     * @param renderManager the renderManager
-     * @param vp the viewPort where this filter is rendered
-     * @param w the width of the filter
-     * @param h the height of the filter
-     */
-    protected abstract void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h);
-
-    /**
-     * override this method if you have some cleanup to do
-     * @param r the renderer
-     */
-    protected void cleanUpFilter(Renderer r) {
-    }
-
-    /**
-     * Must return the material used for this filter.
-     * this method is called every frame.
-     *
-     * @return the material used for this filter.
-     */
-    protected abstract Material getMaterial();
-    
-    /**
-     * Override if you want to do something special with the depth texture;
-     * @param depthTexture 
-     */
-    protected void setDepthTexture(Texture depthTexture){
-        getMaterial().setTexture("DepthTexture", depthTexture);
-    }
-
-    /**
-     * Override this method if you want to make a pre pass, before the actual rendering of the frame
-     * @param queue
-     */
-    protected void postQueue(RenderQueue queue) {
-    }
-
-    /**
-     * Override this method if you want to modify parameters according to tpf before the rendering of the frame.
-     * This is usefull for animated filters
-     * Also it can be the place to render pre passes
-     * @param tpf the time used to render the previous frame
-     */
-    protected void preFrame(float tpf) {
-    }
-
-    /**
-     * Override this method if you want to make a pass just after the frame has been rendered and just before the filter rendering
-     * @param renderManager
-     * @param viewPort
-     * @param prevFilterBuffer
-     * @param sceneBuffer
-     */
-    protected void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) {
-    }
-
-    /**
-     * Override this method if you want to save extra properties when the filter is saved else only basic properties of the filter will be saved
-     * This method should always begin by super.write(ex);
-     * @param ex
-     * @throws IOException
-     */
-    public void write(JmeExporter ex) throws IOException {
-        OutputCapsule oc = ex.getCapsule(this);
-        oc.write(name, "name", "");
-        oc.write(enabled, "enabled", true);
-    }
-
-    /**
-     * Override this method if you want to load extra properties when the filter
-     * is loaded else only basic properties of the filter will be loaded
-     * This method should always begin by super.read(im);
-     */
-    public void read(JmeImporter im) throws IOException {
-        InputCapsule ic = im.getCapsule(this);
-        name = ic.readString("name", "");
-        enabled = ic.readBoolean("enabled", true);
-    }
-
-    /**
-     * returns the name of the filter
-     * @return the Filter's name
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Sets the name of the filter
-     * @param name
-     */
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    /**
-     * returns the default pass frame buffer
-     * @return
-     */
-    protected FrameBuffer getRenderFrameBuffer() {
-        return defaultPass.renderFrameBuffer;
-    }
-
-    /**
-     * sets the default pas frame buffer
-     * @param renderFrameBuffer
-     */
-    protected void setRenderFrameBuffer(FrameBuffer renderFrameBuffer) {
-        this.defaultPass.renderFrameBuffer = renderFrameBuffer;
-    }
-
-    /**
-     * returns the rendered texture of this filter
-     * @return
-     */
-    protected Texture2D getRenderedTexture() {
-        return defaultPass.renderedTexture;
-    }
-
-    /**
-     * sets the rendered texture of this filter
-     * @param renderedTexture
-     */
-    protected void setRenderedTexture(Texture2D renderedTexture) {
-        this.defaultPass.renderedTexture = renderedTexture;
-    }
-
-    /**
-     * Override this method and return true if your Filter needs the depth texture
-     *
-     * @return true if your Filter need the depth texture
-     */
-    protected boolean isRequiresDepthTexture() {
-        return false;
-    }
-
-    /**
-     * Override this method and return false if your Filter does not need the scene texture
-     *
-     * @return false if your Filter does not need the scene texture
-     */
-    protected boolean isRequiresSceneTexture() {
-        return true;
-    }
-
-    /**
-     * returns the list of the postRender passes
-     * @return
-     */
-    protected List<Pass> getPostRenderPasses() {
-        return postRenderPasses;
-    }
-
-    /**
-     * Enable or disable this filter
-     * @param enabled true to enable
-     */
-    public void setEnabled(boolean enabled) {
-        if (processor != null) {
-            processor.setFilterState(this, enabled);
-        } else {
-            this.enabled = enabled;
-        }
-    }
-
-    /**
-     * returns ttrue if the filter is enabled
-     * @return enabled
-     */
-    public boolean isEnabled() {
-        return enabled;
-    }
-
-    /**
-     * sets a reference to the FilterPostProcessor ti which this filter is attached
-     * @param proc
-     */
-    protected void setProcessor(FilterPostProcessor proc) {
-        processor = proc;
-    }
-
-    /**
-     * This method is called right after the filter has been rendered to the 
-     * framebuffer.
-     * Note that buffer will be null if the filter is the last one in the stack 
-     * and has been rendered to screen
-     * @param r the renderer
-     * @param buffer the framebuffer on hich the filtre has been rendered.
-     */
-    protected void postFilter(Renderer r, FrameBuffer buffer){        
-    }
-}
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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.jme3.post;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.export.*;
+import com.jme3.material.Material;
+import com.jme3.renderer.Caps;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.texture.FrameBuffer;
+import com.jme3.texture.Image.Format;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture2D;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Filters are 2D effects applied to the rendered scene.<br>
+ * The filter is fed with the rendered scene image rendered in an offscreen frame buffer.<br>
+ * This texture is applied on a full-screen quad with a special material.<br>
+ * This material uses a shader that applies the desired effect to the scene texture.<br>
+ * <br>
+ * This class is abstract, any Filter must extend it.<br>
+ * Any filter holds a frameBuffer and a texture<br>
+ * The getMaterial must return a Material that use a GLSL shader implementing the desired effect<br>
+ *
+ * @author Rémy Bouquet aka Nehon
+ */
+public abstract class Filter implements Savable {
+
+
+    private String name;
+    protected Pass defaultPass;
+    protected List<Pass> postRenderPasses;
+    protected Material material;
+    protected boolean enabled = true;
+    protected FilterPostProcessor processor;
+
+    public Filter(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Inner class Pass
+     * Pass are like filters in filters.
+     * Some filters will need multiple passes before the final render
+     */
+    public class Pass {
+
+        protected FrameBuffer renderFrameBuffer;
+        protected Texture2D renderedTexture;
+        protected Texture2D depthTexture;
+        protected Material passMaterial;
+
+        /**
+         * init the pass called internally
+         * @param renderer
+         * @param width
+         * @param height
+         * @param textureFormat
+         * @param depthBufferFormat
+         * @param numSamples
+         */
+        public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat, int numSamples, boolean renderDepth) {
+            Collection<Caps> caps = renderer.getCaps();
+            if (numSamples > 1 && caps.contains(Caps.FrameBufferMultisample) && caps.contains(Caps.OpenGL31)) {
+                renderFrameBuffer = new FrameBuffer(width, height, numSamples);                
+                renderedTexture = new Texture2D(width, height, numSamples, textureFormat);
+                renderFrameBuffer.setDepthBuffer(depthBufferFormat);
+                if (renderDepth) {
+                    depthTexture = new Texture2D(width, height, numSamples, depthBufferFormat);
+                    renderFrameBuffer.setDepthTexture(depthTexture);
+                }
+            } else {
+                renderFrameBuffer = new FrameBuffer(width, height, 1);
+                renderedTexture = new Texture2D(width, height, textureFormat);
+                renderFrameBuffer.setDepthBuffer(depthBufferFormat);
+                if (renderDepth) {
+                    depthTexture = new Texture2D(width, height, depthBufferFormat);
+                    renderFrameBuffer.setDepthTexture(depthTexture);
+                }
+            }
+
+            renderFrameBuffer.setColorTexture(renderedTexture);
+
+
+        }
+
+        /**
+         *  init the pass called internally
+         * @param renderer
+         * @param width
+         * @param height
+         * @param textureFormat
+         * @param depthBufferFormat
+         */
+        public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat) {
+            init(renderer, width, height, textureFormat, depthBufferFormat, 1);
+        }
+
+        public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat, int numSamples) {
+            init(renderer, width, height, textureFormat, depthBufferFormat, numSamples, false);
+        }
+
+        /**
+         *  init the pass called internally
+         * @param renderer
+         * @param width
+         * @param height
+         * @param textureFormat
+         * @param depthBufferFormat
+         * @param numSample
+         * @param material
+         */
+        public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat, int numSample, Material material) {
+            init(renderer, width, height, textureFormat, depthBufferFormat, numSample);
+            passMaterial = material;
+        }
+
+        public boolean requiresSceneAsTexture() {
+            return false;
+        }
+
+        public boolean requiresDepthAsTexture() {
+            return false;
+        }
+
+        public void beforeRender() {
+        }
+
+        public FrameBuffer getRenderFrameBuffer() {
+            return renderFrameBuffer;
+        }
+
+        public void setRenderFrameBuffer(FrameBuffer renderFrameBuffer) {
+            this.renderFrameBuffer = renderFrameBuffer;
+        }
+
+        public Texture2D getDepthTexture() {
+            return depthTexture;
+        }
+
+        public Texture2D getRenderedTexture() {
+            return renderedTexture;
+        }
+
+        public void setRenderedTexture(Texture2D renderedTexture) {
+            this.renderedTexture = renderedTexture;
+        }
+
+        public Material getPassMaterial() {
+            return passMaterial;
+        }
+
+        public void setPassMaterial(Material passMaterial) {
+            this.passMaterial = passMaterial;
+        }
+
+        public void cleanup(Renderer r) {
+            renderFrameBuffer.dispose();
+            renderedTexture.getImage().dispose();
+            if(depthTexture!=null){
+                depthTexture.getImage().dispose();
+            }  
+        }
+    }
+
+    /**
+     * returns the default pass texture format
+     * @return
+     */
+    protected Format getDefaultPassTextureFormat() {
+        return Format.RGBA8;
+    }
+
+    /**
+     * returns the default pass depth format
+     * @return
+     */
+    protected Format getDefaultPassDepthFormat() {
+        return Format.Depth;
+    }
+
+    /**
+     * construct a Filter
+     */
+    protected Filter() {
+        this("filter");
+    }
+
+    /**
+     *
+     * initialize this filter
+     * use InitFilter for overriding filter initialization
+     * @param manager the assetManager
+     * @param renderManager the renderManager
+     * @param vp the viewport
+     * @param w the width
+     * @param h the height
+     */
+    protected final void init(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+        //  cleanup(renderManager.getRenderer());
+        defaultPass = new Pass();
+        defaultPass.init(renderManager.getRenderer(), w, h, getDefaultPassTextureFormat(), getDefaultPassDepthFormat());
+        initFilter(manager, renderManager, vp, w, h);
+    }
+
+    /**
+     * cleanup this filter
+     * @param r
+     */
+    protected final void cleanup(Renderer r) {   
+        processor = null;
+        if (defaultPass != null) {
+            defaultPass.cleanup(r);
+        }
+        if (postRenderPasses != null) {
+            for (Iterator<Pass> it = postRenderPasses.iterator(); it.hasNext();) {
+                Pass pass = it.next();
+                pass.cleanup(r);
+            }
+        }
+        cleanUpFilter(r);
+    }
+
+    /**
+     * Initialization of sub classes filters
+     * This method is called once when the filter is added to the FilterPostProcessor
+     * It should contain Material initializations and extra passes initialization
+     * @param manager the assetManager
+     * @param renderManager the renderManager
+     * @param vp the viewPort where this filter is rendered
+     * @param w the width of the filter
+     * @param h the height of the filter
+     */
+    protected abstract void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h);
+
+    /**
+     * override this method if you have some cleanup to do
+     * @param r the renderer
+     */
+    protected void cleanUpFilter(Renderer r) {
+    }
+
+    /**
+     * Must return the material used for this filter.
+     * this method is called every frame.
+     *
+     * @return the material used for this filter.
+     */
+    protected abstract Material getMaterial();
+    
+    /**
+     * Override if you want to do something special with the depth texture;
+     * @param depthTexture 
+     */
+    protected void setDepthTexture(Texture depthTexture){
+        getMaterial().setTexture("DepthTexture", depthTexture);
+    }
+
+    /**
+     * Override this method if you want to make a pre pass, before the actual rendering of the frame
+     * @param queue
+     */
+    protected void postQueue(RenderQueue queue) {
+    }
+
+    /**
+     * Override this method if you want to modify parameters according to tpf before the rendering of the frame.
+     * This is useful for animated filters
+     * Also it can be the place to render pre passes
+     * @param tpf the time used to render the previous frame
+     */
+    protected void preFrame(float tpf) {
+    }
+
+    /**
+     * Override this method if you want to make a pass just after the frame has been rendered and just before the filter rendering
+     * @param renderManager
+     * @param viewPort
+     * @param prevFilterBuffer
+     * @param sceneBuffer
+     */
+    protected void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) {
+    }
+
+    /**
+     * Override this method if you want to save extra properties when the filter is saved else only basic properties of the filter will be saved
+     * This method should always begin by super.write(ex);
+     * @param ex
+     * @throws IOException
+     */
+    public void write(JmeExporter ex) throws IOException {
+        OutputCapsule oc = ex.getCapsule(this);
+        oc.write(name, "name", "");
+        oc.write(enabled, "enabled", true);
+    }
+
+    /**
+     * Override this method if you want to load extra properties when the filter
+     * is loaded else only basic properties of the filter will be loaded
+     * This method should always begin by super.read(im);
+     */
+    public void read(JmeImporter im) throws IOException {
+        InputCapsule ic = im.getCapsule(this);
+        name = ic.readString("name", "");
+        enabled = ic.readBoolean("enabled", true);
+    }
+
+    /**
+     * returns the name of the filter
+     * @return the Filter's name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets the name of the filter
+     * @param name
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * returns the default pass frame buffer
+     * @return
+     */
+    protected FrameBuffer getRenderFrameBuffer() {
+        return defaultPass.renderFrameBuffer;
+    }
+
+    /**
+     * sets the default pas frame buffer
+     * @param renderFrameBuffer
+     */
+    protected void setRenderFrameBuffer(FrameBuffer renderFrameBuffer) {
+        this.defaultPass.renderFrameBuffer = renderFrameBuffer;
+    }
+
+    /**
+     * returns the rendered texture of this filter
+     * @return
+     */
+    protected Texture2D getRenderedTexture() {
+        return defaultPass.renderedTexture;
+    }
+
+    /**
+     * sets the rendered texture of this filter
+     * @param renderedTexture
+     */
+    protected void setRenderedTexture(Texture2D renderedTexture) {
+        this.defaultPass.renderedTexture = renderedTexture;
+    }
+
+    /**
+     * Override this method and return true if your Filter needs the depth texture
+     *
+     * @return true if your Filter need the depth texture
+     */
+    protected boolean isRequiresDepthTexture() {
+        return false;
+    }
+
+    /**
+     * Override this method and return false if your Filter does not need the scene texture
+     *
+     * @return false if your Filter does not need the scene texture
+     */
+    protected boolean isRequiresSceneTexture() {
+        return true;
+    }
+
+    /**
+     * returns the list of the postRender passes
+     * @return
+     */
+    protected List<Pass> getPostRenderPasses() {
+        return postRenderPasses;
+    }
+
+    /**
+     * Enable or disable this filter
+     * @param enabled true to enable
+     */
+    public void setEnabled(boolean enabled) {
+        if (processor != null) {
+            processor.setFilterState(this, enabled);
+        } else {
+            this.enabled = enabled;
+        }
+    }
+
+    /**
+     * returns true if the filter is enabled
+     * @return enabled
+     */
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    /**
+     * sets a reference to the FilterPostProcessor ti which this filter is attached
+     * @param proc
+     */
+    protected void setProcessor(FilterPostProcessor proc) {
+        processor = proc;
+    }
+
+    /**
+     * This method is called right after the filter has been rendered to the 
+     * framebuffer.
+     * Note that buffer will be null if the filter is the last one in the stack 
+     * and has been rendered to screen
+     * @param r the renderer
+     * @param buffer the framebuffer on which the filter has been rendered.
+     */
+    protected void postFilter(Renderer r, FrameBuffer buffer){        
+    }
+}

+ 8 - 8
jme3-core/src/main/java/com/jme3/renderer/Camera.java

@@ -287,8 +287,8 @@ public class Camera implements Savable, Cloneable {
     }
     }
     
     
 	/**
 	/**
-	 * This method copise the settings of the given camera.
-	 * 
+         * This method copies the settings of the given camera.
+    	 * 
 	 * @param cam
 	 * @param cam
 	 *            the camera we copy the settings from
 	 *            the camera we copy the settings from
 	 */
 	 */
@@ -368,8 +368,8 @@ public class Camera implements Savable, Cloneable {
 
 
     /**
     /**
      * Sets a clipPlane for this camera.
      * Sets a clipPlane for this camera.
-     * The cliPlane is used to recompute the projectionMatrix using the plane as the near plane
-     * This technique is known as the oblique near-plane clipping method introduced by Eric Lengyel
+     * The clipPlane is used to recompute the
+     * projectionMatrix using the plane as the near plane     * This technique is known as the oblique near-plane clipping method introduced by Eric Lengyel
      * more info here
      * more info here
      * <ul>
      * <ul>
      * <li><a href="http://www.terathon.com/code/oblique.html">http://www.terathon.com/code/oblique.html</a>
      * <li><a href="http://www.terathon.com/code/oblique.html">http://www.terathon.com/code/oblique.html</a>
@@ -668,8 +668,8 @@ public class Camera implements Savable, Cloneable {
     }
     }
 
 
     /**
     /**
-     * <code>setRotation</code> sets the orientation of this camera. 
-     * This will be equivelant to setting each of the axes:
+     * <code>setRotation</code> sets the orientation of this camera. This will
+     * be equivalent to setting each of the axes:
      * <code><br>
      * <code><br>
      * cam.setLeft(rotation.getRotationColumn(0));<br>
      * cam.setLeft(rotation.getRotationColumn(0));<br>
      * cam.setUp(rotation.getRotationColumn(1));<br>
      * cam.setUp(rotation.getRotationColumn(1));<br>
@@ -803,7 +803,7 @@ public class Camera implements Savable, Cloneable {
     }
     }
 
 
     /**
     /**
-     * <code>lookAt</code> is a convienence method for auto-setting the frame
+     * <code>lookAt</code> is a convenience method for auto-setting the frame
      * based on a world position the user desires the camera to look at. It
      * based on a world position the user desires the camera to look at. It
      * repoints the camera towards the given position using the difference
      * repoints the camera towards the given position using the difference
      * between the position and the current camera location as a direction
      * between the position and the current camera location as a direction
@@ -996,7 +996,7 @@ public class Camera implements Savable, Cloneable {
 
 
     /**
     /**
      * <code>contains</code> tests a bounding volume against the planes of the
      * <code>contains</code> tests a bounding volume against the planes of the
-     * camera's frustum. The frustums planes are set such that the normals all
+     * camera's frustum. The frustum's planes are set such that the normals all
      * face in towards the viewable scene. Therefore, if the bounding volume is
      * face in towards the viewable scene. Therefore, if the bounding volume is
      * on the negative side of the plane is can be culled out.
      * on the negative side of the plane is can be culled out.
      *
      *

+ 1 - 1
jme3-core/src/main/java/com/jme3/renderer/Renderer.java

@@ -269,7 +269,7 @@ public interface Renderer {
     /**
     /**
      * Renders <code>count</code> meshes, with the geometry data supplied.
      * Renders <code>count</code> meshes, with the geometry data supplied.
      * The shader which is currently set with <code>setShader</code> is
      * The shader which is currently set with <code>setShader</code> is
-     * responsible for transforming the input verticies into clip space
+     * responsible for transforming the input vertices into clip space
      * and shading it based on the given vertex attributes.
      * and shading it based on the given vertex attributes.
      * The int variable gl_InstanceID can be used to access the current
      * The int variable gl_InstanceID can be used to access the current
      * instance of the mesh being rendered inside the vertex shader.
      * instance of the mesh being rendered inside the vertex shader.