update dependencies, more sane alpha interpolation implementation
parent
265d71ae67
commit
ec041f9269
@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
@ -0,0 +1,112 @@
|
||||
package quimufu.colourful_portals.client;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import net.minecraft.client.texture.Animator;
|
||||
import net.minecraft.client.texture.NativeImage;
|
||||
import net.minecraft.client.texture.SpriteContents;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This code is mostly copies from minecraft source. it is owned by mojang.
|
||||
*/
|
||||
public class AlphaBlendingAnimator implements Animator {
|
||||
int frame;
|
||||
int currentTime;
|
||||
|
||||
final SpriteContents spriteContents;
|
||||
final SpriteContents.Animation animation;
|
||||
@Nullable
|
||||
private final AlphaBlendingInterpolation interpolation;
|
||||
|
||||
public AlphaBlendingAnimator(SpriteContents spriteContents, SpriteContents.Animation animation) {
|
||||
this.spriteContents = spriteContents;
|
||||
this.animation = animation;
|
||||
this.interpolation = new AlphaBlendingInterpolation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(int x, int y) {
|
||||
++this.currentTime;
|
||||
SpriteContents.AnimationFrame animationFrame = this.animation.frames.get(this.frame);
|
||||
if (this.currentTime >= animationFrame.time) {
|
||||
int i = animationFrame.index;
|
||||
this.frame = (this.frame + 1) % this.animation.frames.size();
|
||||
this.currentTime = 0;
|
||||
int j = this.animation.frames.get((int)this.frame).index;
|
||||
if (i != j) {
|
||||
this.animation.upload(x, y, j);
|
||||
}
|
||||
} else if (this.interpolation != null) {
|
||||
if (!RenderSystem.isOnRenderThread()) {
|
||||
RenderSystem.recordRenderCall(() -> this.interpolation.apply(x, y, this));
|
||||
} else {
|
||||
this.interpolation.apply(x, y, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (this.interpolation != null) {
|
||||
this.interpolation.close();
|
||||
}
|
||||
}
|
||||
|
||||
public class AlphaBlendingInterpolation
|
||||
implements AutoCloseable {
|
||||
private final NativeImage[] images;
|
||||
|
||||
AlphaBlendingInterpolation() {
|
||||
this.images = new NativeImage[spriteContents.mipmapLevelsImages.length];
|
||||
for (int i = 0; i < this.images.length; ++i) {
|
||||
int j = spriteContents.getWidth() >> i;
|
||||
int k = spriteContents.getHeight() >> i;
|
||||
this.images[i] = new NativeImage(j, k, false);
|
||||
}
|
||||
}
|
||||
|
||||
void apply(int x, int y, AlphaBlendingAnimator animator) {
|
||||
SpriteContents.Animation animation = animator.animation;
|
||||
List<SpriteContents.AnimationFrame> list = animation.frames;
|
||||
SpriteContents.AnimationFrame animationFrame = list.get(animator.frame);
|
||||
double d = 1.0 - (double)animator.currentTime / (double)animationFrame.time;
|
||||
int i = animationFrame.index;
|
||||
int j = list.get((animator.frame + 1) % list.size()).index;
|
||||
if (i != j) {
|
||||
for (int k = 0; k < this.images.length; ++k) {
|
||||
int l = spriteContents.getWidth() >> k;
|
||||
int m = spriteContents.getHeight() >> k;
|
||||
for (int n = 0; n < m; ++n) {
|
||||
for (int o = 0; o < l; ++o) {
|
||||
int p = this.getPixelColor(animation, i, k, o, n);
|
||||
int q = this.getPixelColor(animation, j, k, o, n);
|
||||
int a = this.lerp(d, p >> 24 & 0xFF, q >> 24 & 0xFF);
|
||||
int r = this.lerp(d, p >> 16 & 0xFF, q >> 16 & 0xFF);
|
||||
int s = this.lerp(d, p >> 8 & 0xFF, q >> 8 & 0xFF);
|
||||
int t = this.lerp(d, p & 0xFF, q & 0xFF);
|
||||
this.images[k].setColor(o, n, a << 24 | r << 16 | s << 8 | t);
|
||||
}
|
||||
}
|
||||
}
|
||||
spriteContents.upload(x, y, 0, 0, this.images);
|
||||
}
|
||||
}
|
||||
|
||||
private int getPixelColor(SpriteContents.Animation animation, int frameIndex, int layer, int x, int y) {
|
||||
return spriteContents.mipmapLevelsImages[layer].getColor(x + (animation.getFrameX(frameIndex) * spriteContents.getWidth() >> layer), y + (animation.getFrameY(frameIndex) * spriteContents.getHeight() >> layer));
|
||||
}
|
||||
|
||||
private int lerp(double delta, int to, int from) {
|
||||
return (int)(delta * (double)to + (1.0 - delta) * (double)from);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
for (NativeImage nativeImage : this.images) {
|
||||
nativeImage.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package quimufu.colourful_portals.client;
|
||||
|
||||
public interface AlphaInterpolationHolder {
|
||||
|
||||
public void colourful_portals$setInterpolateAlpha(boolean interpolateAlpha);
|
||||
public boolean colourful_portals$isInterpolateAlpha();
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package quimufu.colourful_portals.mixin;
|
||||
|
||||
import net.minecraft.client.texture.Animator;
|
||||
import net.minecraft.client.texture.SpriteContents;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import quimufu.colourful_portals.client.AlphaBlendingAnimator;
|
||||
import quimufu.colourful_portals.client.AlphaInterpolationHolder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(targets = "net.minecraft.client.texture.SpriteContents$Animation")
|
||||
public class AnimationMixin implements AlphaInterpolationHolder {
|
||||
@Shadow
|
||||
@Final
|
||||
private boolean interpolation;
|
||||
|
||||
@Unique
|
||||
private SpriteContents parent;
|
||||
|
||||
@Unique
|
||||
private boolean interpolateAlpha = false;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
public void assignParent(SpriteContents parent, List frames, int frameCount, boolean interpolation, CallbackInfo ci) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public void colourful_portals$setInterpolateAlpha(boolean interpolateAlpha) {
|
||||
this.interpolateAlpha = interpolateAlpha;
|
||||
}
|
||||
|
||||
public boolean colourful_portals$isInterpolateAlpha() {
|
||||
return interpolateAlpha;
|
||||
}
|
||||
|
||||
@Inject(at = @At("RETURN"), method = "createAnimator()Lnet/minecraft/client/texture/Animator;", cancellable = true)
|
||||
public void createAnimator(CallbackInfoReturnable<Animator> cir) {
|
||||
if (this.interpolateAlpha && this.interpolation) {
|
||||
cir.setReturnValue(new AlphaBlendingAnimator(parent, (SpriteContents.Animation) (Object) this));
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package quimufu.colourful_portals.mixin;
|
||||
|
||||
import net.minecraft.client.resource.metadata.AnimationResourceMetadata;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import quimufu.colourful_portals.client.AlphaInterpolationHolder;
|
||||
|
||||
@Mixin(AnimationResourceMetadata.class)
|
||||
public class AnimationResourceMetadataMixin implements AlphaInterpolationHolder {
|
||||
|
||||
@Unique
|
||||
private boolean interpolateAlpha = false;
|
||||
public void colourful_portals$setInterpolateAlpha(boolean interpolateAlpha) {
|
||||
this.interpolateAlpha = interpolateAlpha;
|
||||
}
|
||||
public boolean colourful_portals$isInterpolateAlpha() {
|
||||
return interpolateAlpha;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package quimufu.colourful_portals.mixin;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.client.resource.metadata.AnimationResourceMetadata;
|
||||
import net.minecraft.client.resource.metadata.AnimationResourceMetadataReader;
|
||||
import net.minecraft.util.JsonHelper;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import quimufu.colourful_portals.client.AlphaInterpolationHolder;
|
||||
|
||||
@Mixin(AnimationResourceMetadataReader.class)
|
||||
public class AnimationResourceMetadataReaderMixin {
|
||||
|
||||
@Inject(at = @At("RETURN"), method = "fromJson(Lcom/google/gson/JsonObject;)Lnet/minecraft/client/resource/metadata/AnimationResourceMetadata;", cancellable = true)
|
||||
void extractInterpolateAlpha(JsonObject jsonObject, CallbackInfoReturnable<AnimationResourceMetadata> cir) {
|
||||
boolean interpolateAlpha = JsonHelper.getBoolean(jsonObject, "interpolateAlpha", false);
|
||||
AnimationResourceMetadata returnValue = cir.getReturnValue();
|
||||
((AlphaInterpolationHolder)returnValue).colourful_portals$setInterpolateAlpha(interpolateAlpha);
|
||||
cir.setReturnValue(returnValue);
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
package quimufu.colourful_portals.mixin;
|
||||
|
||||
import net.minecraft.client.texture.NativeImage;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@Mixin(targets = "net/minecraft/client/texture/SpriteContents$Interpolation")
|
||||
public abstract class InterpolationMixin {
|
||||
|
||||
@Shadow
|
||||
protected abstract int lerp(double delta, int to, int from);
|
||||
|
||||
ThreadLocal<Integer> colourBefore = new ThreadLocal<>();
|
||||
ThreadLocal<Double> delta = new ThreadLocal<>();
|
||||
|
||||
@Redirect(method = "apply", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/texture/NativeImage;setColor(III)V"))
|
||||
private void injected(NativeImage instance, int x, int y, int color) {
|
||||
int alpha = lerp(delta.get(), (color >> 24) & 0xFF, (colourBefore.get() >> 24) & 0xFF);
|
||||
|
||||
instance.setColor(x, y, (alpha << 24) | (color & 0xFFFFFF));
|
||||
}
|
||||
|
||||
@ModifyVariable(method = "apply", at = @At("STORE"), ordinal = 10)
|
||||
private int injected(int x) {
|
||||
colourBefore.set(x);
|
||||
return x;
|
||||
}
|
||||
|
||||
@ModifyVariable(method = "apply", at = @At("STORE"), ordinal = 0)
|
||||
private double injected(double deltaV) {
|
||||
delta.set(deltaV);
|
||||
return deltaV;
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package quimufu.colourful_portals.mixin;
|
||||
|
||||
import net.minecraft.client.resource.metadata.AnimationResourceMetadata;
|
||||
import net.minecraft.client.texture.SpriteContents;
|
||||
import net.minecraft.client.texture.SpriteDimensions;
|
||||
import net.minecraft.resource.metadata.ResourceMetadata;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import quimufu.colourful_portals.client.AlphaInterpolationHolder;
|
||||
|
||||
@Mixin(SpriteContents.class)
|
||||
public abstract class SpriteContentsMixin {
|
||||
|
||||
@Unique
|
||||
private final ThreadLocal<Boolean> redirect = ThreadLocal.withInitial(() -> true);
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
@Nullable
|
||||
private SpriteContents.@Nullable Animation animation;
|
||||
|
||||
@Shadow
|
||||
public abstract boolean isPixelTransparent(int frame, int x, int y);
|
||||
|
||||
@Inject(at = @At("RETURN"), method = "createAnimation(Lnet/minecraft/client/texture/SpriteDimensions;IILnet/minecraft/client/resource/metadata/AnimationResourceMetadata;)Lnet/minecraft/client/texture/SpriteContents$Animation;", cancellable = true)
|
||||
void passInterpolateAlpha(SpriteDimensions dimensions, int imageWidth, int imageHeight, AnimationResourceMetadata metadata, CallbackInfoReturnable<AlphaInterpolationHolder> cir) {
|
||||
AlphaInterpolationHolder returnValue = cir.getReturnValue();
|
||||
if (returnValue != null) {
|
||||
returnValue.colourful_portals$setInterpolateAlpha(((AlphaInterpolationHolder) metadata).colourful_portals$isInterpolateAlpha());
|
||||
cir.setReturnValue(returnValue);
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(at = @At("RETURN"), method = "isPixelTransparent(III)Z", cancellable = true)
|
||||
void correctIsPixelTransparent(int frame, int x, int y, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (redirect.get() && animation != null && ((AlphaInterpolationHolder) animation).colourful_portals$isInterpolateAlpha()) {
|
||||
redirect.set(false);
|
||||
cir.setReturnValue(this.isPixelTransparent(frame, x, y) || this.isPixelTransparent(frame + 1, x, y));
|
||||
redirect.set(true);
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"animation": {
|
||||
"interpolate": true,
|
||||
"frametime": 12
|
||||
"frametime": 12,
|
||||
"interpolateAlpha": true
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"animation": {
|
||||
"interpolate": true,
|
||||
"frametime": 12
|
||||
"frametime": 12,
|
||||
"interpolateAlpha": true
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"animation": {
|
||||
"interpolate": true,
|
||||
"frametime": 12
|
||||
"frametime": 12,
|
||||
"interpolateAlpha": true
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"animation": {
|
||||
"interpolate": true,
|
||||
"frametime": 12
|
||||
"frametime": 12,
|
||||
"interpolateAlpha": true
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"animation": {
|
||||
"interpolate": true,
|
||||
"frametime": 12
|
||||
"frametime": 12,
|
||||
"interpolateAlpha": true
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"animation": {
|
||||
"interpolate": true,
|
||||
"frametime": 12
|
||||
"frametime": 12,
|
||||
"interpolateAlpha": true
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"animation": {
|
||||
"interpolate": true,
|
||||
"frametime": 12
|
||||
"frametime": 12,
|
||||
"interpolateAlpha": true
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"animation": {
|
||||
"interpolate": true,
|
||||
"frametime": 12
|
||||
"frametime": 12,
|
||||
"interpolateAlpha": true
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"animation": {
|
||||
"interpolate": true,
|
||||
"frametime": 12
|
||||
"frametime": 12,
|
||||
"interpolateAlpha": true
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"animation": {
|
||||
"interpolate": true,
|
||||
"frametime": 12
|
||||
"frametime": 12,
|
||||
"interpolateAlpha": true
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"animation": {
|
||||
"interpolate": true,
|
||||
"frametime": 12
|
||||
"frametime": 12,
|
||||
"interpolateAlpha": true
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"animation": {
|
||||
"interpolate": true,
|
||||
"frametime": 12
|
||||
"frametime": 12,
|
||||
"interpolateAlpha": true
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"animation": {
|
||||
"interpolate": true,
|
||||
"frametime": 12
|
||||
"frametime": 12,
|
||||
"interpolateAlpha": true
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"animation": {
|
||||
"interpolate": true,
|
||||
"frametime": 12
|
||||
"frametime": 12,
|
||||
"interpolateAlpha": true
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"animation": {
|
||||
"interpolate": true,
|
||||
"frametime": 12
|
||||
"frametime": 12,
|
||||
"interpolateAlpha": true
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"animation": {
|
||||
"interpolate": true,
|
||||
"frametime": 12
|
||||
"frametime": 12,
|
||||
"interpolateAlpha": true
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"animation": {
|
||||
"interpolate": true,
|
||||
"frametime": 12
|
||||
"frametime": 12,
|
||||
"interpolateAlpha": true
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
accessWidener v2 named
|
||||
extendable class net/minecraft/client/texture/SpriteContents$Animation
|
||||
accessible class net/minecraft/client/texture/SpriteContents$AnimationFrame
|
||||
extendable class net/minecraft/client/texture/SpriteContents$Interpolation
|
||||
accessible field net/minecraft/client/texture/SpriteContents$AnimationFrame time I
|
||||
accessible field net/minecraft/client/texture/SpriteContents$Animation frames Ljava/util/List;
|
||||
accessible field net/minecraft/client/texture/SpriteContents$AnimationFrame index I
|
||||
accessible method net/minecraft/client/texture/SpriteContents$Animation upload (III)V
|
||||
accessible method net/minecraft/client/texture/SpriteContents$Interpolation apply (IILnet/minecraft/client/texture/SpriteContents$AnimatorImpl;)V
|
||||
accessible class net/minecraft/client/texture/SpriteContents$AnimatorImpl
|
||||
accessible field net/minecraft/client/texture/SpriteContents mipmapLevelsImages [Lnet/minecraft/client/texture/NativeImage;
|
||||
accessible method net/minecraft/client/texture/SpriteContents upload (IIII[Lnet/minecraft/client/texture/NativeImage;)V
|
||||
accessible method net/minecraft/client/texture/SpriteContents$Animation getFrameX (I)I
|
||||
accessible method net/minecraft/client/texture/SpriteContents$Animation getFrameY (I)I
|
Loading…
Reference in New Issue