    001package net.minecraft.client.renderer.texture;
    002
    003import cpw.mods.fml.relauncher.Side;
    004import cpw.mods.fml.relauncher.SideOnly;
    005import java.util.ArrayList;
    006import java.util.Arrays;
    007import java.util.HashSet;
    008import java.util.Iterator;
    009import java.util.List;
    010import java.util.Set;
    011import net.minecraft.client.renderer.StitcherException;
    012
    013@SideOnly(Side.CLIENT)
    014public class Stitcher
    015{
    016    private final Set setStitchHolders;
    017    private final List stitchSlots;
    018    private int currentWidth;
    019    private int currentHeight;
    020    private final int maxWidth;
    021    private final int maxHeight;
    022    private final boolean forcePowerOf2;
    023
    024    /** Max size (width or height) of a single tile */
    025    private final int maxTileDimension;
    026    private Texture atlasTexture;
    027    private final String textureName;
    028
    029    public Stitcher(String par1Str, int par2, int par3, boolean par4)
    030    {
    031        this(par1Str, par2, par3, par4, 0);
    032    }
    033
    034    public Stitcher(String par1, int par2, int par3, boolean par4, int par5)
    035    {
    036        this.setStitchHolders = new HashSet(256);
    037        this.stitchSlots = new ArrayList(256);
    038        this.currentWidth = 0;
    039        this.currentHeight = 0;
    040        this.textureName = par1;
    041        this.maxWidth = par2;
    042        this.maxHeight = par3;
    043        this.forcePowerOf2 = par4;
    044        this.maxTileDimension = par5;
    045    }
    046
    047    public void addStitchHolder(StitchHolder par1StitchHolder)
    048    {
    049        if (this.maxTileDimension > 0)
    050        {
    051            par1StitchHolder.setNewDimension(this.maxTileDimension);
    052        }
    053
    054        this.setStitchHolders.add(par1StitchHolder);
    055    }
    056
    057    public Texture getTexture()
    058    {
    059        if (this.forcePowerOf2)
    060        {
    061            this.currentWidth = this.getCeilPowerOf2(this.currentWidth);
    062            this.currentHeight = this.getCeilPowerOf2(this.currentHeight);
    063        }
    064
    065        this.atlasTexture = TextureManager.instance().createEmptyTexture(this.textureName, 1, this.currentWidth, this.currentHeight, 6408);
    066        this.atlasTexture.fillRect(this.atlasTexture.getTextureRect(), -65536);
    067        List list = this.getStichSlots();
    068
    069        for (int i = 0; i < list.size(); ++i)
    070        {
    071            StitchSlot stitchslot = (StitchSlot)list.get(i);
    072            StitchHolder stitchholder = stitchslot.getStitchHolder();
    073            this.atlasTexture.copyFrom(stitchslot.getOriginX(), stitchslot.getOriginY(), stitchholder.func_98150_a(), stitchholder.isRotated());
    074        }
    075
    076        TextureManager.instance().registerTexture(this.textureName, this.atlasTexture);
    077        return this.atlasTexture;
    078    }
    079
    080    public void doStitch()
    081    {
    082        StitchHolder[] astitchholder = (StitchHolder[])this.setStitchHolders.toArray(new StitchHolder[this.setStitchHolders.size()]);
    083        Arrays.sort(astitchholder);
    084        this.atlasTexture = null;
    085
    086        for (int i = 0; i < astitchholder.length; ++i)
    087        {
    088            StitchHolder stitchholder = astitchholder[i];
    089
    090            if (!this.allocateSlot(stitchholder))
    091            {
    092                throw new StitcherException(stitchholder);
    093            }
    094        }
    095    }
    096
    097    public List getStichSlots()
    098    {
    099        ArrayList arraylist = new ArrayList();
    100        Iterator iterator = this.stitchSlots.iterator();
    101
    102        while (iterator.hasNext())
    103        {
    104            StitchSlot stitchslot = (StitchSlot)iterator.next();
    105            stitchslot.getAllStitchSlots(arraylist);
    106        }
    107
    108        return arraylist;
    109    }
    110
    111    /**
    112     * Returns power of 2 >= the specified value
    113     */
    114    private int getCeilPowerOf2(int par1)
    115    {
    116        int j = par1 - 1;
    117        j |= j >> 1;
    118        j |= j >> 2;
    119        j |= j >> 4;
    120        j |= j >> 8;
    121        j |= j >> 16;
    122        return j + 1;
    123    }
    124
    125    /**
    126     * Attempts to find space for specified tile
    127     */
    128    private boolean allocateSlot(StitchHolder par1StitchHolder)
    129    {
    130        for (int i = 0; i < this.stitchSlots.size(); ++i)
    131        {
    132            if (((StitchSlot)this.stitchSlots.get(i)).func_94182_a(par1StitchHolder))
    133            {
    134                return true;
    135            }
    136
    137            par1StitchHolder.rotate();
    138
    139            if (((StitchSlot)this.stitchSlots.get(i)).func_94182_a(par1StitchHolder))
    140            {
    141                return true;
    142            }
    143
    144            par1StitchHolder.rotate();
    145        }
    146
    147        return this.expandAndAllocateSlot(par1StitchHolder);
    148    }
    149
    150    /**
    151     * Expand stitched texture in order to make space for specified tile
    152     */
    153    private boolean expandAndAllocateSlot(StitchHolder par1StitchHolder)
    154    {
    155        int i = Math.min(par1StitchHolder.getHeight(), par1StitchHolder.getWidth());
    156        boolean flag = this.currentWidth == 0 && this.currentHeight == 0;
    157        boolean flag1;
    158
    159        if (this.forcePowerOf2)
    160        {
    161            int j = this.getCeilPowerOf2(this.currentWidth);
    162            int k = this.getCeilPowerOf2(this.currentHeight);
    163            int l = this.getCeilPowerOf2(this.currentWidth + i);
    164            int i1 = this.getCeilPowerOf2(this.currentHeight + i);
    165            boolean flag2 = l <= this.maxWidth;
    166            boolean flag3 = i1 <= this.maxHeight;
    167
    168            if (!flag2 && !flag3)
    169            {
    170                return false;
    171            }
    172
    173            int j1 = Math.max(par1StitchHolder.getHeight(), par1StitchHolder.getWidth());
    174
    175            if (flag && !flag2 && this.getCeilPowerOf2(this.currentHeight + j1) > this.maxHeight)
    176            {
    177                return false;
    178            }
    179
    180            boolean flag4 = j != l;
    181            boolean flag5 = k != i1;
    182
    183            if (flag4 ^ flag5)
    184            {
    185                flag1 = flag5 && flag3; //Forge: Bug fix: Attempt to fill all downward space before expanding width
    186            }
    187            else
    188            {
    189                flag1 = flag2 && j <= k;
    190            }
    191        }
    192        else
    193        {
    194            boolean flag6 = this.currentWidth + i <= this.maxWidth;
    195            boolean flag7 = this.currentHeight + i <= this.maxHeight;
    196
    197            if (!flag6 && !flag7)
    198            {
    199                return false;
    200            }
    201
    202            flag1 = (flag || this.currentWidth <= this.currentHeight) && flag6;
    203        }
    204
    205        StitchSlot stitchslot;
    206
    207        if (flag1)
    208        {
    209            if (par1StitchHolder.getWidth() > par1StitchHolder.getHeight())
    210            {
    211                par1StitchHolder.rotate();
    212            }
    213
    214            if (this.currentHeight == 0)
    215            {
    216                this.currentHeight = par1StitchHolder.getHeight();
    217            }
    218
    219            stitchslot = new StitchSlot(this.currentWidth, 0, par1StitchHolder.getWidth(), this.currentHeight);
    220            this.currentWidth += par1StitchHolder.getWidth();
    221        }
    222        else
    223        {
    224            stitchslot = new StitchSlot(0, this.currentHeight, this.currentWidth, par1StitchHolder.getHeight());
    225            this.currentHeight += par1StitchHolder.getHeight();
    226        }
    227
    228        stitchslot.func_94182_a(par1StitchHolder);
    229        this.stitchSlots.add(stitchslot);
    230        return true;
    231    }
    232}