Skip to content

Instantly share code, notes, and snippets.

@Ensamisten
Created April 8, 2026 11:12
Show Gist options
  • Select an option

  • Save Ensamisten/81875d939cf29196eb0642afcaf32aa4 to your computer and use it in GitHub Desktop.

Select an option

Save Ensamisten/81875d939cf29196eb0642afcaf32aa4 to your computer and use it in GitHub Desktop.
package io.github.ensamisten.client.screen;
import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.blaze3d.textures.GpuSampler;
import com.mojang.blaze3d.textures.GpuTextureView;
import io.github.ensamisten.Allyship;
import io.github.simonscholz.qrcode.QrCodeConfig;
import io.github.simonscholz.qrcode.QrCodeFactory;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.Identifier;
import java.awt.image.BufferedImage;
import java.io.IOException;
@Environment(EnvType.CLIENT)
public class QrScreen extends Screen {
private static final int QR_SIZE = 150;
private static final int PANEL_PADDING = 16;
private final String clipboard;
private Identifier qrTexture;
// Fields
private DynamicTexture qrDynamicTexture;
private Identifier qrTextureId;
public QrScreen(Component title, String clipboard) {
super(title);
this.clipboard = clipboard;
}
@Override
protected void init() {
// Release old texture if reinitializing
if (qrDynamicTexture != null) {
Minecraft.getInstance().getTextureManager().release(qrTextureId);
qrDynamicTexture = null;
qrTextureId = null;
}
try {
generateQrCodeImage();
} catch (Exception e) {
Allyship.LOGGER.error("Failed to generate QR code", e);
}
}
@Override
public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta) {
super.extractRenderState(graphics, mouseX, mouseY, delta);
if (qrDynamicTexture == null) return;
// Force GPU upload before we try to use the texture view
qrDynamicTexture.upload();
GpuTextureView textureView = qrDynamicTexture.getTextureView();
GpuSampler sampler = qrDynamicTexture.getSampler();
if (textureView == null || sampler == null) return;
int qrX = (this.width - QR_SIZE) / 2;
int qrY = (this.height - QR_SIZE) / 2;
graphics.fill(
qrX - PANEL_PADDING,
qrY - PANEL_PADDING,
qrX + QR_SIZE + PANEL_PADDING,
qrY + QR_SIZE + PANEL_PADDING,
0xCC000000
);
graphics.text(
this.font,
"QR Code",
this.width / 2 - this.font.width("QR Code") / 2,
qrY - PANEL_PADDING - this.font.lineHeight - 4,
0xFFFFFFFF,
true
);
// Use the GpuTextureView overload directly — avoids TextureManager lookup issues
graphics.blit(
textureView,
sampler,
qrX, // x0
qrY, // y0
qrX + QR_SIZE, // x1
qrY + QR_SIZE, // y1
0.0f, // u0
1.0f, // u1
0.0f, // v0
1.0f // v1
);
}
private void generateQrCodeImage() throws IOException {
QrCodeConfig config = new QrCodeConfig.Builder(clipboard)
.qrCodeSize(QR_SIZE)
.build();
BufferedImage bufferedImage =
QrCodeFactory.createQrCodeApi().createQrCodeImage(config);
NativeImage nativeImage = bufferedImageToNative(bufferedImage);
qrDynamicTexture = new DynamicTexture(() -> "Allyship QR Code", nativeImage);
qrTextureId = Identifier.withDefaultNamespace("allyship/qr_" + System.nanoTime());
Minecraft.getInstance().getTextureManager().register(qrTextureId, qrDynamicTexture);
}
private static NativeImage bufferedImageToNative(BufferedImage image) {
NativeImage nativeImage =
new NativeImage(NativeImage.Format.RGBA, image.getWidth(), image.getHeight(), false);
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
int argb = image.getRGB(x, y);
int a = (argb >>> 24) & 0xFF;
int r = (argb >>> 16) & 0xFF;
int g = (argb >>> 8) & 0xFF;
int b = (argb) & 0xFF;
int abgr = (a << 24) | (b << 16) | (g << 8) | r;
nativeImage.setPixel(x, y, abgr);
}
}
return nativeImage;
}
@Override
public boolean isPauseScreen() {
return false;
}
@Override
public void onClose() {
super.onClose();
if (qrTexture != null) {
Minecraft.getInstance()
.getTextureManager()
.release(qrTexture);
qrTexture = null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment