Skip to content

feat(rendering): add GuiRenderHelper#itemWithTransparency, GuiRenderHelper#tessellateBlock - #33

Merged
Gu-ZT merged 4 commits into
Anvil-Dev:dev/26.1from
ZhuRuoLing:dev/26.1
May 17, 2026
Merged

Gu-ZT merged 4 commits into
Anvil-Dev:dev/26.1from
ZhuRuoLing:dev/26.1

Conversation

@ZhuRuoLing

Copy link
Copy Markdown
Contributor

No description provided.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds two new GUI rendering helpers — GuiRenderExtras.itemWithTransparency (alpha-aware item rendering) and GuiRenderExtras.tessellateBlock (block-state rendering via a custom Picture-In-Picture renderer) — together with the mixins, internal interfaces, render state, access transformer entry, a test screen, and a /anvillib_test_client screen client command to exercise them. Drive-by changes also refactor the BloomPostEffect blur passes into a new GaussianBlur class and fix the executeDraw*SetPiplineexecuteDraw*SetPipeline typo across the rendering and font modules.

Changes:

  • New translucent-item rendering path: GuiGraphicsExtractorExtension + GuiGraphicsExtractorMixin + ItemStackRenderStateMixin (with ItemStackRenderStateInternals) + GuiRendererMixin @ModifyArgs on submitBlitFromItemAtlas to swap pipeline/alpha when transparency is enforced.
  • New block-state PIP rendering: BlockStatePipRenderingState + BlockStatePipRenderer registered via RegisterPictureInPictureRenderersEvent, exposed through several GuiRenderExtras.tessellateBlock overloads.
  • Extracted Gaussian blur into GaussianBlur and removed the inline blur path/UBO/parameter fields from BloomPostEffect.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
module.rendering/.../gui/GuiRenderExtras.java New public entry point with itemWithTransparency + many tessellateBlock overloads.
module.rendering/.../gui/state/BlockStatePipRenderingState.java New PIP render state record holding block state, pose and bounds.
module.rendering/.../gui/renderer/BlockStatePipRenderer.java New PIP renderer that tessellates a block (and optional BE) into the PIP texture.
module.rendering/.../gui/renderer/package-info.java Adds non-null defaults for the new renderer package.
module.rendering/.../mixins/GuiGraphicsExtractorMixin.java Implements translucentItem on GuiGraphicsExtractor.
module.rendering/.../mixins/ItemStackRenderStateMixin.java Injects alpha + transparency-enforced flag into ItemStackRenderState.
module.rendering/.../mixins/GuiRendererMixin.java @ModifyArgs pipeline + alpha for item blits; renames typo'd callback methods.
module.rendering/.../internal/ItemStackRenderStateInternals.java Internal accessor bridging mixin interface methods.
module.rendering/.../extension/GuiGraphicsExtractorExtension.java Extension interface exposed via mixin.
module.rendering/.../state/LibGuiElementRenderState.java Renames executeDraw*SetPipline…SetPipeline.
module.rendering/.../AnvilLibRendering.java Registers BlockStatePipRenderer.
module.rendering/.../bloom/BloomPostEffect.java Drops inline blur fields and blurOnce/applyRedirect.
module.rendering/.../blur/GaussianBlur.java New class taking over the blur logic.
module.rendering/resources/anvillib_rendering.mixins.json Registers the two new mixins.
module.rendering/resources/META-INF/accesstransformer.cfg Makes GuiGraphicsExtractor$ScissorStack public.
module.font/.../SdfTextRenderState.java Adopts the renamed executeDrawAfterSetPipeline interface method.
module.test/.../client/AnvilLibTestClient.java Registers /anvillib_test_client screen command.
module.test/.../client/screen/GuiTestScreen.java New screen exercising the new helpers.
module.test/.../client/gui/SdfGraphicsLayer.java Skip SDF rendering when a screen is open.
Comments suppressed due to low confidence (12)

