mod.rankshank.arbitraria.client.texture.CustomTextureMap.java Source code

Java tutorial

Introduction

Here is the source code for mod.rankshank.arbitraria.client.texture.CustomTextureMap.java

Source

/*
 * This class was created by: RANKSHANK as a part of  the Arbitraria mod.
 * Full source can be found @ https://github.com/RANKSHANK/Arbitraria
 *
 * Arbitraria is provided in binary and source forms under the Arbitraria License.
 * Arbitraria License can be found in the repository @  https://github.com/RANKSHANK/Arbitraria
 */

package mod.rankshank.arbitraria.client.texture;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import mod.rankshank.arbitraria.client.vars.ClientReflectionHandles;
import mod.rankshank.arbitraria.common.init.Arbitraria;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.texture.*;
import net.minecraft.client.resources.IResource;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory;
import net.minecraft.crash.ICrashReportDetail;
import net.minecraft.util.ReportedException;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.fml.client.FMLClientHandler;
import net.minecraftforge.fml.common.ProgressManager;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.apache.commons.io.IOUtils;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

import static com.google.common.collect.Lists.newArrayList;

@SideOnly(Side.CLIENT)
public class CustomTextureMap extends AbstractTexture implements ITickableTextureObject {

    public final ResourceLocation TEXTURE_KEY;

    private int mipmapLevels = 4;

    private final Map<String, TextureAtlasSprite> mapUploadedSprites;
    private final Map<String, TextureAtlasSprite> mapRegisteredSprites;
    private final List<TextureAtlasSprite> animationList;

    private final TextureAtlasSprite missing;

    private final ImmutableList<IIconRegistrar> registrars;

    public CustomTextureMap(ResourceLocation texture_key, IIconRegistrar... registrars) {
        this.registrars = ImmutableList.copyOf(registrars);
        TEXTURE_KEY = texture_key;
        mapUploadedSprites = Maps.newHashMap();
        mapRegisteredSprites = Maps.newHashMap();
        animationList = newArrayList();
        missing = makeAtlas(new ResourceLocation("missingno"));
    }

    private void initMissingImage() {
        int[] textureData = TextureUtil.MISSING_TEXTURE_DATA;
        this.missing.setIconWidth(16);
        this.missing.setIconHeight(16);
        int[][] mipData = new int[this.mipmapLevels + 1][];
        mipData[0] = textureData;
        this.missing.setFramesTextureData(newArrayList(new int[][][] { mipData }));
    }

    @Override
    public void loadTexture(IResourceManager resourceManager) throws IOException {
        this.deleteGlTexture();
        initMissingImage();
        int i = Minecraft.getGLMaximumTextureSize();
        Stitcher stitcher = new Stitcher(i, i, 0, this.mipmapLevels);
        this.mapUploadedSprites.clear();
        this.mapRegisteredSprites.clear();
        animationList.clear();

        registrars.forEach(icon -> icon.onRegister(loc -> registerSprite(loc)));

        int j = Integer.MAX_VALUE;
        int k = 1 << this.mipmapLevels;

        ProgressManager.ProgressBar bar = ProgressManager.push("Texture" + TEXTURE_KEY.toString() + "stitching",
                this.mapRegisteredSprites.size());

        for (Map.Entry<String, TextureAtlasSprite> entry : this.mapRegisteredSprites.entrySet()) {
            TextureAtlasSprite textureatlassprite = entry.getValue();
            ResourceLocation resourcelocation = this.getResourceLocation(textureatlassprite);
            bar.step(resourcelocation.getResourcePath());
            IResource iresource = null;

            if (textureatlassprite.hasCustomLoader(resourceManager, resourcelocation)) {
                if (textureatlassprite.load(resourceManager, resourcelocation)) {
                    continue;
                }
            } else
                try {
                    PngSizeInfo pngsizeinfo = PngSizeInfo
                            .makeFromResource(resourceManager.getResource(resourcelocation));
                    iresource = resourceManager.getResource(resourcelocation);
                    boolean flag = iresource.getMetadata("animation") != null;
                    textureatlassprite.loadSprite(pngsizeinfo, flag);
                } catch (RuntimeException runtimeexception) {
                    //LOGGER.error("Unable to parse metadata from {}", new Object[] {resourcelocation, runtimeexception});
                    FMLClientHandler.instance().trackBrokenTexture(resourcelocation, runtimeexception.getMessage());
                    continue;
                } catch (IOException ioexception) {
                    //LOGGER.error("Using missing texture, unable to load {}", new Object[] {resourcelocation, ioexception});
                    FMLClientHandler.instance().trackMissingTexture(resourcelocation);
                    continue;
                } finally {
                    IOUtils.closeQuietly(iresource);
                }

            j = Math.min(j, Math.min(textureatlassprite.getIconWidth(), textureatlassprite.getIconHeight()));
            int squarCheck = Math.min(Integer.lowestOneBit(textureatlassprite.getIconWidth()),
                    Integer.lowestOneBit(textureatlassprite.getIconHeight()));

            if (squarCheck < k) {
                Arbitraria.log("TEXTURE DERP @" + textureatlassprite.getIconName());
            }

            stitcher.addSprite(textureatlassprite);
        }

        ProgressManager.pop(bar);
        int l = Math.min(j, k);
        int i1 = MathHelper.log2(l);

        missing.generateMipmaps(this.mipmapLevels);
        stitcher.addSprite(missing);
        bar = ProgressManager.push("Texture creation", 2);

        bar.step("Stitching");
        stitcher.doStitch();

        bar.step("Allocating GL texture");
        TextureUtil.allocateTextureImpl(this.getGlTextureId(), this.mipmapLevels, stitcher.getCurrentWidth(),
                stitcher.getCurrentHeight());
        Map<String, TextureAtlasSprite> map = Maps.newHashMap(this.mapRegisteredSprites);

        ProgressManager.pop(bar);
        bar = ProgressManager.push("Texture mipmap and upload", stitcher.getStichSlots().size());

        for (TextureAtlasSprite stitchingSprite : stitcher.getStichSlots()) {
            bar.step(stitchingSprite.getIconName());
            if (stitchingSprite == this.missing || this.generateMipmaps(resourceManager, stitchingSprite)) {
                String s = stitchingSprite.getIconName();
                map.remove(s);
                this.mapUploadedSprites.put(s, stitchingSprite);

                try {
                    TextureUtil.uploadTextureMipmap(stitchingSprite.getFrameTextureData(0),
                            stitchingSprite.getIconWidth(), stitchingSprite.getIconHeight(),
                            stitchingSprite.getOriginX(), stitchingSprite.getOriginY(), false, false);
                } catch (Throwable throwable) {
                    CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Stitching texture atlas");
                    CrashReportCategory crashreportcategory = crashreport
                            .makeCategory("Texture being stitched together");
                    crashreportcategory.addCrashSection("Atlas path", this.TEXTURE_KEY);
                    crashreportcategory.addCrashSection("Sprite", stitchingSprite);
                    throw new ReportedException(crashreport);
                }

                if (stitchingSprite.hasAnimationMetadata()) {
                    this.animationList.add(stitchingSprite);
                }
            }
        }
    }

