feat(rendering): add GuiRenderHelper#itemWithTransparency, GuiRenderHelper#tessellateBlock - #33
Conversation
There was a problem hiding this comment.
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*SetPipline → executeDraw*SetPipeline typo across the rendering and font modules.
Changes:
- New translucent-item rendering path:
GuiGraphicsExtractorExtension+GuiGraphicsExtractorMixin+ItemStackRenderStateMixin(withItemStackRenderStateInternals) +GuiRendererMixin@ModifyArgs onsubmitBlitFromItemAtlasto swap pipeline/alpha when transparency is enforced. - New block-state PIP rendering:
BlockStatePipRenderingState+BlockStatePipRendererregistered viaRegisterPictureInPictureRenderersEvent, exposed through severalGuiRenderExtras.tessellateBlockoverloads. - Extracted Gaussian blur into
GaussianBlurand removed the inline blur path/UBO/parameter fields fromBloomPostEffect.
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
colorfield inBlockStatePipRenderingStateis accepted by everytessellateBlockoverload (defaulting to-1) but is never read insideBlockStatePipRenderer.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 callingputBakedQuad/tesselateBlockto 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_2is 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
processcallsblurOnce(..., true)twice andblurOnce(..., 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 everyblurOncecall 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
GuiRenderHelperreferenced in the PR title doesn't exist — the class introduced isGuiRenderExtras. Either rename the class to match the PR title or update the PR title/description to refer toGuiRenderExtras.
public class GuiRenderExtras {
module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java:84
- Missing space around
*ingameTime* 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 matchingpopMatrix()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.levelis dereferenced without a null check, butGuiTestScreenoverridesisInGameUi()to returntrueand can be opened from any context via the/anvillib_test_client screencommand. When the screen is open at the title screen or before a world is loaded,minecraft.levelisnulland 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 aYProtation, then a secondYProtation driven bygameTime. 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 likeonRegisterClientCommands.
@SubscribeEvent
public static void on(RegisterClientCommandsEvent event) {
module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/gui/GuiRenderExtras.java:18
itemWithTransparencydoes not validatealpha. Values outside [0,1] (e.g. negative or >1) propagate intoARGB.color(newAlpha, color)inGuiRendererMixin#modifyAlpha, where they will be cast/packed into an int channel and yield undefined visual results. Consider clampingalphato [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
tessellateBlockoverloads at lines 67-94 and 51-65 differ only in whethercoloris provided. The third overload at 109-117 (noambientOcclusion) and the one at 119-128 produce different defaults (falsevs explicit) but the implicit-vs-explicit pattern makes it easy for a caller to accidentally pick the wrong overload (e.g. omittinglevel/blockPosresolves 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.
No description provided.