package micdoodle8.mods.galacticraft.core.util; import micdoodle8.mods.galacticraft.api.vector.Vector3; import micdoodle8.mods.galacticraft.core.GalacticraftCore; import micdoodle8.mods.galacticraft.core.entities.player.GCPlayerStats; import micdoodle8.mods.galacticraft.core.network.PacketSimple; import micdoodle8.mods.galacticraft.core.network.PacketSimple.EnumSimplePacket; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.BlockPos; import net.minecraftforge.fml.common.network.NetworkRegistry.TargetPoint; public class ColorUtil { //Credit to Mark Ransom @ StackOverflow for the colorwheel idea static Vector3 red = new Vector3(255, 0, 0); static Vector3 orange = new Vector3(255, 160, 0); static Vector3 yellow = new Vector3(255, 255, 0); static Vector3 green = new Vector3(0, 255, 0); static Vector3 cyan = new Vector3(0, 255, 255); static Vector3 blue = new Vector3(0, 0, 255); static Vector3 magenta = new Vector3(255, 0, 255); static Vector3 white = new Vector3(255, 255, 255); static Vector3 black = new Vector3(0, 0, 0); static Vector3 mud = new Vector3(94, 81, 74); static double[] colorwheelAngles = { -110D, -30D, 0D, 60D, 120D, 180D, 215D, 250D, 330D, 360D, 420D, 480D }; static Vector3[] colorwheelColors = { blue, magenta, red, orange, yellow, green, cyan, blue, magenta, red, orange, yellow }; private static Vector3 hue_to_rgb(double deg) { deg = deg % 360; double previous_angle = colorwheelAngles[1]; for (int i = 2; i < colorwheelAngles.length - 2; i++) { Double angle = colorwheelAngles[i]; if (deg <= angle) { return interpolateInArray(colorwheelColors, i, (angle - deg) / (angle - previous_angle)); } previous_angle = angle; } return null; } private static double rgb_to_hue(Vector3 input) { double maxCol = Math.max(Math.max(input.x, input.y), input.z); if (maxCol <= 0) { return 0; } Vector3 rgb = input.scale(255D / maxCol); double mindist = 1024; int mini = 0; for (int i = 2; i < colorwheelAngles.length - 2; i++) { Vector3 color = colorwheelColors[i]; double separation = color.distance(rgb); if (separation < mindist) { mindist = separation; mini = i; } } double separation1; double separation2; separation1 = colorwheelColors[mini - 1].distance(rgb); separation2 = colorwheelColors[mini + 1].distance(rgb); double hue; if (separation1 < separation2) { double separationtot = colorwheelColors[mini - 1].distance(colorwheelColors[mini]); hue = interpolateInArray(colorwheelAngles, mini, mindist / separationtot); if (hue < 0) { hue += 360D; } } else { double separationtot = colorwheelColors[mini + 1].distance(colorwheelColors[mini]); hue = interpolateInArray(colorwheelAngles, mini + 1, separation2 / separationtot); if (hue > 360D) { hue -= 360D; } } return hue; } private static double cubicInterpolate(double y0, double y1, double y2, double y3, double mu) { double a0, a1, a2, a3, mu2; mu2 = mu * mu; a3 = y3 - y2 - y0 + y1; a2 = y0 - y1 - a3; a1 = y2 - y0; a0 = y1; return (a3 * mu * mu2 + a2 * mu2 + a1 * mu + a0); } private static Vector3 interpolateInArray(Vector3[] array, int i, double mu) { Vector3 point0 = array[i + 1]; Vector3 point1 = array[i]; Vector3 point2 = array[i - 1]; Vector3 point3 = array[i - 2]; double x = cubicInterpolate(point0.x, point1.x, point2.x, point3.x, mu); double y = cubicInterpolate(point0.y, point1.y, point2.y, point3.y, mu); double z = cubicInterpolate(point0.z, point1.z, point2.z, point3.z, mu); return new Vector3(x, y, z); } private static double interpolateInArray(double[] array, int i, double mu) { return cubicInterpolate(array[i + 1], array[i], array[i - 1], array[i - 2], mu); } public static Vector3 addColorsRealistically(Vector3 color1, Vector3 color2) { double hue1 = ColorUtil.rgb_to_hue(color1); double hue2 = ColorUtil.rgb_to_hue(color2); if (hue1 - hue2 > 180D) { hue2 += 360D; } if (hue2 - hue1 > 180D) { hue1 += 360D; } double hueresult = (hue1 + hue2) / 2; if (hueresult > 360D) { hueresult -= 360D; } //TODO: if hue1 and hue2 differ by close to 180degrees, add in some 'mud' color //TODO: add greyscale here return ColorUtil.hue_to_rgb(hueresult).scale(1 / 255D); } public static int addColorsRealistically(int color1, int color2) { Vector3 result = addColorsRealistically(toVec3(color1), toVec3(color2)); return fromVec3(result); } public static int addColorsBasic(int color1, int color2) { int g = color1 >> 8; int r = g >> 8; g &= 255; int b = color1 & 255; int gg = color2 >> 8; int rr = gg >> 8; gg &= 255; int bb = color2 & 255; r = (r + rr) / 2; g = (g + gg) / 2; b = (b + bb) / 2; r = r << 16; g = g << 8; return r | g | b; } public static Vector3 toVec3(int col) { int gg = col >> 8; int rr = gg >> 8; gg &= 255; int bb = col & 255; return new Vector3(rr / 255F, gg / 255F, bb / 255F); } public static int fromVec3(Vector3 result) { int r = (int) (result.x * 255D + 0.499D); int g = (int) (result.y * 255D + 0.499D); int b = (int) (result.z * 255D + 0.499D); r = r << 16; g = g << 8; return r | g | b; } public static int to32BitColor(int a, int r, int g, int b) { a = a << 24; r = r << 16; g = g << 8; return a | r | g | b; } public static int to32BitColorB(byte r, byte g, byte b) { int rr = (r & 255) << 16; int gg = (g & 255) << 8; return rr | gg | (b & 255); } public static int lighten(int col, float factor) { int gg = col >> 8; int rr = gg >> 8; gg &= 255; int bb = col & 255; rr *= (1F + factor); gg *= (1F + factor); bb *= (1F + factor); if (rr > 255) { rr = 255; } if (gg > 255) { gg = 255; } if (bb > 255) { bb = 255; } return rr << 16 | gg << 8 | bb; } /** * Lighten to the specified intensity * @param col * @return */ public static int lightenFully(int col, int intensity) { if (intensity == 0) return 0; int gg = col >> 8; int rr = gg >> 8; gg &= 255; int bb = col & 255; rr = 255 - rr; gg = 255 - gg; bb = 255 - bb; double greyInvert = Math.min(rr, Math.min(gg, bb)); double delta = Math.max(rr, Math.max(gg, bb)); delta = (delta - greyInvert) / delta; if (greyInvert >= intensity) { return col; } double factor = (intensity - greyInvert) / intensity / Math.pow(delta, 0.6); rr -= 24; //this -24 and math.pow(delta 0.6) found empirically, there's no science here! gg -= 24; bb -= 24; rr *= factor; gg *= factor; bb *= factor; if (rr > 255) { rr = 255; } if (gg > 255) { gg = 255; } if (bb > 255) { bb = 255; } rr = 255 - rr; gg = 255 - gg; bb = 255 - bb; if (rr > 255) { rr = 255; } if (gg > 255) { gg = 255; } if (bb > 255) { bb = 255; } return rr << 16 | gg << 8 | bb; } public static int toGreyscale(int col) { int gg = col >> 8; int grey = gg >> 8; grey += gg & 255; grey += col & 255; grey /= 3; return grey << 16 | grey << 8 | (grey & 255); } public static void sendUpdatedColorsToPlayer(GCPlayerStats stats) { int dimID = stats.getPlayer().get().dimension; GalacticraftCore.packetPipeline.sendTo(new PacketSimple(EnumSimplePacket.C_RECOLOR_ALL_GLASS, dimID, new Object[] { Integer.valueOf(stats.getGlassColor1()), Integer.valueOf(stats.getGlassColor2()), Integer.valueOf(stats.getGlassColor3()) }), stats.getPlayer().get()); } public static void updateColorsForArea(int dimID, BlockPos pos, int range, int color1, int color2, int color3) { GalacticraftCore.packetPipeline.sendToAllAround(new PacketSimple(EnumSimplePacket.C_RECOLOR_ALL_GLASS, dimID, new Object[] { color1, color2, color3 }), new TargetPoint(dimID, pos.getX(), pos.getY(), pos.getZ(), range)); } public static void setGLColor(int col) { int gg = col >> 8; int rr = gg >> 8; gg &= 255; int bb = col & 255; GlStateManager.color(rr / 255F, gg / 255F, bb / 255F, 1.0F); } }