package net.minecraft.client.renderer.texture;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import javax.imageio.ImageIO;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.StitcherException;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.resources.IResource;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.data.AnimationMetadataSection;
import net.minecraft.client.resources.data.TextureMetadataSection;
import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory;
import net.minecraft.item.Item;
import net.minecraft.util.IIcon;
import net.minecraft.util.MathHelper;
import net.minecraft.util.ReportedException;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.ForgeHooksClient;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@SideOnly(Side.CLIENT)
public class TextureMap extends AbstractTexture implements ITickableTextureObject, IIconRegister
{
private static final boolean ENABLE_SKIP = Boolean.parseBoolean(System.getProperty("fml.skipFirstTextureLoad", "true"));
private static final Logger logger = LogManager.getLogger();
public static final ResourceLocation locationBlocksTexture = new ResourceLocation("textures/atlas/blocks.png");
public static final ResourceLocation locationItemsTexture = new ResourceLocation("textures/atlas/items.png");
private final List listAnimatedSprites = Lists.newArrayList();
private final Map mapRegisteredSprites = Maps.newHashMap();
private final Map mapUploadedSprites = Maps.newHashMap();
/** 0 = terrain.png, 1 = items.png */
private final int textureType;
private final String basePath;
private int mipmapLevels;
private int anisotropicFiltering = 1;
private final TextureAtlasSprite missingImage = new TextureAtlasSprite("missingno");
private static final String __OBFID = "CL_00001058";
private boolean skipFirst = false;
public TextureMap(int p_i1281_1_, String p_i1281_2_)
{
this(p_i1281_1_, p_i1281_2_, false);
}
public TextureMap(int p_i1281_1_, String p_i1281_2_, boolean skipFirst)
{
this.textureType = p_i1281_1_;
this.basePath = p_i1281_2_;
this.registerIcons();
this.skipFirst = skipFirst && ENABLE_SKIP;
}
private void initMissingImage()
{
int[] aint;
if ((float)this.anisotropicFiltering > 1.0F)
{
boolean flag = true;
boolean flag1 = true;
boolean flag2 = true;
this.missingImage.setIconWidth(32);
this.missingImage.setIconHeight(32);
aint = new int[1024];
System.arraycopy(TextureUtil.missingTextureData, 0, aint, 0, TextureUtil.missingTextureData.length);
TextureUtil.prepareAnisotropicData(aint, 16, 16, 8);
}
else
{
aint = TextureUtil.missingTextureData;
this.missingImage.setIconWidth(16);
this.missingImage.setIconHeight(16);
}
int[][] aint1 = new int[this.mipmapLevels + 1][];
aint1[0] = aint;
this.missingImage.setFramesTextureData(Lists.newArrayList(new int[][][] {aint1}));
}
public void loadTexture(IResourceManager p_110551_1_) throws IOException
{
this.initMissingImage();
this.deleteGlTexture();
this.loadTextureAtlas(p_110551_1_);
}
public void loadTextureAtlas(IResourceManager p_110571_1_)
{
registerIcons(); //Re-gather list of Icons, allows for addition/removal of blocks/items after this map was initially constructed.
int i = Minecraft.getGLMaximumTextureSize();
Stitcher stitcher = new Stitcher(i, i, true, 0, this.mipmapLevels);
this.mapUploadedSprites.clear();
this.listAnimatedSprites.clear();
int j = Integer.MAX_VALUE;
ForgeHooksClient.onTextureStitchedPre(this);
cpw.mods.fml.common.ProgressManager.ProgressBar bar = cpw.mods.fml.common.ProgressManager.push("Texture Loading", skipFirst ? 0 : this.mapRegisteredSprites.size());
Iterator iterator = this.mapRegisteredSprites.entrySet().iterator();
TextureAtlasSprite textureatlassprite;
while (!skipFirst && iterator.hasNext())
{
Entry entry = (Entry)iterator.next();
ResourceLocation resourcelocation = new ResourceLocation((String)entry.getKey());
textureatlassprite = (TextureAtlasSprite)entry.getValue();
ResourceLocation resourcelocation1 = this.completeResourceLocation(resourcelocation, 0);
bar.step(resourcelocation1.getResourcePath());
if (textureatlassprite.hasCustomLoader(p_110571_1_, resourcelocation))
{
if (!textureatlassprite.load(p_110571_1_, resourcelocation))
{
j = Math.min(j, Math.min(textureatlassprite.getIconWidth(), textureatlassprite.getIconHeight()));
stitcher.addSprite(textureatlassprite);
}
continue;
}
try
{
IResource iresource = p_110571_1_.getResource(resourcelocation1);
BufferedImage[] abufferedimage = new BufferedImage[1 + this.mipmapLevels];
abufferedimage[0] = ImageIO.read(iresource.getInputStream());
TextureMetadataSection texturemetadatasection = (TextureMetadataSection)iresource.getMetadata("texture");
if (texturemetadatasection != null)
{
List list = texturemetadatasection.getListMipmaps();
int l;
if (!list.isEmpty())
{
int k = abufferedimage[0].getWidth();
l = abufferedimage[0].getHeight();
if (MathHelper.roundUpToPowerOfTwo(k) != k || MathHelper.roundUpToPowerOfTwo(l) != l)
{
throw new RuntimeException("Unable to load extra miplevels, source-texture is not power of two");
}
}
Iterator iterator3 = list.iterator();
while (iterator3.hasNext())
{
l = ((Integer)iterator3.next()).intValue();
if (l > 0 && l < abufferedimage.length - 1 && abufferedimage[l] == null)
{
ResourceLocation resourcelocation2 = this.completeResourceLocation(resourcelocation, l);
try
{
abufferedimage[l] = ImageIO.read(p_110571_1_.getResource(resourcelocation2).getInputStream());
}
catch (IOException ioexception)
{
logger.error("Unable to load miplevel {} from: {}", new Object[] {Integer.valueOf(l), resourcelocation2, ioexception});
}
}
}
}
AnimationMetadataSection animationmetadatasection = (AnimationMetadataSection)iresource.getMetadata("animation");
textureatlassprite.loadSprite(abufferedimage, animationmetadatasection, (float)this.anisotropicFiltering > 1.0F);
}
catch (RuntimeException runtimeexception)
{
//logger.error("Unable to parse metadata from " + resourcelocation1, runtimeexception);
cpw.mods.fml.client.FMLClientHandler.instance().trackBrokenTexture(resourcelocation1, runtimeexception.getMessage());
continue;
}
catch (IOException ioexception1)
{
//logger.error("Using missing texture, unable to load " + resourcelocation1, ioexception1);
cpw.mods.fml.client.FMLClientHandler.instance().trackMissingTexture(resourcelocation1);
continue;
}
j = Math.min(j, Math.min(textureatlassprite.getIconWidth(), textureatlassprite.getIconHeight()));
stitcher.addSprite(textureatlassprite);
}
cpw.mods.fml.common.ProgressManager.pop(bar);
int i1 = MathHelper.calculateLogBaseTwo(j);
if (i1 < this.mipmapLevels)
{
logger.debug("{}: dropping miplevel from {} to {}, because of minTexel: {}", new Object[] {this.basePath, Integer.valueOf(this.mipmapLevels), Integer.valueOf(i1), Integer.valueOf(j)});
this.mipmapLevels = i1;
}
Iterator iterator1 = this.mapRegisteredSprites.values().iterator();
bar = cpw.mods.fml.common.ProgressManager.push("Mipmap generation", skipFirst ? 0 : this.mapRegisteredSprites.size());
while (!skipFirst && iterator1.hasNext())
{
final TextureAtlasSprite textureatlassprite1 = (TextureAtlasSprite)iterator1.next();
bar.step(textureatlassprite1.getIconName());
try
{
textureatlassprite1.generateMipmaps(this.mipmapLevels);
}
catch (Throwable throwable1)
{
CrashReport crashreport = CrashReport.makeCrashReport(throwable1, "Applying mipmap");
CrashReportCategory crashreportcategory = crashreport.makeCategory("Sprite being mipmapped");
crashreportcategory.addCrashSectionCallable("Sprite name", new Callable()
{
private static final String __OBFID = "CL_00001059";
public String call()
{
return textureatlassprite1.getIconName();
}
});
crashreportcategory.addCrashSectionCallable("Sprite size", new Callable()
{
private static final String __OBFID = "CL_00001060";
public String call()
{
return textureatlassprite1.getIconWidth() + " x " + textureatlassprite1.getIconHeight();
}
});
crashreportcategory.addCrashSectionCallable("Sprite frames", new Callable()
{
private static final String __OBFID = "CL_00001061";
public String call()
{
return textureatlassprite1.getFrameCount() + " frames";
}
});
crashreportcategory.addCrashSection("Mipmap levels", Integer.valueOf(this.mipmapLevels));
throw new ReportedException(crashreport);
}
}
this.missingImage.generateMipmaps(this.mipmapLevels);
stitcher.addSprite(this.missingImage);
cpw.mods.fml.common.ProgressManager.pop(bar);
skipFirst = false;
bar = cpw.mods.fml.common.ProgressManager.push("Texture creation", 3);
try
{
bar.step("Stitching");
stitcher.doStitch();
}
catch (StitcherException stitcherexception)
{
throw stitcherexception;
}
logger.info("Created: {}x{} {}-atlas", new Object[] {Integer.valueOf(stitcher.getCurrentWidth()), Integer.valueOf(stitcher.getCurrentHeight()), this.basePath});
bar.step("Allocating GL texture");
TextureUtil.allocateTextureImpl(this.getGlTextureId(), this.mipmapLevels, stitcher.getCurrentWidth(), stitcher.getCurrentHeight(), (float)this.anisotropicFiltering);
HashMap hashmap = Maps.newHashMap(this.mapRegisteredSprites);
Iterator iterator2 = stitcher.getStichSlots().iterator();
bar.step("Uploading GL texture");
while (iterator2.hasNext())
{
textureatlassprite = (TextureAtlasSprite)iterator2.next();
String s = textureatlassprite.getIconName();
hashmap.remove(s);
this.mapUploadedSprites.put(s, textureatlassprite);
try
{
TextureUtil.uploadTextureMipmap(textureatlassprite.getFrameTextureData(0), textureatlassprite.getIconWidth(), textureatlassprite.getIconHeight(), textureatlassprite.getOriginX(), textureatlassprite.getOriginY(), false, false);
}
catch (Throwable throwable)
{
CrashReport crashreport1 = CrashReport.makeCrashReport(throwable, "Stitching texture atlas");
CrashReportCategory crashreportcategory1 = crashreport1.makeCategory("Texture being stitched together");
crashreportcategory1.addCrashSection("Atlas path", this.basePath);
crashreportcategory1.addCrashSection("Sprite", textureatlassprite);
throw new ReportedException(crashreport1);
}
if (textureatlassprite.hasAnimationMetadata())
{
this.listAnimatedSprites.add(textureatlassprite);
}
else
{
textureatlassprite.clearFramesTextureData();
}
}
iterator2 = hashmap.values().iterator();
while (iterator2.hasNext())
{
textureatlassprite = (TextureAtlasSprite)iterator2.next();
textureatlassprite.copyFrom(this.missingImage);
}
ForgeHooksClient.onTextureStitchedPost(this);
cpw.mods.fml.common.ProgressManager.pop(bar);
}
private ResourceLocation completeResourceLocation(ResourceLocation p_147634_1_, int p_147634_2_)
{
return p_147634_2_ == 0 ? new ResourceLocation(p_147634_1_.getResourceDomain(), String.format("%s/%s%s", new Object[] {this.basePath, p_147634_1_.getResourcePath(), ".png"})): new ResourceLocation(p_147634_1_.getResourceDomain(), String.format("%s/mipmaps/%s.%d%s", new Object[] {this.basePath, p_147634_1_.getResourcePath(), Integer.valueOf(p_147634_2_), ".png"}));
}
private void registerIcons()
{
this.mapRegisteredSprites.clear();
Iterator iterator;
if (this.textureType == 0)
{
iterator = Block.blockRegistry.iterator();
while (iterator.hasNext())
{
Block block = (Block)iterator.next();
if (block.getMaterial() != Material.air)
{
block.registerIcons(this);
}
}
Minecraft.getMinecraft().renderGlobal.registerDestroyBlockIcons(this);
RenderManager.instance.updateIcons(this);
}
iterator = Item.itemRegistry.iterator();
while (iterator.hasNext())
{
Item item = (Item)iterator.next();
if (item != null && item.getSpriteNumber() == this.textureType)
{
item.registerIcons(this);
}
}
}
public TextureAtlasSprite getAtlasSprite(String p_110572_1_)
{
TextureAtlasSprite textureatlassprite = (TextureAtlasSprite)this.mapUploadedSprites.get(p_110572_1_);
if (textureatlassprite == null)
{
textureatlassprite = this.missingImage;
}
return textureatlassprite;
}
public void updateAnimations()
{
TextureUtil.bindTexture(this.getGlTextureId());
Iterator iterator = this.listAnimatedSprites.iterator();
while (iterator.hasNext())
{
TextureAtlasSprite textureatlassprite = (TextureAtlasSprite)iterator.next();
textureatlassprite.updateAnimation();
}
}
public IIcon registerIcon(String p_94245_1_)
{
if (p_94245_1_ == null)
{
throw new IllegalArgumentException("Name cannot be null!");
}
else if (p_94245_1_.indexOf(92) == -1) // Disable backslashes (\) in texture asset paths.
{
Object object = (TextureAtlasSprite)this.mapRegisteredSprites.get(p_94245_1_);
if (object == null)
{
if (this.textureType == 1)
{
if ("clock".equals(p_94245_1_))
{
object = new TextureClock(p_94245_1_);
}
else if ("compass".equals(p_94245_1_))
{
object = new TextureCompass(p_94245_1_);
}
else
{
object = new TextureAtlasSprite(p_94245_1_);
}
}
else
{
object = new TextureAtlasSprite(p_94245_1_);
}
this.mapRegisteredSprites.put(p_94245_1_, object);
}
return (IIcon)object;
}
else
{
throw new IllegalArgumentException("Name cannot contain slashes!");
}
}
public int getTextureType()
{
return this.textureType;
}
public void tick()
{
this.updateAnimations();
}
public void setMipmapLevels(int p_147633_1_)
{
this.mipmapLevels = p_147633_1_;
}
public void setAnisotropicFiltering(int p_147632_1_)
{
this.anisotropicFiltering = p_147632_1_;
}
//===================================================================================================
// Forge Start
//===================================================================================================
/**
* 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.
*
* @param name The name of the entry to find
* @return The registered entry, null if nothing was registered.
*/
public TextureAtlasSprite getTextureExtry(String name)
{
return (TextureAtlasSprite)mapRegisteredSprites.get(name);
}
/**
* Adds a texture registry entry to this map for the specified name if one does not already exist.
* Returns false if the map already contains a entry for the specified name.
*
* @param name Entry name
* @param entry Entry instance
* @return True if the entry was added to the map, false otherwise.
*/
public boolean setTextureEntry(String name, TextureAtlasSprite entry)
{
if (!mapRegisteredSprites.containsKey(name))
{
mapRegisteredSprites.put(name, entry);
return true;
}
return false;
}
}