/*******************************************************************************
* Copyright (c) 2015
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*******************************************************************************/
package jsettlers.common;
/**
* This class represents a color with an alpha value.
*
* @author Michael Zangl
*/
public final class Color {
/**
* Constant to quickly access black.
*/
public static final Color BLACK = new Color(0, 0, 0, 1);
/**
* Constant to quickly access white.
*/
public static final Color WHITE = new Color(1, 1, 1, 1);
/**
* Constant to quickly access red.
*/
public static final Color RED = new Color(1, 0, 0, 1);
/**
* Constant to quickly access blue.
*/
public static final Color BLUE = new Color(0, 0, 1, 1);
/**
* Constant to quickly access green.
*/
public static final Color GREEN = new Color(0, 1, 0, 1);
/**
* Constant to quickly access a light green.
*/
public static final Color LIGHT_GREEN = new Color(0, 0.7f, 0, 1);
/**
* Constant to quickly access orange.
*/
public static final Color ORANGE = new Color(1, 0.6f, 0, 1);
/**
* Constant to quickly access cyan.
*/
public static final Color CYAN = new Color(0, 1, 1, 1);
/**
* Constant to quickly access transparent.
*/
public static final Color TRANSPARENT = new Color(0, 0, 0, 0);
private static final int SHIFT_ARGB_A = 24;
private static final int SHIFT_ARGB_R = 16;
private static final int SHIFT_ARGB_G = 8;
private static final int SHIFT_ARGB_B = 0;
private static final int ARGB_FIELD_MAX = 0xff;
private static final float VALUE_CONSIDERED_TRANSPARENT_BELOW = .1f;
private static final int SHORT_SHIFT_RED = 11;
private static final int SHORT_SHIFT_GREEN = 6;
private static final int SHORT_SHIFT_BLUE = 1;
private static final int SHORT_FIELD_MAX = 0x1f;
private static final int SHORT_MASK_ALPHA = 1;
private final float blue;
private final float red;
private final float green;
private final float alpha;
private final int argb;
private final short shortColor;
/**
* Creates a new color using the argb notation.
*
* @param argb
* An integer in the hexadecimal form: AARRGGBB
*/
public Color(int argb) {
this(argb, argbFieldToFloat(argb >> SHIFT_ARGB_R), argbFieldToFloat(argb >> SHIFT_ARGB_G), argbFieldToFloat(argb >> SHIFT_ARGB_B),
argbFieldToFloat(argb >> SHIFT_ARGB_A));
}
private Color(float red, float green, float blue, float alpha) {
this(Color.getARGB(red, green, blue, alpha), red, green, blue, alpha);
}
private Color(int argb, float red, float green, float blue, float alpha) {
this.argb = argb;
this.red = red;
this.green = green;
this.blue = blue;
this.alpha = alpha;
this.shortColor = toShortColorForced(1);
}
/**
* Converts this color to a greyscale color.
*
* @return The color in grey scale.
*/
public Color toGreyScale() {
float intensity = 0.2126f * red + 0.7152f * green + 0.0722f * blue;
return new Color(intensity, intensity, intensity, alpha);
}
/**
* Multiplies all color components with those of the other color.
*
* @param color
* The color.
* @return A new color.
*/
public Color multiply(Color color) {
return new Color(red * color.getRed(), green * color.getGreen(), blue * color.getBlue(), alpha * color.getAlpha());
}
/**
* Gets the (float) alpha value.
*
* @return The alpha value. Range is 0..1
*/
public float getAlpha() {
return alpha;
}
/**
* Gets the (float) blue value.
*
* @return The blue value. Range is 0..1
*/
public float getBlue() {
return blue;
}
/**
* Gets the (float) green value.
*
* @return The green value. Range is 0..1
*/
public float getGreen() {
return green;
}
/**
* Gets the (float) red value.
*
* @return The red value. Range is 0..1
*/
public float getRed() {
return red;
}
/**
* Gets this color in ARGB notation.
*
* @return The color as integer in ARGB format.
*/
public int getARGB() {
return argb;
}
/**
* Converts a color given in float values to ARGB.
*
* @param red
* The red component. Range 0..1
* @param green
* The green component. Range 0..1
* @param blue
* The blue component. Range 0..1
* @param alpha
* The alpha component. Range 0..1
* @return The color in argb notation.
*/
public static int getARGB(float red, float green, float blue,
float alpha) {
return floatToARGBField(alpha) << SHIFT_ARGB_A
| floatToARGBField(red) << SHIFT_ARGB_R
| floatToARGBField(green) << SHIFT_ARGB_G
| floatToARGBField(blue) << SHIFT_ARGB_B;
}
/**
* Gets this color in ABGR notation.
*
* @return The color as integer in ABGR format.
*/
public int getABGR() {
return (argb & 0xff00ff00) | ((argb & 0xff) << 16) | ((argb >> 16) & 0xff);
}
/**
* Converts a color given in float values to ARGB.
*
* @param red
* The red component. Range 0..1
* @param green
* The green component. Range 0..1
* @param blue
* The blue component. Range 0..1
* @param alpha
* The alpha component. Range 0..1
* @return The color in abgr notation.
*/
public static int getABGR(float red, float green, float blue, float alpha) {
return getARGB(blue, green, red, alpha);
}
private static int floatToARGBField(float f) {
return floatToAnyField(f, ARGB_FIELD_MAX);
}
private static int floatToAnyField(float f, int fieldMax) {
return (int) (f * fieldMax) & fieldMax;
}
private static float argbFieldToFloat(int f) {
return (float) (f & ARGB_FIELD_MAX) / ARGB_FIELD_MAX;
}
/**
* Convert a 16 bit color to a 32 bit color
*
* @param The
* 16 bit color in
* @return The 32 bit color;
*/
public static final int convertTo32Bit(int color16bit) {
// TODO: Make faster
float red = (float) ((color16bit >> 11) & 0x1f) / 0x1f;
float green = (float) ((color16bit >> 6) & 0x1f) / 0x1f;
float blue = (float) ((color16bit >> 1) & 0x1f) / 0x1f;
float alpha = color16bit & 0x1;
return Color.getARGB(red, green, blue, alpha);
}
private static final int[] table6to5 = new int[64];
private static final int[] table5to8 = new int[2 << 5];
static {
// Generate table6to5
for (int i = 0; i < 64; i++) {
table6to5[i] = Math.round(i / 63.0f * 31.0f);
}
for (int i = 0; i < table5to8.length; i++) {
table5to8[i] = Math.round(i / (table5to8.length - 1f) * 255.0f);
}
}
private static final int convertColorChannel6to5(int c) {
return table6to5[c];
}
public static final int convert565to555(int rgb565) {
int r5 = (rgb565 & 0xf800) >> 11;
int g6 = (rgb565 & 0x07e0) >> 5;
int b5 = rgb565 & 0x001f;
int g5 = convertColorChannel6to5(g6);
int rgb555 = r5;
rgb555 = rgb555 << 5;
rgb555 |= g5;
rgb555 = rgb555 << 5;
rgb555 |= b5;
return rgb555;
}
/**
* Converts this color to a short color value required by OpenGL.
*
* @param multiply
* The factor to multiply this color with.
* @return The short color.
*/
public short toShortColor(float multiply) {
if (multiply == 1) {
return shortColor;
} else if (multiply < 0) {
return BLACK.toShortColor(1);
} else {
return toShortColorForced(multiply);
}
}
private short toShortColorForced(float multiply) {
if (alpha < VALUE_CONSIDERED_TRANSPARENT_BELOW) {
return 0;
} else {
return (short) (convertToShortField(red, multiply) << SHORT_SHIFT_RED
| convertToShortField(green, multiply) << SHORT_SHIFT_GREEN
| convertToShortField(blue, multiply) << SHORT_SHIFT_BLUE | SHORT_MASK_ALPHA);
}
}
private int convertToShortField(float value, float multiply) {
return floatToAnyField(Math.min(1, value * multiply), SHORT_FIELD_MAX);
}
/**
* Converts a short value to a color object.
*
* @param s
* The short
* @return The color object
* @see #toShortColor(float)
*/
public static Color fromShort(short s) {
return new Color((float) (s >> SHORT_SHIFT_RED & SHORT_FIELD_MAX) / SHORT_FIELD_MAX, (float) (s >> SHORT_SHIFT_GREEN & SHORT_FIELD_MAX)
/ SHORT_FIELD_MAX, (float) (s >> SHORT_SHIFT_BLUE & SHORT_FIELD_MAX)
/ SHORT_FIELD_MAX, s & SHORT_MASK_ALPHA);
}
@Override
public String toString() {
return getClass().getName() + "[argb=" + String.format("%08x", getARGB()) + "]";
}
}