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

Only stitch/export first frame of animation

This commit is contained in:
Eclipse
2025-10-18 11:57:32 +00:00
parent bf07311112
commit 14329fbb13
6 changed files with 70 additions and 24 deletions

View File

@@ -2,31 +2,33 @@ package org.geysermc.rainbow.client;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.item.ClientItem; import net.minecraft.client.renderer.item.ClientItem;
import net.minecraft.client.renderer.texture.SpriteContents;
import net.minecraft.client.resources.model.AtlasManager;
import net.minecraft.client.resources.model.EquipmentAssetManager; import net.minecraft.client.resources.model.EquipmentAssetManager;
import net.minecraft.client.resources.model.EquipmentClientInfo; import net.minecraft.client.resources.model.EquipmentClientInfo;
import net.minecraft.client.resources.model.ModelManager; import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.client.resources.model.ResolvedModel; import net.minecraft.client.resources.model.ResolvedModel;
import net.minecraft.data.AtlasIds;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.world.item.equipment.EquipmentAsset; import net.minecraft.world.item.equipment.EquipmentAsset;
import org.geysermc.rainbow.client.accessor.ResolvedModelAccessor; import org.geysermc.rainbow.client.accessor.ResolvedModelAccessor;
import org.geysermc.rainbow.client.mixin.EntityRenderDispatcherAccessor; import org.geysermc.rainbow.client.mixin.EntityRenderDispatcherAccessor;
import org.geysermc.rainbow.mapping.AssetResolver; import org.geysermc.rainbow.mapping.AssetResolver;
import org.geysermc.rainbow.mapping.texture.TextureResource;
import org.geysermc.rainbow.mixin.SpriteContentsAccessor;
import java.io.IOException;
import java.io.InputStream;
import java.util.Optional; import java.util.Optional;
public class MinecraftAssetResolver implements AssetResolver { public class MinecraftAssetResolver implements AssetResolver {
private final ModelManager modelManager; private final ModelManager modelManager;
private final EquipmentAssetManager equipmentAssetManager; private final EquipmentAssetManager equipmentAssetManager;
private final ResourceManager resourceManager; private final AtlasManager atlasManager;
public MinecraftAssetResolver(Minecraft minecraft) { public MinecraftAssetResolver(Minecraft minecraft) {
modelManager = minecraft.getModelManager(); modelManager = minecraft.getModelManager();
equipmentAssetManager = ((EntityRenderDispatcherAccessor) minecraft.getEntityRenderDispatcher()).getEquipmentAssets(); equipmentAssetManager = ((EntityRenderDispatcherAccessor) minecraft.getEntityRenderDispatcher()).getEquipmentAssets();
resourceManager = minecraft.getResourceManager(); atlasManager = minecraft.getAtlasManager();
} }
@Override @Override
@@ -45,7 +47,8 @@ public class MinecraftAssetResolver implements AssetResolver {
} }
@Override @Override
public InputStream openAsset(ResourceLocation location) throws IOException { public Optional<TextureResource> getBlockTexture(ResourceLocation location) {
return resourceManager.open(location); SpriteContents contents = atlasManager.getAtlasOrThrow(AtlasIds.BLOCKS).getSprite(location).contents();
return Optional.of(new TextureResource(((SpriteContentsAccessor) contents).getOriginalImage(), contents.width(), contents.height()));
} }
} }

View File

