package net.minecraft.client.renderer; import cpw.mods.fml.client.TextureFXManager; import cpw.mods.fml.common.FMLLog; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.nio.IntBuffer; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.imageio.ImageIO; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.settings.GameSettings; import net.minecraft.client.texturepacks.ITexturePack; import net.minecraft.client.texturepacks.TexturePackList; import net.minecraft.util.Icon; import net.minecraft.util.IntHashMap; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import net.minecraftforge.client.ForgeHooksClient; @SideOnly(Side.CLIENT) public class RenderEngine { private HashMap textureMap = new HashMap(); /** Texture contents map (key: texture name, value: int[] contents) */ private HashMap textureContentsMap = new HashMap(); /** A mapping from GL texture names (integers) to BufferedImage instances */ private IntHashMap textureNameToImageMap = new IntHashMap(); /** Stores the image data for the texture. */ private IntBuffer imageData = GLAllocation.createDirectIntBuffer(4194304); /** A mapping from image URLs to ThreadDownloadImageData instances */ private Map urlToImageDataMap = new HashMap(); /** Reference to the GameSettings object */ private GameSettings options; /** Texture pack */ public TexturePackList texturePack; /** Missing texture image */ private BufferedImage missingTextureImage = new BufferedImage(64, 64, 2); public final TextureMap textureMapBlocks; public final TextureMap textureMapItems; private int boundTexture; public static Logger log = FMLLog.getLogger(); public RenderEngine(TexturePackList par1TexturePackList, GameSettings par2GameSettings) { this.texturePack = par1TexturePackList; this.options = par2GameSettings; Graphics graphics = this.missingTextureImage.getGraphics(); graphics.setColor(Color.WHITE); graphics.fillRect(0, 0, 64, 64); graphics.setColor(Color.BLACK); int i = 10; int j = 0; while (i < 64) { String s = j++ % 2 == 0 ? "missing" : "texture"; graphics.drawString(s, 1, i); i += graphics.getFont().getSize(); if (j % 2 == 0) { i += 5; } } graphics.dispose(); this.textureMapBlocks = new TextureMap(0, "terrain", "textures/blocks/", this.missingTextureImage); this.textureMapItems = new TextureMap(1, "items", "textures/items/", this.missingTextureImage); } public int[] getTextureContents(String par1Str) { ITexturePack itexturepack = this.texturePack.getSelectedTexturePack(); int[] aint = (int[])this.textureContentsMap.get(par1Str); if (aint != null) { return aint; } else { try { InputStream inputstream = itexturepack.getResourceAsStream(par1Str); int[] aint1; if (inputstream == null) { aint1 = this.getImageContentsAndAllocate(this.missingTextureImage); } else { BufferedImage bufferedimage = this.readTextureImage(inputstream); TextureFXManager.instance().fixTransparency(bufferedimage, par1Str); aint1 = this.getImageContentsAndAllocate(bufferedimage); } this.textureContentsMap.put(par1Str, aint1); return aint1; } catch (Exception ioexception) { log.log(Level.INFO, String.format("An error occured reading texture file %s (getTexture)", par1Str), ioexception); ioexception.printStackTrace(); int[] aint2 = this.getImageContentsAndAllocate(this.missingTextureImage); this.textureContentsMap.put(par1Str, aint2); return aint2; } } } private int[] getImageContentsAndAllocate(BufferedImage par1BufferedImage) { return this.getImageContents(par1BufferedImage, new int[par1BufferedImage.getWidth() * par1BufferedImage.getHeight()]); } private int[] getImageContents(BufferedImage par1BufferedImage, int[] par2ArrayOfInteger) { int i = par1BufferedImage.getWidth(); int j = par1BufferedImage.getHeight(); par1BufferedImage.getRGB(0, 0, i, j, par2ArrayOfInteger, 0, i); return par2ArrayOfInteger; } public void bindTexture(String par1Str) { this.bindTexture(this.getTexture(par1Str)); } private void bindTexture(int par1) { if (par1 != this.boundTexture) { GL11.glBindTexture(GL11.GL_TEXTURE_2D, par1); this.boundTexture = par1; } } public void resetBoundTexture() { this.boundTexture = -1; } public int getTexture(String par1Str) { if (par1Str.equals("/terrain.png")) { this.textureMapBlocks.getTexture().bindTexture(0); return this.textureMapBlocks.getTexture().getGlTextureId(); } else if (par1Str.equals("/gui/items.png")) { this.textureMapItems.getTexture().bindTexture(0); return this.textureMapItems.getTexture().getGlTextureId(); } else { Integer integer = (Integer)this.textureMap.get(par1Str); if (integer != null) { return integer.intValue(); } else { String s1 = par1Str; try { ForgeHooksClient.onTextureLoadPre(par1Str); int i = GLAllocation.generateTextureNames(); TextureFXManager.instance().bindTextureToName(par1Str, i); boolean flag = par1Str.startsWith("%blur%"); if (flag) { par1Str = par1Str.substring(6); } boolean flag1 = par1Str.startsWith("%clamp%"); if (flag1) { par1Str = par1Str.substring(7); } InputStream inputstream = this.texturePack.getSelectedTexturePack().getResourceAsStream(par1Str); if (inputstream == null) { this.setupTextureExt(this.missingTextureImage, i, flag, flag1); } else { BufferedImage bufferedimage = this.readTextureImage(inputstream); TextureFXManager.instance().fixTransparency(bufferedimage, par1Str); this.setupTextureExt(bufferedimage, i, flag, flag1); } this.textureMap.put(s1, Integer.valueOf(i)); ForgeHooksClient.onTextureLoad(par1Str, texturePack.getSelectedTexturePack()); return i; } catch (Exception exception) { exception.printStackTrace(); int j = GLAllocation.generateTextureNames(); this.setupTexture(this.missingTextureImage, j); this.textureMap.put(par1Str, Integer.valueOf(j)); return j; } } } } /** * Copy the supplied image onto a newly-allocated OpenGL texture, returning the allocated texture name */ public int allocateAndSetupTexture(BufferedImage par1BufferedImage) { int i = GLAllocation.generateTextureNames(); this.setupTexture(par1BufferedImage, i); this.textureNameToImageMap.addKey(i, par1BufferedImage); return i; } /** * Copy the supplied image onto the specified OpenGL texture */ public void setupTexture(BufferedImage par1BufferedImage, int par2) { this.setupTextureExt(par1BufferedImage, par2, false, false); } public void setupTextureExt(BufferedImage par1BufferedImage, int par2, boolean par3, boolean par4) { this.bindTexture(par2); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); if (par3) { GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); } if (par4) { GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP); } else { GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); } int j = par1BufferedImage.getWidth(); int k = par1BufferedImage.getHeight(); TextureFXManager.instance().setTextureDimensions(par2, j, k); int[] aint = new int[j * k]; par1BufferedImage.getRGB(0, 0, j, k, aint, 0, j); if (this.options != null && this.options.anaglyph) { aint = this.colorToAnaglyph(aint); } this.imageData.clear(); this.imageData.put(aint); this.imageData.position(0).limit(aint.length); GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, j, k, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, this.imageData); } private int[] colorToAnaglyph(int[] par1ArrayOfInteger) { int[] aint1 = new int[par1ArrayOfInteger.length]; for (int i = 0; i < par1ArrayOfInteger.length; ++i) { int j = par1ArrayOfInteger[i] >> 24 & 255; int k = par1ArrayOfInteger[i] >> 16 & 255; int l = par1ArrayOfInteger[i] >> 8 & 255; int i1 = par1ArrayOfInteger[i] & 255; int j1 = (k * 30 + l * 59 + i1 * 11) / 100; int k1 = (k * 30 + l * 70) / 100; int l1 = (k * 30 + i1 * 70) / 100; aint1[i] = j << 24 | j1 << 16 | k1 << 8 | l1; } return aint1; } public void createTextureFromBytes(int[] par1ArrayOfInteger, int par2, int par3, int par4) { this.bindTexture(par4); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); if (this.options != null && this.options.anaglyph) { par1ArrayOfInteger = this.colorToAnaglyph(par1ArrayOfInteger); } this.imageData.clear(); this.imageData.put(par1ArrayOfInteger); this.imageData.position(0).limit(par1ArrayOfInteger.length); GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, par2, par3, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, this.imageData); } /** * Deletes a single GL texture */ public void deleteTexture(int par1) { this.textureNameToImageMap.removeObject(par1); GL11.glDeleteTextures(par1); } /** * Takes a URL of a downloadable image and the name of the local image to be used as a fallback. If the image has * been downloaded, returns the GL texture of the downloaded image, otherwise returns the GL texture of the fallback * image. */ public int getTextureForDownloadableImage(String par1Str, String par2Str) { ThreadDownloadImageData threaddownloadimagedata = (ThreadDownloadImageData)this.urlToImageDataMap.get(par1Str); if (threaddownloadimagedata != null && threaddownloadimagedata.image != null && !threaddownloadimagedata.textureSetupComplete) { if (threaddownloadimagedata.textureName < 0) { threaddownloadimagedata.textureName = this.allocateAndSetupTexture(threaddownloadimagedata.image); } else { this.setupTexture(threaddownloadimagedata.image, threaddownloadimagedata.textureName); } threaddownloadimagedata.textureSetupComplete = true; } return threaddownloadimagedata != null && threaddownloadimagedata.textureName >= 0 ? threaddownloadimagedata.textureName : (par2Str == null ? -1 : this.getTexture(par2Str)); } /** * Checks if urlToImageDataMap has image data for the given key */ public boolean hasImageData(String par1Str) { return this.urlToImageDataMap.containsKey(par1Str); } /** * Return a ThreadDownloadImageData instance for the given URL. If it does not already exist, it is created and * uses the passed ImageBuffer. If it does, its reference count is incremented. */ public ThreadDownloadImageData obtainImageData(String par1Str, IImageBuffer par2IImageBuffer) { ThreadDownloadImageData threaddownloadimagedata = (ThreadDownloadImageData)this.urlToImageDataMap.get(par1Str); if (threaddownloadimagedata == null) { this.urlToImageDataMap.put(par1Str, new ThreadDownloadImageData(par1Str, par2IImageBuffer)); } else { ++threaddownloadimagedata.referenceCount; } return threaddownloadimagedata; } /** * Decrements the reference count for a given URL, deleting the image data if the reference count hits 0 */ public void releaseImageData(String par1Str) { ThreadDownloadImageData threaddownloadimagedata = (ThreadDownloadImageData)this.urlToImageDataMap.get(par1Str); if (threaddownloadimagedata != null) { --threaddownloadimagedata.referenceCount; if (threaddownloadimagedata.referenceCount == 0) { if (threaddownloadimagedata.textureName >= 0) { this.deleteTexture(threaddownloadimagedata.textureName); } this.urlToImageDataMap.remove(par1Str); } } } public void updateDynamicTextures() { this.textureMapBlocks.updateAnimations(); this.textureMapItems.updateAnimations(); } /** * Call setupTexture on all currently-loaded textures again to account for changes in rendering options */ public void refreshTextures() { ITexturePack itexturepack = this.texturePack.getSelectedTexturePack(); this.refreshTextureMaps(); Iterator iterator = this.textureNameToImageMap.getKeySet().iterator(); BufferedImage bufferedimage; while (iterator.hasNext()) { int i = ((Integer)iterator.next()).intValue(); bufferedimage = (BufferedImage)this.textureNameToImageMap.lookup(i); this.setupTexture(bufferedimage, i); } ThreadDownloadImageData threaddownloadimagedata; for (iterator = this.urlToImageDataMap.values().iterator(); iterator.hasNext(); threaddownloadimagedata.textureSetupComplete = false) { threaddownloadimagedata = (ThreadDownloadImageData)iterator.next(); } iterator = this.textureMap.keySet().iterator(); String s; while (iterator.hasNext()) { s = (String)iterator.next(); try { int j = ((Integer)this.textureMap.get(s)).intValue(); boolean flag = s.startsWith("%blur%"); if (flag) { s = s.substring(6); } boolean flag1 = s.startsWith("%clamp%"); if (flag1) { s = s.substring(7); } BufferedImage bufferedimage1 = this.readTextureImage(itexturepack.getResourceAsStream(s)); TextureFXManager.instance().fixTransparency(bufferedimage1, s); this.setupTextureExt(bufferedimage1, j, flag, flag1); } catch (Exception ioexception) { log.log(Level.INFO,String.format("An error occured reading texture file %s (refreshTexture)", s), ioexception); ioexception.printStackTrace(); } } iterator = this.textureContentsMap.keySet().iterator(); while (iterator.hasNext()) { s = (String)iterator.next(); try { bufferedimage = this.readTextureImage(itexturepack.getResourceAsStream(s)); TextureFXManager.instance().fixTransparency(bufferedimage, s); this.getImageContents(bufferedimage, (int[])this.textureContentsMap.get(s)); } catch (Exception ioexception1) { log.log(Level.INFO,String.format("An error occured reading texture file data %s (refreshTexture)", s), ioexception1); ioexception1.printStackTrace(); } } Minecraft.getMinecraft().fontRenderer.readFontData(); Minecraft.getMinecraft().standardGalacticFontRenderer.readFontData(); } /** * Returns a BufferedImage read off the provided input stream. Args: inputStream */ private BufferedImage readTextureImage(InputStream par1InputStream) throws IOException { BufferedImage bufferedimage = ImageIO.read(par1InputStream); par1InputStream.close(); return bufferedimage; } public void refreshTextureMaps() { this.textureMapBlocks.refreshTextures(); this.textureMapItems.refreshTextures(); } public Icon getMissingIcon(int par1) { switch (par1) { case 0: return this.textureMapBlocks.getMissingIcon(); case 1: default: return this.textureMapItems.getMissingIcon(); } } }