From 0f7ec7e7fd3a9ab279bfcbf273b69599f9e2972c Mon Sep 17 00:00:00 2001 From: Fry Date: Mon, 26 Jun 2017 07:58:19 +0400 Subject: [PATCH] Added dependencies and dependency ordering for textures. (#4070) --- .../texture/TextureAtlasSprite.java.patch | 13 +- .../renderer/texture/TextureMap.java.patch | 126 ++++++++++++------ .../client/model/ModelLoader.java | 2 +- src/main/resources/forge.exc | 3 +- .../debug/CustomSpriteTest.java | 44 +++--- 5 files changed, 117 insertions(+), 71 deletions(-) diff --git a/patches/minecraft/net/minecraft/client/renderer/texture/TextureAtlasSprite.java.patch b/patches/minecraft/net/minecraft/client/renderer/texture/TextureAtlasSprite.java.patch index f00d1c6fd8..c74308c789 100644 --- a/patches/minecraft/net/minecraft/client/renderer/texture/TextureAtlasSprite.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/texture/TextureAtlasSprite.java.patch @@ -17,7 +17,7 @@ } public void func_94217_a(TextureAtlasSprite p_94217_1_) -@@ -398,4 +396,30 @@ +@@ -398,4 +396,39 @@ { return "TextureAtlasSprite{name='" + this.field_110984_i + '\'' + ", frameCount=" + this.field_110976_a.size() + ", rotated=" + this.field_130222_e + ", x=" + this.field_110975_c + ", y=" + this.field_110974_d + ", height=" + this.field_130224_d + ", width=" + this.field_130223_c + ", u0=" + this.field_110979_l + ", u1=" + this.field_110980_m + ", v0=" + this.field_110977_n + ", v1=" + this.field_110978_o + '}'; } @@ -40,11 +40,20 @@ + * Returning false from this function will prevent this icon from being stitched onto the master texture. + * @param manager Main resource manager + * @param location File resource location ++ * @param textureGetter accessor for dependencies. All of them will be loaded before this one + * @return False to prevent this Icon from being stitched + */ -+ public boolean load(net.minecraft.client.resources.IResourceManager manager, net.minecraft.util.ResourceLocation location) ++ public boolean load(net.minecraft.client.resources.IResourceManager manager, net.minecraft.util.ResourceLocation location, java.util.function.Function textureGetter) + { + return true; + } ++ ++ /** ++ * @return all textures that should be loaded before this texture. ++ */ ++ public java.util.Collection getDependencies() { ++ return com.google.common.collect.ImmutableList.of(); ++ } ++ + /*===================================== FORGE END ======================================*/ } diff --git a/patches/minecraft/net/minecraft/client/renderer/texture/TextureMap.java.patch b/patches/minecraft/net/minecraft/client/renderer/texture/TextureMap.java.patch index 3b0eade84a..c21d8c94ef 100644 --- a/patches/minecraft/net/minecraft/client/renderer/texture/TextureMap.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/texture/TextureMap.java.patch @@ -1,22 +1,6 @@ --- ../src-base/minecraft/net/minecraft/client/renderer/texture/TextureMap.java +++ ../src-work/minecraft/net/minecraft/client/renderer/texture/TextureMap.java -@@ -27,6 +27,7 @@ - @SideOnly(Side.CLIENT) - public class TextureMap extends AbstractTexture implements ITickableTextureObject - { -+ private static final boolean ENABLE_SKIP = Boolean.parseBoolean(System.getProperty("fml.skipFirstTextureLoad", "true")); - private static final Logger field_147635_d = LogManager.getLogger(); - public static final ResourceLocation field_174945_f = new ResourceLocation("missingno"); - public static final ResourceLocation field_110575_b = new ResourceLocation("textures/atlas/blocks.png"); -@@ -37,6 +38,7 @@ - private final ITextureMapPopulator field_174946_m; - private int field_147636_j; - private final TextureAtlasSprite field_94249_f; -+ private boolean skipFirst = false; - - public TextureMap(String p_i46099_1_) - { -@@ -45,12 +47,23 @@ +@@ -45,12 +45,23 @@ public TextureMap(String p_i46100_1_, @Nullable ITextureMapPopulator p_i46100_2_) { @@ -28,7 +12,7 @@ + this(basePathIn, null, skipFirst); + } + -+ public TextureMap(String p_i46100_1_, ITextureMapPopulator p_i46100_2_, boolean skipFirst) ++ public TextureMap(String p_i46100_1_, @Nullable ITextureMapPopulator p_i46100_2_, boolean skipFirst) + { this.field_94258_i = Lists.newArrayList(); this.field_110574_e = Maps.newHashMap(); @@ -40,7 +24,7 @@ } private void func_110569_e() -@@ -74,6 +87,7 @@ +@@ -74,6 +85,7 @@ public void func_174943_a(IResourceManager p_174943_1_, ITextureMapPopulator p_174943_2_) { this.field_110574_e.clear(); @@ -48,50 +32,88 @@ p_174943_2_.func_177059_a(this); this.func_110569_e(); this.func_147631_c(); -@@ -88,13 +102,25 @@ +@@ -88,13 +100,58 @@ this.field_94258_i.clear(); int j = Integer.MAX_VALUE; int k = 1 << this.field_147636_j; + net.minecraftforge.fml.common.FMLLog.log.info("Max texture size: {}", i); + net.minecraftforge.fml.common.ProgressManager.ProgressBar bar = net.minecraftforge.fml.common.ProgressManager.push("Texture stitching", skipFirst ? 0 : this.field_110574_e.size()); ++ loadedSprites.clear(); -+ if(!skipFirst) - for (Entry entry : this.field_110574_e.entrySet()) +- for (Entry entry : this.field_110574_e.entrySet()) ++ if (!skipFirst) { - TextureAtlasSprite textureatlassprite = entry.getValue(); - ResourceLocation resourcelocation = this.func_184396_a(textureatlassprite); -+ bar.step(resourcelocation.toString()); - IResource iresource = null; +- TextureAtlasSprite textureatlassprite = entry.getValue(); +- ResourceLocation resourcelocation = this.func_184396_a(textureatlassprite); +- IResource iresource = null; ++ for (Entry entry : Maps.newHashMap(this.field_110574_e).entrySet()) ++ { ++ final ResourceLocation location = new ResourceLocation(entry.getKey()); ++ bar.step(location.toString()); ++ j = loadTexture(stitcher, p_110571_1_, location, entry.getValue(), bar, j, k); ++ } ++ } ++ finishLoading(stitcher, bar, j, k); ++ } ++ private int loadTexture(Stitcher stitcher, IResourceManager p_110571_1_, ResourceLocation location, TextureAtlasSprite textureatlassprite, net.minecraftforge.fml.common.ProgressManager.ProgressBar bar, int j, int k) ++ { ++ if (loadedSprites.contains(location)) { ++ return j; ++ } ++ ResourceLocation resourcelocation = this.func_184396_a(textureatlassprite); ++ IResource iresource = null; ++ ++ for(ResourceLocation loading : loadingSprites) ++ { ++ if(location.equals(loading)) ++ { ++ final String error = "circular model dependencies, stack: [" + com.google.common.base.Joiner.on(", ").join(loadingSprites) + "]"; ++ net.minecraftforge.fml.client.FMLClientHandler.instance().trackBrokenTexture(resourcelocation, error); ++ } ++ } ++ loadingSprites.addLast(location); ++ try ++ { ++ for (ResourceLocation dependency : textureatlassprite.getDependencies()) ++ { ++ if (!field_110574_e.containsKey(dependency.toString())) ++ { ++ func_174942_a(dependency); ++ } ++ TextureAtlasSprite depSprite = field_110574_e.get(dependency.toString()); ++ j = loadTexture(stitcher, p_110571_1_, dependency, depSprite, bar, j, k); ++ } + if (textureatlassprite.hasCustomLoader(p_110571_1_, resourcelocation)) + { -+ if (textureatlassprite.load(p_110571_1_, resourcelocation)) ++ if (textureatlassprite.load(p_110571_1_, resourcelocation, l -> field_110574_e.get(l.toString()))) + { -+ continue; ++ return j; + } + } + else try { PngSizeInfo pngsizeinfo = PngSizeInfo.func_188532_a(p_110571_1_.func_110536_a(resourcelocation)); -@@ -104,12 +130,14 @@ +@@ -104,13 +161,13 @@ } catch (RuntimeException runtimeexception) { - field_147635_d.error("Unable to parse metadata from {}", resourcelocation, runtimeexception); -+ //LOGGER.error("Unable to parse metadata from {}", resourcelocation, runtimeexception); +- continue; + net.minecraftforge.fml.client.FMLClientHandler.instance().trackBrokenTexture(resourcelocation, runtimeexception.getMessage()); - continue; ++ return j; } catch (IOException ioexception) { - field_147635_d.error("Using missing texture, unable to load {}", resourcelocation, ioexception); -+ //LOGGER.error("Using missing texture, unable to load {}", resourcelocation, ioexception); +- continue; + net.minecraftforge.fml.client.FMLClientHandler.instance().trackMissingTexture(resourcelocation); - continue; ++ return j; } finally -@@ -122,17 +150,18 @@ + { +@@ -122,16 +179,28 @@ if (j1 < k) { @@ -101,19 +123,28 @@ + field_147635_d.warn("Texture {} with size {}x{} will have visual artifacts at mip level {}, it can only support level {}. Please report to the mod author that the texture should be some multiple of 16x16.", resourcelocation, Integer.valueOf(textureatlassprite.func_94211_a()), Integer.valueOf(textureatlassprite.func_94216_b()), Integer.valueOf(MathHelper.func_151239_c(k)), Integer.valueOf(MathHelper.func_151239_c(j1))); } ++ if (func_184397_a(p_110571_1_, textureatlassprite)) stitcher.func_110934_a(textureatlassprite); ++ return j; } ++ finally ++ { ++ loadingSprites.removeLast(); ++ loadedSprites.add(location); ++ } ++ } ++ private void finishLoading(Stitcher stitcher, net.minecraftforge.fml.common.ProgressManager.ProgressBar bar, int j, int k) ++ { + net.minecraftforge.fml.common.ProgressManager.pop(bar); int l = Math.min(j, k); int i1 = MathHelper.func_151239_c(l); -- if (i1 < this.field_147636_j) -+ if (false && i1 < this.field_147636_j) // FORGE: do not lower the mipmap level ++ if (false) // FORGE: do not lower the mipmap level + if (i1 < this.field_147636_j) { field_147635_d.warn("{}: dropping miplevel from {} to {}, because of minimum power of two: {}", this.field_94254_c, Integer.valueOf(this.field_147636_j), Integer.valueOf(i1), Integer.valueOf(l)); - this.field_147636_j = i1; -@@ -140,9 +169,12 @@ +@@ -140,9 +209,12 @@ this.field_94249_f.func_147963_d(this.field_147636_j); stitcher.func_110934_a(this.field_94249_f); @@ -126,7 +157,7 @@ stitcher.func_94305_f(); } catch (StitcherException stitcherexception) -@@ -151,11 +183,16 @@ +@@ -151,12 +223,16 @@ } field_147635_d.info("Created: {}x{} {}-atlas", Integer.valueOf(stitcher.func_110935_a()), Integer.valueOf(stitcher.func_110936_b()), this.field_94254_c); @@ -139,11 +170,12 @@ + for (TextureAtlasSprite textureatlassprite1 : stitcher.func_94309_g()) { +- if (textureatlassprite1 == this.field_94249_f || this.func_184397_a(p_110571_1_, textureatlassprite1)) + bar.step(textureatlassprite1.func_94215_i()); - if (textureatlassprite1 == this.field_94249_f || this.func_184397_a(p_110571_1_, textureatlassprite1)) { String s = textureatlassprite1.func_94215_i(); -@@ -186,6 +223,13 @@ + map.remove(s); +@@ -186,6 +262,13 @@ { textureatlassprite2.func_94217_a(this.field_94249_f); } @@ -157,7 +189,7 @@ } private boolean func_184397_a(IResourceManager p_184397_1_, final TextureAtlasSprite p_184397_2_) -@@ -195,7 +239,7 @@ +@@ -195,7 +278,7 @@ label62: { boolean flag; @@ -166,7 +198,7 @@ try { iresource = p_184397_1_.func_110536_a(resourcelocation); -@@ -292,7 +336,7 @@ +@@ -292,7 +375,7 @@ } else { @@ -175,7 +207,7 @@ if (textureatlassprite == null) { -@@ -318,4 +362,48 @@ +@@ -318,4 +401,54 @@ { return this.field_94249_f; } @@ -183,6 +215,12 @@ + //=================================================================================================== + // Forge Start + //=================================================================================================== ++ ++ private static final boolean ENABLE_SKIP = Boolean.parseBoolean(System.getProperty("fml.skipFirstTextureLoad", "true")); ++ private boolean skipFirst = false; ++ private final java.util.Deque loadingSprites = new java.util.ArrayDeque<>(); ++ private final java.util.Set loadedSprites = new java.util.HashSet<>(); ++ + /** + * Grabs the registered entry for the specified name, returning null if there was not a entry. + * Opposed to registerIcon, this will not instantiate the entry, useful to test if a mapping exists. diff --git a/src/main/java/net/minecraftforge/client/model/ModelLoader.java b/src/main/java/net/minecraftforge/client/model/ModelLoader.java index 2d7e2ef17c..e4dc0681c4 100644 --- a/src/main/java/net/minecraftforge/client/model/ModelLoader.java +++ b/src/main/java/net/minecraftforge/client/model/ModelLoader.java @@ -949,7 +949,7 @@ public final class ModelLoader extends ModelBakery } @Override - public boolean load(IResourceManager manager, ResourceLocation location) + public boolean load(IResourceManager manager, ResourceLocation location, Function textureGetter) { BufferedImage image = new BufferedImage(this.getIconWidth(), this.getIconHeight(), BufferedImage.TYPE_INT_ARGB); Graphics2D graphics = image.createGraphics(); diff --git a/src/main/resources/forge.exc b/src/main/resources/forge.exc index b5084aa9d3..6220bc7a8e 100644 --- a/src/main/resources/forge.exc +++ b/src/main/resources/forge.exc @@ -50,6 +50,7 @@ net/minecraft/item/ItemStack.(Lnet/minecraft/item/Item;IILnet/minecraft/nb net/minecraft/block/BlockRedstoneWire.canConnectTo(Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/util/EnumFacing;Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/math/BlockPos;)Z=|p_176343_0_,p_176343_1_,world,pos net/minecraft/client/renderer/block/model/BakedQuad.([IILnet/minecraft/util/EnumFacing;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;ZLnet/minecraft/client/renderer/vertex/VertexFormat;)V=|p_i46574_1_,p_i46574_2_,p_i46574_3_,p_i46574_4_,applyDiffuseLighting,format net/minecraft/client/renderer/texture/TextureMap.(Ljava/lang/String;Lnet/minecraft/client/renderer/texture/ITextureMapPopulator;Z)V=|p_i46100_1_,p_i46100_2_,skipFirst +net/minecraft/client/renderer/texture/TextureMap.loadTexture(Lnet/minecraft/client/renderer/texture/Stitcher;Lnet/minecraft/client/resources/IResourceManager;Lnet/minecraft/util/ResourceLocation;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;Lnet/minecraftforge/fml/common/ProgressManager$ProgressBar;II)I=|stitcher,p_110571_1_,location,textureatlassprite,bar,j,k net/minecraft/world/storage/loot/LootPool.([Lnet/minecraft/world/storage/loot/LootEntry;[Lnet/minecraft/world/storage/loot/conditions/LootCondition;Lnet/minecraft/world/storage/loot/RandomValueRange;Lnet/minecraft/world/storage/loot/RandomValueRange;Ljava/lang/String;)V=|p_i46643_1_,p_i46643_2_,p_i46643_3_,p_i46643_4_ net/minecraft/world/storage/loot/LootEntry.(II[Lnet/minecraft/world/storage/loot/conditions/LootCondition;Ljava/lang/String;)V=|p_i46642_1_,p_i46642_2_,p_i46642_3_,entryName @@ -59,4 +60,4 @@ net/minecraft/world/storage/loot/LootEntryEmpty.(II[Lnet/minecraft/world/s net/minecraft/world/chunk/BlockStateContainer.setBits(IZ)V=|p_186012_1_,forceBits net/minecraft/village/Village.getPlayerReputation(Ljava/util/UUID;)I=|p_82684_1_ -net/minecraft/village/Village.modifyPlayerReputation(Ljava/util/UUID;I)I=|p_82688_1_,p_82688_2_ \ No newline at end of file +net/minecraft/village/Village.modifyPlayerReputation(Ljava/util/UUID;I)I=|p_82688_1_,p_82688_2_ diff --git a/src/test/java/net/minecraftforge/debug/CustomSpriteTest.java b/src/test/java/net/minecraftforge/debug/CustomSpriteTest.java index 621e588539..c6fcc3f799 100644 --- a/src/test/java/net/minecraftforge/debug/CustomSpriteTest.java +++ b/src/test/java/net/minecraftforge/debug/CustomSpriteTest.java @@ -1,11 +1,11 @@ package net.minecraftforge.debug; +import com.google.common.collect.ImmutableList; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureMap; -import net.minecraft.client.resources.IResource; import net.minecraft.client.resources.IResourceManager; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.util.ResourceLocation; @@ -18,9 +18,8 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.apache.logging.log4j.Logger; import javax.annotation.Nonnull; -import javax.imageio.ImageIO; -import java.awt.image.BufferedImage; -import java.io.IOException; +import java.util.Collection; +import java.util.function.Function; /** * Test for {@link TextureStitchEvent.Pre}. @@ -37,7 +36,7 @@ public class CustomSpriteTest public static class Registration { @SubscribeEvent - public static void registrBlocks(RegistryEvent.Register event) + public static void registerBlocks(RegistryEvent.Register event) { event.getRegistry().register(new Block(Material.WOOD).setRegistryName(MOD_ID, "custom_sprite_block").setCreativeTab(CreativeTabs.MISC)); } @@ -53,8 +52,8 @@ public class CustomSpriteTest @SubscribeEvent public void textureStitch(TextureStitchEvent.Pre event) { - DelegateSprite bottom = DelegateSprite.make("bottom", new ResourceLocation("textures/blocks/diamond_block.png")); - DelegateSprite top = DelegateSprite.make("top", new ResourceLocation("textures/blocks/tnt_side.png")); + DelegateSprite bottom = DelegateSprite.make("bottom", new ResourceLocation("blocks/diamond_block")); + DelegateSprite top = DelegateSprite.make("top", new ResourceLocation("blocks/tnt_side")); TextureMap textureMap = event.getMap(); textureMap.setTextureEntry(bottom); @@ -83,24 +82,23 @@ public class CustomSpriteTest } @Override - public boolean load(@Nonnull IResourceManager manager, @Nonnull ResourceLocation location) + public Collection getDependencies() { - BufferedImage image; - try - { - IResource resource = manager.getResource(delegate); - image = ImageIO.read(resource.getInputStream()); + return ImmutableList.of(delegate); + } + + @Override + public boolean load(@Nonnull IResourceManager manager, @Nonnull ResourceLocation location, @Nonnull Function textureGetter) + { + final TextureAtlasSprite sprite = textureGetter.apply(delegate); + width = sprite.getIconWidth(); + height = sprite.getIconHeight(); + final int[][] oldPixels = sprite.getFrameTextureData(0); + final int[][] pixels = new int[Minecraft.getMinecraft().gameSettings.mipmapLevels + 1][]; + pixels[0] = new int[width * height]; + for (int p = 0; p < width * height; p++) { + pixels[0][p] = oldPixels[0][p] >> 8; } - catch (IOException ioe) - { - logger.error("Could not find resource", ioe); - return true; - } - this.width = image.getWidth(); - this.height = image.getHeight(); - int[][] pixels = new int[Minecraft.getMinecraft().gameSettings.mipmapLevels + 1][]; - pixels[0] = new int[image.getWidth() * image.getHeight()]; - image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels[0], 0, image.getWidth()); this.clearFramesTextureData(); this.framesTextureData.add(pixels); return false;