chore: recode animations and eases

This commit is contained in:
TopchetoEU 2023-01-18 16:08:02 +02:00
parent 54c77dced0
commit 00a25c3681
15 changed files with 119 additions and 136 deletions

View File

@ -107,12 +107,12 @@ public final class AnimatedChunks implements ClientModInitializer, ModMenuApi {
} }
public AnimatedChunks() { public AnimatedChunks() {
var eases = new Manager<>(new Descriptor<Ease>(x -> 1, "default") var eases = new Manager<>(new Descriptor<Ease>(() -> "t = 1;", "default")
.author("TopchetoEU") .author("TopchetoEU")
.description("Ends the animation as soon as it has started.") .description("Ends the animation as soon as it has started.")
.displayName("No animation") .displayName("No animation")
); );
var animations = new Manager<>(new Descriptor<Animation>((a, b, c, d, e, f, g, h) -> {}, "default") var animations = new Manager<>(new Descriptor<Animation>(() -> ";", "default")
.author("TopchetoEU") .author("TopchetoEU")
.description("Does nothing.") .description("Does nothing.")
.displayName("No animation") .displayName("No animation")

View File

@ -0,0 +1,26 @@
package me.topchetoeu.animatedchunks;
import java.util.Map;
public interface StatementFactory {
/**
* Returns a GLSL statement, with access to at least the following variables:
* <ul>
* <li>playerPos - vec3, the position of the player</li>
* <li>chunkPos - vec3, the position of the current chunk</li>
* <li>pos - vec3, the position of the current vertex</li>
* <li>x - the raw stage of the animation, from 0 to 1</li>
* <li>t - the eased stage of the animation, from 0 to 1</li>
* <li>tmp0 - tmp7 - temporary float variables</li>
* <li>tmp8 - tmp11 - temporary vec3 variables</li>
* <li>tmp12 - tmp15 - temporary vec4 variables</li>
* </ul>
*/
String statement();
/**
* Returns all uniforms that are used by the statement
*/
public default Map<String, Float> uniforms() {
return Map.of();
}
}

View File

@ -1,18 +1,5 @@
package me.topchetoeu.animatedchunks.animation; package me.topchetoeu.animatedchunks.animation;
import net.minecraft.client.util.math.MatrixStack; import me.topchetoeu.animatedchunks.StatementFactory;
public interface Animation { public interface Animation extends StatementFactory { }
/**
* Animations using the currently set ease
* @param progress The point at which the animation currently is (a value between 0 and 1)
* @param matrices The matrix stack used for rendering
* @param chunkX The current chunk's x (in blocks) which is animated
* @param chunkY The current chunk's y (in blocks) which is animated
* @param chunkZ The current chunk's z (in blocks) which is animated
* @param playerX The player's x (in blocks)
* @param playerY The player's y (in blocks)
* @param playerZ The player's z (in blocks)
*/
void animate(float progress, MatrixStack matrices, int chunkX, int chunkY, int chunkZ, float playerX, float playerY, float playerZ);
}

View File

@ -6,9 +6,6 @@ import java.util.Hashtable;
import me.topchetoeu.animatedchunks.Manager; import me.topchetoeu.animatedchunks.Manager;
import me.topchetoeu.animatedchunks.easing.Ease; import me.topchetoeu.animatedchunks.easing.Ease;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.util.math.Vector3d;
import net.minecraft.util.math.BlockPos;
public final class Animator { public final class Animator {
public static class ChunkLoc { public static class ChunkLoc {
@ -152,33 +149,4 @@ public final class Animator {
if (!chunkToStage.containsKey(new ChunkLoc(x, y, z))) return 1f; if (!chunkToStage.containsKey(new ChunkLoc(x, y, z))) return 1f;
return chunkToStage.get(new ChunkLoc(x, y, z)); return chunkToStage.get(new ChunkLoc(x, y, z));
} }
public void animate(MatrixStack matrices, float progress, BlockPos chunkPos, Vector3d playerPos) {
if (progress < 0) progress = 0;
if (progress > 1) progress = 1;
if (progress < 0.999) {
float _progress = EASES.getValue().ease(progress);
ANIMATIONS.getValue().animate(
_progress, matrices,
chunkPos.getX() * 16, chunkPos.getY() * 16, chunkPos.getZ() * 16,
(float)playerPos.x, (float)playerPos.y, (float)playerPos.z
);
// matrices.translate(0, 0, 16);
}
}
public void animate(MatrixStack matrices, BlockPos chunkPos, Vector3d playerPos) {
if (!isChunkLoaded(chunkPos.getX(), chunkPos.getY(), chunkPos.getZ())) {
matrices.scale(0, 0, 0);
}
else {
animate(matrices, getChunkProgress(chunkPos.getX(), chunkPos.getY(), chunkPos.getZ()), chunkPos, playerPos);
}
}
public void animate(MatrixStack matrices, BlockPos chunkPos) {
animate(matrices, chunkPos, new Vector3d(0, 0, 0));
}
public void animate(MatrixStack matrices, float progress, BlockPos chunkPos) {
animate(matrices, progress, chunkPos, new Vector3d(0, 0, 0));
}
} }

View File

@ -1,6 +1,6 @@
package me.topchetoeu.animatedchunks.animation; package me.topchetoeu.animatedchunks.animation;
import net.minecraft.client.util.math.MatrixStack; import java.util.Map;
public class FallAnimation implements Animation { public class FallAnimation implements Animation {
private float offset; private float offset;
@ -12,12 +12,11 @@ public class FallAnimation implements Animation {
this.offset = offset; this.offset = offset;
} }
@Override public Map<String, Float> uniforms() {
public void animate(float progress, MatrixStack matrices, int chunkX, int chunkY, int chunkZ, float playerX, float playerY, float playerZ) { return Map.of("animation_f", offset);
animate(progress, matrices);
} }
public void animate(float progress, MatrixStack matrices) { public String statement() {
matrices.translate(0, offset * (1 - progress), 0); return "pos += vec3(0, animation_f * (1 - t));";
} }
public FallAnimation(float offset) { public FallAnimation(float offset) {

View File

@ -1,7 +1,6 @@
package me.topchetoeu.animatedchunks.animation; package me.topchetoeu.animatedchunks.animation;
import net.minecraft.client.util.math.MatrixStack; import java.util.Map;
import net.minecraft.util.math.Vec2f;
public class FlyInAnimation implements Animation { public class FlyInAnimation implements Animation {
private float offset; private float offset;
@ -13,13 +12,21 @@ public class FlyInAnimation implements Animation {
this.offset = offset; this.offset = offset;
} }
public Map<String, Float> uniforms() {
@Override return Map.of("animation_f", offset);
public void animate(float progress, MatrixStack matrices, int chunkX, int chunkY, int chunkZ, float playerX, float playerY, float playerZ) {
Vec2f direction = new Vec2f(playerX, playerZ).add(new Vec2f(-chunkX, -chunkZ)).normalize().multiply(-offset);
matrices.translate(direction.x * (1 - progress), 0, direction.y * (1 - progress));
} }
@Override
public String statement() {
return "tmp8 = normalize(chunkPos.xz - playerPos.xz) * animation_f; tmp8 *= (1 - t); pos += tmp8;";
}
// @Override
// public void animate(float progress, MatrixStack matrices, int chunkX, int chunkY, int chunkZ, float playerX, float playerY, float playerZ) {
// Vec2f direction = new Vec2f(playerX, playerZ).add(new Vec2f(-chunkX, -chunkZ)).normalize().multiply(-offset);
// matrices.translate(direction.x * (1 - progress), 0, direction.y * (1 - progress));
// }
public FlyInAnimation() { public FlyInAnimation() {
offset = 50; offset = 50;

View File

@ -1,6 +1,6 @@
package me.topchetoeu.animatedchunks.animation; package me.topchetoeu.animatedchunks.animation;
import net.minecraft.client.util.math.MatrixStack; import java.util.Map;
public final class RiseAnimation implements Animation { public final class RiseAnimation implements Animation {
private float offset; private float offset;
@ -12,12 +12,11 @@ public final class RiseAnimation implements Animation {
this.offset = offset; this.offset = offset;
} }
@Override public Map<String, Float> uniforms() {
public void animate(float progress, MatrixStack matrices, int chunkX, int chunkY, int chunkZ, float playerX, float playerY, float playerZ) { return Map.of("animation_f", offset);
animate(progress, matrices);
} }
public void animate(float progress, MatrixStack matrices) { public String statement() {
matrices.translate(0, offset * (progress - 1), 0); return "pos += vec3(0, animation_f * (t - 1));";
} }
public RiseAnimation(float offset) { public RiseAnimation(float offset) {

View File

@ -1,10 +1,11 @@
package me.topchetoeu.animatedchunks.animation; package me.topchetoeu.animatedchunks.animation;
import net.minecraft.client.util.math.MatrixStack; import java.util.Map;
public class ScaleAnimation implements Animation { public class ScaleAnimation implements Animation {
public static float xOffset = 8, yOffset = 8, zOffset = 8;
private boolean scaleY = true; private boolean scaleY = true;
private float xOffset = 8, yOffset = 8, zOffset = 8;
public boolean isScalingY() { public boolean isScalingY() {
return scaleY; return scaleY;
@ -13,38 +14,31 @@ public class ScaleAnimation implements Animation {
this.scaleY = scaleY; this.scaleY = scaleY;
} }
public float getXOffset() { @Override
return xOffset; public Map<String, Float> uniforms() {
} return Map.of("animation_ox", xOffset, "animation_oy", yOffset, "animation_oz", zOffset, "animation_sy", scaleY ? 1f : 0f);
public void setXOffset(float xOffset) {
this.xOffset = xOffset;
}
public float getYOffset() {
return yOffset;
}
public void setYOffset(float yOffset) {
this.yOffset = yOffset;
}
public float getZOffset() {
return zOffset;
}
public void setZOffset(float zOffset) {
this.zOffset = zOffset;
} }
@Override @Override
public void animate(float progress, MatrixStack matrices, int chunkX, int chunkY, int chunkZ, float playerX, float playerY, float playerZ) { public String statement() {
float scaleX = progress; return
float scaleZ = progress; "tmp8 = vec3(animation_ox, animation_oy, animation_oz);" +
"tmp9 = vec3(t);" +
matrices.translate(xOffset, yOffset, zOffset); "if (animation_sy < .5f) tmp9.y = 0;" +
matrices.scale(scaleX, 1, scaleZ); "pos += tmp8;" +
matrices.translate(-xOffset, -yOffset, -zOffset); "pos *= tmp9;" +
"pos -= tmp8;";
} }
public ScaleAnimation() { // @Override
// public void animate(float progress, MatrixStack matrices, int chunkX, int chunkY, int chunkZ, float playerX, float playerY, float playerZ) {
// float scaleX = progress;
// float scaleZ = progress;
} // matrices.translate(xOffset, yOffset, zOffset);
// matrices.scale(scaleX, 1, scaleZ);
// matrices.translate(-xOffset, -yOffset, -zOffset);
// }
public ScaleAnimation() { }
} }

View File

@ -1,34 +1,30 @@
package me.topchetoeu.animatedchunks.easing; package me.topchetoeu.animatedchunks.easing;
public interface Ease { import me.topchetoeu.animatedchunks.StatementFactory;
/**
* Converts the linear progress of an animation to an eased progress
* @param x The progress of the animation being eased
* @return The new, eased progress
*/
float ease(float x);
public interface Ease extends StatementFactory {
/** /**
* Converts a function to an ease out version of itself. * Converts a ease-in statement to an ease-out statement
* Mathematically, the function is being "rotated" 180 degrees * Mathematically, the function is being "rotated" 180 degrees
* @param func The function to convert * @param func The ease statement to convert
* @return The ease out version of the function
*/ */
public static Ease easeOut(Ease func) { public static Ease easeOut(Ease func) {
return x -> 1 - func.ease(1 - x); return () -> "x = 1 - x; " + func.statement() + "x = 1 - x; t = 1 - t;";
// return x -> 1 - func.ease(1 - x);
} }
/** /**
* Converts a function to an ease in-out version of itself. * Converts a ease statement to an ease in-out statement
* Mathematically, the function is being split into two, where in the interval [0; 0.5], the ease-out function is being used, and in the other interval [0.5; 1], the ease-in function is being used * Mathematically, the function is being split into two, where in the interval [0; 0.5), the ease-in function is being used, and in the other interval [0.5; 1], the ease-out function is being used
* @param func The function to convert * @param func The ease statement to convert
* @return The ease in-out version of the function * @return The ease in-out statement
*/ */
public static Ease easeInOut(Ease func) { public static Ease easeInOut(Ease func) {
return x -> { return () -> "x *= 2; if (x < 1f) { " + easeOut(func) + "} else { x -= 1; " + func.statement() + " } x /= 2;";
float x2 = 2 * x; // return x -> {
// float x2 = 2 * x;
if (x < 0.5f) return (1 - func.ease(1 - x2)) / 2; // if (x < 0.5f) return (1 - func.ease(1 - x2)) / 2;
else return (1 + func.ease(x2 - 1)) / 2; // else return (1 + func.ease(x2 - 1)) / 2;
}; // };
} }
} }

View File

@ -1,5 +1,7 @@
package me.topchetoeu.animatedchunks.easing; package me.topchetoeu.animatedchunks.easing;
import java.util.Map;
public class ElasticEase implements Ease { public class ElasticEase implements Ease {
private float steepness = 1; private float steepness = 1;
private int periods = 3; private int periods = 3;
@ -19,11 +21,21 @@ public class ElasticEase implements Ease {
} }
@Override @Override
public float ease(float x) { public Map<String, Float> uniforms() {
float amplitude = (float)Math.pow(2, -steepness * x) * (1 - x); return Map.of("ease_s", steepness, "ease_p", (float)periods);
float wave = (float)Math.sin(2 * Math.PI * periods * x - Math.PI / 2); }
return amplitude * wave + 1; @Override
public String statement() {
return
"tmp0 = pow(2, -ease_s * x) * (1 - x);" +
"tmp1 = sin(6.28 * ease_p * x - 1.57);" +
"t = tmp0 * tmp1 + 1;";
// float amplitude = (float)Math.pow(2, -steepness * x) * (1 - x);
// float wave = (float)Math.sin(2 * Math.PI * periods * x - Math.PI / 2);
// return amplitude * wave + 1;
} }
} }

View File

@ -1,7 +1,7 @@
package me.topchetoeu.animatedchunks.easing; package me.topchetoeu.animatedchunks.easing;
public class LinearEase implements Ease { public class LinearEase implements Ease {
public float ease(float x) { public String statement() {
return x; return "t = x;";
} }
} }

View File

@ -1,8 +1,7 @@
package me.topchetoeu.animatedchunks.easing; package me.topchetoeu.animatedchunks.easing;
public class QuadraticEase implements Ease { public class QuadraticEase implements Ease {
@Override public String statement() {
public float ease(float x) { return "t = x * x;";
return x * x;
} }
} }

View File

@ -1,8 +1,7 @@
package me.topchetoeu.animatedchunks.easing; package me.topchetoeu.animatedchunks.easing;
public class SineEase implements Ease { public class SineEase implements Ease {
@Override public String statement() {
public float ease(float x) { return "t = sin(x * 1.57);";
return (float)Math.sin(x * Math.PI / 2);
} }
} }

View File

@ -20,7 +20,6 @@ import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexFormat; import net.minecraft.client.render.VertexFormat;
import net.minecraft.client.render.VertexFormats; import net.minecraft.client.render.VertexFormats;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Matrix4f; import net.minecraft.util.math.Matrix4f;
import net.minecraft.util.math.Quaternion; import net.minecraft.util.math.Quaternion;
import net.minecraft.util.math.Vec3f; import net.minecraft.util.math.Vec3f;
@ -173,7 +172,7 @@ public class ChunkPreview extends DrawableHelper implements Drawable, Element, S
// x += n; // x += n;
// y += n; // y += n;
animator.animate(matrices, progress, new BlockPos(x * 16, 0, y * 16)); // animator.animate(matrices, progress, new BlockPos(x * 16, 0, y * 16));
// if (progress < 0) progress = 0; // if (progress < 0) progress = 0;
// if (progress > 1) progress = 1; // if (progress > 1) progress = 1;

View File

@ -11,8 +11,6 @@ import net.minecraft.client.render.WorldRenderer;
import net.minecraft.client.render.WorldRenderer.ChunkInfo; import net.minecraft.client.render.WorldRenderer.ChunkInfo;
import net.minecraft.client.render.chunk.ChunkBuilder.BuiltChunk; import net.minecraft.client.render.chunk.ChunkBuilder.BuiltChunk;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.util.math.Vector3d;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Matrix4f; import net.minecraft.util.math.Matrix4f;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
@ -56,7 +54,7 @@ public abstract class WorldRendererMixin {
matrices.push(); matrices.push();
AnimatedChunks.getInstance().animator.animate(matrices, new BlockPos(chunk.getOrigin().getX(), 0, chunk.getOrigin().getZ()), new Vector3d(playerX, playerY, playerZ)); // AnimatedChunks.getInstance().animator.animate(matrices, new BlockPos(chunk.getOrigin().getX(), 0, chunk.getOrigin().getZ()), new Vector3d(playerX, playerY, playerZ));
// if (getProgressManager().isChunkLoaded(x, 0, z)) { // if (getProgressManager().isChunkLoaded(x, 0, z)) {
// float progress = getProgressManager().getChunkProgress(x, 0, z); // float progress = getProgressManager().getChunkProgress(x, 0, z);