mirror of
https://github.com/TotalFreedomMC/PlayerParticles.git
synced 2024-12-27 09:54:15 +00:00
Change icosphere style behavior with the dust_color_transition effect
This commit is contained in:
parent
2d86ba65af
commit
723caece21
6 changed files with 259 additions and 102 deletions
|
@ -1,7 +1,7 @@
|
|||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
|
||||
plugins {
|
||||
id 'com.github.johnrengelman.shadow' version '7.0.0'
|
||||
id 'com.github.johnrengelman.shadow' version '7.1.0'
|
||||
id 'maven-publish'
|
||||
id 'java-library'
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ sourceCompatibility = 1.8
|
|||
targetCompatibility = 1.8
|
||||
compileJava.options.encoding = 'UTF-8'
|
||||
group = 'dev.esophose'
|
||||
version = '7.24'
|
||||
version = '7.25'
|
||||
|
||||
java {
|
||||
withJavadocJar()
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
=== v7.24 ===
|
||||
* Fixed configs not generating properly on newer versions of 1.18.1
|
||||
=== v7.23 ===
|
||||
+ Added support for the new 1.18 particle block_marker
|
||||
=== v7.22 ===
|
||||
|
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -10,6 +10,9 @@ import java.util.List;
|
|||
import org.bukkit.Location;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
/*
|
||||
* Equations Source: https://www.desmos.com/calculator/cscx2zcrlf
|
||||
*/
|
||||
public class ParticleStyleBatman extends DefaultParticleStyle {
|
||||
|
||||
private int step = 0;
|
||||
|
|
|
@ -2,12 +2,17 @@ package dev.esophose.playerparticles.styles;
|
|||
|
||||
import dev.esophose.playerparticles.config.CommentedFileConfiguration;
|
||||
import dev.esophose.playerparticles.particles.PParticle;
|
||||
import dev.esophose.playerparticles.particles.ParticleEffect;
|
||||
import dev.esophose.playerparticles.particles.ParticlePair;
|
||||
import dev.esophose.playerparticles.particles.data.ColorTransition;
|
||||
import dev.esophose.playerparticles.particles.data.OrdinaryColor;
|
||||
import dev.esophose.playerparticles.util.HexUtils;
|
||||
import dev.esophose.playerparticles.util.VectorUtils;
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -46,7 +51,24 @@ public class ParticleStyleIcosphere extends DefaultParticleStyle {
|
|||
double yRotation = multiplier * this.angularVelocityY;
|
||||
double zRotation = multiplier * this.angularVelocityZ;
|
||||
|
||||
if (particle.getColor().equals(OrdinaryColor.RAINBOW)) {
|
||||
if (particle.getEffect() == ParticleEffect.DUST_COLOR_TRANSITION) {
|
||||
ColorTransition colorTransition = particle.getColorTransition();
|
||||
Color startColor = new Color(colorTransition.getStartColor().getRed(), colorTransition.getStartColor().getGreen(), colorTransition.getStartColor().getBlue());
|
||||
Color endColor = new Color(colorTransition.getEndColor().getRed(), colorTransition.getEndColor().getGreen(), colorTransition.getEndColor().getBlue());
|
||||
|
||||
List<Vector> sortedPoints = new ArrayList<>(points);
|
||||
sortedPoints.sort(Comparator.comparingDouble(Vector::getY));
|
||||
|
||||
HexUtils.AnimatedGradient gradient = new HexUtils.AnimatedGradient(Arrays.asList(startColor, endColor), sortedPoints.size(), 2);
|
||||
|
||||
for (Vector point : sortedPoints) {
|
||||
Color color = gradient.next();
|
||||
OrdinaryColor ordinaryColor = new OrdinaryColor(color.getRed(), color.getGreen(), color.getBlue());
|
||||
ColorTransition optionalData = new ColorTransition(ordinaryColor, ordinaryColor);
|
||||
VectorUtils.rotateVector(point, xRotation, yRotation, zRotation);
|
||||
particles.add(new PParticle(location.clone().add(point), 0, 0, 0, 0, false, optionalData));
|
||||
}
|
||||
} else if (particle.getColor().equals(OrdinaryColor.RAINBOW)) {
|
||||
double lowest = points.stream().mapToDouble(Vector::getY).min().orElse(1);
|
||||
double highest = points.stream().mapToDouble(Vector::getY).max().orElse(2);
|
||||
double range = highest - lowest;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package dev.esophose.playerparticles.util;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
|
@ -11,24 +12,50 @@ import org.bukkit.command.CommandSender;
|
|||
|
||||
public final class HexUtils {
|
||||
|
||||
private static final Pattern RAINBOW_PATTERN = Pattern.compile("<(rainbow|r)(:\\d*\\.?\\d+){0,2}>");
|
||||
private static final Pattern GRADIENT_PATTERN = Pattern.compile("<(gradient|g)(:#([A-Fa-f0-9]){6})*>");
|
||||
private static final int CHARS_UNTIL_LOOP = 30;
|
||||
private static final Pattern RAINBOW_PATTERN = Pattern.compile("<(?<type>rainbow|r)(#(?<speed>\\d+))?(:(?<saturation>\\d*\\.?\\d+))?(:(?<brightness>\\d*\\.?\\d+))?(:(?<loop>l|L|loop))?>");
|
||||
private static final Pattern GRADIENT_PATTERN = Pattern.compile("<(?<type>gradient|g)(#(?<speed>\\d+))?(?<hex>(:#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})){2,})(:(?<loop>l|L|loop))?>");
|
||||
private static final List<Pattern> HEX_PATTERNS = Arrays.asList(
|
||||
Pattern.compile("<#([A-Fa-f0-9]){6}>"), // <#FFFFFF>
|
||||
Pattern.compile("&#([A-Fa-f0-9]){6}"), // &#FFFFFF
|
||||
Pattern.compile("#([A-Fa-f0-9]){6}") // #FFFFFF
|
||||
Pattern.compile("<#([A-Fa-f0-9]){6}>"), // <#FFFFFF>
|
||||
Pattern.compile("\\{#([A-Fa-f0-9]){6}}"), // {#FFFFFF}
|
||||
Pattern.compile("&#([A-Fa-f0-9]){6}"), // &#FFFFFF
|
||||
Pattern.compile("#([A-Fa-f0-9]){6}") // #FFFFFF
|
||||
);
|
||||
|
||||
private static final Pattern STOP = Pattern.compile("<(gradient|g)(:#([A-Fa-f0-9]){6})*>|<(rainbow|r)(:\\d*\\.?\\d+){0,2}>|(&[a-f0-9r])|<#([A-Fa-f0-9]){6}>|&#([A-Fa-f0-9]){6}|#([A-Fa-f0-9]){6}|" + org.bukkit.ChatColor.COLOR_CHAR);
|
||||
private static final Pattern STOP = Pattern.compile(
|
||||
"<(rainbow|r)(#(\\d+))?(:(\\d*\\.?\\d+))?(:(\\d*\\.?\\d+))?(:(l|L|loop))?>|" +
|
||||
"<(gradient|g)(#(\\d+))?((:#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})){2,})(:(l|L|loop))?>|" +
|
||||
"(&[a-f0-9r])|" +
|
||||
"<#([A-Fa-f0-9]){6}>|" +
|
||||
"\\{#([A-Fa-f0-9]){6}}|" +
|
||||
"&#([A-Fa-f0-9]){6}|" +
|
||||
"#([A-Fa-f0-9]){6}|" +
|
||||
org.bukkit.ChatColor.COLOR_CHAR
|
||||
);
|
||||
|
||||
private HexUtils() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a capture group from a regex Matcher if it exists
|
||||
*
|
||||
* @param matcher The Matcher
|
||||
* @param group The group name
|
||||
* @return the capture group value, or null if not found
|
||||
*/
|
||||
private static String getCaptureGroup(Matcher matcher, String group) {
|
||||
try {
|
||||
return matcher.group(group);
|
||||
} catch (IllegalStateException | IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a CommandSender a colored message
|
||||
*
|
||||
* @param sender The CommandSender to send to
|
||||
* @param sender The CommandSender to send to
|
||||
* @param message The message to send
|
||||
*/
|
||||
public static void sendMessage(CommandSender sender, String message) {
|
||||
|
@ -57,29 +84,64 @@ public final class HexUtils {
|
|||
while (matcher.find()) {
|
||||
StringBuilder parsedRainbow = new StringBuilder();
|
||||
|
||||
String match = matcher.group();
|
||||
int tagLength = match.startsWith("<ra") ? 8 : 2;
|
||||
// Possible parameters and their defaults
|
||||
int speed = -1;
|
||||
float saturation = 1.0F;
|
||||
float brightness = 1.0F;
|
||||
boolean looping = getCaptureGroup(matcher, "looping") != null;
|
||||
|
||||
int indexOfClose = match.indexOf(">");
|
||||
String extraDataContent = match.substring(tagLength, indexOfClose);
|
||||
|
||||
double[] extraData;
|
||||
if (!extraDataContent.isEmpty()) {
|
||||
extraDataContent = extraDataContent.substring(1);
|
||||
extraData = Arrays.stream(extraDataContent.split(":")).mapToDouble(Double::parseDouble).toArray();
|
||||
} else {
|
||||
extraData = new double[0];
|
||||
String speedGroup = getCaptureGroup(matcher, "speed");
|
||||
if (speedGroup != null) {
|
||||
try {
|
||||
speed = Integer.parseInt(speedGroup);
|
||||
} catch (NumberFormatException ignored) { }
|
||||
}
|
||||
|
||||
float saturation = extraData.length > 0 ? (float) extraData[0] : 1.0F;
|
||||
float brightness = extraData.length > 1 ? (float) extraData[1] : 1.0F;
|
||||
String saturationGroup = getCaptureGroup(matcher, "saturation");
|
||||
if (saturationGroup != null) {
|
||||
try {
|
||||
saturation = Float.parseFloat(saturationGroup);
|
||||
} catch (NumberFormatException ignored) { }
|
||||
}
|
||||
|
||||
String brightnessGroup = getCaptureGroup(matcher, "brightness");
|
||||
if (brightnessGroup != null) {
|
||||
try {
|
||||
brightness = Float.parseFloat(brightnessGroup);
|
||||
} catch (NumberFormatException ignored) { }
|
||||
}
|
||||
|
||||
int stop = findStop(parsed, matcher.end());
|
||||
String content = parsed.substring(matcher.end(), stop);
|
||||
Rainbow rainbow = new Rainbow(content.length(), saturation, brightness);
|
||||
int contentLength = content.length();
|
||||
char[] chars = content.toCharArray();
|
||||
for (int i = 0; i < chars.length - 1; i++)
|
||||
if (chars[i] == '&' && "KkLlMmNnOoRr".indexOf(chars[i + 1]) > -1)
|
||||
contentLength -= 2;
|
||||
|
||||
for (char c : content.toCharArray())
|
||||
parsedRainbow.append(translateHex(rainbow.next())).append(c);
|
||||
int length = looping ? Math.min(contentLength, CHARS_UNTIL_LOOP) : contentLength;
|
||||
|
||||
ColorGenerator rainbow;
|
||||
if (speed == -1) {
|
||||
rainbow = new Rainbow(length, saturation, brightness);
|
||||
} else {
|
||||
rainbow = new AnimatedRainbow(length, saturation, brightness, speed);
|
||||
}
|
||||
|
||||
String compoundedFormat = ""; // Carry the format codes through the rainbow gradient
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
char c = chars[i];
|
||||
if (c == '&' && i + 1 < chars.length) {
|
||||
char next = chars[i + 1];
|
||||
org.bukkit.ChatColor color = org.bukkit.ChatColor.getByChar(next);
|
||||
if (color != null && color.isFormat()) {
|
||||
compoundedFormat += String.valueOf(ChatColor.COLOR_CHAR) + next;
|
||||
i++; // Skip next character
|
||||
continue;
|
||||
}
|
||||
}
|
||||
parsedRainbow.append(translateHex(rainbow.next())).append(compoundedFormat).append(c);
|
||||
}
|
||||
|
||||
String before = parsed.substring(0, matcher.start());
|
||||
String after = parsed.substring(stop);
|
||||
|
@ -97,19 +159,51 @@ public final class HexUtils {
|
|||
while (matcher.find()) {
|
||||
StringBuilder parsedGradient = new StringBuilder();
|
||||
|
||||
String match = matcher.group();
|
||||
int tagLength = match.startsWith("<gr") ? 10 : 3;
|
||||
int speed = -1;
|
||||
boolean looping = getCaptureGroup(matcher, "loop") != null;
|
||||
|
||||
int indexOfClose = match.indexOf(">");
|
||||
String hexContent = match.substring(tagLength, indexOfClose);
|
||||
List<Color> hexSteps = Arrays.stream(hexContent.split(":")).map(Color::decode).collect(Collectors.toList());
|
||||
List<Color> hexSteps = Arrays.stream(getCaptureGroup(matcher, "hex").substring(1).split(":"))
|
||||
.map(x -> x.length() != 4 ? x : String.format("#%s%s%s%s%s%s", x.charAt(1), x.charAt(1), x.charAt(2), x.charAt(2), x.charAt(3), x.charAt(3)))
|
||||
.map(Color::decode)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
String speedGroup = getCaptureGroup(matcher, "speed");
|
||||
if (speedGroup != null) {
|
||||
try {
|
||||
speed = Integer.parseInt(speedGroup);
|
||||
} catch (NumberFormatException ignored) { }
|
||||
}
|
||||
|
||||
int stop = findStop(parsed, matcher.end());
|
||||
String content = parsed.substring(matcher.end(), stop);
|
||||
Gradient gradient = new Gradient(hexSteps, content.length());
|
||||
int contentLength = content.length();
|
||||
char[] chars = content.toCharArray();
|
||||
for (int i = 0; i < chars.length - 1; i++)
|
||||
if (chars[i] == '&' && "KkLlMmNnOoRr".indexOf(chars[i + 1]) > -1)
|
||||
contentLength -= 2;
|
||||
|
||||
for (char c : content.toCharArray())
|
||||
parsedGradient.append(translateHex(gradient.next())).append(c);
|
||||
int length = looping ? Math.min(contentLength, CHARS_UNTIL_LOOP) : contentLength;
|
||||
ColorGenerator gradient;
|
||||
if (speed == -1) {
|
||||
gradient = new Gradient(hexSteps, length);
|
||||
} else {
|
||||
gradient = new AnimatedGradient(hexSteps, length, speed);
|
||||
}
|
||||
|
||||
String compoundedFormat = ""; // Carry the format codes through the gradient
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
char c = chars[i];
|
||||
if (c == '&' && i + 1 < chars.length) {
|
||||
char next = chars[i + 1];
|
||||
org.bukkit.ChatColor color = org.bukkit.ChatColor.getByChar(next);
|
||||
if (color != null && color.isFormat()) {
|
||||
compoundedFormat += String.valueOf(ChatColor.COLOR_CHAR) + next;
|
||||
i++; // Skip next character
|
||||
continue;
|
||||
}
|
||||
}
|
||||
parsedGradient.append(translateHex(gradient.next())).append(compoundedFormat).append(c);
|
||||
}
|
||||
|
||||
String before = parsed.substring(0, matcher.start());
|
||||
String after = parsed.substring(stop);
|
||||
|
@ -144,7 +238,7 @@ public final class HexUtils {
|
|||
/**
|
||||
* Returns the index before the color changes
|
||||
*
|
||||
* @param content The content to search through
|
||||
* @param content The content to search through
|
||||
* @param searchAfter The index at which to search after
|
||||
* @return the index of the color stop, or the end of the string index if none is found
|
||||
*/
|
||||
|
@ -158,7 +252,7 @@ public final class HexUtils {
|
|||
}
|
||||
|
||||
private static String cleanHex(String hex) {
|
||||
if (hex.startsWith("<")) {
|
||||
if (hex.startsWith("<") || hex.startsWith("{")) {
|
||||
return hex.substring(1, hex.length() - 1);
|
||||
} else if (hex.startsWith("&")) {
|
||||
return hex.substring(1);
|
||||
|
@ -249,107 +343,130 @@ public final class HexUtils {
|
|||
|
||||
}
|
||||
|
||||
private interface ColorGenerator {
|
||||
|
||||
/**
|
||||
* @return the next color in the sequence
|
||||
*/
|
||||
Color next();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows generation of a multi-part gradient with a fixed number of steps
|
||||
* Allows generation of a multi-part gradient with a defined number of steps
|
||||
*/
|
||||
public static class Gradient {
|
||||
public static class Gradient implements ColorGenerator {
|
||||
|
||||
private final List<Color> colors;
|
||||
private final int stepSize;
|
||||
private int step, stepIndex;
|
||||
private final List<TwoStopGradient> gradients;
|
||||
private final int steps;
|
||||
protected long step;
|
||||
|
||||
public Gradient(List<Color> colors, int totalColors) {
|
||||
public Gradient(List<Color> colors, int steps) {
|
||||
if (colors.size() < 2)
|
||||
throw new IllegalArgumentException("Must provide at least 2 colors");
|
||||
|
||||
if (totalColors < 1)
|
||||
throw new IllegalArgumentException("Must have at least 1 total color");
|
||||
this.gradients = new ArrayList<>();
|
||||
this.steps = steps - 1;
|
||||
this.step = 0;
|
||||
|
||||
this.colors = colors;
|
||||
this.stepSize = totalColors / (colors.size() - 1);
|
||||
this.step = this.stepIndex = 0;
|
||||
float increment = (float) this.steps / (colors.size() - 1);
|
||||
for (int i = 0; i < colors.size() - 1; i++)
|
||||
this.gradients.add(new TwoStopGradient(colors.get(i), colors.get(i + 1), increment * i, increment * (i + 1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the next color in the gradient
|
||||
*/
|
||||
@Override
|
||||
public Color next() {
|
||||
// Gradients will use the first color of the entire spectrum won't be available to preserve prettiness
|
||||
if (NMSUtil.getVersionNumber() < 16)
|
||||
return this.colors.get(0);
|
||||
// Gradients will use the first color if the entire spectrum won't be available to preserve prettiness
|
||||
if (NMSUtil.getVersionNumber() < 16 || this.steps <= 1)
|
||||
return this.gradients.get(0).colorAt(0);
|
||||
|
||||
// Do some wizardry to get a function that bounces back and forth between 0 and a cap given an increasing input
|
||||
// Thanks to BomBardyGamer for assisting with this
|
||||
int adjustedStep = (int) Math.round(Math.abs(((2 * Math.asin(Math.sin(this.step * (Math.PI / (2 * this.steps))))) / Math.PI) * this.steps));
|
||||
|
||||
Color color;
|
||||
if (this.stepIndex + 1 < this.colors.size()) {
|
||||
Color start = this.colors.get(this.stepIndex);
|
||||
Color end = this.colors.get(this.stepIndex + 1);
|
||||
float interval = (float) this.step / this.stepSize;
|
||||
|
||||
color = getGradientInterval(start, end, interval);
|
||||
if (this.gradients.size() < 2) {
|
||||
color = this.gradients.get(0).colorAt(adjustedStep);
|
||||
} else {
|
||||
color = this.colors.get(this.colors.size() - 1);
|
||||
}
|
||||
|
||||
this.step += 1;
|
||||
if (this.step >= this.stepSize) {
|
||||
this.step = 0;
|
||||
this.stepIndex++;
|
||||
float segment = (float) this.steps / this.gradients.size();
|
||||
int index = (int) Math.min(Math.floor(adjustedStep / segment), this.gradients.size() - 1);
|
||||
color = this.gradients.get(index).colorAt(adjustedStep);
|
||||
}
|
||||
|
||||
this.step++;
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a color along a linear gradient between two colors
|
||||
*
|
||||
* @param start The start color
|
||||
* @param end The end color
|
||||
* @param interval The interval to get, between 0 and 1 inclusively
|
||||
* @return A Color at the interval between the start and end colors
|
||||
*/
|
||||
public static Color getGradientInterval(Color start, Color end, float interval) {
|
||||
if (0 > interval || interval > 1)
|
||||
throw new IllegalArgumentException("Interval must be between 0 and 1 inclusively.");
|
||||
private static class TwoStopGradient {
|
||||
|
||||
int r = (int) (end.getRed() * interval + start.getRed() * (1 - interval));
|
||||
int g = (int) (end.getGreen() * interval + start.getGreen() * (1 - interval));
|
||||
int b = (int) (end.getBlue() * interval + start.getBlue() * (1 - interval));
|
||||
private final Color startColor;
|
||||
private final Color endColor;
|
||||
private final float lowerRange;
|
||||
private final float upperRange;
|
||||
|
||||
private TwoStopGradient(Color startColor, Color endColor, float lowerRange, float upperRange) {
|
||||
this.startColor = startColor;
|
||||
this.endColor = endColor;
|
||||
this.lowerRange = lowerRange;
|
||||
this.upperRange = upperRange;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the color of this gradient at the given step
|
||||
*
|
||||
* @param step The step
|
||||
* @return The color of this gradient at the given step
|
||||
*/
|
||||
public Color colorAt(int step) {
|
||||
return new Color(
|
||||
this.calculateHexPiece(step, this.startColor.getRed(), this.endColor.getRed()),
|
||||
this.calculateHexPiece(step, this.startColor.getGreen(), this.endColor.getGreen()),
|
||||
this.calculateHexPiece(step, this.startColor.getBlue(), this.endColor.getBlue())
|
||||
);
|
||||
}
|
||||
|
||||
private int calculateHexPiece(int step, int channelStart, int channelEnd) {
|
||||
float range = this.upperRange - this.lowerRange;
|
||||
float interval = (channelEnd - channelStart) / range;
|
||||
return Math.round(interval * (step - this.lowerRange) + channelStart);
|
||||
}
|
||||
|
||||
return new Color(r, g, b);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows generation of a rainbow gradient with a fixed numbef of steps
|
||||
* Allows generation of an animated multi-part gradient with a defined number of steps
|
||||
*/
|
||||
public static class Rainbow {
|
||||
public static class AnimatedGradient extends Gradient {
|
||||
|
||||
private final float hueStep, saturation, brightness;
|
||||
private float hue;
|
||||
public AnimatedGradient(List<Color> colors, int steps, int speed) {
|
||||
super(colors, steps);
|
||||
|
||||
this.step = System.currentTimeMillis() / speed;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows generation of a rainbow gradient with a fixed number of steps
|
||||
*/
|
||||
public static class Rainbow implements ColorGenerator {
|
||||
|
||||
protected final float hueStep, saturation, brightness;
|
||||
protected float hue;
|
||||
|
||||
public Rainbow(int totalColors, float saturation, float brightness) {
|
||||
if (totalColors < 1)
|
||||
throw new IllegalArgumentException("Must have at least 1 total color");
|
||||
|
||||
if (0.0F > saturation || saturation > 1.0F)
|
||||
throw new IllegalArgumentException("Saturation must be between 0.0 and 1.0");
|
||||
|
||||
if (0.0F > brightness || brightness > 1.0F)
|
||||
throw new IllegalArgumentException("Saturation must be between 0.0 and 1.0");
|
||||
totalColors = 1;
|
||||
|
||||
this.hueStep = 1.0F / totalColors;
|
||||
this.saturation = saturation;
|
||||
this.brightness = brightness;
|
||||
this.saturation = Math.max(0, Math.min(1, saturation));
|
||||
this.brightness = Math.max(0, Math.min(1, brightness));
|
||||
this.hue = 0;
|
||||
}
|
||||
|
||||
public Rainbow(int totalColors) {
|
||||
this(totalColors, 1.0F, 1.0F);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the next color in the gradient
|
||||
*/
|
||||
@Override
|
||||
public Color next() {
|
||||
Color color = Color.getHSBColor(this.hue, this.saturation, this.brightness);
|
||||
this.hue += this.hueStep;
|
||||
|
@ -358,4 +475,17 @@ public final class HexUtils {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows generation of an animated rainbow gradient with a fixed number of steps
|
||||
*/
|
||||
public static class AnimatedRainbow extends Rainbow {
|
||||
|
||||
public AnimatedRainbow(int totalColors, float saturation, float brightness, int speed) {
|
||||
super(totalColors, saturation, brightness);
|
||||
|
||||
this.hue = (float) ((((Math.floor(System.currentTimeMillis() / 50.0)) / 360) * speed) % 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue