diff --git a/src/main/java/top/hendrixshen/magiclib/render/RenderMixinPlugin.java b/src/main/java/top/hendrixshen/magiclib/render/RenderMixinPlugin.java new file mode 100644 index 00000000..c87a108b --- /dev/null +++ b/src/main/java/top/hendrixshen/magiclib/render/RenderMixinPlugin.java @@ -0,0 +1,6 @@ +package top.hendrixshen.magiclib.render; + +import top.hendrixshen.magiclib.dependency.impl.MagicMixinPlugin; + +public class RenderMixinPlugin extends MagicMixinPlugin { +} diff --git a/src/main/java/top/hendrixshen/magiclib/render/api/IRendererLevelPost.java b/src/main/java/top/hendrixshen/magiclib/render/api/IRendererLevelPost.java new file mode 100644 index 00000000..72c13141 --- /dev/null +++ b/src/main/java/top/hendrixshen/magiclib/render/api/IRendererLevelPost.java @@ -0,0 +1,11 @@ +package top.hendrixshen.magiclib.render.api; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import top.hendrixshen.magiclib.render.impl.RenderContext; + +@Environment(EnvType.CLIENT) +@FunctionalInterface +public interface IRendererLevelPost { + void render(RenderContext context); +} diff --git a/src/main/java/top/hendrixshen/magiclib/render/impl/RenderContext.java b/src/main/java/top/hendrixshen/magiclib/render/impl/RenderContext.java new file mode 100644 index 00000000..a22c0ce5 --- /dev/null +++ b/src/main/java/top/hendrixshen/magiclib/render/impl/RenderContext.java @@ -0,0 +1,86 @@ +package top.hendrixshen.magiclib.render.impl; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import org.joml.Matrix4f; + +import lombok.Getter; + +@Environment(EnvType.CLIENT) +public class RenderContext { + @Getter + private final PoseStack poseStack; + + public RenderContext(PoseStack poseStack) { + this.poseStack = poseStack; + } + + public void pushMatrix() { + this.poseStack.pushPose(); + } + + public void popMatrix() { + this.poseStack.popPose(); + } + + public void translate(double x, double y, double z) { + this.poseStack.translate(x, y, z); + } + + public void scale(double x, double y, double z) { + this.poseStack.scale((float)x, (float)y, (float)z); + } + + public void mulPoseMatrix(Matrix4f matrix4f) { + //#if MC > 11605 || MC < 11500 + this.poseStack.mulPoseMatrix(matrix4f); + //#else + //$$ this.poseStack.last().pose().multiply(matrix4f); + //#endif + } + + public void enableDepthTest() { + RenderSystem.enableDepthTest(); + } + + public void disableDepthTest() { + RenderSystem.disableDepthTest(); + } + + public void depthMask(boolean mask) { + RenderSystem.depthMask(mask); + } + + public void enableBlend() { + RenderSystem.enableBlend(); + } + + public void blendFunc(GlStateManager.SourceFactor srcFactor, GlStateManager.DestFactor dstFactor) { + RenderSystem.blendFunc(srcFactor, dstFactor); + } + + //#if MC < 11904 + //$$ public void enableTexture() { + //$$ RenderSystem.enableTexture(); + //$$ } + //#endif + + //#if MC < 11700 + //$$ public void enableAlphaTest() { + //$$ RenderSystem.enableAlphaTest(); + //$$ } + //$$ + //$$ public void disableLighting() { + //$$ RenderSystem.disableLighting(); + //$$ } + //#endif + + //#if MC < 11600 + //$$ public void color4f(float red, float green, float blue, float alpha) { + //$$ RenderSystem.color4f(red, green, blue, alpha); + //$$ } + //#endif +} diff --git a/src/main/java/top/hendrixshen/magiclib/render/impl/RenderEventHandler.java b/src/main/java/top/hendrixshen/magiclib/render/impl/RenderEventHandler.java new file mode 100644 index 00000000..c91875c6 --- /dev/null +++ b/src/main/java/top/hendrixshen/magiclib/render/impl/RenderEventHandler.java @@ -0,0 +1,27 @@ +package top.hendrixshen.magiclib.render.impl; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.vertex.PoseStack; +import lombok.Getter; +import net.minecraft.client.Minecraft; +import top.hendrixshen.magiclib.render.api.IRendererLevelPost; + +import java.util.List; + +public class RenderEventHandler { + @Getter + private static final RenderEventHandler instance = new RenderEventHandler(); + private static final Minecraft mc = Minecraft.getInstance(); + private static final List levelPostRenderers = Lists.newArrayList(); + + public static void register(IRendererLevelPost renderer) { + RenderEventHandler.levelPostRenderers.add(renderer); + } + + public void dispatchPostRenderLevelEvent(PoseStack poseStack) { + mc.getProfiler().popPush("MagicRenderEventHandler::dispatchRenderWorldPostEvent"); + RenderContext renderContext = new RenderContext(poseStack); + RenderEventHandler.levelPostRenderers.forEach(renderer -> renderer.render(renderContext)); + mc.getProfiler().pop(); + } +} diff --git a/src/main/java/top/hendrixshen/magiclib/render/impl/TextRenderer.java b/src/main/java/top/hendrixshen/magiclib/render/impl/TextRenderer.java new file mode 100644 index 00000000..f9cd5a7f --- /dev/null +++ b/src/main/java/top/hendrixshen/magiclib/render/impl/TextRenderer.java @@ -0,0 +1,217 @@ +package top.hendrixshen.magiclib.render.impl; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.vertex.Tesselator; +import lombok.Getter; +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.NotNull; +import org.joml.Matrix4f; +import top.hendrixshen.magiclib.compat.minecraft.api.network.chat.ComponentCompatApi; + +import java.util.Collections; +import java.util.List; + +//#if MC < 11904 +//$$ import com.mojang.blaze3d.systems.RenderSystem; +//$$ import com.mojang.blaze3d.vertex.PoseStack; +//#endif + +//#if MC > 11404 +import net.minecraft.client.renderer.MultiBufferSource; +//#endif + +public class TextRenderer { + private final List lines = Lists.newArrayList(); + private Vec3 pos = Vec3.ZERO; + @Getter + private double fontSize = 0.02; + private double lineHeight = (Minecraft.getInstance().font.lineHeight + 1.0) / Minecraft.getInstance().font.lineHeight; + private int color = 0xFFFFFFFF; + private int backgroundColor = 0x00000000; + private boolean shadow = false; + private boolean seeThrough = false; + + public void render(RenderContext context) { + if (this.lines.isEmpty()) { + return; + } + + Minecraft mc = Minecraft.getInstance(); + Camera camera = mc.gameRenderer.getMainCamera(); + + if (camera.isInitialized() && mc.player != null) { + double x = this.pos.x(); + double y = this.pos.y(); + double z = this.pos.z(); + double camX = camera.getPosition().x(); + double camY = camera.getPosition().y(); + double camZ = camera.getPosition().z(); + //#if MC < 11904 + //$$ context = new RenderContext(new PoseStack()); + //#endif + context.pushMatrix(); + context.translate(x - camX, y - camY, z - camZ); + //#if MC > 11902 + context.mulPoseMatrix(new Matrix4f().rotation(camera.rotationCompat())); + //#else + //$$ context.mulPoseMatrix(new Matrix4f(camera.rotationCompat())); + //#endif + context.scale(this.fontSize, -this.fontSize, this.fontSize); + //#if MC < 11700 + //$$ context.disableLighting(); + //#endif + + if (this.seeThrough) { + context.disableDepthTest(); + } else { + context.enableDepthTest(); + } + + //#if MC < 11904 + //$$ context.enableTexture(); + //#endif + context.depthMask(true); + context.scale(-1.0, 1.0, 1.0); + int lineNum = this.lines.size(); + double maxTextWidth = this.lines.stream().mapToInt(mc.font::width).max().orElse(0); + double totalTextX = maxTextWidth; + double totalTextY = mc.font.lineHeight * lineNum + (this.lineHeight - 1) * (lineNum - 1); + context.translate(-totalTextX * 0.5, -totalTextY * 0.5, 0); + //#if MC < 11904 + //#if MC > 11605 + //$$ RenderSystem.applyModelViewMatrix(); + //#else + //$$ context.enableAlphaTest(); + //#endif + //#endif + context.enableBlend(); + context.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); + + for (int i = 0; i < lineNum; i++) { + Component text = this.lines.get(i); + float textX = (float)((maxTextWidth - mc.font.widthCompat(text)) / 2); + float textY = (float)(mc.font.lineHeight * this.lineHeight * i); + + int backgroundColor = this.backgroundColor; + + while (true) { + //#if MC > 11404 + MultiBufferSource.BufferSource source = MultiBufferSource.immediate(Tesselator.getInstance().getBuilder()); + //#endif + Matrix4f matrix4f = context.getPoseStack().last().pose(); + //#if MC > 11502 + mc.font.drawInBatch(text, textX, textY, this.color, this.shadow, matrix4f, source, + //#elseif MC > 11404 + //$$ mc.font.drawInBatch(text.getColoredString(), textX, textY, this.color, this.shadow, matrix4f, source, + //#else + //$$ mc.font.drawInBatch(text.getColoredString(), textX, textY, this.color, this.shadow, matrix4f, + //#endif + //#if MC > 11903 + this.seeThrough ? net.minecraft.client.gui.Font.DisplayMode.SEE_THROUGH : net.minecraft.client.gui.Font.DisplayMode.NORMAL, + //#else + //$$ this.seeThrough, + //#endif + backgroundColor, 0xF000F0); + //#if MC > 11404 + source.endBatch(); + //#endif + + if (backgroundColor == 0) { + break; + } else { + backgroundColor = 0; + } + } + } + + //#if MC < 11600 + //$$ context.color4f(1.0F, 1.0F, 1.0F, 1.0F); + //#endif + //#if MC < 11904 + //$$ context.enableDepthTest(); + //#endif + context.popMatrix(); + } + } + + private TextRenderer addLines(Component... lines) { + Collections.addAll(this.lines, lines); + return this; + } + + private TextRenderer setLines(Component... lines) { + this.lines.clear(); + this.addLines(lines); + return this; + } + + public TextRenderer text(String text) { + return this.text(ComponentCompatApi.literal(text)); + } + + public TextRenderer text(Component text) { + return this.setLines(text); + } + + public TextRenderer addLine(String text) { + return this.addLines(ComponentCompatApi.literal(text)); + } + + public TextRenderer addLine(Component text) { + return this.addLines(text); + } + + public TextRenderer lineHeight(double lineHeight) { + this.lineHeight = lineHeight; + return this; + } + + public TextRenderer pos(double x, double y, double z) { + return this.pos(new Vec3(x, y, z)); + } + + public TextRenderer pos(Vec3 pos) { + this.pos = pos; + return this; + } + + public TextRenderer blockCenter(@NotNull BlockPos pos) { + return this.pos(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5); + } + + public TextRenderer fontSize(double fontSize) { + this.fontSize = fontSize; + return this; + } + + public TextRenderer color(int color) { + this.color = color; + return this; + } + + public TextRenderer bgColor(int backgroundColor) { + this.backgroundColor = backgroundColor; + return this; + } + + public TextRenderer color(int color, int backgroundColor) { + this.color(color); + this.bgColor(backgroundColor); + return this; + } + + public TextRenderer shadow(boolean shadow) { + this.shadow = shadow; + return this; + } + + public TextRenderer seeThrough(boolean seeThrough) { + this.seeThrough = seeThrough; + return this; + } +} diff --git a/src/main/java/top/hendrixshen/magiclib/render/mixin/MixinGameRenderer.java b/src/main/java/top/hendrixshen/magiclib/render/mixin/MixinGameRenderer.java new file mode 100644 index 00000000..e9f3760e --- /dev/null +++ b/src/main/java/top/hendrixshen/magiclib/render/mixin/MixinGameRenderer.java @@ -0,0 +1,45 @@ +package top.hendrixshen.magiclib.render.mixin; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import org.spongepowered.asm.mixin.Mixin; + +//#if MC > 11404 +import top.hendrixshen.magiclib.compat.preprocess.api.DummyClass; +//#else +//$$ import com.mojang.blaze3d.vertex.PoseStack; +//$$ import net.minecraft.client.Camera; +//$$ import net.minecraft.client.renderer.GameRenderer; +//$$ import org.spongepowered.asm.mixin.Final; +//$$ import org.spongepowered.asm.mixin.Shadow; +//$$ import org.spongepowered.asm.mixin.injection.At; +//$$ import org.spongepowered.asm.mixin.injection.Inject; +//$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +//$$ import top.hendrixshen.magiclib.compat.minecraft.api.math.Vector3fCompatApi; +//$$ import top.hendrixshen.magiclib.render.impl.RenderEventHandler; +//#endif + +@Environment(EnvType.CLIENT) +//#if MC > 11404 +@Mixin(DummyClass.class) +//#else +//$$ @Mixin(GameRenderer.class) +//#endif +public class MixinGameRenderer { + //#if MC < 11500 + //$$ @Shadow + //$$ @Final + //$$ private Camera mainCamera; + //$$ + //$$ @Inject( + //$$ method = "render(FJ)V", + //$$ at = @At( + //$$ value = "CONSTANT", + //$$ args = "stringValue=hand" + //$$ ) + //$$ ) + //$$ private void postRenderLevel(float tickDelta, long endTime, CallbackInfo ci) { + //$$ RenderEventHandler.getInstance().dispatchPostRenderLevelEvent(new PoseStack()); + //$$ } + //#endif +} diff --git a/src/main/java/top/hendrixshen/magiclib/render/mixin/MixinLevelRenderer.java b/src/main/java/top/hendrixshen/magiclib/render/mixin/MixinLevelRenderer.java new file mode 100644 index 00000000..520f1044 --- /dev/null +++ b/src/main/java/top/hendrixshen/magiclib/render/mixin/MixinLevelRenderer.java @@ -0,0 +1,45 @@ +package top.hendrixshen.magiclib.render.mixin; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import org.joml.Matrix4f; +import org.spongepowered.asm.mixin.Mixin; + +//#if MC > 11404 +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Camera; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.LightTexture; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import top.hendrixshen.magiclib.render.impl.RenderEventHandler; +//#else +//$$ import top.hendrixshen.magiclib.compat.preprocess.api.DummyClass; +//#endif + +@Environment(EnvType.CLIENT) +//#if MC > 11404 +@Mixin(LevelRenderer.class) +//#else +//$$ @Mixin(DummyClass.class) +//#endif +public class MixinLevelRenderer { + //#if MC > 11404 + @Inject( + method = "renderLevel", + at = @At( + value = "INVOKE", + //#if MC > 11903 + target = "Lnet/minecraft/client/renderer/LevelRenderer;renderDebug(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/client/Camera;)V" + //#else + //$$ target = "Lnet/minecraft/client/renderer/LevelRenderer;renderDebug(Lnet/minecraft/client/Camera;)V" + //#endif + ) + ) + private void postRenderLevel(PoseStack poseStack, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f matrix4f, CallbackInfo ci) { + RenderEventHandler.getInstance().dispatchPostRenderLevelEvent(poseStack); + } + //#endif +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 612fe9ca..ec02333b 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -43,7 +43,8 @@ "${mod_id}-carpet.mixins.json", "${mod_id}-i18n.mixins.json", "${mod_id}-malilib.mixins.json", - "${mod_id}-minecraft-compat-api.mixins.json" + "${mod_id}-minecraft-compat-api.mixins.json", + "${mod_id}-render.mixins.json" ], "depends": { "minecraft": "${minecraft_dependency}" diff --git a/src/main/resources/magiclib-render.mixins.json b/src/main/resources/magiclib-render.mixins.json new file mode 100644 index 00000000..d98744d6 --- /dev/null +++ b/src/main/resources/magiclib-render.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "package": "top.hendrixshen.magiclib.render.mixin", + "plugin": "top.hendrixshen.magiclib.render.RenderMixinPlugin", + "minVersion": "0.8", + "compatibilityLevel": "JAVA_8", + "injectors": { + "defaultRequire": 1 + }, + "client": [ + "MixinGameRenderer", + "MixinLevelRenderer" + ] +}