001package net.minecraft.client.renderer.texture;
002
003import cpw.mods.fml.client.TextureFXManager;
004import cpw.mods.fml.relauncher.Side;
005import cpw.mods.fml.relauncher.SideOnly;
006import java.awt.image.BufferedImage;
007import java.io.File;
008import java.io.IOException;
009import java.nio.ByteBuffer;
010import javax.imageio.ImageIO;
011import net.minecraft.client.Minecraft;
012import net.minecraft.client.renderer.OpenGlHelper;
013import net.minecraft.src.FMLRenderAccessLibrary;
014
015import org.lwjgl.opengl.GL11;
016import org.lwjgl.opengl.GL12;
017
018@SideOnly(Side.CLIENT)
019public class Texture
020{
021    private int glTextureId;
022    private int textureId;
023    private int textureType;
024
025    /** Width of this texture in pixels. */
026    private final int width;
027
028    /** Height of this texture in pixels. */
029    private final int height;
030    private final int textureDepth;
031    private final int textureFormat;
032    private final int textureTarget;
033    private final int textureMinFilter;
034    private final int textureMagFilter;
035    private final int textureWrap;
036    private final boolean mipmapActive;
037    private final String textureName;
038    private Rect2i textureRect;
039    private boolean transferred;
040
041    /**
042     * Uninitialized boolean. If true, the texture is re-uploaded every time it's modified. If false, every tick after
043     * it's been modified at least once in that tick.
044     */
045    private boolean autoCreate;
046
047    /**
048     * False if the texture has been modified since it was last uploaded to the GPU.
049     */
050    private boolean textureNotModified;
051    private ByteBuffer textureData;
052
053    private Texture(String par1Str, int par2, int par3, int par4, int par5, int par6, int par7, int par8, int par9)
054    {
055        this.textureName = par1Str;
056        this.textureType = par2;
057        this.width = par3;
058        this.height = par4;
059        this.textureDepth = par5;
060        this.textureFormat = par7;
061        this.textureMinFilter = par8;
062        this.textureMagFilter = par9;
063        this.textureWrap = par6;
064        this.textureRect = new Rect2i(0, 0, par3, par4);
065
066        if (par4 == 1 && par5 == 1)
067        {
068            this.textureTarget = 3552;
069        }
070        else if (par5 == 1)
071        {
072            this.textureTarget = 3553;
073        }
074        else
075        {
076            this.textureTarget = 32879;
077        }
078
079        this.mipmapActive = par8 != 9728 && par8 != 9729 || par9 != 9728 && par9 != 9729;
080
081        if (par2 != 2)
082        {
083            this.glTextureId = GL11.glGenTextures();
084            GL11.glBindTexture(this.textureTarget, this.glTextureId);
085            GL11.glTexParameteri(this.textureTarget, GL11.GL_TEXTURE_MIN_FILTER, par8);
086            GL11.glTexParameteri(this.textureTarget, GL11.GL_TEXTURE_MAG_FILTER, par9);
087            GL11.glTexParameteri(this.textureTarget, GL11.GL_TEXTURE_WRAP_S, par6);
088            GL11.glTexParameteri(this.textureTarget, GL11.GL_TEXTURE_WRAP_T, par6);
089        }
090        else
091        {
092            this.glTextureId = -1;
093        }
094
095        this.textureId = TextureManager.instance().getNextTextureId();
096    }
097
098    public Texture(String par1Str, int par2, int par3, int par4, int par5, int par6, int par7, int par8, BufferedImage par9BufferedImage)
099    {
100        this(par1Str, par2, par3, par4, 1, par5, par6, par7, par8, par9BufferedImage);
101    }
102
103    public Texture(String par1Str, int par2, int par3, int par4, int par5, int par6, int par7, int par8, int par9, BufferedImage par10BufferedImage)
104    {
105        this(par1Str, par2, par3, par4, par5, par6, par7, par8, par9);
106
107        if (par10BufferedImage == null)
108        {
109            if (par3 != -1 && par4 != -1)
110            {
111                byte[] abyte = new byte[par3 * par4 * par5 * 4];
112
113                for (int i2 = 0; i2 < abyte.length; ++i2)
114                {
115                    abyte[i2] = 0;
116                }
117
118                this.textureData = ByteBuffer.allocateDirect(abyte.length);
119                this.textureData.clear();
120                this.textureData.put(abyte);
121                this.textureData.position(0).limit(abyte.length);
122
123                if (this.autoCreate)
124                {
125                    this.uploadTexture();
126                }
127                else
128                {
129                    this.textureNotModified = false;
130                }
131            }
132            else
133            {
134                this.transferred = false;
135            }
136        }
137        else
138        {
139            this.transferred = true;
140            this.transferFromImage(par10BufferedImage);
141
142            if (par2 != 2)
143            {
144                this.uploadTexture();
145                this.autoCreate = false;
146            }
147        }
148    }
149
150    public final Rect2i getTextureRect()
151    {
152        return this.textureRect;
153    }
154
155    public void fillRect(Rect2i par1Rect2i, int par2)
156    {
157        if (this.textureTarget != 32879)
158        {
159            Rect2i rect2i1 = new Rect2i(0, 0, this.width, this.height);
160            rect2i1.intersection(par1Rect2i);
161            this.textureData.position(0);
162
163            for (int j = rect2i1.getRectY(); j < rect2i1.getRectY() + rect2i1.getRectHeight(); ++j)
164            {
165                int k = j * this.width * 4;
166
167                for (int l = rect2i1.getRectX(); l < rect2i1.getRectX() + rect2i1.getRectWidth(); ++l)
168                {
169                    this.textureData.put(k + l * 4 + 0, (byte)(par2 >> 24 & 255));
170                    this.textureData.put(k + l * 4 + 1, (byte)(par2 >> 16 & 255));
171                    this.textureData.put(k + l * 4 + 2, (byte)(par2 >> 8 & 255));
172                    this.textureData.put(k + l * 4 + 3, (byte)(par2 >> 0 & 255));
173                }
174            }
175
176            if (this.autoCreate)
177            {
178                this.uploadTexture();
179            }
180            else
181            {
182                this.textureNotModified = false;
183            }
184        }
185    }
186
187    public void writeImage(String par1Str)
188    {
189        BufferedImage bufferedimage = new BufferedImage(this.width, this.height, 2);
190        ByteBuffer bytebuffer = this.getTextureData();
191        byte[] abyte = new byte[this.width * this.height * 4];
192        bytebuffer.position(0);
193        bytebuffer.get(abyte);
194
195        for (int i = 0; i < this.width; ++i)
196        {
197            for (int j = 0; j < this.height; ++j)
198            {
199                int k = j * this.width * 4 + i * 4;
200                byte b0 = 0;
201                int l = b0 | (abyte[k + 2] & 255) << 0;
202                l |= (abyte[k + 1] & 255) << 8;
203                l |= (abyte[k + 0] & 255) << 16;
204                l |= (abyte[k + 3] & 255) << 24;
205                bufferedimage.setRGB(i, j, l);
206            }
207        }
208
209        this.textureData.position(this.width * this.height * 4);
210
211        try
212        {
213            ImageIO.write(bufferedimage, "png", new File(Minecraft.getMinecraftDir(), par1Str));
214        }
215        catch (IOException ioexception)
216        {
217            ioexception.printStackTrace();
218        }
219    }
220
221    public void copyFrom(int par1, int par2, Texture par3Texture, boolean par4)
222    {
223        if (this.textureTarget != 32879)
224        {
225            if (textureNotModified && !par4)
226            {
227                FMLRenderAccessLibrary.doTextureCopy(this, par3Texture, par1, par2);
228                return;
229            }
230
231            ByteBuffer bytebuffer = par3Texture.getTextureData();
232            this.textureData.position(0);
233            bytebuffer.position(0);
234
235            for (int k = 0; k < par3Texture.getHeight(); ++k)
236            {
237                int l = par2 + k;
238                int i1 = k * par3Texture.getWidth() * 4;
239                int j1 = l * this.width * 4;
240
241                if (par4)
242                {
243                    l = par1 + (par3Texture.getHeight() - k - 1); //BUGFIX: targetY -> targetX and -1
244                }
245
246                for (int k1 = 0; k1 < par3Texture.getWidth(); ++k1)
247                {
248                    int l1 = j1 + (k1 + par1) * 4;
249                    int i2 = i1 + k1 * 4;
250
251                    if (par4)
252                    {
253                        l1 = (par2 + k1) * this.width * 4 + l * 4; //BUGFIX: targetX -> targetY and parens
254                    }
255
256                    this.textureData.put(l1 + 0, bytebuffer.get(i2 + 0));
257                    this.textureData.put(l1 + 1, bytebuffer.get(i2 + 1));
258                    this.textureData.put(l1 + 2, bytebuffer.get(i2 + 2));
259                    this.textureData.put(l1 + 3, bytebuffer.get(i2 + 3));
260                }
261            }
262
263            this.textureData.position(this.width * this.height * 4);
264
265            if (this.autoCreate)
266            {
267                this.uploadTexture();
268            }
269            else
270            {
271                this.textureNotModified = false;
272            }
273        }
274    }
275
276    public void transferFromImage(BufferedImage par1BufferedImage)
277    {
278        if (this.textureTarget != 32879)
279        {
280            int i = par1BufferedImage.getWidth();
281            int j = par1BufferedImage.getHeight();
282
283            if (i <= this.width && j <= this.height)
284            {
285                int[] aint = new int[] {3, 0, 1, 2};
286                int[] aint1 = new int[] {3, 2, 1, 0};
287                int[] aint2 = this.textureFormat == 32993 ? aint1 : aint;
288                int[] aint3 = new int[this.width * this.height];
289                int k = par1BufferedImage.getTransparency();
290                par1BufferedImage.getRGB(0, 0, this.width, this.height, aint3, 0, i);
291                byte[] abyte = new byte[this.width * this.height * 4];
292
293                for (int l = 0; l < this.height; ++l)
294                {
295                    for (int i1 = 0; i1 < this.width; ++i1)
296                    {
297                        int j1 = l * this.width + i1;
298                        int k1 = j1 * 4;
299                        abyte[k1 + aint2[0]] = (byte)(aint3[j1] >> 24 & 255);
300                        abyte[k1 + aint2[1]] = (byte)(aint3[j1] >> 16 & 255);
301                        abyte[k1 + aint2[2]] = (byte)(aint3[j1] >> 8 & 255);
302                        abyte[k1 + aint2[3]] = (byte)(aint3[j1] >> 0 & 255);
303                    }
304                }
305
306                this.textureData = ByteBuffer.allocateDirect(abyte.length);
307                this.textureData.clear();
308                this.textureData.put(abyte);
309                this.textureData.limit(abyte.length);
310
311                if (this.autoCreate)
312                {
313                    this.uploadTexture();
314                }
315                else
316                {
317                    this.textureNotModified = false;
318                }
319            }
320            else
321            {
322                Minecraft.getMinecraft().getLogAgent().logWarning("transferFromImage called with a BufferedImage with dimensions (" + i + ", " + j + ") larger than the Texture dimensions (" + this.width + ", " + this.height + "). Ignoring.");
323            }
324        }
325    }
326
327    public int getTextureId()
328    {
329        return this.textureId;
330    }
331
332    public int getGlTextureId()
333    {
334        return this.glTextureId;
335    }
336
337    public int getWidth()
338    {
339        return this.width;
340    }
341
342    public int getHeight()
343    {
344        return this.height;
345    }
346
347    public String getTextureName()
348    {
349        return this.textureName;
350    }
351
352    public void bindTexture(int par1)
353    {
354        if (this.textureDepth == 1)
355        {
356            GL11.glEnable(GL11.GL_TEXTURE_2D);
357        }
358        else
359        {
360            GL11.glEnable(GL12.GL_TEXTURE_3D);
361        }
362
363        OpenGlHelper.setActiveTexture(OpenGlHelper.defaultTexUnit + par1);
364        GL11.glBindTexture(this.textureTarget, this.glTextureId);
365
366        if (!this.textureNotModified)
367        {
368            this.uploadTexture();
369        }
370    }
371
372    public void uploadTexture()
373    {
374        this.textureData.flip();
375
376        if (this.height != 1 && this.textureDepth != 1)
377        {
378            GL12.glTexImage3D(this.textureTarget, 0, this.textureFormat, this.width, this.height, this.textureDepth, 0, this.textureFormat, GL11.GL_UNSIGNED_BYTE, this.textureData);
379        }
380        else if (this.height != 1)
381        {
382            GL11.glTexImage2D(this.textureTarget, 0, this.textureFormat, this.width, this.height, 0, this.textureFormat, GL11.GL_UNSIGNED_BYTE, this.textureData);
383        }
384        else
385        {
386            GL11.glTexImage1D(this.textureTarget, 0, this.textureFormat, this.width, 0, this.textureFormat, GL11.GL_UNSIGNED_BYTE, this.textureData);
387        }
388
389        this.textureNotModified = true;
390    }
391
392    public ByteBuffer getTextureData()
393    {
394        return this.textureData;
395    }
396
397    public void createAndUploadTexture()
398    {
399        this.glTextureId = GL11.glGenTextures();
400        GL11.glBindTexture(this.textureTarget, this.glTextureId);
401        System.out.printf("Buffer %s %x %d is %s\n",textureName, textureTarget, glTextureId, textureData);
402        textureData.position(textureData.limit());
403        uploadTexture();
404    }
405}