mirror of
https://github.com/TotalFreedomMC/PlayerParticles.git
synced 2024-12-28 02:14: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
|
import org.apache.tools.ant.filters.ReplaceTokens
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id 'com.github.johnrengelman.shadow' version '7.0.0'
|
id 'com.github.johnrengelman.shadow' version '7.1.0'
|
||||||
id 'maven-publish'
|
id 'maven-publish'
|
||||||
id 'java-library'
|
id 'java-library'
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ sourceCompatibility = 1.8
|
||||||
targetCompatibility = 1.8
|
targetCompatibility = 1.8
|
||||||
compileJava.options.encoding = 'UTF-8'
|
compileJava.options.encoding = 'UTF-8'
|
||||||
group = 'dev.esophose'
|
group = 'dev.esophose'
|
||||||
version = '7.24'
|
version = '7.25'
|
||||||
|
|
||||||
java {
|
java {
|
||||||
withJavadocJar()
|
withJavadocJar()
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
=== v7.24 ===
|
||||||
|
* Fixed configs not generating properly on newer versions of 1.18.1
|
||||||
=== v7.23 ===
|
=== v7.23 ===
|
||||||
+ Added support for the new 1.18 particle block_marker
|
+ Added support for the new 1.18 particle block_marker
|
||||||
=== v7.22 ===
|
=== v7.22 ===
|
||||||
|
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,5 +1,5 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
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
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|
|
@ -10,6 +10,9 @@ import java.util.List;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Equations Source: https://www.desmos.com/calculator/cscx2zcrlf
|
||||||
|
*/
|
||||||
public class ParticleStyleBatman extends DefaultParticleStyle {
|
public class ParticleStyleBatman extends DefaultParticleStyle {
|
||||||
|
|
||||||
private int step = 0;
|
private int step = 0;
|
||||||
|
|
|
@ -2,12 +2,17 @@ package dev.esophose.playerparticles.styles;
|
||||||
|
|
||||||
import dev.esophose.playerparticles.config.CommentedFileConfiguration;
|
import dev.esophose.playerparticles.config.CommentedFileConfiguration;
|
||||||
import dev.esophose.playerparticles.particles.PParticle;
|
import dev.esophose.playerparticles.particles.PParticle;
|
||||||
|
import dev.esophose.playerparticles.particles.ParticleEffect;
|
||||||
import dev.esophose.playerparticles.particles.ParticlePair;
|
import dev.esophose.playerparticles.particles.ParticlePair;
|
||||||
|
import dev.esophose.playerparticles.particles.data.ColorTransition;
|
||||||
import dev.esophose.playerparticles.particles.data.OrdinaryColor;
|
import dev.esophose.playerparticles.particles.data.OrdinaryColor;
|
||||||
|
import dev.esophose.playerparticles.util.HexUtils;
|
||||||
import dev.esophose.playerparticles.util.VectorUtils;
|
import dev.esophose.playerparticles.util.VectorUtils;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -46,7 +51,24 @@ public class ParticleStyleIcosphere extends DefaultParticleStyle {
|
||||||
double yRotation = multiplier * this.angularVelocityY;
|
double yRotation = multiplier * this.angularVelocityY;
|
||||||
double zRotation = multiplier * this.angularVelocityZ;
|
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 lowest = points.stream().mapToDouble(Vector::getY).min().orElse(1);
|
||||||
double highest = points.stream().mapToDouble(Vector::getY).max().orElse(2);
|
double highest = points.stream().mapToDouble(Vector::getY).max().orElse(2);
|
||||||
double range = highest - lowest;
|
double range = highest - lowest;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package dev.esophose.playerparticles.util;
|
package dev.esophose.playerparticles.util;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
@ -11,24 +12,50 @@ import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
public final class HexUtils {
|
public final class HexUtils {
|
||||||
|
|
||||||
private static final Pattern RAINBOW_PATTERN = Pattern.compile("<(rainbow|r)(:\\d*\\.?\\d+){0,2}>");
|
private static final int CHARS_UNTIL_LOOP = 30;
|
||||||
private static final Pattern GRADIENT_PATTERN = Pattern.compile("<(gradient|g)(:#([A-Fa-f0-9]){6})*>");
|
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(
|
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() {
|
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
|
* 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
|
* @param message The message to send
|
||||||
*/
|
*/
|
||||||
public static void sendMessage(CommandSender sender, String message) {
|
public static void sendMessage(CommandSender sender, String message) {
|
||||||
|
@ -57,29 +84,64 @@ public final class HexUtils {
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
StringBuilder parsedRainbow = new StringBuilder();
|
StringBuilder parsedRainbow = new StringBuilder();
|
||||||
|
|
||||||
String match = matcher.group();
|
// Possible parameters and their defaults
|
||||||
int tagLength = match.startsWith("<ra") ? 8 : 2;
|
int speed = -1;
|
||||||
|
float saturation = 1.0F;
|
||||||
|
float brightness = 1.0F;
|
||||||
|
boolean looping = getCaptureGroup(matcher, "looping") != null;
|
||||||
|
|
||||||
int indexOfClose = match.indexOf(">");
|
String speedGroup = getCaptureGroup(matcher, "speed");
|
||||||
String extraDataContent = match.substring(tagLength, indexOfClose);
|
if (speedGroup != null) {
|
||||||
|
try {
|
||||||
double[] extraData;
|
speed = Integer.parseInt(speedGroup);
|
||||||
if (!extraDataContent.isEmpty()) {
|
} catch (NumberFormatException ignored) { }
|
||||||
extraDataContent = extraDataContent.substring(1);
|
|
||||||
extraData = Arrays.stream(extraDataContent.split(":")).mapToDouble(Double::parseDouble).toArray();
|
|
||||||
} else {
|
|
||||||
extraData = new double[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float saturation = extraData.length > 0 ? (float) extraData[0] : 1.0F;
|
String saturationGroup = getCaptureGroup(matcher, "saturation");
|
||||||
float brightness = extraData.length > 1 ? (float) extraData[1] : 1.0F;
|
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());
|
int stop = findStop(parsed, matcher.end());
|
||||||
String content = parsed.substring(matcher.end(), stop);
|
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())
|
int length = looping ? Math.min(contentLength, CHARS_UNTIL_LOOP) : contentLength;
|
||||||
parsedRainbow.append(translateHex(rainbow.next())).append(c);
|
|
||||||
|
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 before = parsed.substring(0, matcher.start());
|
||||||
String after = parsed.substring(stop);
|
String after = parsed.substring(stop);
|
||||||
|
@ -97,19 +159,51 @@ public final class HexUtils {
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
StringBuilder parsedGradient = new StringBuilder();
|
StringBuilder parsedGradient = new StringBuilder();
|
||||||
|
|
||||||
String match = matcher.group();
|
int speed = -1;
|
||||||
int tagLength = match.startsWith("<gr") ? 10 : 3;
|
boolean looping = getCaptureGroup(matcher, "loop") != null;
|
||||||
|
|
||||||
int indexOfClose = match.indexOf(">");
|
List<Color> hexSteps = Arrays.stream(getCaptureGroup(matcher, "hex").substring(1).split(":"))
|
||||||
String hexContent = match.substring(tagLength, indexOfClose);
|
.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)))
|
||||||
List<Color> hexSteps = Arrays.stream(hexContent.split(":")).map(Color::decode).collect(Collectors.toList());
|
.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());
|
int stop = findStop(parsed, matcher.end());
|
||||||
String content = parsed.substring(matcher.end(), stop);
|
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())
|
int length = looping ? Math.min(contentLength, CHARS_UNTIL_LOOP) : contentLength;
|
||||||
parsedGradient.append(translateHex(gradient.next())).append(c);
|
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 before = parsed.substring(0, matcher.start());
|
||||||
String after = parsed.substring(stop);
|
String after = parsed.substring(stop);
|
||||||
|
@ -144,7 +238,7 @@ public final class HexUtils {
|
||||||
/**
|
/**
|
||||||
* Returns the index before the color changes
|
* 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
|
* @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
|
* @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) {
|
private static String cleanHex(String hex) {
|
||||||
if (hex.startsWith("<")) {
|
if (hex.startsWith("<") || hex.startsWith("{")) {
|
||||||
return hex.substring(1, hex.length() - 1);
|
return hex.substring(1, hex.length() - 1);
|
||||||
} else if (hex.startsWith("&")) {
|
} else if (hex.startsWith("&")) {
|
||||||
return hex.substring(1);
|
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 List<TwoStopGradient> gradients;
|
||||||
private final int stepSize;
|
private final int steps;
|
||||||
private int step, stepIndex;
|
protected long step;
|
||||||
|
|
||||||
public Gradient(List<Color> colors, int totalColors) {
|
public Gradient(List<Color> colors, int steps) {
|
||||||
if (colors.size() < 2)
|
if (colors.size() < 2)
|
||||||
throw new IllegalArgumentException("Must provide at least 2 colors");
|
throw new IllegalArgumentException("Must provide at least 2 colors");
|
||||||
|
|
||||||
if (totalColors < 1)
|
this.gradients = new ArrayList<>();
|
||||||
throw new IllegalArgumentException("Must have at least 1 total color");
|
this.steps = steps - 1;
|
||||||
|
this.step = 0;
|
||||||
|
|
||||||
this.colors = colors;
|
float increment = (float) this.steps / (colors.size() - 1);
|
||||||
this.stepSize = totalColors / (colors.size() - 1);
|
for (int i = 0; i < colors.size() - 1; i++)
|
||||||
this.step = this.stepIndex = 0;
|
this.gradients.add(new TwoStopGradient(colors.get(i), colors.get(i + 1), increment * i, increment * (i + 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* @return the next color in the gradient
|
|
||||||
*/
|
|
||||||
public Color next() {
|
public Color next() {
|
||||||
// Gradients will use the first color of the entire spectrum won't be available to preserve prettiness
|
// Gradients will use the first color if the entire spectrum won't be available to preserve prettiness
|
||||||
if (NMSUtil.getVersionNumber() < 16)
|
if (NMSUtil.getVersionNumber() < 16 || this.steps <= 1)
|
||||||
return this.colors.get(0);
|
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;
|
Color color;
|
||||||
if (this.stepIndex + 1 < this.colors.size()) {
|
if (this.gradients.size() < 2) {
|
||||||
Color start = this.colors.get(this.stepIndex);
|
color = this.gradients.get(0).colorAt(adjustedStep);
|
||||||
Color end = this.colors.get(this.stepIndex + 1);
|
|
||||||
float interval = (float) this.step / this.stepSize;
|
|
||||||
|
|
||||||
color = getGradientInterval(start, end, interval);
|
|
||||||
} else {
|
} else {
|
||||||
color = this.colors.get(this.colors.size() - 1);
|
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 += 1;
|
|
||||||
if (this.step >= this.stepSize) {
|
|
||||||
this.step = 0;
|
|
||||||
this.stepIndex++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.step++;
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static class TwoStopGradient {
|
||||||
* 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.");
|
|
||||||
|
|
||||||
int r = (int) (end.getRed() * interval + start.getRed() * (1 - interval));
|
private final Color startColor;
|
||||||
int g = (int) (end.getGreen() * interval + start.getGreen() * (1 - interval));
|
private final Color endColor;
|
||||||
int b = (int) (end.getBlue() * interval + start.getBlue() * (1 - interval));
|
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;
|
public AnimatedGradient(List<Color> colors, int steps, int speed) {
|
||||||
private float hue;
|
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) {
|
public Rainbow(int totalColors, float saturation, float brightness) {
|
||||||
if (totalColors < 1)
|
if (totalColors < 1)
|
||||||
throw new IllegalArgumentException("Must have at least 1 total color");
|
totalColors = 1;
|
||||||
|
|
||||||
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");
|
|
||||||
|
|
||||||
this.hueStep = 1.0F / totalColors;
|
this.hueStep = 1.0F / totalColors;
|
||||||
this.saturation = saturation;
|
this.saturation = Math.max(0, Math.min(1, saturation));
|
||||||
this.brightness = brightness;
|
this.brightness = Math.max(0, Math.min(1, brightness));
|
||||||
this.hue = 0;
|
this.hue = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rainbow(int totalColors) {
|
@Override
|
||||||
this(totalColors, 1.0F, 1.0F);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the next color in the gradient
|
|
||||||
*/
|
|
||||||
public Color next() {
|
public Color next() {
|
||||||
Color color = Color.getHSBColor(this.hue, this.saturation, this.brightness);
|
Color color = Color.getHSBColor(this.hue, this.saturation, this.brightness);
|
||||||
this.hue += this.hueStep;
|
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