module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/gui/renderer/BlockStatePipRenderer.java:90

  • The color field in BlockStatePipRenderingState is accepted by every tessellateBlock overload (defaulting to -1) but is never read inside BlockStatePipRenderer.renderToTexture. As a result, callers passing a tint color silently get no effect. Either remove the parameter from the state/overloads or apply it (e.g., when calling putBakedQuad/tesselateBlock to tint the geometry).
        blockRenderer.tesselateBlock(
            (x, y, z, quad, instance) -> {
                poseStack.pushPose();
                poseStack.translate(x, y, z);
                poseStack.translate(-0.5f, 0, -0.5f);
                VertexConsumer buffer = this.bufferSource.getBuffer(quad.materialInfo().itemRenderType());
                buffer.putBakedQuad(poseStack.last(), quad, instance);
                poseStack.popPose();
            },
            0,
            0,
            0,
            BlockAndTintGetter.EMPTY,
            BlockPos.ZERO,
            state,
            minecraft.getModelManager().getBlockStateModelSet().get(state),
            seed
        );

module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/gui/state/BlockStatePipRenderingState.java:28

  • SQRT_2 is defined but never used in this class.
    private static final float SQRT_2 = 1.4142135623730950488016887242097f;

module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/blur/GaussianBlur.java:108

  • process calls blurOnce(..., true) twice and blurOnce(..., false) twice, instead of alternating horizontal/vertical passes. A Gaussian separable blur normally interleaves H and V passes. Verify this is intentional — otherwise each axis is blurred independently with redundant work and the cross-axis blur on the previously blurred axis never happens correctly.
        commandEncoder.clearColorTexture(tempTarget.getColorTexture(), 0);
        blurOnce(commandEncoder, input, tempTarget, true);
        commandEncoder.clearColorTexture(inputTarget.getColorTexture(), 0);
        blurOnce(commandEncoder, tempTarget.getColorTexture(), inputTarget, true);

        commandEncoder.clearColorTexture(tempTarget.getColorTexture(), 0);
        blurOnce(commandEncoder, inputTarget.getColorTexture(), tempTarget, false);
        commandEncoder.clearColorTexture(inputTarget.getColorTexture(), 0);
        blurOnce(commandEncoder, tempTarget.getColorTexture(), inputTarget, false);

        return inputTarget.getColorTexture();
    }

module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/blur/GaussianBlur.java:129

  • device.createTextureView(inputTarget) is invoked on every blurOnce call and never closed/released. Texture views are GPU resources; creating one per pass leaks them. Prefer reusing a cached view, or close the view after the render pass.
            blurPass.bindTexture("DiffuseSampler", device.createTextureView(inputTarget), inputSampler);

module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/gui/GuiRenderExtras.java:14

  • The public API name GuiRenderHelper referenced in the PR title doesn't exist — the class introduced is GuiRenderExtras. Either rename the class to match the PR title or update the PR title/description to refer to GuiRenderExtras.
public class GuiRenderExtras {

module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java:84

  • Missing space around * in gameTime* 4.25f — inconsistent with the surrounding style and with the rest of the file.
        poseStack.mulPose(Axis.YP.rotationDegrees(gameTime* 4.25f));

module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java:25

  • graphics.pose().pushMatrix().scale(1) is a no-op (scaling by 1) and the matching popMatrix() at the end of the method then pops what was just pushed. Either drop both, or pass a meaningful scale factor.
        graphics.pose().pushMatrix().scale(1);

module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java:76

  • minecraft.level is dereferenced without a null check, but GuiTestScreen overrides isInGameUi() to return true and can be opened from any context via the /anvillib_test_client screen command. When the screen is open at the title screen or before a world is loaded, minecraft.level is null and this line will throw an NPE every frame.
        float gameTime = (minecraft.level.getGameTime() + minecraft.getDeltaTracker().getGameTimeDeltaPartialTick(true));

module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java:84

  • The Axis.XP.rotationDegrees(30) line at 81 is immediately followed by a YP rotation, then a second YP rotation driven by gameTime. The first two static rotations have no effect that the dynamic third can't subsume, and the XP rotation gets overridden visually after YP — verify this is the intended orientation pipeline. As-is the code reads as if rotations were accidentally duplicated.
        poseStack.mulPose(Axis.XP.rotationDegrees(30));
        poseStack.mulPose(Axis.YP.rotationDegrees(45));

