001package net.minecraft.client.renderer.texture;
002
003import cpw.mods.fml.relauncher.Side;
004import cpw.mods.fml.relauncher.SideOnly;
005
006import java.awt.image.BufferedImage;
007import java.io.BufferedReader;
008import java.util.ArrayList;
009import java.util.List;
010
011import net.minecraft.client.texturepacks.ITexturePack;
012import net.minecraft.util.Icon;
013import net.minecraft.util.Tuple;
014
015@SideOnly(Side.CLIENT)
016public class TextureStitched implements Icon
017{
018    private final String textureName;
019
020    /** texture sheet containing this texture */
021    protected Texture textureSheet;
022    protected List textureList;
023    private List listAnimationTuples;
024    protected boolean rotated;
025
026    /** x position of this icon on the texture sheet in pixels */
027    protected int originX;
028
029    /** y position of this icon on the texture sheet in pixels */
030    protected int originY;
031
032    /** width of this icon in pixels */
033    private int width;
034
035    /** height of this icon in pixels */
036    private int height;
037    private float minU;
038    private float maxU;
039    private float minV;
040    private float maxV;
041    private float widthNorm;
042    private float heightNorm;
043    protected int frameCounter = 0;
044    protected int tickCounter = 0;
045
046    public static TextureStitched makeTextureStitched(String par0Str)
047    {
048        return (TextureStitched)("clock".equals(par0Str) ? new TextureClock() : ("compass".equals(par0Str) ? new TextureCompass() : new TextureStitched(par0Str)));
049    }
050
051    protected TextureStitched(String par1)
052    {
053        this.textureName = par1;
054    }
055
056    public void init(Texture par1Texture, List par2List, int par3, int par4, int par5, int par6, boolean par7)
057    {
058        this.textureSheet = par1Texture;
059        this.textureList = par2List;
060        this.originX = par3;
061        this.originY = par4;
062        this.width = par5;
063        this.height = par6;
064        this.rotated = par7;
065        float f = 0.01F / (float)par1Texture.getWidth();
066        float f1 = 0.01F / (float)par1Texture.getHeight();
067        this.minU = (float)par3 / (float)par1Texture.getWidth() + f;
068        this.maxU = (float)(par3 + par5) / (float)par1Texture.getWidth() - f;
069        this.minV = (float)par4 / (float)par1Texture.getHeight() + f1;
070        this.maxV = (float)(par4 + par6) / (float)par1Texture.getHeight() - f1;
071        this.widthNorm = (float)par5 / 16.0F;
072        this.heightNorm = (float)par6 / 16.0F;
073    }
074
075    public void copyFrom(TextureStitched par1TextureStitched)
076    {
077        this.init(par1TextureStitched.textureSheet, par1TextureStitched.textureList, par1TextureStitched.originX, par1TextureStitched.originY, par1TextureStitched.width, par1TextureStitched.height, par1TextureStitched.rotated);
078    }
079
080    /**
081     * Returns the X position of this icon on its texture sheet, in pixels.
082     */
083    public int getOriginX()
084    {
085        return this.originX;
086    }
087
088    /**
089     * Returns the Y position of this icon on its texture sheet, in pixels.
090     */
091    public int getOriginY()
092    {
093        return this.originY;
094    }
095
096    /**
097     * Returns the minimum U coordinate to use when rendering with this icon.
098     */
099    public float getMinU()
100    {
101        return this.minU;
102    }
103
104    /**
105     * Returns the maximum U coordinate to use when rendering with this icon.
106     */
107    public float getMaxU()
108    {
109        return this.maxU;
110    }
111
112    /**
113     * Gets a U coordinate on the icon. 0 returns uMin and 16 returns uMax. Other arguments return in-between values.
114     */
115    public float getInterpolatedU(double par1)
116    {
117        float f = this.maxU - this.minU;
118        return this.minU + f * ((float)par1 / 16.0F);
119    }
120
121    /**
122     * Returns the minimum V coordinate to use when rendering with this icon.
123     */
124    public float getMinV()
125    {
126        return this.minV;
127    }
128
129    /**
130     * Returns the maximum V coordinate to use when rendering with this icon.
131     */
132    public float getMaxV()
133    {
134        return this.maxV;
135    }
136
137    /**
138     * Gets a V coordinate on the icon. 0 returns vMin and 16 returns vMax. Other arguments return in-between values.
139     */
140    public float getInterpolatedV(double par1)
141    {
142        float f = this.maxV - this.minV;
143        return this.minV + f * ((float)par1 / 16.0F);
144    }
145
146    public String getIconName()
147    {
148        return this.textureName;
149    }
150
151    /**
152     * Returns the width of the texture sheet this icon is on, in pixels.
153     */
154    public int getSheetWidth()
155    {
156        return this.textureSheet.getWidth();
157    }
158
159    /**
160     * Returns the height of the texture sheet this icon is on, in pixels.
161     */
162    public int getSheetHeight()
163    {
164        return this.textureSheet.getHeight();
165    }
166
167    public void updateAnimation()
168    {
169        if (this.listAnimationTuples != null)
170        {
171            Tuple tuple = (Tuple)this.listAnimationTuples.get(this.frameCounter);
172            ++this.tickCounter;
173
174            if (this.tickCounter >= ((Integer)tuple.getSecond()).intValue())
175            {
176                int i = ((Integer)tuple.getFirst()).intValue();
177                this.frameCounter = (this.frameCounter + 1) % this.listAnimationTuples.size();
178                this.tickCounter = 0;
179                tuple = (Tuple)this.listAnimationTuples.get(this.frameCounter);
180                int j = ((Integer)tuple.getFirst()).intValue();
181
182                if (i != j && j >= 0 && j < this.textureList.size())
183                {
184                    this.textureSheet.copyFrom(this.originX, this.originY, (Texture)this.textureList.get(j), this.rotated);
185                }
186            }
187        }
188        else
189        {
190            int k = this.frameCounter;
191            this.frameCounter = (this.frameCounter + 1) % this.textureList.size();
192
193            if (k != this.frameCounter)
194            {
195                this.textureSheet.copyFrom(this.originX, this.originY, (Texture)this.textureList.get(this.frameCounter), this.rotated);
196            }
197        }
198    }
199
200    public void readAnimationInfo(BufferedReader par1BufferedReader)
201    {
202        ArrayList arraylist = new ArrayList();
203
204        try
205        {
206            for (String s = par1BufferedReader.readLine(); s != null; s = par1BufferedReader.readLine())
207            {
208                s = s.trim();
209
210                if (s.length() > 0)
211                {
212                    String[] astring = s.split(",");
213                    String[] astring1 = astring;
214                    int i = astring.length;
215
216                    for (int j = 0; j < i; ++j)
217                    {
218                        String s1 = astring1[j];
219                        int k = s1.indexOf(42);
220
221                        if (k > 0)
222                        {
223                            Integer integer = new Integer(s1.substring(0, k));
224                            Integer integer1 = new Integer(s1.substring(k + 1));
225                            arraylist.add(new Tuple(integer, integer1));
226                        }
227                        else
228                        {
229                            arraylist.add(new Tuple(new Integer(s1), Integer.valueOf(1)));
230                        }
231                    }
232                }
233            }
234        }
235        catch (Exception exception)
236        {
237            System.err.println("Failed to read animation info for " + this.textureName + ": " + exception.getMessage());
238        }
239
240        if (!arraylist.isEmpty() && arraylist.size() < 600)
241        {
242            this.listAnimationTuples = arraylist;
243        }
244    }
245
246    //===================================================================================================
247    //                                           Forge Start
248    //===================================================================================================
249    /**
250     * Called when texture packs are refreshed, from TextureManager.createNewTexture,
251     * allows for finer control over loading the animation lists and verification of the image.
252     * If the return value from this is true, no further loading will be done by vanilla code.
253     * 
254     * You need to add all Texture's to the textures argument. At the end of this function at least one
255     * entry should be in that argument, or a error should of been thrown.
256     * 
257     * @param manager The invoking manager
258     * @param texturepack Current texture pack
259     * @param name The name of the texture
260     * @param fileName Resource path for this texture
261     * @param image Buffered image of the loaded resource
262     * @param textures ArrayList of element type Texture, split textures should be added to this list for the stitcher to handle.  
263     * @return Return true to skip further vanilla texture loading for this texture
264     */
265    public boolean loadTexture(TextureManager manager, ITexturePack texturepack, String name, String fileName, BufferedImage image, ArrayList textures)
266    {
267        return false;
268    }
269}