    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}