Skip to content

Commit

Permalink
shadow color changes
Browse files Browse the repository at this point in the history
  • Loading branch information
kashike committed Dec 8, 2024
1 parent de37bf6 commit 00fed47
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 62 deletions.
103 changes: 48 additions & 55 deletions api/src/main/java/net/kyori/adventure/text/format/ShadowColor.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import net.kyori.adventure.util.ARGBLike;
import net.kyori.adventure.util.RGBLike;
import org.intellij.lang.annotations.Pattern;
import net.kyori.adventure.util.ARGB;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand All @@ -40,35 +41,6 @@
* @sinceMinecraft 1.21.4
*/
public interface ShadowColor extends StyleBuilderApplicable, ARGBLike {
/**
* Linearly interpolates between {@code a} and {@code b} by {@code t}.
*
* <p>This returns a color blended between color {@code a}, at {@code t=0.0}, and color {@code b}, at {@code t=1.0}.</p>
*
* @param t the interpolation value, between {@code 0.0} and {@code 1.0} (both inclusive)
* @param a the lower bound ({@code t=0.0})
* @param b the upper bound ({@code t=1.0})
* @return the interpolated value, a color between the two input colors {@code a} and {@code b}
* @since 4.18.0
*/
static @NotNull ShadowColor lerp(final float t, final @NotNull ARGBLike a, final @NotNull ARGBLike b) {
final float clampedT = Math.min(1.0f, Math.max(0.0f, t)); // clamp between 0 and 1
final int ar = a.red();
final int br = b.red();
final int ag = a.green();
final int bg = b.green();
final int ab = a.blue();
final int bb = b.blue();
final int aa = a.alpha();
final int ba = b.alpha();
return shadowColor(
Math.round(ar + clampedT * (br - ar)),
Math.round(ag + clampedT * (bg - ag)),
Math.round(ab + clampedT * (bb - ab)),
Math.round(aa + clampedT * (ba - aa))
);
}

/**
* Return a shadow color that will disable the shadow on a component.
*
Expand All @@ -84,15 +56,14 @@ public interface ShadowColor extends StyleBuilderApplicable, ARGBLike {
*
* <p>This int will be in the format {@code 0xAARRGGBB}</p>
*
* @param value the int-packed ARGB value
* @param argb the int-packed ARGB value
* @return a shadow color
* @since 4.18.0
*/
@Contract(pure = true)
static @NotNull ShadowColor shadowColor(final int value) {
if (value == ShadowColorImpl.NONE_VALUE) return none();

return new ShadowColorImpl(value);
static @NotNull ShadowColor shadowColor(final int argb) {
if (argb == ShadowColorImpl.NONE_VALUE) return none();
return new ShadowColorImpl(argb);
}

/**
Expand All @@ -112,27 +83,20 @@ public interface ShadowColor extends StyleBuilderApplicable, ARGBLike {
final @Range(from = 0x0, to = 0xff) int blue,
final @Range(from = 0x0, to = 0xff) int alpha
) {
final int value =
(alpha & 0xff) << 24
| (red & 0xff) << 16
| (green & 0xff) << 8
| (blue & 0xff);

if (value == ShadowColorImpl.NONE_VALUE) return none();
return new ShadowColorImpl(value);
return shadowColor(ARGB.argb(red, green, blue, alpha));
}

/**
* Create a shadow color from an existing colour plus an alpha value.
*
* @param color the existing color
* @param rgb the existing color
* @param alpha the alpha
* @return a shadow colour
* @since 4.18.0
*/
@Contract(pure = true)
static @NotNull ShadowColor shadowColor(final @NotNull RGBLike color, final @Range(from = 0x0, to = 0xff) int alpha) {
return shadowColor(color.red(), color.green(), color.blue(), alpha);
static @NotNull ShadowColor shadowColor(final @NotNull RGBLike rgb, final @Range(from = 0x0, to = 0xff) int alpha) {
return shadowColor(rgb.red(), rgb.green(), rgb.blue(), alpha);
}

/**
Expand Down Expand Up @@ -169,8 +133,8 @@ public interface ShadowColor extends StyleBuilderApplicable, ARGBLike {
final int g = Integer.parseInt(value.substring(3, 5), 16);
final int b = Integer.parseInt(value.substring(5, 7), 16);
final int a = Integer.parseInt(value.substring(7, 9), 16);
return new ShadowColorImpl((a << 24) | (r << 16) | (g << 8) | b);
} catch (NumberFormatException ignored) {
return new ShadowColorImpl(ARGB.argb(a, r, g, b));
} catch (final NumberFormatException ignored) {
return null;
}
}
Expand All @@ -185,10 +149,10 @@ public interface ShadowColor extends StyleBuilderApplicable, ARGBLike {
*/
default @NotNull String asHexString() {
final int argb = this.value();
final int a = (argb >> 24) & 0xFF;
final int r = (argb >> 16) & 0xFF;
final int g = (argb >> 8) & 0xFF;
final int b = argb & 0xFF;
final int a = ARGB.alpha(argb);
final int r = ARGB.red(argb);
final int g = ARGB.green(argb);
final int b = ARGB.blue(argb);
return String.format("#%02X%02X%02X%02X", r, g, b, a);
}

Expand All @@ -200,7 +164,7 @@ public interface ShadowColor extends StyleBuilderApplicable, ARGBLike {
*/
@Override
default @Range(from = 0x0, to = 0xff) int red() {
return (this.value() >> 16) & 0xff;
return ARGB.red(this.value());
}

/**
Expand All @@ -211,7 +175,7 @@ public interface ShadowColor extends StyleBuilderApplicable, ARGBLike {
*/
@Override
default @Range(from = 0x0, to = 0xff) int green() {
return (this.value() >> 8) & 0xff;
return ARGB.green(this.value());
}

/**
Expand All @@ -222,7 +186,7 @@ public interface ShadowColor extends StyleBuilderApplicable, ARGBLike {
*/
@Override
default @Range(from = 0x0, to = 0xff) int blue() {
return this.value() & 0xff;
return ARGB.blue(this.value());
}

/**
Expand All @@ -233,7 +197,7 @@ public interface ShadowColor extends StyleBuilderApplicable, ARGBLike {
*/
@Override
default @Range(from = 0x0, to = 0xff) int alpha() {
return (this.value() >> 24) & 0xff;
return ARGB.alpha(this.value());
}

/**
Expand All @@ -244,6 +208,35 @@ public interface ShadowColor extends StyleBuilderApplicable, ARGBLike {
*/
int value();

/**
* Linearly interpolates between {@code a} and {@code b} by {@code t}.
*
* <p>This returns a color blended between color {@code a}, at {@code t=0.0}, and color {@code b}, at {@code t=1.0}.</p>
*
* @param t the interpolation value, between {@code 0.0} and {@code 1.0} (both inclusive)
* @param a the lower bound ({@code t=0.0})
* @param b the upper bound ({@code t=1.0})
* @return the interpolated value, a color between the two input colors {@code a} and {@code b}
* @since 4.18.0
*/
static @NotNull ShadowColor lerp(final float t, final @NotNull ARGBLike a, final @NotNull ARGBLike b) {
final float clampedT = Math.min(1.0f, Math.max(0.0f, t)); // clamp between 0 and 1
final int ar = a.red();
final int br = b.red();
final int ag = a.green();
final int bg = b.green();
final int ab = a.blue();
final int bb = b.blue();
final int aa = a.alpha();
final int ba = b.alpha();
return shadowColor(
Math.round(ar + clampedT * (br - ar)),
Math.round(ag + clampedT * (bg - ag)),
Math.round(ab + clampedT * (bb - ab)),
Math.round(aa + clampedT * (ba - aa))
);
}

@Override
default void styleApply(final Style.@NotNull Builder style) {
style.shadowColor(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ final class ShadowColorImpl implements ShadowColor, Examinable {
static final int NONE_VALUE = 0;
static final ShadowColorImpl NONE = new ShadowColorImpl(NONE_VALUE);

private final int value;
private final int value; // ARGB

ShadowColorImpl(final int value) {
this.value = value;
Expand Down
8 changes: 7 additions & 1 deletion api/src/main/java/net/kyori/adventure/text/format/Style.java
Original file line number Diff line number Diff line change
Expand Up @@ -562,11 +562,17 @@ default boolean hasDecoration(final @NotNull TextDecoration decoration) {
*/
enum Merge {
/**
* Merges {@link Style#color()} and {@link Style#shadowColor()}.
* Merges {@link Style#color()}.
*
* @since 4.0.0
*/
COLOR,
/**
* Merges {@link Style#shadowColor()}.
*
* @since 4.0.0
*/
SHADOW_COLOR,
/**
* Merges {@link Style#decorations()}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -426,15 +426,17 @@ static final class BuilderImpl implements Builder {
this.color(color);
}
}
}


if (merges.contains(Merge.SHADOW_COLOR)) {
final ShadowColor shadowColor = that.shadowColor();
if (shadowColor != null) {
if (strategy == Merge.Strategy.ALWAYS || (strategy == Merge.Strategy.IF_ABSENT_ON_TARGET && this.shadowColor == null)) {
this.shadowColor(shadowColor);
}
}
}

if (merges.contains(Merge.DECORATIONS)) {
for (int i = 0, length = DecorationMap.DECORATIONS.length; i < length; i++) {
final TextDecoration decoration = DecorationMap.DECORATIONS[i];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import java.util.List;
import java.util.stream.Stream;
import net.kyori.adventure.util.ARGB;
import net.kyori.adventure.util.HSVLike;
import net.kyori.adventure.util.RGBLike;
import net.kyori.examination.Examinable;
Expand Down Expand Up @@ -68,7 +69,7 @@ public interface TextColor extends Comparable<TextColor>, Examinable, RGBLike, S
* @since 4.0.0
*/
static @NotNull TextColor color(final int value) {
final int truncatedValue = value & 0xffffff;
final int truncatedValue = ARGB.rgb(value);
final NamedTextColor named = NamedTextColor.namedColor(truncatedValue);
return named != null ? named : new TextColorImpl(truncatedValue);
}
Expand Down Expand Up @@ -226,7 +227,7 @@ public interface TextColor extends Comparable<TextColor>, Examinable, RGBLike, S
*/
@Override
default @Range(from = 0x0, to = 0xff) int red() {
return (this.value() >> 16) & 0xff;
return ARGB.red(this.value());
}

/**
Expand All @@ -237,7 +238,7 @@ public interface TextColor extends Comparable<TextColor>, Examinable, RGBLike, S
*/
@Override
default @Range(from = 0x0, to = 0xff) int green() {
return (this.value() >> 8) & 0xff;
return ARGB.green(this.value());
}

/**
Expand All @@ -248,7 +249,7 @@ public interface TextColor extends Comparable<TextColor>, Examinable, RGBLike, S
*/
@Override
default @Range(from = 0x0, to = 0xff) int blue() {
return this.value() & 0xff;
return ARGB.blue(this.value());
}

/**
Expand Down
59 changes: 59 additions & 0 deletions api/src/main/java/net/kyori/adventure/util/ARGB.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* This file is part of adventure, licensed under the MIT License.
*
* Copyright (c) 2017-2024 KyoriPowered
*
* 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 net.kyori.adventure.util;

public interface ARGB {
static int argb(final int alpha, final int red, final int green, final int blue) {
return alpha << 24 | red << 16 | green << 8 | blue;
}

static int argb(final float alpha, final float red, final float green, final float blue) {
return argb(
(int) Math.floor(alpha * 255f),
(int) Math.floor(red * 255f),
(int) Math.floor(green * 255f),
(int) Math.floor(blue * 255f)
);
}

static int rgb(final int argb) {
return argb & 0xffffff;
}

static int alpha(final int argb) {
return argb >>> 24;
}

static int red(final int argb) {
return (argb >> 16) & 0xff;
}

static int green(final int argb) {
return (argb >> 8) & 0xff;
}

static int blue(final int argb) {
return argb & 0xff;
}
}
Loading

0 comments on commit 00fed47

Please sign in to comment.