@@ -1,7 +1,7 @@
package org.geysermc.rainbow.datagen; package org.geysermc.rainbow.datagen;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing; import com.google.common.hash.Hashing;
import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import net.fabricmc.fabric.api.client.datagen.v1.provider.FabricModelProvider; import net.fabricmc.fabric.api.client.datagen.v1.provider.FabricModelProvider;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
@@ -10,6 +10,7 @@ import net.minecraft.client.data.models.model.ModelInstance;
import net.minecraft.client.renderer.block.model.BlockModel; import net.minecraft.client.renderer.block.model.BlockModel;
import net.minecraft.client.renderer.block.model.ItemModelGenerator; import net.minecraft.client.renderer.block.model.ItemModelGenerator;
import net.minecraft.client.renderer.item.ClientItem; import net.minecraft.client.renderer.item.ClientItem;
import net.minecraft.client.resources.metadata.animation.AnimationMetadataSection;
import net.minecraft.client.resources.model.EquipmentClientInfo; import net.minecraft.client.resources.model.EquipmentClientInfo;
import net.minecraft.client.resources.model.ResolvedModel; import net.minecraft.client.resources.model.ResolvedModel;
import net.minecraft.client.resources.model.UnbakedModel; import net.minecraft.client.resources.model.UnbakedModel;
@@ -28,6 +29,7 @@ import org.geysermc.rainbow.Rainbow;
import org.geysermc.rainbow.RainbowIO; import org.geysermc.rainbow.RainbowIO;
import org.geysermc.rainbow.mapping.AssetResolver; import org.geysermc.rainbow.mapping.AssetResolver;
import org.geysermc.rainbow.mapping.PackSerializer; import org.geysermc.rainbow.mapping.PackSerializer;
import org.geysermc.rainbow.mapping.texture.TextureResource;
import org.geysermc.rainbow.pack.BedrockPack; import org.geysermc.rainbow.pack.BedrockPack;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -196,8 +198,15 @@ public abstract class RainbowModelProvider extends FabricModelProvider {
} }
@Override @Override
public InputStream openAsset(ResourceLocation location) throws IOException { public Optional<TextureResource> getBlockTexture(ResourceLocation location) {
return resourceManager.open(location); return resourceManager.getResource(Rainbow.decorateTextureLocation(location))
.flatMap(resource -> RainbowIO.safeIO(() -> {
Optional<AnimationMetadataSection> animationMetadata = resource.metadata().getSection(AnimationMetadataSection.TYPE);
try (InputStream textureStream = resource.open()) {
NativeImage texture = NativeImage.read(textureStream);
return new TextureResource(texture, animationMetadata.map(animation -> animation.calculateFrameSize(texture.getWidth(), texture.getHeight())));
}
}));
} }
} }
} }

View File