    private boolean generateMipmaps(IResourceManager resourceManager, TextureAtlasSprite texture) {
        ResourceLocation resourcelocation = this.getResourceLocation(texture);
        IResource iresource = null;
        loadFrames: {
            boolean flag;
            if (texture.hasCustomLoader(resourceManager, resourcelocation))
                break loadFrames;

            try {
                iresource = resourceManager.getResource(resourcelocation);
                texture.loadSpriteFrames(iresource, this.mipmapLevels + 1);
                break loadFrames;
            } catch (RuntimeException runtimeexception) {
                flag = false;
            } catch (IOException ioexception) {
                return false;
            } finally {
                IOUtils.closeQuietly(iresource);
            }

            return flag;
        }

        try {
            texture.generateMipmaps(this.mipmapLevels);
            return true;
        } catch (Throwable throwable) {
            CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Applying mipmap");
            CrashReportCategory crashreportcategory = crashreport.makeCategory("Sprite being mipmapped");
            crashreportcategory.setDetail("Sprite name", new ICrashReportDetail<String>() {

                @Override
                public String call() throws Exception {
                    return texture.getIconName();
                }
            });
            crashreportcategory.setDetail("Sprite size", new ICrashReportDetail<String>() {

                @Override
                public String call() throws Exception {
                    return texture.getIconWidth() + " x " + texture.getIconHeight();
                }
            });
            crashreportcategory.setDetail("Sprite frames", new ICrashReportDetail<String>() {

                @Override
                public String call() throws Exception {
                    return texture.getFrameCount() + " frames";
                }
            });
            crashreportcategory.addCrashSection("Mipmap levels", this.mipmapLevels);
            throw new ReportedException(crashreport);
        }
    }

    public TextureAtlasSprite registerSprite(@Nonnull ResourceLocation location) {
        TextureAtlasSprite textureatlassprite = mapRegisteredSprites.get(location.toString());

        if (textureatlassprite == null) {
            textureatlassprite = makeAtlas(location);
            this.mapRegisteredSprites.put(location.toString(), textureatlassprite);
        }

        return textureatlassprite;
    }

    private ResourceLocation getResourceLocation(TextureAtlasSprite sprite) {
        ResourceLocation resourcelocation = new ResourceLocation(sprite.getIconName());
        return new ResourceLocation(resourcelocation.getResourceDomain(),
                String.format("%s/%s%s", "textures", resourcelocation.getResourcePath(), ".png"));
    }

    public TextureAtlasSprite getAtlasSprite(String iconName) {
        TextureAtlasSprite textureatlassprite = this.mapUploadedSprites.get(iconName);

        if (textureatlassprite == null)
            textureatlassprite = missing;

        return textureatlassprite;
    }

    private TextureAtlasSprite makeAtlas(@Nonnull ResourceLocation location) {
        TextureAtlasSprite sprite = null;
        try {
            sprite = (TextureAtlasSprite) ClientReflectionHandles.TextureAtlasSprite_MakeAtlasSprite.invoke(null,
                    location);
        } catch (Exception ex) {
            Arbitraria.error(new Throwable(String.format("ISSUE CREATING TEXTURE ATLAS from %s for %s",
                    location.toString(), TEXTURE_KEY.toString())), ex);
        }
        return sprite;
    }

    @Override
    public void tick() {
        GlStateManager.bindTexture(this.getGlTextureId());
        animationList.forEach(TextureAtlasSprite::updateAnimation);
    }

    public interface IIconRegistrar {

        void onRegister(Function<ResourceLocation, TextureAtlasSprite> register);

    }
}