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}