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}