        poseStack.mulPose(Axis.YP.rotationDegrees(gameTime* 4.25f));

module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/AnvilLibTestClient.java:38

  • The subscribed event handler is named on(RegisterClientCommandsEvent) — a single-letter name that matches several other unrelated subscribers on this class. Even for test code this is hard to grep for and confusing; consider a descriptive name like onRegisterClientCommands.
    @SubscribeEvent
    public static void on(RegisterClientCommandsEvent event) {

module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/gui/GuiRenderExtras.java:18

  • itemWithTransparency does not validate alpha. Values outside [0,1] (e.g. negative or >1) propagate into ARGB.color(newAlpha, color) in GuiRendererMixin#modifyAlpha, where they will be cast/packed into an int channel and yield undefined visual results. Consider clamping alpha to [0,1] at the public API boundary.
    public static void itemWithTransparency(GuiGraphicsExtractor guiGraphicsExtractor, ItemStack stack, int x, int y, float alpha) {
        GuiGraphicsExtractorExtension.of(guiGraphicsExtractor).translucentItem(stack, x, y, alpha);
    }

module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/gui/GuiRenderExtras.java:137

  • The two tessellateBlock overloads at lines 67-94 and 51-65 differ only in whether color is provided. The third overload at 109-117 (no ambientOcclusion) and the one at 119-128 produce different defaults (false vs explicit) but the implicit-vs-explicit pattern makes it easy for a caller to accidentally pick the wrong overload (e.g. omitting level/blockPos resolves to a no-AO version). Consider replacing this overload sprawl with a builder or named-arg style helper for clarity.
    public static void tessellateBlock(
        GuiGraphicsExtractor guiGraphicsExtractor,
        BlockState blockState,
        @Nullable Level level,
        @Nullable BlockPos blockPos,
        int x0,
        int y0,
        int width,
        boolean ambientOcclusion,
        PoseStack poseStack3D
    ) {
        tessellateBlock(guiGraphicsExtractor, blockState, level, blockPos, x0, y0, x0 + width, y0 + width, -1, ambientOcclusion, poseStack3D);
    }

    public static void tessellateBlock(
        GuiGraphicsExtractor guiGraphicsExtractor,
        BlockState blockState,
        @Nullable Level level,
        @Nullable BlockPos blockPos,
        int x0,
        int y0,
        boolean ambientOcclusion,
        PoseStack poseStack3D
    ) {
        tessellateBlock(guiGraphicsExtractor, blockState, level, blockPos, x0, y0, x0 + 32, y0 + 32, -1, ambientOcclusion, poseStack3D);
    }

    public static void tessellateBlock(
        GuiGraphicsExtractor guiGraphicsExtractor,
        BlockState blockState,
        int x0,
        int y0,
        PoseStack poseStack3D
    ) {
        tessellateBlock(guiGraphicsExtractor, blockState, null, null, x0, y0, x0 + 32, y0 + 32, -1, false, poseStack3D);
    }

    public static void tessellateBlock(
        GuiGraphicsExtractor guiGraphicsExtractor,
        BlockState blockState,
        int x0,
        int y0,
        boolean ambientOcclusion,
        PoseStack poseStack3D
    ) {
        tessellateBlock(guiGraphicsExtractor, blockState, null, null, x0, y0, x0 + 32, y0 + 32, -1, ambientOcclusion, poseStack3D);
    }

    public static void tessellateBlock(
        GuiGraphicsExtractor guiGraphicsExtractor,
        BlockState blockState,
        int x0,
        int y0
    ) {
        tessellateBlock(guiGraphicsExtractor, blockState, null, null, x0, y0, x0 + 32, y0 + 32, -1, false, BlockStatePipRenderingState.IDENTITY_POSE_3D);
    }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Gu-ZT
Gu-ZT merged commit 64bcf21 into Anvil-Dev:dev/26.1 May 17, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants