mirror of
https://github.com/GeyserMC/Rainbow.git
synced 2025-12-19 14:59:16 +00:00
Work on re-introducing 3D icon generation
This commit is contained in:
@@ -14,13 +14,10 @@ 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.rainbow.CodecUtil;
|
||||
import org.geysermc.rainbow.mapping.geometry.GeometryRenderer;
|
||||
import org.geysermc.rainbow.client.mixin.PictureInPictureRendererAccessor;
|
||||
import org.joml.Matrix3x2fStack;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Objects;
|
||||
|
||||
// TODO maybe just use this even for normal 2D items, not sure, could be useful for composite models and stuff
|
||||
@@ -29,7 +26,7 @@ public class MinecraftGeometryRenderer implements GeometryRenderer {
|
||||
public static final MinecraftGeometryRenderer INSTANCE = new MinecraftGeometryRenderer();
|
||||
|
||||
@Override
|
||||
public boolean render(ItemStack stack, Path path) {
|
||||
public NativeImage render(ItemStack stack) {
|
||||
TrackingItemStackRenderState itemRenderState = new TrackingItemStackRenderState();
|
||||
Minecraft.getInstance().getItemModelResolver().updateForTopItem(itemRenderState, stack, ItemDisplayContext.GUI, null, null, 0);
|
||||
itemRenderState.setOversizedInGui(true);
|
||||
@@ -43,13 +40,12 @@ public class MinecraftGeometryRenderer implements GeometryRenderer {
|
||||
//noinspection DataFlowIssue
|
||||
((PictureInPictureCopyRenderer) itemRenderer).rainbow$allowTextureCopy();
|
||||
itemRenderer.prepare(oversizedRenderState, new GuiRenderState(), 4);
|
||||
writeAsPNG(path, ((PictureInPictureRendererAccessor) itemRenderer).getTexture());
|
||||
return writeToImage(((PictureInPictureRendererAccessor) itemRenderer).getTexture());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// Simplified TextureUtil#writeAsPNG with some modifications to just write to a NativeImage, flip the image and just generate it at full size
|
||||
private static NativeImage writeToImage(GpuTexture texture) {
|
||||
RenderSystem.assertOnRenderThread();
|
||||
int width = texture.getWidth(0);
|
||||
int height = texture.getHeight(0);
|
||||
@@ -58,25 +54,21 @@ public class MinecraftGeometryRenderer implements GeometryRenderer {
|
||||
GpuBuffer buffer = RenderSystem.getDevice().createBuffer(() -> "Texture output buffer", GpuBuffer.USAGE_COPY_DST | GpuBuffer.USAGE_MAP_READ, bufferSize);
|
||||
CommandEncoder commandEncoder = RenderSystem.getDevice().createCommandEncoder();
|
||||
|
||||
NativeImage image = new NativeImage(width, height, false);
|
||||
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);
|
||||
image.setPixelABGR(x, height - y - 1, colour);
|
||||
}
|
||||
}
|
||||
|
||||
CodecUtil.ensureDirectoryExists(path.getParent());
|
||||
nativeImage.writeToFile(path);
|
||||
} catch (IOException var19) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
buffer.close();
|
||||
};
|
||||
commandEncoder.copyTextureToBuffer(texture, buffer, 0, writer, 0);
|
||||
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ public class BedrockItemMapper {
|
||||
bedrockIdentifier = itemModelLocation;
|
||||
}
|
||||
|
||||
BedrockGeometryContext geometry = BedrockGeometryContext.create(bedrockIdentifier, itemModel, context.packContext);
|
||||
BedrockGeometryContext geometry = BedrockGeometryContext.create(bedrockIdentifier, context.stack, itemModel, context.packContext);
|
||||
if (context.packContext.reportSuccesses()) {
|
||||
// Not a problem, but just report to get the model printed in the report file
|
||||
context.report("creating mapping for block model " + itemModelLocation);
|
||||
|
||||
@@ -4,5 +4,7 @@ import org.geysermc.rainbow.mapping.geometry.GeometryRenderer;
|
||||
import org.geysermc.rainbow.definition.GeyserMappings;
|
||||
import org.geysermc.rainbow.pack.PackPaths;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public record PackContext(GeyserMappings mappings, PackPaths paths, BedrockItemConsumer itemConsumer, AssetResolver assetResolver,
|
||||
GeometryRenderer geometryRenderer, boolean reportSuccesses) {}
|
||||
Optional<GeometryRenderer> geometryRenderer, boolean reportSuccesses) {}
|
||||
|
||||
@@ -5,6 +5,7 @@ import net.minecraft.client.renderer.block.model.TextureSlots;
|
||||
import net.minecraft.client.resources.model.Material;
|
||||
import net.minecraft.client.resources.model.ResolvedModel;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.geysermc.rainbow.Rainbow;
|
||||
import org.geysermc.rainbow.mapping.PackContext;
|
||||
import org.geysermc.rainbow.mapping.animation.AnimationMapper;
|
||||
@@ -23,7 +24,7 @@ public record BedrockGeometryContext(Optional<Supplier<StitchedGeometry>> geomet
|
||||
.map(ResourceLocation::withDefaultNamespace)
|
||||
.toList();
|
||||
|
||||
public static BedrockGeometryContext create(ResourceLocation bedrockIdentifier, ResolvedModel model, PackContext context) {
|
||||
public static BedrockGeometryContext create(ResourceLocation bedrockIdentifier, ItemStack stackToRender, ResolvedModel model, PackContext context) {
|
||||
ResolvedModel parentModel = model.parent();
|
||||
// debugName() returns the resource location of the model as a string
|
||||
boolean handheld = parentModel != null && HANDHELD_MODELS.contains(ResourceLocation.parse(parentModel.debugName()));
|
||||
@@ -52,7 +53,7 @@ public record BedrockGeometryContext(Optional<Supplier<StitchedGeometry>> geomet
|
||||
}));
|
||||
|
||||
animation = Optional.of(AnimationMapper.mapAnimation(safeIdentifier, "bone", model.getTopTransforms()));
|
||||
icon = new TextureHolder(modelLocation); // TODO
|
||||
icon = new TextureHolder(modelLocation, context.geometryRenderer().map(renderer -> () -> renderer.render(stackToRender)));
|
||||
}
|
||||
|
||||
return new BedrockGeometryContext(geometry, animation, icon, handheld);
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package org.geysermc.rainbow.mapping.geometry;
|
||||
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public interface GeometryRenderer {
|
||||
|
||||
boolean render(ItemStack stack, Path path);
|
||||
NativeImage render(ItemStack stack);
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package org.geysermc.rainbow.mapping.geometry;
|
||||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class NoopGeometryRenderer implements GeometryRenderer {
|
||||
public static final NoopGeometryRenderer INSTANCE = new NoopGeometryRenderer();
|
||||
|
||||
@Override
|
||||
public boolean render(ItemStack stack, Path path) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -20,19 +20,21 @@ public record BedrockItem(ResourceLocation identifier, String textureName, Bedro
|
||||
|
||||
public CompletableFuture<?> save(PackSerializer serializer, Path attachableDirectory, Path geometryDirectory, Path animationDirectory,
|
||||
Function<TextureHolder, CompletableFuture<?>> textureSaver) {
|
||||
return CompletableFuture.supplyAsync(() -> geometryContext.geometry().map(Supplier::get))
|
||||
return CompletableFuture.allOf(
|
||||
textureSaver.apply(geometryContext.icon()),
|
||||
CompletableFuture.supplyAsync(() -> geometryContext.geometry().map(Supplier::get))
|
||||
.thenCompose(stitchedGeometry -> {
|
||||
List<TextureHolder> attachableTextures = new ArrayList<>();
|
||||
Optional<BedrockAttachable> createdAttachable = attachableCreator.create(identifier, stitchedGeometry, attachableTextures::add);
|
||||
return CompletableFuture.allOf(
|
||||
textureSaver.apply(geometryContext.icon()),
|
||||
createdAttachable.map(attachable -> attachable.save(serializer, attachableDirectory)).orElse(noop()),
|
||||
CompletableFuture.allOf(attachableTextures.stream().map(textureSaver).toArray(CompletableFuture[]::new)),
|
||||
stitchedGeometry.map(BedrockGeometryContext.StitchedGeometry::geometry).map(geometry -> geometry.save(serializer, geometryDirectory)).orElse(noop()),
|
||||
stitchedGeometry.map(BedrockGeometryContext.StitchedGeometry::stitchedTextures).map(textureSaver).orElse(noop()),
|
||||
geometryContext.animation().map(context -> context.animation().save(serializer, animationDirectory, Rainbow.fileSafeResourceLocation(identifier))).orElse(noop())
|
||||
);
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private static <T> CompletableFuture<T> noop() {
|
||||
|
||||
@@ -19,7 +19,6 @@ import org.geysermc.rainbow.mapping.BedrockItemMapper;
|
||||
import org.geysermc.rainbow.mapping.PackContext;
|
||||
import org.geysermc.rainbow.mapping.PackSerializer;
|
||||
import org.geysermc.rainbow.mapping.geometry.GeometryRenderer;
|
||||
import org.geysermc.rainbow.mapping.geometry.NoopGeometryRenderer;
|
||||
import org.geysermc.rainbow.definition.GeyserMappings;
|
||||
import org.geysermc.rainbow.mapping.geometry.TextureHolder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -36,6 +35,7 @@ import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class BedrockPack {
|
||||
@@ -53,7 +53,7 @@ public class BedrockPack {
|
||||
private final ProblemReporter.Collector reporter;
|
||||
|
||||
public BedrockPack(String name, PackManifest manifest, PackPaths paths, PackSerializer serializer, AssetResolver assetResolver,
|
||||
GeometryRenderer geometryRenderer, ProblemReporter.Collector reporter,
|
||||
Optional<GeometryRenderer> geometryRenderer, ProblemReporter.Collector reporter,
|
||||
boolean reportSuccesses) {
|
||||
this.name = name;
|
||||
this.manifest = manifest;
|
||||
@@ -206,7 +206,7 @@ public class BedrockPack {
|
||||
private UnaryOperator<Path> manifestPath = resolve(MANIFEST_FILE);
|
||||
private UnaryOperator<Path> itemAtlasPath = resolve(ITEM_ATLAS_FILE);
|
||||
private Path packZipFile = null;
|
||||
private GeometryRenderer geometryRenderer = NoopGeometryRenderer.INSTANCE;
|
||||
private GeometryRenderer geometryRenderer = null;
|
||||
private ProblemReporter.Collector reporter;
|
||||
private boolean reportSuccesses = false;
|
||||
|
||||
@@ -294,7 +294,7 @@ public class BedrockPack {
|
||||
PackPaths paths = new PackPaths(mappingsPath, packRootPath, attachablesPath.apply(packRootPath),
|
||||
geometryPath.apply(packRootPath), animationPath.apply(packRootPath), manifestPath.apply(packRootPath),
|
||||
itemAtlasPath.apply(packRootPath), Optional.ofNullable(packZipFile));
|
||||
return new BedrockPack(name, manifest, paths, packSerializer, assetResolver, geometryRenderer, reporter, reportSuccesses);
|
||||
return new BedrockPack(name, manifest, paths, packSerializer, assetResolver, Optional.ofNullable(geometryRenderer), reporter, reportSuccesses);
|
||||
}
|
||||
|
||||
private static UnaryOperator<Path> resolve(Path child) {
|
||||
|
||||
Reference in New Issue
Block a user