1
0
mirror of https://github.com/GeyserMC/Rainbow.git synced 2025-12-19 14:59:16 +00:00

Create geometry renderer

This commit is contained in:
Eclipse
2025-07-06 14:39:10 +00:00
parent c04493c24b
commit 3ddf8eb400
6 changed files with 147 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
package org.geysermc.packgenerator.mapping.geometry;
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.GpuTexture;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.navigation.ScreenRectangle;
import net.minecraft.client.gui.render.pip.OversizedItemRenderer;
import net.minecraft.client.gui.render.state.GuiItemRenderState;
import net.minecraft.client.gui.render.state.GuiRenderState;
import net.minecraft.client.gui.render.state.pip.OversizedItemRenderState;
import net.minecraft.client.renderer.item.TrackingItemStackRenderState;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import org.geysermc.packgenerator.mixin.PictureInPictureRendererAccessor;
import org.geysermc.packgenerator.render.PictureInPictureCopyRenderer;
import org.joml.Matrix3x2fStack;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Objects;
public class GeometryRenderer {
public static void render(ItemStack stack, Path path) {
TrackingItemStackRenderState itemRenderState = new TrackingItemStackRenderState();
Minecraft.getInstance().getItemModelResolver().updateForTopItem(itemRenderState, stack, ItemDisplayContext.GUI, null, null, 0);
itemRenderState.setOversizedInGui(true);
GuiItemRenderState guiItemRenderState = new GuiItemRenderState("geometry_render", new Matrix3x2fStack(16), itemRenderState, 0, 0, null);
ScreenRectangle sizeBounds = guiItemRenderState.oversizedItemBounds();
Objects.requireNonNull(sizeBounds);
OversizedItemRenderState oversizedRenderState = new OversizedItemRenderState(guiItemRenderState, sizeBounds.left(), sizeBounds.top(), sizeBounds.right() + 4, sizeBounds.bottom() + 4);
try (OversizedItemRenderer itemRenderer = new OversizedItemRenderer(Minecraft.getInstance().renderBuffers().bufferSource())) {
//noinspection DataFlowIssue
((PictureInPictureCopyRenderer) itemRenderer).geyser_mappings_generator$allowTextureCopy();
itemRenderer.prepare(oversizedRenderState, new GuiRenderState(), 4);
writeAsPNG(path, ((PictureInPictureRendererAccessor) itemRenderer).getTexture());
}
}
// Simplified TextureUtil#writeAsPNG with some modifications to flip the image and just generate it at full size
private static void writeAsPNG(Path path, GpuTexture texture) {
RenderSystem.assertOnRenderThread();
int width = texture.getWidth(0);
int height = texture.getHeight(0);
int bufferSize = texture.getFormat().pixelSize() * width * height;
GpuBuffer buffer = RenderSystem.getDevice().createBuffer(() -> "Texture output buffer", GpuBuffer.USAGE_COPY_DST | GpuBuffer.USAGE_MAP_READ, bufferSize);
CommandEncoder commandEncoder = RenderSystem.getDevice().createCommandEncoder();
Runnable writer = () -> {
try (GpuBuffer.MappedView mappedView = commandEncoder.mapBuffer(buffer, true, false)) {
try (NativeImage nativeImage = new NativeImage(width, height, false)) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int colour = mappedView.data().getInt((x + y * width) * texture.getFormat().pixelSize());
nativeImage.setPixelABGR(x, height - y - 1, colour);
}
}
nativeImage.writeToFile(path);
} catch (IOException var19) {
// TODO
}
}
buffer.close();
};
commandEncoder.copyTextureToBuffer(texture, buffer, 0, writer, 0);
}
}

View File

@@ -0,0 +1,16 @@
package org.geysermc.packgenerator.mixin;
import net.minecraft.client.gui.render.state.GuiItemRenderState;
import net.minecraft.client.gui.render.state.ScreenArea;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.ModifyConstant;
@Mixin(GuiItemRenderState.class)
public abstract class GuiItemRenderStateMixin implements ScreenArea {
@ModifyConstant(method = "calculateOversizedItemBounds", constant = @Constant(intValue = 16))
public int neverReturnNull(int i) {
return -1;
}
}

View File

@@ -0,0 +1,13 @@
package org.geysermc.packgenerator.mixin;
import com.mojang.blaze3d.textures.GpuTexture;
import net.minecraft.client.gui.render.pip.PictureInPictureRenderer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(PictureInPictureRenderer.class)
public interface PictureInPictureRendererAccessor {
@Accessor
GpuTexture getTexture();
}

View File

@@ -0,0 +1,34 @@
package org.geysermc.packgenerator.mixin;
import com.mojang.blaze3d.textures.GpuTexture;
import net.minecraft.client.gui.render.pip.PictureInPictureRenderer;
import org.geysermc.packgenerator.render.PictureInPictureCopyRenderer;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.ModifyConstant;
@Mixin(PictureInPictureRenderer.class)
public abstract class PictureInPictureRendererMixin implements AutoCloseable, PictureInPictureCopyRenderer {
@Shadow
private @Nullable GpuTexture texture;
@Unique
private boolean allowTextureCopy = false;
@Override
public void geyser_mappings_generator$allowTextureCopy() {
if (texture != null) {
throw new IllegalStateException("texture already created");
}
allowTextureCopy = true;
}
@ModifyConstant(method = "prepareTexturesAndProjection", constant = @Constant(intValue = 12))
public int allowUsageCopySrc(int usage) {
return allowTextureCopy ? usage | GpuTexture.USAGE_COPY_SRC : usage;
}
}

View File

@@ -0,0 +1,6 @@
package org.geysermc.packgenerator.render;
public interface PictureInPictureCopyRenderer {
void geyser_mappings_generator$allowTextureCopy();
}

View File

@@ -9,7 +9,10 @@
"BlockModelWrapperMixin$UnbakedMixin", "BlockModelWrapperMixin$UnbakedMixin",
"ConditionalItemModelAccessor", "ConditionalItemModelAccessor",
"EntityRenderDispatcherAccessor", "EntityRenderDispatcherAccessor",
"GuiItemRenderStateMixin",
"ModelManagerMixin", "ModelManagerMixin",
"PictureInPictureRendererAccessor",
"PictureInPictureRendererMixin",
"SelectItemModelAccessor", "SelectItemModelAccessor",
"SelectItemModelMixin", "SelectItemModelMixin",
"SelectItemModelMixin$UnbakedSwitchMixin", "SelectItemModelMixin$UnbakedSwitchMixin",