Package com.ardor3d.math

Source Code of com.ardor3d.math.ColorRGBA

/**
* Copyright (c) 2008-2012 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
* Ardor3D is free software: you can redistribute it and/or modify it
* under the terms of its license which may be found in the accompanying
* LICENSE file or at <http://www.ardor3d.com/LICENSE>.
*/

package com.ardor3d.math;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

import com.ardor3d.math.type.ReadOnlyColorRGBA;
import com.ardor3d.util.export.InputCapsule;
import com.ardor3d.util.export.OutputCapsule;
import com.ardor3d.util.export.Savable;

/**
* ColorRGBA is a 4 component color value (red, green, blue, alpha). The standard range for each individual component is
* [0f, 1f]. Non-standard use of color (for example HDR rendering) may need to use values outside of this range however,
* so the value is not clipped or enforced.
*/
public class ColorRGBA implements Cloneable, Savable, Externalizable, ReadOnlyColorRGBA, Poolable {

    private static final long serialVersionUID = 1L;

    private static final ObjectPool<ColorRGBA> COLOR_POOL = ObjectPool.create(ColorRGBA.class,
            MathConstants.maxMathPoolSize);

    /**
     * the color black (0, 0, 0, 1).
     */
    public static final ReadOnlyColorRGBA BLACK = new ColorRGBA(0f, 0f, 0f, 1f);
    /**
     * the color black with a zero alpha value (0, 0, 0, 0).
     */
    public static final ReadOnlyColorRGBA BLACK_NO_ALPHA = new ColorRGBA(0f, 0f, 0f, 0f);
    /**
     * the color white (1, 1, 1, 1).
     */
    public static final ReadOnlyColorRGBA WHITE = new ColorRGBA(1f, 1f, 1f, 1f);
    /**
     * the color gray (.2f, .2f, .2f, 1).
     */
    public static final ReadOnlyColorRGBA DARK_GRAY = new ColorRGBA(0.2f, 0.2f, 0.2f, 1.0f);
    /**
     * the color gray (.5f, .5f, .5f, 1).
     */
    public static final ReadOnlyColorRGBA GRAY = new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f);
    /**
     * the color gray (.8f, .8f, .8f, 1).
     */
    public static final ReadOnlyColorRGBA LIGHT_GRAY = new ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f);
    /**
     * the color red (1, 0, 0, 1).
     */
    public static final ReadOnlyColorRGBA RED = new ColorRGBA(1f, 0f, 0f, 1f);
    /**
     * the color green (0, 1, 0, 1).
     */
    public static final ReadOnlyColorRGBA GREEN = new ColorRGBA(0f, 1f, 0f, 1f);
    /**
     * the color blue (0, 0, 1, 1).
     */
    public static final ReadOnlyColorRGBA BLUE = new ColorRGBA(0f, 0f, 1f, 1f);
    /**
     * the color yellow (1, 1, 0, 1).
     */
    public static final ReadOnlyColorRGBA YELLOW = new ColorRGBA(1f, 1f, 0f, 1f);
    /**
     * the color magenta (1, 0, 1, 1).
     */
    public static final ReadOnlyColorRGBA MAGENTA = new ColorRGBA(1f, 0f, 1f, 1f);
    /**
     * the color cyan (0, 1, 1, 1).
     */
    public static final ReadOnlyColorRGBA CYAN = new ColorRGBA(0f, 1f, 1f, 1f);
    /**
     * the color orange (251/255f, 130/255f, 0, 1).
     */
    public static final ReadOnlyColorRGBA ORANGE = new ColorRGBA(251f / 255f, 130f / 255f, 0f, 1f);
    /**
     * the color brown (65/255f, 40/255f, 25/255f, 1).
     */
    public static final ReadOnlyColorRGBA BROWN = new ColorRGBA(65f / 255f, 40f / 255f, 25f / 255f, 1f);
    /**
     * the color pink (1, 0.68f, 0.68f, 1).
     */
    public static final ReadOnlyColorRGBA PINK = new ColorRGBA(1f, 0.68f, 0.68f, 1f);

    protected float _r = 0;
    protected float _g = 0;
    protected float _b = 0;
    protected float _a = 0;

    /**
     * Constructs a new, mutable color set to (1, 1, 1, 1).
     */
    public ColorRGBA() {
        this(1, 1, 1, 1);
    }

    /**
     * Constructs a new, mutable color set to the (r, g, b, a) values of the provided source color.
     *
     * @param src
     */
    public ColorRGBA(final ReadOnlyColorRGBA src) {
        this(src.getRed(), src.getGreen(), src.getBlue(), src.getAlpha());
    }

    /**
     * Constructs a new color set to (r, g, b, a).
     *
     * @param r
     * @param g
     * @param b
     * @param a
     */
    public ColorRGBA(final float r, final float g, final float b, final float a) {
        _r = r;
        _g = g;
        _b = b;
        _a = a;
    }

    @Override
    public float getRed() {
        return _r;
    }

    @Override
    public float getGreen() {
        return _g;
    }

    @Override
    public float getBlue() {
        return _b;
    }

    @Override
    public float getAlpha() {
        return _a;
    }

    /**
     * @param index
     * @return r value if index == 0, g value if index == 1, b value if index == 2 or a value if index == 3
     * @throws IllegalArgumentException
     *             if index is not one of 0, 1, 2, 3.
     */
    @Override
    public float getValue(final int index) {
        switch (index) {
            case 0:
                return getRed();
            case 1:
                return getGreen();
            case 2:
                return getBlue();
            case 3:
                return getAlpha();
        }
        throw new IllegalArgumentException("index must be either 0, 1, 2 or 3");
    }

    /**
     * @param index
     *            which field index in this color to set.
     * @param value
     *            to set to one of r, g, b or a.
     * @throws IllegalArgumentException
     *             if index is not one of 0, 1, 2, 3.
     */
    public void setValue(final int index, final float value) {
        switch (index) {
            case 0:
                setRed(value);
                return;
            case 1:
                setGreen(value);
                return;
            case 2:
                setBlue(value);
                return;
            case 3:
                setAlpha(value);
                return;
        }
        throw new IllegalArgumentException("index must be either 0, 1, 2 or 3");
    }

    /**
     * Stores the float values of this color in the given float array.
     *
     * @param store
     *            if null, a new float[4] array is created.
     * @return the float array
     * @throws NullPointerException
     *             if store is null.
     * @throws ArrayIndexOutOfBoundsException
     *             if store is not at least length 4.
     */
    @Override
    public float[] toArray(float[] store) {
        if (store == null) {
            store = new float[4];
        }
        // do last first to ensure size is correct before any edits occur.
        store[3] = getAlpha();
        store[2] = getBlue();
        store[1] = getGreen();
        store[0] = getRed();
        return store;
    }

    /**
     * Sets the red component of this color to the given float value.
     *
     * @param r
     *            new red value, generally should be in the range [0.0f, 1.0f]
     */
    public void setRed(final float r) {
        _r = r;
    }

    /**
     * Sets the green component of this color to the given float value.
     *
     * @param g
     *            new green value, generally should be in the range [0.0f, 1.0f]
     */
    public void setGreen(final float g) {
        _g = g;
    }

    /**
     * Sets the blue component of this color to the given float value.
     *
     * @param b
     *            new blue value, generally should be in the range [0.0f, 1.0f]
     */
    public void setBlue(final float b) {
        _b = b;
    }

    /**
     * Sets the alpha component of this color to the given float value. Consider that an alpha of 1.0f means opaque (can
     * not see through) and 0.0f means transparent.
     *
     * @param a
     *            new alpha value, generally should be in the range [0.0f, 1.0f]
     */
    public void setAlpha(final float a) {
        _a = a;
    }

    /**
     * Sets the value of this color to (r, g, b, a)
     *
     * @param r
     *            new red value, generally should be in the range [0.0f, 1.0f]
     * @param g
     *            new green value, generally should be in the range [0.0f, 1.0f]
     * @param b
     *            new blue value, generally should be in the range [0.0f, 1.0f]
     * @param a
     *            new alpha value, generally should be in the range [0.0f, 1.0f]
     * @return this color for chaining
     */
    public ColorRGBA set(final float r, final float g, final float b, final float a) {
        setRed(r);
        setGreen(g);
        setBlue(b);
        setAlpha(a);
        return this;
    }

    /**
     * Sets the value of this color to the (r, g, b, a) values of the provided source color.
     *
     * @param source
     * @return this color for chaining
     * @throws NullPointerException
     *             if source is null.
     */
    public ColorRGBA set(final ReadOnlyColorRGBA source) {
        _r = source.getRed();
        _g = source.getGreen();
        _b = source.getBlue();
        _a = source.getAlpha();
        return this;
    }

    /**
     * Sets the value of this color to (0, 0, 0, 0)
     *
     * @return this color for chaining
     */
    public ColorRGBA zero() {
        return set(0, 0, 0, 0);
    }

    /**
     * Brings all values (r,g,b,a) into the range [0.0f, 1.0f]. If a value is above or below this range it is replaced
     * with the appropriate end of the range.
     *
     * @param store
     *            the color to store the result in for return. If null, a new color object is created and returned.
     */
    @Override
    public ColorRGBA clamp(final ColorRGBA store) {
        ColorRGBA result = store;
        if (result == null) {
            result = new ColorRGBA(this);
        } else if (result != this) {
            result.set(this);
        }

        if (result._r < 0.0f) {
            result._r = 0.0f;
        } else if (result._r > 1.0f) {
            result._r = 1.0f;
        }

        if (result._g < 0.0f) {
            result._g = 0.0f;
        } else if (result._g > 1.0f) {
            result._g = 1.0f;
        }

        if (result._b < 0.0f) {
            result._b = 0.0f;
        } else if (result._b > 1.0f) {
            result._b = 1.0f;
        }

        if (result._a < 0.0f) {
            result._a = 0.0f;
        } else if (result._a > 1.0f) {
            result._a = 1.0f;
        }

        return result;
    }

    /**
     * Brings all values (r,g,b,a) into the range [0.0f, 1.0f]. If a value is above or below this range it is replaced
     * with the appropriate end of the range.
     *
     * @return this color for chaining
     */
    public ColorRGBA clampLocal() {
        return clamp(this);
    }

    /**
     * @param store
     *            the color to store the result in for return. If null, a new color object is created and returned.
     * @return a random, mutable opaque color.
     */
    public static ColorRGBA randomColor(final ColorRGBA store) {
        ColorRGBA result = store;
        if (result == null) {
            result = new ColorRGBA();
        }

        result._r = MathUtils.nextRandomFloat();
        result._g = MathUtils.nextRandomFloat();
        result._b = MathUtils.nextRandomFloat();
        result._a = 1.0f;
        return result;
    }

    /**
     * @return this color, stored as an integer by converting the values to the range [0, 255] and combining them as
     *         single byte values into a 4 byte int in the order ARGB. Note that this method expects color values in the
     *         [0.0f, 1.0f] range.
     */
    @Override
    public int asIntARGB() {
        final int argb = ((int) (_a * 255) & 0xFF) << 24 | ((int) (_r * 255) & 0xFF) << 16
                | ((int) (_g * 255) & 0xFF) << 8 | (int) (_b * 255) & 0xFF;
        return argb;
    }

    /**
     * @return this color, stored as an integer by converting the values to the range [0, 255] and combining them as
     *         single byte values into a 4 byte int in the order RGBA. Note that this method expects color values in the
     *         [0.0f, 1.0f] range.
     */
    @Override
    public int asIntRGBA() {
        final int rgba = ((int) (_r * 255) & 0xFF) << 24 | ((int) (_g * 255) & 0xFF) << 16
                | ((int) (_b * 255) & 0xFF) << 8 | (int) (_a * 255) & 0xFF;
        return rgba;
    }

    /**
     * Reads a color, packed into a 4 byte int as 1 byte values in the order ARGB. These byte values are normalized to
     * the range [0.0f, 1.0f]
     *
     * @param color
     * @return this color for chaining
     */
    public ColorRGBA fromIntARGB(final 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;
        return this;
    }

    /**
     * Reads a color, packed into a 4 byte int as 1 byte values in the order RGBA. These byte values are normalized to
     * the range [0.0f, 1.0f]
     *
     * @param color
     * @return this color for chaining
     */
    public ColorRGBA fromIntRGBA(final 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;
        return this;
    }

    /**
     * @return this string as a hex value (#RRGGBBAA). e.g. opaque blue is #0000ffff
     */
    @Override
    public String asHexRRGGBBAA() {
        final StringBuilder sb = new StringBuilder("#");
        final String red = Integer.toHexString(Math.round(MathUtils.clamp(getRed(), 0f, 1f) * 255));
        final String green = Integer.toHexString(Math.round(MathUtils.clamp(getGreen(), 0f, 1f) * 255));
        final String blue = Integer.toHexString(Math.round(MathUtils.clamp(getBlue(), 0f, 1f) * 255));
        final String alpha = Integer.toHexString(Math.round(MathUtils.clamp(getAlpha(), 0f, 1f) * 255));
        if (red.length() < 2) {
            sb.append('0');
        }
        sb.append(red);
        if (green.length() < 2) {
            sb.append('0');
        }
        sb.append(green);
        if (blue.length() < 2) {
            sb.append('0');
        }
        sb.append(blue);
        if (alpha.length() < 2) {
            sb.append('0');
        }
        sb.append(alpha);
        return sb.toString();
    }

    /**
     * Adds the given values to those of this color and returns them in store.
     *
     * @param r
     * @param g
     * @param b
     * @param a
     * @param store
     *            the color to store the result in for return. If null, a new color object is created and returned.
     * @return (this.r + r, this.g + g, this.b + b, this.a + a)
     */
    @Override
    public ColorRGBA add(final float r, final float g, final float b, final float a, final ColorRGBA store) {
        ColorRGBA result = store;
        if (result == null) {
            result = new ColorRGBA();
        }

        return result.set(getRed() + r, getGreen() + g, getBlue() + b, getAlpha() + a);
    }

    /**
     * Increments the values of this color with the given r, g, b and a values.
     *
     * @param r
     * @param g
     * @param b
     * @param a
     * @return this color for chaining
     */
    public ColorRGBA addLocal(final float r, final float g, final float b, final float a) {
        return set(getRed() + r, getGreen() + g, getBlue() + b, getAlpha() + a);
    }

    /**
     * Adds the values of the given source color to those of this color and returns them in store.
     *
     * @param source
     * @param store
     *            the color to store the result in for return. If null, a new color object is created and returned.
     * @return (this.r + source.r, this.g + source.g, this.b + source.b, this.a + source.a)
     * @throws NullPointerException
     *             if source is null.
     */
    @Override
    public ColorRGBA add(final ReadOnlyColorRGBA source, final ColorRGBA store) {
        return add(source.getRed(), source.getGreen(), source.getBlue(), source.getAlpha(), store);
    }

    /**
     * Increments the values of this color with the r, g, b and a values of the given color.
     *
     * @param source
     * @return this color for chaining
     * @throws NullPointerException
     *             if source is null.
     */
    public ColorRGBA addLocal(final ReadOnlyColorRGBA source) {
        return addLocal(source.getRed(), source.getGreen(), source.getBlue(), source.getAlpha());
    }

    /**
     * Subtracts the given values from those of this color and returns them in store.
     *
     * @param r
     * @param g
     * @param b
     * @param a
     * @param store
     *            the color to store the result in for return. If null, a new color object is created and returned.
     * @return (this.r - r, this.g - g, this.b - b, this.a - a)
     */
    @Override
    public ColorRGBA subtract(final float r, final float g, final float b, final float a, final ColorRGBA store) {
        ColorRGBA result = store;
        if (result == null) {
            result = new ColorRGBA();
        }

        return result.set(getRed() - r, getGreen() - g, getBlue() - b, getAlpha() - a);
    }

    /**
     * Decrements the values of this color by the given r, g, b and a values.
     *
     * @param r
     * @param g
     * @param b
     * @param a
     * @return this color for chaining
     */
    public ColorRGBA subtractLocal(final float r, final float g, final float b, final float a) {
        return set(getRed() - r, getGreen() - g, getBlue() - b, getAlpha() - a);
    }

    /**
     * Subtracts the values of the given source color from those of this color and returns them in store.
     *
     * @param source
     * @param store
     *            the color to store the result in for return. If null, a new color object is created and returned.
     * @return (this.r - source.r, this.g - source.g, this.b - source.b, this.a - source.a)
     * @throws NullPointerException
     *             if source is null.
     */
    @Override
    public ColorRGBA subtract(final ReadOnlyColorRGBA source, final ColorRGBA store) {
        return subtract(source.getRed(), source.getGreen(), source.getBlue(), source.getAlpha(), store);
    }

    /**
     * Decrements the values of this color by the r, g, b and a values from the given source color.
     *
     * @param source
     * @return this color for chaining
     * @throws NullPointerException
     *             if source is null.
     */
    public ColorRGBA subtractLocal(final ReadOnlyColorRGBA source) {
        return subtractLocal(source.getRed(), source.getGreen(), source.getBlue(), source.getAlpha());
    }

    /**
     * Multiplies the values of this color by the given scalar value and returns the result in store.
     *
     * @param scalar
     * @param store
     *            the color to store the result in for return. If null, a new color object is created and returned.
     * @return a new color (this.r * scalar, this.g * scalar, this.b * scalar, this.a * scalar)
     */
    @Override
    public ColorRGBA multiply(final float scalar, final ColorRGBA store) {
        ColorRGBA result = store;
        if (result == null) {
            result = new ColorRGBA();
        }

        return result.set(getRed() * scalar, getGreen() * scalar, getBlue() * scalar, getAlpha() * scalar);
    }

    /**
     * Internally modifies the values of this color by multiplying them each by the given scalar value.
     *
     * @param scalar
     * @return this color for chaining
     *
     *         .
     */
    public ColorRGBA multiplyLocal(final float scalar) {
        return set(getRed() * scalar, getGreen() * scalar, getBlue() * scalar, getAlpha() * scalar);
    }

    /**
     * Multiplies the values of this color by the given scalar value and returns the result in store.
     *
     * @param scale
     * @param store
     *            the color to store the result in for return. If null, a new color object is created and returned.
     * @return a new color (this.r * scale.r, this.g * scale.g, this.b * scale.b, this.a * scale.a)
     */
    @Override
    public ColorRGBA multiply(final ReadOnlyColorRGBA scale, final ColorRGBA store) {
        ColorRGBA result = store;
        if (result == null) {
            result = new ColorRGBA();
        }

        return result.set(getRed() * scale.getRed(), getGreen() * scale.getGreen(), getBlue() * scale.getBlue(),
                getAlpha() * scale.getAlpha());
    }

    /**
     * Internally modifies the values of this color by multiplying them each by the given scale values.
     *
     * @param scale
     * @return this color for chaining
     */
    public ColorRGBA multiplyLocal(final ReadOnlyColorRGBA scale) {
        return set(getRed() * scale.getRed(), getGreen() * scale.getGreen(), getBlue() * scale.getBlue(), getAlpha()
                * scale.getAlpha());
    }

    /**
     * Divides the values of this color by the given scalar value and returns the result in store.
     *
     * @param scalar
     * @param store
     *            the color to store the result in for return. If null, a new color object is created and returned.
     * @return a new color (this.r / scalar, this.g / scalar, this.b / scalar, this.a / scalar)
     */
    @Override
    public ColorRGBA divide(final float scalar, final ColorRGBA store) {
        ColorRGBA result = store;
        if (result == null) {
            result = new ColorRGBA();
        }

        return result.set(getRed() / scalar, getGreen() / scalar, getBlue() / scalar, getAlpha() / scalar);
    }

    /**
     * Internally modifies the values of this color by dividing them each by the given scalar value.
     *
     * @param scalar
     * @return this color for chaining
     * @throws ArithmeticException
     *             if scalar is 0
     */
    public ColorRGBA divideLocal(final float scalar) {
        final float invScalar = 1.0f / scalar;

        return set(getRed() * invScalar, getGreen() * invScalar, getBlue() * invScalar, getAlpha() * invScalar);
    }

    /**
     * Divides the values of this color by the given scale values and returns the result in store.
     *
     * @param scale
     * @param store
     *            the color to store the result in for return. If null, a new color object is created and returned.
     * @return a new color (this.r / scale.r, this.g / scale.g, this.b / scale.b, this.a / scale.a)
     */
    @Override
    public ColorRGBA divide(final ReadOnlyColorRGBA scale, final ColorRGBA store) {
        ColorRGBA result = store;
        if (result == null) {
            result = new ColorRGBA();
        }

        return result.set(getRed() / scale.getRed(), getGreen() / scale.getGreen(), getBlue() / scale.getBlue(),
                getAlpha() / scale.getAlpha());
    }

    /**
     * Internally modifies the values of this color by dividing them each by the given scale values.
     *
     * @param scale
     * @return this color for chaining
     */
    public ColorRGBA divideLocal(final ReadOnlyColorRGBA scale) {
        return set(getRed() / scale.getRed(), getGreen() / scale.getGreen(), getBlue() / scale.getBlue(), getAlpha()
                / scale.getAlpha());
    }

    /**
     * Performs a linear interpolation between this color and the given end color, using the given scalar as a percent.
     * iow, if changeAmnt is closer to 0, the result will be closer to the current value of this color and if it is
     * closer to 1, the result will be closer to the end value.
     *
     * @param endColor
     * @param scalar
     * @param store
     *            the color to store the result in for return. If null, a new color object is created and returned.
     * @return a new mutable color as described above.
     * @throws NullPointerException
     *             if endVec is null.
     */
    @Override
    public ColorRGBA lerp(final ReadOnlyColorRGBA endColor, final float scalar, final ColorRGBA store) {
        ColorRGBA result = store;
        if (result == null) {
            result = new ColorRGBA();
        }

        final float r = (1.0f - scalar) * getRed() + scalar * endColor.getRed();
        final float g = (1.0f - scalar) * getGreen() + scalar * endColor.getGreen();
        final float b = (1.0f - scalar) * getBlue() + scalar * endColor.getBlue();
        final float a = (1.0f - scalar) * getAlpha() + scalar * endColor.getAlpha();
        return result.set(r, g, b, a);
    }

    /**
     * Performs a linear interpolation between this color and the given end color, using the given scalar as a percent.
     * iow, if changeAmnt is closer to 0, the result will be closer to the current value of this color and if it is
     * closer to 1, the result will be closer to the end value. The result is stored back in this color.
     *
     * @param endColor
     * @param scalar
     * @return this color for chaining
     * @throws NullPointerException
     *             if endVec is null.
     */
    public ColorRGBA lerpLocal(final ReadOnlyColorRGBA endColor, final float scalar) {
        setRed((1.0f - scalar) * getRed() + scalar * endColor.getRed());
        setGreen((1.0f - scalar) * getGreen() + scalar * endColor.getGreen());
        setBlue((1.0f - scalar) * getBlue() + scalar * endColor.getBlue());
        setAlpha((1.0f - scalar) * getAlpha() + scalar * endColor.getAlpha());
        return this;
    }

    /**
     * Performs a linear interpolation between the given begin and end colors, using the given scalar as a percent. iow,
     * if changeAmnt is closer to 0, the result will be closer to the begin value and if it is closer to 1, the result
     * will be closer to the end value.
     *
     * @param beginColor
     * @param endColor
     * @param scalar
     *            the scalar as a percent.
     * @param store
     *            the color to store the result in for return. If null, a new color object is created and returned.
     * @return a new mutable color as described above.
     * @throws NullPointerException
     *             if beginVec or endVec are null.
     */
    public static ColorRGBA lerp(final ReadOnlyColorRGBA beginColor, final ReadOnlyColorRGBA endColor,
            final float scalar, final ColorRGBA store) {
        ColorRGBA result = store;
        if (result == null) {
            result = new ColorRGBA();
        }

        final float r = (1.0f - scalar) * beginColor.getRed() + scalar * endColor.getRed();
        final float g = (1.0f - scalar) * beginColor.getGreen() + scalar * endColor.getGreen();
        final float b = (1.0f - scalar) * beginColor.getBlue() + scalar * endColor.getBlue();
        final float a = (1.0f - scalar) * beginColor.getAlpha() + scalar * endColor.getAlpha();
        return result.set(r, g, b, a);
    }

    /**
     * Performs a linear interpolation between the given begin and end colors, using the given scalar as a percent. iow,
     * if changeAmnt is closer to 0, the result will be closer to the begin value and if it is closer to 1, the result
     * will be closer to the end value. The result is stored back in this color.
     *
     * @param beginColor
     * @param endColor
     * @param changeAmnt
     *            the scalar as a percent.
     * @return this color for chaining
     * @throws NullPointerException
     *             if beginVec or endVec are null.
     */
    public ColorRGBA lerpLocal(final ReadOnlyColorRGBA beginColor, final ReadOnlyColorRGBA endColor, final float scalar) {
        setRed((1.0f - scalar) * beginColor.getRed() + scalar * endColor.getRed());
        setGreen((1.0f - scalar) * beginColor.getGreen() + scalar * endColor.getGreen());
        setBlue((1.0f - scalar) * beginColor.getBlue() + scalar * endColor.getBlue());
        setAlpha((1.0f - scalar) * beginColor.getAlpha() + scalar * endColor.getAlpha());
        return this;
    }

    /**
     * Check a color... if it is null or its values are NaN or infinite, return false. Else return true.
     *
     * @param color
     *            the color to check
     * @return true or false as stated above.
     */
    public static boolean isValid(final ReadOnlyColorRGBA color) {
        if (color == null) {
            return false;
        }
        if (Float.isNaN(color.getRed()) || Float.isNaN(color.getGreen()) || Float.isNaN(color.getBlue())
                || Float.isNaN(color.getAlpha())) {
            return false;
        }
        if (Float.isInfinite(color.getRed()) || Float.isInfinite(color.getGreen()) || Float.isInfinite(color.getBlue())
                || Float.isInfinite(color.getAlpha())) {
            return false;
        }
        return true;
    }

    /**
     * @return the string representation of this color.
     */
    @Override
    public String toString() {
        return "com.ardor3d.math.ColorRGBA [R=" + getRed() + ", G=" + getGreen() + ", B=" + getBlue() + ", A="
                + getAlpha() + "]";
    }

    /**
     * @return returns a unique code for this color object based on its values. If two colors are numerically equal,
     *         they will return the same hash code value.
     */
    @Override
    public int hashCode() {
        int result = 17;

        final int r = Float.floatToIntBits(getRed());
        result += 31 * result + r;

        final int g = Float.floatToIntBits(getGreen());
        result += 31 * result + g;

        final int b = Float.floatToIntBits(getBlue());
        result += 31 * result + b;

        final int a = Float.floatToIntBits(getAlpha());
        result += 31 * result + a;

        return result;
    }

    /**
     * @param o
     *            the object to compare for equality
     * @return true if this color and the provided color have the same r, g, b and a values.
     */
    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof ReadOnlyColorRGBA)) {
            return false;
        }
        final ReadOnlyColorRGBA comp = (ReadOnlyColorRGBA) o;
        return getRed() == comp.getRed() && getGreen() == comp.getGreen() && getBlue() == comp.getBlue()
                && getAlpha() == comp.getAlpha();
    }

    // /////////////////
    // Method for Cloneable
    // /////////////////

    @Override
    public ColorRGBA clone() {
        return new ColorRGBA(this);
    }

    // /////////////////
    // Methods for Savable
    // /////////////////

    @Override
    public Class<? extends ColorRGBA> getClassTag() {
        return this.getClass();
    }

    @Override
    public void write(final OutputCapsule capsule) throws IOException {
        capsule.write(getRed(), "r", 1);
        capsule.write(getGreen(), "g", 1);
        capsule.write(getBlue(), "b", 1);
        capsule.write(getAlpha(), "a", 1);
    }

    @Override
    public void read(final InputCapsule capsule) throws IOException {
        setRed(capsule.readFloat("r", 1));
        setGreen(capsule.readFloat("g", 1));
        setBlue(capsule.readFloat("b", 1));
        setAlpha(capsule.readFloat("a", 1));
    }

    // /////////////////
    // Methods for Externalizable
    // /////////////////

    /**
     * Used with serialization. Not to be called manually.
     *
     * @param in
     *            ObjectInput
     * @throws IOException
     * @throws ClassNotFoundException
     */
    @Override
    public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
        setRed(in.readFloat());
        setGreen(in.readFloat());
        setBlue(in.readFloat());
        setAlpha(in.readFloat());
    }

    /**
     * Used with serialization. Not to be called manually.
     *
     * @param out
     *            ObjectOutput
     * @throws IOException
     */
    @Override
    public void writeExternal(final ObjectOutput out) throws IOException {
        out.writeFloat(getRed());
        out.writeFloat(getGreen());
        out.writeFloat(getBlue());
        out.writeFloat(getAlpha());
    }

    // /////////////////
    // Methods for creating temp variables (pooling)
    // /////////////////

    /**
     * @return An instance of ColorRGBA that is intended for temporary use in calculations and so forth. Multiple calls
     *         to the method should return instances of this class that are not currently in use.
     */
    public final static ColorRGBA fetchTempInstance() {
        if (MathConstants.useMathPools) {
            return ColorRGBA.COLOR_POOL.fetch();
        } else {
            return new ColorRGBA();
        }
    }

    /**
     * Releases a ColorRGBA back to be used by a future call to fetchTempInstance. TAKE CARE: this ColorRGBA object
     * should no longer have other classes referencing it or "Bad Things" will happen.
     *
     * @param color
     *            the ColorRGBA to release.
     */
    public final static void releaseTempInstance(final ColorRGBA color) {
        if (MathConstants.useMathPools) {
            ColorRGBA.COLOR_POOL.release(color);
        }
    }

    /**
     * Parses the given string for a color value. Currently we support hex notation - # followed by 1, 2, 3, 4, 6, or 8
     * chars 0-9A-F.
     * <ul>
     * <li>chars: pattern - notes</li>
     * <li>1: V - RGB is parsed as val/15, A=1</li>
     * <li>2: VA - RGB is parsed as V/15, A as A/15</li>
     * <li>3: RGB - RGB is parsed as R/15, G/15, B/15, A=1</li>
     * <li>4: RGB - RGBA are parsed as R/15, G/15, B/15, A/15</li>
     * <li>6: RRGGBB - RGB is parsed as RR/255, GG/255, BB/255, A=1</li>
     * <li>8: RRGGBBAA - RGBA is parsed as RR/255, GG/255, BB/255, AA/255</li>
     * </ul>
     *
     * @param colorString
     * @param store
     * @return
     */
    public static ColorRGBA parseColor(final String colorString, final ColorRGBA store) {
        ColorRGBA rVal = store;
        if (rVal == null) {
            rVal = new ColorRGBA();
        }

        // XXX: should we parse words too? eg 'red'...
        if (colorString.length() == 0 || colorString.charAt(0) != '#') {
            throw new IllegalArgumentException("must start with #.");
        }

        float r = 1, g = 1, b = 1, a = 1;
        final int length = colorString.length();
        if (length == 2) {
            r = Integer.parseInt(colorString.substring(1, 2), 16) / 15f;
            g = b = r;
            a = 1;
        } else if (length == 3) {
            r = Integer.parseInt(colorString.substring(1, 2), 16) / 15f;
            g = b = r;
            a = Integer.parseInt(colorString.substring(2, 3), 16) / 15f;
        } else if (length == 4) {
            r = Integer.parseInt(colorString.substring(1, 2), 16) / 15f;
            g = Integer.parseInt(colorString.substring(2, 3), 16) / 15f;
            b = Integer.parseInt(colorString.substring(3, 4), 16) / 15f;
            a = 1;
        } else if (length == 5) {
            r = Integer.parseInt(colorString.substring(1, 2), 16) / 15f;
            g = Integer.parseInt(colorString.substring(2, 3), 16) / 15f;
            b = Integer.parseInt(colorString.substring(3, 4), 16) / 15f;
            a = Integer.parseInt(colorString.substring(4, 5), 16) / 15f;
        } else if (length == 7) {
            r = Integer.parseInt(colorString.substring(1, 3), 16) / 255f;
            g = Integer.parseInt(colorString.substring(3, 5), 16) / 255f;
            b = Integer.parseInt(colorString.substring(5, 7), 16) / 255f;
            a = 1;
        } else if (length == 9) {
            r = Integer.parseInt(colorString.substring(1, 3), 16) / 255f;
            g = Integer.parseInt(colorString.substring(3, 5), 16) / 255f;
            b = Integer.parseInt(colorString.substring(5, 7), 16) / 255f;
            a = Integer.parseInt(colorString.substring(7, 9), 16) / 255f;
        } else {
            throw new IllegalArgumentException("unsupported value, must be 1, 2, 3, 4, 5, 7 or 9 hexvalues: "
                    + colorString);
        }
        rVal.set(r, g, b, a);

        return rVal;
    }
}
TOP

Related Classes of com.ardor3d.math.ColorRGBA

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.