From 0d6c265845390bc9372d22b6eba7c73fba62f22f Mon Sep 17 00:00:00 2001 From: Sollace Date: Fri, 23 Dec 2022 16:33:05 +0100 Subject: [PATCH] Improve rendering of field of view effects --- .../unicopia/client/gui/GradientUtil.java | 128 ++++++++++++++++++ .../unicopia/client/gui/UHud.java | 96 +++++-------- 2 files changed, 163 insertions(+), 61 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/client/gui/GradientUtil.java diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/GradientUtil.java b/src/main/java/com/minelittlepony/unicopia/client/gui/GradientUtil.java new file mode 100644 index 00000000..2dae20d8 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/GradientUtil.java @@ -0,0 +1,128 @@ +package com.minelittlepony.unicopia.client.gui; + +import org.joml.Matrix4f; + +import com.mojang.blaze3d.systems.RenderSystem; + +import net.minecraft.client.render.*; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.MathHelper; + +public interface GradientUtil { + + static void fillVerticalGradient(MatrixStack matrices, int startX, int startY, int stopY, int endX, int endY, int colorStart, int colorStop, int colorEnd, int z) { + RenderSystem.disableTexture(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.setShader(GameRenderer::getPositionColorProgram); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferBuilder = tessellator.getBuffer(); + fillVerticalGradient(matrices.peek().getPositionMatrix(), bufferBuilder, startX, startY, stopY, endX, endY, z, colorStart, colorStop, colorEnd); + tessellator.draw(); + RenderSystem.disableBlend(); + RenderSystem.enableTexture(); + } + + private static void fillVerticalGradient(Matrix4f matrix, BufferBuilder builder, int startX, int startY, int stopY, int endX, int endY, int z, int colorStart, int colorStop, int colorEnd) { + final float fromA = (colorStart >> 24 & 0xFF) / 255F; + final float fromR = (colorStart >> 16 & 0xFF) / 255F; + final float fromG = (colorStart >> 8 & 0xFF) / 255F; + final float fromB = (colorStart & 0xFF) / 255F; + + final float stopA = (colorStop >> 24 & 0xFF) / 255F; + final float stopR = (colorStop >> 16 & 0xFF) / 255F; + final float stopG = (colorStop >> 8 & 0xFF) / 255F; + final float stopB = (colorStop & 0xFF) / 255F; + + final float toA = (colorEnd >> 24 & 0xFF) / 255F; + final float toR = (colorEnd >> 16 & 0xFF) / 255F; + final float toG = (colorEnd >> 8 & 0xFF) / 255F; + final float toB = (colorEnd & 0xFF) / 255F; + + builder.begin(VertexFormat.DrawMode.TRIANGLE_FAN, VertexFormats.POSITION_COLOR); + + builder.vertex(matrix, endX, stopY, z).color(stopR, stopG, stopB, stopA).next(); + builder.vertex(matrix, endX, startY, z).color(fromR, fromG, fromB, fromA).next(); + builder.vertex(matrix, startX, startY, z).color(fromR, fromG, fromB, fromA).next(); + builder.vertex(matrix, startX, stopY, z).color(stopR, stopG, stopB, stopA).next(); + builder.vertex(matrix, startX, endY, z).color(toR, toG, toB, toA).next(); + builder.vertex(matrix, endX, endY, z).color(stopR, toG, toB, toA).next(); + } + + static void fillRadialGradient(MatrixStack matrices, int startX, int startY, int endX, int endY, int colorStart, int colorEnd, int z, float radius) { + RenderSystem.disableTexture(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.setShader(GameRenderer::getPositionColorProgram); + Tessellator tessellator = Tessellator.getInstance(); + if (fillRadials(matrices.peek().getPositionMatrix(), tessellator.getBuffer(), startX, startY, endX, endY, z, colorStart, colorEnd, radius)) { + tessellator.draw(); + } + RenderSystem.disableBlend(); + RenderSystem.enableTexture(); + } + + private static boolean fillRadials(Matrix4f matrix, BufferBuilder builder, int startX, int startY, int endX, int endY, int z, int colorStart, int colorEnd, float radius) { + final float fromA = (colorStart >> 24 & 0xFF) / 255F; + final float fromR = (colorStart >> 16 & 0xFF) / 255F; + final float fromG = (colorStart >> 8 & 0xFF) / 255F; + final float fromB = (colorStart & 0xFF) / 255F; + final float toA = (colorEnd >> 24 & 0xFF) / 255F; + final float toR = (colorEnd >> 16 & 0xFF) / 255F; + final float toG = (colorEnd >> 8 & 0xFF) / 255F; + final float toB = (colorEnd & 0xFF) / 255F; + + double increment = DrawableUtil.TAU / 30D; + + float width = endX - startX; + float height = endY - startY; + + float outerRadius = MathHelper.sqrt((width * width) + (height * height)) / 2F; + + float innerRadius = outerRadius * (1 - radius); + + builder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); + for (double angle = 0; angle < DrawableUtil.TAU; angle += increment) { + clampedVertex(builder, matrix, innerRadius, angle + increment, z, startX, endX, startY, endY).color(toR, toG, toB, toA).next(); + clampedVertex(builder, matrix, innerRadius, angle, z, startX, endX, startY, endY).color(toR, toG, toB, toA).next(); + clampedVertex(builder, matrix, outerRadius, angle, z, startX, endX, startY, endY).color(fromR, fromG, fromB, fromA).next(); + clampedVertex(builder, matrix, outerRadius, angle + increment, z, startX, endX, startY, endY).color(fromR, fromG, fromB, fromA).next(); + } + return true; + } + + static float getX(double radius, double angle) { + return (float)(radius * MathHelper.sin((float)angle)); + } + + static float getY(double radius, double angle) { + return (float)(radius * MathHelper.cos((float)angle)); + } + + private static VertexConsumer clampedVertex(BufferBuilder bufferBuilder, Matrix4f model, double radius, double angle, float z, int minX, int maxX, int minY, int maxY) { + float midX = (maxX - minX) / 2F; + float midY = (maxY - minY) / 2F; + + float x = midX + getX(radius, angle); + float y = midY + getY(radius, angle); + + float xPad = (maxX - minX) / 10F; + float yPad = (maxY - minY) / 20F; + + if (x < minX + xPad) { + x = minX; + } + if (x > maxX - xPad) { + x = maxX; + } + + if (y < minY + yPad) { + y = minY; + } + if (y > maxY - yPad) { + y = maxY; + } + + return bufferBuilder.vertex(model, x, y, z); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java index 8e528b94..f4f71dca 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java @@ -3,7 +3,6 @@ package com.minelittlepony.unicopia.client.gui; import java.util.List; import org.jetbrains.annotations.Nullable; - import com.minelittlepony.unicopia.*; import com.minelittlepony.unicopia.ability.AbilityDispatcher; import com.minelittlepony.unicopia.ability.AbilitySlot; @@ -224,21 +223,21 @@ public class UHud extends DrawableHelper { float strength = MathHelper.clamp(pulse + i, 0.3F, 1F); - int alpha1 = (int)(strength * 205) << 24 & -16777216; + int alpha1 = (int)(strength * 205); int alpha2 = (int)(alpha1 * 0.6F); - - fillGradient(matrices, 0, 0, scaledWidth, scaledHeight / 2, 0xFFFFFF | alpha1, 0xFFFFFF | alpha2); - fillGradient(matrices, 0, scaledHeight / 2, scaledWidth, scaledHeight, 0xFFFFFF | alpha2, 0xFFFFFF | alpha1); + int color = 0xFFFFFF; if (hasEffect) { - matrices.push(); - matrices.translate(scaledWidth, 0, 0); - matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(90)); - - fillGradient(matrices, 0, 0, scaledHeight, scaledWidth / 2, 0xFFFFFF | 0, 0xFFFFFF | alpha2); - fillGradient(matrices, 0, scaledWidth / 2, scaledHeight, scaledWidth, 0xFFFFFF | alpha2, 0xFFFFFF | 0); - - matrices.pop(); + GradientUtil.fillRadialGradient(matrices, 0, 0, scaledWidth, scaledHeight, + color | (alpha1 << 24), + color | (alpha2 << 24), + getZOffset(), 1); + } else { + GradientUtil.fillVerticalGradient(matrices, 0, 0, scaledHeight / 2, scaledWidth, scaledHeight, + color | (alpha1 << 24), + color | (alpha2 << 24), + color | (alpha1 << 24), + getZOffset()); } } @@ -271,7 +270,12 @@ public class UHud extends DrawableHelper { } } - float exhaustion = pony.getMagicalReserves().getExhaustion().getPercentFill(); + if (UItems.ALICORN_AMULET.isApplicable(client.player)) { + float radius = (float)pony.getArmour().getTicks(UItems.ALICORN_AMULET) / (5 * ItemTracker.DAYS); + renderVignette(matrices, 0x000000, radius, radius, scaledWidth, scaledHeight); + } + + float exhaustion = MathHelper.clamp(pony.getMagicalReserves().getExhaustion().getPercentFill(), 0, 0.6F); if (exhaustion > 0) { if (exhaustion > 0.5F && (heartbeatSound == null || heartbeatSound.isDone())) { @@ -282,59 +286,29 @@ public class UHud extends DrawableHelper { ); } - int color = 0x880000; - float rate = exhaustion > 0.5F ? 2.5F : 7F; - float radius = (1 + (float)Math.sin(client.player.age / rate)) / 2F; - radius = 0.1F + radius * 0.1F; - int alpha1 = (int)(MathHelper.clamp(exhaustion * radius * 2, 0, 1) * 205) << 24 & -16777216; - int alpha2 = 0; - - int halfWidth = (int)(scaledWidth * radius); - int halfHeight = (int)(scaledHeight * radius); - - fillGradient(matrices, 0, 0, scaledWidth, halfHeight, color | alpha1, color | alpha2); - fillGradient(matrices, 0, scaledHeight - halfHeight, scaledWidth, scaledHeight, color | alpha2, color | alpha1); - - matrices.push(); - matrices.translate(scaledWidth, 0, 0); - matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(90)); - - fillGradient(matrices, 0, 0, scaledHeight, halfWidth, color | alpha1, color | alpha2); - fillGradient(matrices, 0, scaledWidth - halfWidth, scaledHeight, scaledWidth, color | alpha2, color | alpha1); - - matrices.pop(); - } - - if (UItems.ALICORN_AMULET.isApplicable(client.player)) { - int color = 0x000000; - - long timer = pony.getArmour().getTicks(UItems.ALICORN_AMULET); - - float radius = (float)timer / (5 * ItemTracker.DAYS); - - int alpha1 = (int)(MathHelper.clamp(radius * 2, 0, 1) * 205) << 24 & -16777216; - int alpha2 = 0; - - int halfWidth = (int)(scaledWidth * radius); - int halfHeight = (int)(scaledHeight * radius); - - fillGradient(matrices, 0, 0, scaledWidth, halfHeight, color | alpha1, color | alpha2); - fillGradient(matrices, 0, scaledHeight - halfHeight, scaledWidth, scaledHeight, color | alpha2, color | alpha1); - - matrices.push(); - matrices.translate(scaledWidth, 0, 0); - matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(90)); - - fillGradient(matrices, 0, 0, scaledHeight, halfWidth, color | alpha1, color | alpha2); - fillGradient(matrices, 0, scaledWidth - halfWidth, scaledHeight, scaledWidth, color | alpha2, color | alpha1); - - matrices.pop(); + renderVignette(matrices, 0x880000, exhaustion * radius, 0.1F + radius * 0.3F, scaledWidth, scaledHeight); } } + private void renderVignette(MatrixStack matrices, int color, float alpha, float radius, int scaledWidth, int scaledHeight) { + if (radius <= 0) { + return; + } + + color &= 0xFFFFFF; + float alpha2 = MathHelper.clamp(radius - 1, 0, 1) * 255; + float alpha1 = Math.max(alpha2, MathHelper.clamp(alpha * 2, 0, 1) * 205); + GradientUtil.fillRadialGradient(matrices, 0, 0, scaledWidth, scaledHeight, + color | (int)alpha1 << 24, + color | (int)alpha2 << 24, + getZOffset(), Math.min(1, radius)); + } + + + public void setMessage(Text message) { this.message = message; this.messageTime = 60;