@@ -6,9 +6,8 @@ import net.minecraft.client.resources.model.ResolvedModel;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.equipment.EquipmentAsset; import net.minecraft.world.item.equipment.EquipmentAsset;
import org.geysermc.rainbow.mapping.texture.TextureResource;
import java.io.IOException;
import java.io.InputStream;
import java.util.Optional; import java.util.Optional;
public interface AssetResolver { public interface AssetResolver {
@@ -19,5 +18,5 @@ public interface AssetResolver {
Optional<EquipmentClientInfo> getEquipmentInfo(ResourceKey<EquipmentAsset> key); Optional<EquipmentClientInfo> getEquipmentInfo(ResourceKey<EquipmentAsset> key);
InputStream openAsset(ResourceLocation location) throws IOException; Optional<TextureResource> getBlockTexture(ResourceLocation location);
} }

View File

@@ -1,13 +1,13 @@
package org.geysermc.rainbow.mapping.texture; package org.geysermc.rainbow.mapping.texture;
import com.mojang.blaze3d.platform.NativeImage;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.ProblemReporter; import net.minecraft.util.ProblemReporter;
import org.geysermc.rainbow.Rainbow;
import org.geysermc.rainbow.RainbowIO; import org.geysermc.rainbow.RainbowIO;
import org.geysermc.rainbow.image.NativeImageUtil;
import org.geysermc.rainbow.mapping.AssetResolver; import org.geysermc.rainbow.mapping.AssetResolver;
import java.io.FileNotFoundException; import java.util.Objects;
import java.io.InputStream;
import java.util.Optional; import java.util.Optional;
public class BuiltInTextureHolder extends TextureHolder { public class BuiltInTextureHolder extends TextureHolder {
@@ -21,9 +21,12 @@ public class BuiltInTextureHolder extends TextureHolder {
@Override @Override
public Optional<byte[]> load(AssetResolver assetResolver, ProblemReporter reporter) { public Optional<byte[]> load(AssetResolver assetResolver, ProblemReporter reporter) {
return RainbowIO.safeIO(() -> { return RainbowIO.safeIO(() -> {
try (InputStream texture = assetResolver.openAsset(Rainbow.decorateTextureLocation(source))) { try (TextureResource texture = assetResolver.getBlockTexture(source).orElse(null)) {
return texture.readAllBytes(); Objects.requireNonNull(texture);
} catch (FileNotFoundException | NullPointerException exception) { try (NativeImage firstFrame = texture.getFirstFrame(false)) {
return NativeImageUtil.writeToByteArray(firstFrame);
}
} catch (NullPointerException exception) {
reportMissing(reporter); reportMissing(reporter);
return null; return null;
} }

View File

@@ -6,7 +6,6 @@ import net.minecraft.client.renderer.block.model.TextureSlots;
import net.minecraft.client.renderer.texture.SpriteContents; import net.minecraft.client.renderer.texture.SpriteContents;
import net.minecraft.client.renderer.texture.SpriteLoader; import net.minecraft.client.renderer.texture.SpriteLoader;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.metadata.animation.FrameSize;
import net.minecraft.client.resources.model.Material; import net.minecraft.client.resources.model.Material;
import net.minecraft.data.AtlasIds; import net.minecraft.data.AtlasIds;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
@@ -17,7 +16,6 @@ import org.geysermc.rainbow.mixin.SpriteContentsAccessor;
import org.geysermc.rainbow.mixin.SpriteLoaderAccessor; import org.geysermc.rainbow.mixin.SpriteLoaderAccessor;
import org.geysermc.rainbow.mixin.TextureSlotsAccessor; import org.geysermc.rainbow.mixin.TextureSlotsAccessor;
import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -58,10 +56,12 @@ public record StitchedTextures(Map<String, TextureAtlasSprite> sprites, Supplier
private static Optional<SpriteContents> readSpriteContents(ResourceLocation location, PackContext context) { private static Optional<SpriteContents> readSpriteContents(ResourceLocation location, PackContext context) {
return RainbowIO.safeIO(() -> { return RainbowIO.safeIO(() -> {
try (InputStream textureStream = context.assetResolver().openAsset(Rainbow.decorateTextureLocation(location))) { try (TextureResource texture = context.assetResolver().getBlockTexture(location).orElse(null)) {
NativeImage texture = NativeImage.read(textureStream); if (texture != null) {
return new SpriteContents(location, new FrameSize(texture.getWidth(), texture.getHeight()), texture); return new SpriteContents(location, texture.sizeOfFrame(), texture.getFirstFrame(true));
} }
}
return null;
}); });
} }

View File

@@ -0,0 +1,32 @@
package org.geysermc.rainbow.mapping.texture;
import com.mojang.blaze3d.platform.NativeImage;
import net.minecraft.client.resources.metadata.animation.FrameSize;
import java.util.Optional;
public record TextureResource(NativeImage texture, Optional<FrameSize> frameSize) implements AutoCloseable {
public TextureResource(NativeImage texture, int width, int height) {
this(texture, texture.getWidth() != width || texture.getHeight() != height ? Optional.of(new FrameSize(width, height)) : Optional.empty());
}
public NativeImage getFirstFrame(boolean copy) {
if (frameSize.isEmpty() && !copy) {
return texture;
}
FrameSize size = sizeOfFrame();
NativeImage firstFrame = new NativeImage(size.width(), size.height(), false);
texture.copyRect(firstFrame, 0, 0, 0, 0, size.width(), size.height(), false, false);
return firstFrame;
}
public FrameSize sizeOfFrame() {
return frameSize.orElseGet(() -> new FrameSize(texture.getWidth(), texture.getHeight()));
}
@Override
public void close() {
texture.close();
}
}