001package net.minecraft.client.renderer;
002
003import cpw.mods.fml.client.TextureFXManager;
004import cpw.mods.fml.common.FMLLog;
005import cpw.mods.fml.relauncher.Side;
006import cpw.mods.fml.relauncher.SideOnly;
007import java.awt.Color;
008import java.awt.Dimension;
009import java.awt.Graphics;
010import java.awt.image.BufferedImage;
011import java.io.IOException;
012import java.io.InputStream;
013import java.nio.IntBuffer;
014import java.util.HashMap;
015import java.util.Iterator;
016import java.util.Map;
017import java.util.logging.Level;
018import java.util.logging.Logger;
019
020import javax.imageio.ImageIO;
021import net.minecraft.client.Minecraft;
022import net.minecraft.client.renderer.texture.TextureMap;
023import net.minecraft.client.settings.GameSettings;
024import net.minecraft.client.texturepacks.ITexturePack;
025import net.minecraft.client.texturepacks.TexturePackList;
026import net.minecraft.util.Icon;
027import net.minecraft.util.IntHashMap;
028import org.lwjgl.opengl.GL11;
029import org.lwjgl.opengl.GL12;
030
031import net.minecraftforge.client.ForgeHooksClient;
032
033@SideOnly(Side.CLIENT)
034public class RenderEngine
035{
036    private HashMap textureMap = new HashMap();
037
038    /** Texture contents map (key: texture name, value: int[] contents) */
039    private HashMap textureContentsMap = new HashMap();
040
041    /** A mapping from GL texture names (integers) to BufferedImage instances */
042    private IntHashMap textureNameToImageMap = new IntHashMap();
043
044    /** Stores the image data for the texture. */
045    private IntBuffer imageData = GLAllocation.createDirectIntBuffer(4194304);
046
047    /** A mapping from image URLs to ThreadDownloadImageData instances */
048    private Map urlToImageDataMap = new HashMap();
049
050    /** Reference to the GameSettings object */
051    private GameSettings options;
052
053    /** Texture pack */
054    public TexturePackList texturePack;
055
056    /** Missing texture image */
057    private BufferedImage missingTextureImage = new BufferedImage(64, 64, 2);
058    public final TextureMap field_94154_l;
059    public final TextureMap field_94155_m;
060    private int field_94153_n;
061
062    public static Logger log = FMLLog.getLogger();
063
064    public RenderEngine(TexturePackList par1TexturePackList, GameSettings par2GameSettings)
065    {
066        this.texturePack = par1TexturePackList;
067        this.options = par2GameSettings;
068        Graphics graphics = this.missingTextureImage.getGraphics();
069        graphics.setColor(Color.WHITE);
070        graphics.fillRect(0, 0, 64, 64);
071        graphics.setColor(Color.BLACK);
072        int i = 10;
073        int j = 0;
074
075        while (i < 64)
076        {
077            String s = j++ % 2 == 0 ? "missing" : "texture";
078            graphics.drawString(s, 1, i);
079            i += graphics.getFont().getSize();
080
081            if (j % 2 == 0)
082            {
083                i += 5;
084            }
085        }
086
087        graphics.dispose();
088        this.field_94154_l = new TextureMap(0, "terrain", "textures/blocks/", this.missingTextureImage);
089        this.field_94155_m = new TextureMap(1, "items", "textures/items/", this.missingTextureImage);
090    }
091
092    public int[] getTextureContents(String par1Str)
093    {
094        ITexturePack itexturepack = this.texturePack.getSelectedTexturePack();
095        int[] aint = (int[])this.textureContentsMap.get(par1Str);
096
097        if (aint != null)
098        {
099            return aint;
100        }
101        else
102        {
103            try
104            {
105                InputStream inputstream = itexturepack.getResourceAsStream(par1Str);
106                int[] aint1;
107
108                if (inputstream == null)
109                {
110                    aint1 = this.getImageContentsAndAllocate(this.missingTextureImage);
111                }
112                else
113                {
114                    BufferedImage bufferedimage = this.readTextureImage(inputstream);
115                    TextureFXManager.instance().fixTransparency(bufferedimage, par1Str);
116                    aint1 = this.getImageContentsAndAllocate(bufferedimage);
117                }
118
119                this.textureContentsMap.put(par1Str, aint1);
120                return aint1;
121            }
122            catch (Exception ioexception)
123            {
124                log.log(Level.INFO, String.format("An error occured reading texture file %s (getTexture)", par1Str), ioexception);
125                ioexception.printStackTrace();
126                int[] aint2 = this.getImageContentsAndAllocate(this.missingTextureImage);
127                this.textureContentsMap.put(par1Str, aint2);
128                return aint2;
129            }
130        }
131    }
132
133    private int[] getImageContentsAndAllocate(BufferedImage par1BufferedImage)
134    {
135        return this.getImageContents(par1BufferedImage, new int[par1BufferedImage.getWidth() * par1BufferedImage.getHeight()]);
136    }
137
138    private int[] getImageContents(BufferedImage par1BufferedImage, int[] par2ArrayOfInteger)
139    {
140        int i = par1BufferedImage.getWidth();
141        int j = par1BufferedImage.getHeight();
142        par1BufferedImage.getRGB(0, 0, i, j, par2ArrayOfInteger, 0, i);
143        return par2ArrayOfInteger;
144    }
145
146    public void func_98187_b(String par1Str)
147    {
148        this.bindTexture(this.getTexture(par1Str));
149    }
150
151    private void bindTexture(int par1)
152    {
153        if (par1 != this.field_94153_n)
154        {
155            GL11.glBindTexture(GL11.GL_TEXTURE_2D, par1);
156            this.field_94153_n = par1;
157        }
158    }
159
160    public void func_98185_a()
161    {
162        this.field_94153_n = -1;
163    }
164
165    public int getTexture(String par1Str)
166    {
167        if (par1Str.equals("/terrain.png"))
168        {
169            this.field_94154_l.func_94246_d().func_94277_a(0);
170            return this.field_94154_l.func_94246_d().func_94282_c();
171        }
172        else if (par1Str.equals("/gui/items.png"))
173        {
174            this.field_94155_m.func_94246_d().func_94277_a(0);
175            return this.field_94155_m.func_94246_d().func_94282_c();
176        }
177        else
178        {
179            Integer integer = (Integer)this.textureMap.get(par1Str);
180
181            if (integer != null)
182            {
183                return integer.intValue();
184            }
185            else
186            {
187                String s1 = par1Str;
188
189                try
190                {
191                    ForgeHooksClient.onTextureLoadPre(par1Str);
192                    int i = GLAllocation.generateTextureNames();
193                    TextureFXManager.instance().bindTextureToName(par1Str, i);
194                    boolean flag = par1Str.startsWith("%blur%");
195
196                    if (flag)
197                    {
198                        par1Str = par1Str.substring(6);
199                    }
200
201                    boolean flag1 = par1Str.startsWith("%clamp%");
202
203                    if (flag1)
204                    {
205                        par1Str = par1Str.substring(7);
206                    }
207
208                    InputStream inputstream = this.texturePack.getSelectedTexturePack().getResourceAsStream(par1Str);
209
210                    if (inputstream == null)
211                    {
212                        this.func_98184_a(this.missingTextureImage, i, flag, flag1);
213                    }
214                    else
215                    {
216                        BufferedImage bufferedimage = this.readTextureImage(inputstream);
217                        TextureFXManager.instance().fixTransparency(bufferedimage, par1Str);
218                        this.func_98184_a(bufferedimage, i, flag, flag1);
219                    }
220
221                    this.textureMap.put(s1, Integer.valueOf(i));
222                    ForgeHooksClient.onTextureLoad(par1Str, texturePack.getSelectedTexturePack());
223                    return i;
224                }
225                catch (Exception exception)
226                {
227                    exception.printStackTrace();
228                    int j = GLAllocation.generateTextureNames();
229                    this.setupTexture(this.missingTextureImage, j);
230                    this.textureMap.put(par1Str, Integer.valueOf(j));
231                    return j;
232                }
233            }
234        }
235    }
236
237    /**
238     * Copy the supplied image onto a newly-allocated OpenGL texture, returning the allocated texture name
239     */
240    public int allocateAndSetupTexture(BufferedImage par1BufferedImage)
241    {
242        int i = GLAllocation.generateTextureNames();
243        this.setupTexture(par1BufferedImage, i);
244        this.textureNameToImageMap.addKey(i, par1BufferedImage);
245        return i;
246    }
247
248    /**
249     * Copy the supplied image onto the specified OpenGL texture
250     */
251    public void setupTexture(BufferedImage par1BufferedImage, int par2)
252    {
253        this.func_98184_a(par1BufferedImage, par2, false, false);
254    }
255
256    public void func_98184_a(BufferedImage par1BufferedImage, int par2, boolean par3, boolean par4)
257    {
258        this.bindTexture(par2);
259        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
260        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
261
262        if (par3)
263        {
264            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
265            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
266        }
267
268        if (par4)
269        {
270            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP);
271            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP);
272        }
273        else
274        {
275            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
276            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
277        }
278
279        int j = par1BufferedImage.getWidth();
280        int k = par1BufferedImage.getHeight();
281        TextureFXManager.instance().setTextureDimensions(par2, j, k);
282        int[] aint = new int[j * k];
283        par1BufferedImage.getRGB(0, 0, j, k, aint, 0, j);
284
285        if (this.options != null && this.options.anaglyph)
286        {
287            aint = this.func_98186_a(aint);
288        }
289
290        this.imageData.clear();
291        this.imageData.put(aint);
292        this.imageData.position(0).limit(aint.length);
293        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);
294    }
295
296    private int[] func_98186_a(int[] par1ArrayOfInteger)
297    {
298        int[] aint1 = new int[par1ArrayOfInteger.length];
299
300        for (int i = 0; i < par1ArrayOfInteger.length; ++i)
301        {
302            int j = par1ArrayOfInteger[i] >> 24 & 255;
303            int k = par1ArrayOfInteger[i] >> 16 & 255;
304            int l = par1ArrayOfInteger[i] >> 8 & 255;
305            int i1 = par1ArrayOfInteger[i] & 255;
306            int j1 = (k * 30 + l * 59 + i1 * 11) / 100;
307            int k1 = (k * 30 + l * 70) / 100;
308            int l1 = (k * 30 + i1 * 70) / 100;
309            aint1[i] = j << 24 | j1 << 16 | k1 << 8 | l1;
310        }
311
312        return aint1;
313    }
314
315    public void createTextureFromBytes(int[] par1ArrayOfInteger, int par2, int par3, int par4)
316    {
317        this.bindTexture(par4);
318        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
319        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
320        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
321        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
322
323        if (this.options != null && this.options.anaglyph)
324        {
325            par1ArrayOfInteger = this.func_98186_a(par1ArrayOfInteger);
326        }
327
328        this.imageData.clear();
329        this.imageData.put(par1ArrayOfInteger);
330        this.imageData.position(0).limit(par1ArrayOfInteger.length);
331        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);
332    }
333
334    /**
335     * Deletes a single GL texture
336     */
337    public void deleteTexture(int par1)
338    {
339        this.textureNameToImageMap.removeObject(par1);
340        GL11.glDeleteTextures(par1);
341    }
342
343    /**
344     * Takes a URL of a downloadable image and the name of the local image to be used as a fallback.  If the image has
345     * been downloaded, returns the GL texture of the downloaded image, otherwise returns the GL texture of the fallback
346     * image.
347     */
348    public int getTextureForDownloadableImage(String par1Str, String par2Str)
349    {
350        ThreadDownloadImageData threaddownloadimagedata = (ThreadDownloadImageData)this.urlToImageDataMap.get(par1Str);
351
352        if (threaddownloadimagedata != null && threaddownloadimagedata.image != null && !threaddownloadimagedata.textureSetupComplete)
353        {
354            if (threaddownloadimagedata.textureName < 0)
355            {
356                threaddownloadimagedata.textureName = this.allocateAndSetupTexture(threaddownloadimagedata.image);
357            }
358            else
359            {
360                this.setupTexture(threaddownloadimagedata.image, threaddownloadimagedata.textureName);
361            }
362
363            threaddownloadimagedata.textureSetupComplete = true;
364        }
365
366        return threaddownloadimagedata != null && threaddownloadimagedata.textureName >= 0 ? threaddownloadimagedata.textureName : (par2Str == null ? -1 : this.getTexture(par2Str));
367    }
368
369    /**
370     * Checks if urlToImageDataMap has image data for the given key
371     */
372    public boolean hasImageData(String par1Str)
373    {
374        return this.urlToImageDataMap.containsKey(par1Str);
375    }
376
377    /**
378     * Return a ThreadDownloadImageData instance for the given URL.  If it does not already exist, it is created and
379     * uses the passed ImageBuffer.  If it does, its reference count is incremented.
380     */
381    public ThreadDownloadImageData obtainImageData(String par1Str, IImageBuffer par2IImageBuffer)
382    {
383        ThreadDownloadImageData threaddownloadimagedata = (ThreadDownloadImageData)this.urlToImageDataMap.get(par1Str);
384
385        if (threaddownloadimagedata == null)
386        {
387            this.urlToImageDataMap.put(par1Str, new ThreadDownloadImageData(par1Str, par2IImageBuffer));
388        }
389        else
390        {
391            ++threaddownloadimagedata.referenceCount;
392        }
393
394        return threaddownloadimagedata;
395    }
396
397    /**
398     * Decrements the reference count for a given URL, deleting the image data if the reference count hits 0
399     */
400    public void releaseImageData(String par1Str)
401    {
402        ThreadDownloadImageData threaddownloadimagedata = (ThreadDownloadImageData)this.urlToImageDataMap.get(par1Str);
403
404        if (threaddownloadimagedata != null)
405        {
406            --threaddownloadimagedata.referenceCount;
407
408            if (threaddownloadimagedata.referenceCount == 0)
409            {
410                if (threaddownloadimagedata.textureName >= 0)
411                {
412                    this.deleteTexture(threaddownloadimagedata.textureName);
413                }
414
415                this.urlToImageDataMap.remove(par1Str);
416            }
417        }
418    }
419
420    public void updateDynamicTextures()
421    {
422        this.field_94154_l.func_94248_c();
423        this.field_94155_m.func_94248_c();
424    }
425
426    /**
427     * Call setupTexture on all currently-loaded textures again to account for changes in rendering options
428     */
429    public void refreshTextures()
430    {
431        ITexturePack itexturepack = this.texturePack.getSelectedTexturePack();
432        this.func_94152_c();
433        Iterator iterator = this.textureNameToImageMap.getKeySet().iterator();
434        BufferedImage bufferedimage;
435
436        while (iterator.hasNext())
437        {
438            int i = ((Integer)iterator.next()).intValue();
439            bufferedimage = (BufferedImage)this.textureNameToImageMap.lookup(i);
440            this.setupTexture(bufferedimage, i);
441        }
442
443        ThreadDownloadImageData threaddownloadimagedata;
444
445        for (iterator = this.urlToImageDataMap.values().iterator(); iterator.hasNext(); threaddownloadimagedata.textureSetupComplete = false)
446        {
447            threaddownloadimagedata = (ThreadDownloadImageData)iterator.next();
448        }
449
450        iterator = this.textureMap.keySet().iterator();
451        String s;
452
453        while (iterator.hasNext())
454        {
455            s = (String)iterator.next();
456
457            try
458            {
459                int j = ((Integer)this.textureMap.get(s)).intValue();
460                boolean flag = s.startsWith("%blur%");
461
462                if (flag)
463                {
464                    s = s.substring(6);
465                }
466
467                boolean flag1 = s.startsWith("%clamp%");
468
469                if (flag1)
470                {
471                    s = s.substring(7);
472                }
473
474                BufferedImage bufferedimage1 = this.readTextureImage(itexturepack.getResourceAsStream(s));
475                TextureFXManager.instance().fixTransparency(bufferedimage1, s);
476                this.func_98184_a(bufferedimage1, j, flag, flag1);
477            }
478            catch (Exception ioexception)
479            {
480                log.log(Level.INFO,String.format("An error occured reading texture file %s (refreshTexture)", s), ioexception);
481                ioexception.printStackTrace();
482            }
483        }
484
485        iterator = this.textureContentsMap.keySet().iterator();
486
487        while (iterator.hasNext())
488        {
489            s = (String)iterator.next();
490
491            try
492            {
493                bufferedimage = this.readTextureImage(itexturepack.getResourceAsStream(s));
494                TextureFXManager.instance().fixTransparency(bufferedimage, s);
495                this.getImageContents(bufferedimage, (int[])this.textureContentsMap.get(s));
496            }
497            catch (Exception ioexception1)
498            {
499                log.log(Level.INFO,String.format("An error occured reading texture file data %s (refreshTexture)", s), ioexception1);
500                ioexception1.printStackTrace();
501            }
502        }
503
504        Minecraft.getMinecraft().fontRenderer.func_98304_a();
505        Minecraft.getMinecraft().standardGalacticFontRenderer.func_98304_a();
506    }
507
508    /**
509     * Returns a BufferedImage read off the provided input stream.  Args: inputStream
510     */
511    private BufferedImage readTextureImage(InputStream par1InputStream) throws IOException
512    {
513        BufferedImage bufferedimage = ImageIO.read(par1InputStream);
514        par1InputStream.close();
515        return bufferedimage;
516    }
517
518    public void func_94152_c()
519    {
520        this.field_94154_l.func_94247_b();
521        this.field_94155_m.func_94247_b();
522    }
523
524    public Icon func_96448_c(int par1)
525    {
526        switch (par1)
527        {
528            case 0:
529                return this.field_94154_l.func_96455_e();
530            case 1:
531            default:
532                return this.field_94155_m.func_96455_e();
533        }
534    }
535}