001 package net.minecraft.src; 002 003 import cpw.mods.fml.common.Side; 004 import cpw.mods.fml.common.asm.SideOnly; 005 import java.awt.Color; 006 import java.awt.Dimension; 007 import java.awt.Graphics; 008 import java.awt.image.BufferedImage; 009 import java.awt.image.ImageObserver; 010 import java.io.IOException; 011 import java.io.InputStream; 012 import java.nio.ByteBuffer; 013 import java.nio.IntBuffer; 014 import java.util.ArrayList; 015 import java.util.HashMap; 016 import java.util.Iterator; 017 import java.util.List; 018 import java.util.Map; 019 import java.util.logging.Level; 020 import java.util.logging.Logger; 021 022 import javax.imageio.ImageIO; 023 024 import net.minecraftforge.client.ForgeHooksClient; 025 026 import org.lwjgl.opengl.GL11; 027 028 import cpw.mods.fml.client.TextureFXManager; 029 import cpw.mods.fml.common.FMLLog; 030 031 @SideOnly(Side.CLIENT) 032 public class RenderEngine 033 { 034 private HashMap textureMap = new HashMap(); 035 036 /** Texture contents map (key: texture name, value: int[] contents) */ 037 private HashMap textureContentsMap = new HashMap(); 038 039 /** A mapping from GL texture names (integers) to BufferedImage instances */ 040 private IntHashMap textureNameToImageMap = new IntHashMap(); 041 042 /** An IntBuffer storing 1 int used as scratch space in RenderEngine */ 043 private IntBuffer singleIntBuffer = GLAllocation.createDirectIntBuffer(1); 044 045 /** Stores the image data for the texture. */ 046 private ByteBuffer imageData = GLAllocation.createDirectByteBuffer(16777216); 047 public List textureList = new ArrayList(); 048 049 /** A mapping from image URLs to ThreadDownloadImageData instances */ 050 private Map urlToImageDataMap = new HashMap(); 051 052 /** Reference to the GameSettings object */ 053 private GameSettings options; 054 055 /** Flag set when a texture should not be repeated */ 056 public boolean clampTexture = false; 057 058 /** Flag set when a texture should use blurry resizing */ 059 public boolean blurTexture = false; 060 061 /** Texture pack */ 062 public TexturePackList texturePack; 063 064 /** Missing texture image */ 065 private BufferedImage missingTextureImage = new BufferedImage(64, 64, 2); 066 public static Logger log = FMLLog.getLogger(); 067 068 public RenderEngine(TexturePackList par1TexturePackList, GameSettings par2GameSettings) 069 { 070 this.texturePack = par1TexturePackList; 071 this.options = par2GameSettings; 072 Graphics var3 = this.missingTextureImage.getGraphics(); 073 var3.setColor(Color.WHITE); 074 var3.fillRect(0, 0, 64, 64); 075 var3.setColor(Color.BLACK); 076 var3.drawString("missingtex", 1, 10); 077 var3.dispose(); 078 } 079 080 public int[] getTextureContents(String par1Str) 081 { 082 ITexturePack var2 = this.texturePack.getSelectedTexturePack(); 083 int[] var3 = (int[])this.textureContentsMap.get(par1Str); 084 085 if (var3 != null) 086 { 087 return var3; 088 } 089 else 090 { 091 try 092 { 093 Object var4 = null; 094 int[] var7; 095 096 if (par1Str.startsWith("##")) 097 { 098 var7 = this.getImageContentsAndAllocate(this.unwrapImageByColumns(this.readTextureImage(var2.getResourceAsStream(par1Str.substring(2))))); 099 } 100 else if (par1Str.startsWith("%clamp%")) 101 { 102 this.clampTexture = true; 103 var7 = this.getImageContentsAndAllocate(this.readTextureImage(var2.getResourceAsStream(par1Str.substring(7)))); 104 this.clampTexture = false; 105 } 106 else if (par1Str.startsWith("%blur%")) 107 { 108 this.blurTexture = true; 109 this.clampTexture = true; 110 var7 = this.getImageContentsAndAllocate(this.readTextureImage(var2.getResourceAsStream(par1Str.substring(6)))); 111 this.clampTexture = false; 112 this.blurTexture = false; 113 } 114 else 115 { 116 InputStream var8 = var2.getResourceAsStream(par1Str); 117 118 if (var8 == null) 119 { 120 var7 = this.getImageContentsAndAllocate(this.missingTextureImage); 121 } 122 else 123 { 124 var7 = this.getImageContentsAndAllocate(this.readTextureImage(var8)); 125 } 126 } 127 128 this.textureContentsMap.put(par1Str, var7); 129 return var7; 130 } 131 catch (Exception var6) 132 { 133 log.log(Level.INFO, String.format("An error occured reading texture file %s (getTexture)", par1Str), var6); 134 var6.printStackTrace(); 135 int[] var5 = this.getImageContentsAndAllocate(this.missingTextureImage); 136 this.textureContentsMap.put(par1Str, var5); 137 return var5; 138 } 139 } 140 } 141 142 private int[] getImageContentsAndAllocate(BufferedImage par1BufferedImage) 143 { 144 int var2 = par1BufferedImage.getWidth(); 145 int var3 = par1BufferedImage.getHeight(); 146 int[] var4 = new int[var2 * var3]; 147 par1BufferedImage.getRGB(0, 0, var2, var3, var4, 0, var2); 148 return var4; 149 } 150 151 private int[] getImageContents(BufferedImage par1BufferedImage, int[] par2ArrayOfInteger) 152 { 153 int var3 = par1BufferedImage.getWidth(); 154 int var4 = par1BufferedImage.getHeight(); 155 par1BufferedImage.getRGB(0, 0, var3, var4, par2ArrayOfInteger, 0, var3); 156 return par2ArrayOfInteger; 157 } 158 159 public int getTexture(String par1Str) 160 { 161 Integer var2 = (Integer)this.textureMap.get(par1Str); 162 163 if (var2 != null) 164 { 165 return var2.intValue(); 166 } 167 else 168 { 169 ITexturePack var6 = this.texturePack.getSelectedTexturePack(); 170 171 try 172 { 173 ForgeHooksClient.onTextureLoadPre(par1Str); 174 this.singleIntBuffer.clear(); 175 GLAllocation.generateTextureNames(this.singleIntBuffer); 176 int var3 = this.singleIntBuffer.get(0); 177 178 if (par1Str.startsWith("##")) 179 { 180 this.setupTexture(this.unwrapImageByColumns(this.readTextureImage(var6.getResourceAsStream(par1Str.substring(2)))), var3); 181 } 182 else if (par1Str.startsWith("%clamp%")) 183 { 184 this.clampTexture = true; 185 this.setupTexture(this.readTextureImage(var6.getResourceAsStream(par1Str.substring(7))), var3); 186 this.clampTexture = false; 187 } 188 else if (par1Str.startsWith("%blur%")) 189 { 190 this.blurTexture = true; 191 this.setupTexture(this.readTextureImage(var6.getResourceAsStream(par1Str.substring(6))), var3); 192 this.blurTexture = false; 193 } 194 else if (par1Str.startsWith("%blurclamp%")) 195 { 196 this.blurTexture = true; 197 this.clampTexture = true; 198 this.setupTexture(this.readTextureImage(var6.getResourceAsStream(par1Str.substring(11))), var3); 199 this.blurTexture = false; 200 this.clampTexture = false; 201 } 202 else 203 { 204 InputStream var7 = var6.getResourceAsStream(par1Str); 205 206 if (var7 == null) 207 { 208 this.setupTexture(this.missingTextureImage, var3); 209 } 210 else 211 { 212 this.setupTexture(this.readTextureImage(var7), var3); 213 } 214 } 215 216 this.textureMap.put(par1Str, Integer.valueOf(var3)); 217 ForgeHooksClient.onTextureLoad(par1Str, var6); 218 return var3; 219 } 220 catch (Exception var5) 221 { 222 var5.printStackTrace(); 223 GLAllocation.generateTextureNames(this.singleIntBuffer); 224 int var4 = this.singleIntBuffer.get(0); 225 this.setupTexture(this.missingTextureImage, var4); 226 this.textureMap.put(par1Str, Integer.valueOf(var4)); 227 return var4; 228 } 229 } 230 } 231 232 /** 233 * Takes an image with multiple 16-pixel-wide columns and creates a new 16-pixel-wide image where the columns are 234 * stacked vertically 235 */ 236 private BufferedImage unwrapImageByColumns(BufferedImage par1BufferedImage) 237 { 238 int var2 = par1BufferedImage.getWidth() / 16; 239 BufferedImage var3 = new BufferedImage(16, par1BufferedImage.getHeight() * var2, 2); 240 Graphics var4 = var3.getGraphics(); 241 242 for (int var5 = 0; var5 < var2; ++var5) 243 { 244 var4.drawImage(par1BufferedImage, -var5 * 16, var5 * par1BufferedImage.getHeight(), (ImageObserver)null); 245 } 246 247 var4.dispose(); 248 return var3; 249 } 250 251 /** 252 * Copy the supplied image onto a newly-allocated OpenGL texture, returning the allocated texture name 253 */ 254 public int allocateAndSetupTexture(BufferedImage par1BufferedImage) 255 { 256 this.singleIntBuffer.clear(); 257 GLAllocation.generateTextureNames(this.singleIntBuffer); 258 int var2 = this.singleIntBuffer.get(0); 259 this.setupTexture(par1BufferedImage, var2); 260 this.textureNameToImageMap.addKey(var2, par1BufferedImage); 261 return var2; 262 } 263 264 /** 265 * Copy the supplied image onto the specified OpenGL texture 266 */ 267 public void setupTexture(BufferedImage par1BufferedImage, int par2) 268 { 269 GL11.glBindTexture(GL11.GL_TEXTURE_2D, par2); 270 GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); 271 GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); 272 273 if (this.blurTexture) 274 { 275 GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); 276 GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); 277 } 278 279 if (this.clampTexture) 280 { 281 GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP); 282 GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP); 283 } 284 else 285 { 286 GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); 287 GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); 288 } 289 290 int var3 = par1BufferedImage.getWidth(); 291 int var4 = par1BufferedImage.getHeight(); 292 TextureFXManager.instance().setTextureDimensions(par2, var3, var4, (List<TextureFX>)textureList); 293 int[] var5 = new int[var3 * var4]; 294 byte[] var6 = new byte[var3 * var4 * 4]; 295 par1BufferedImage.getRGB(0, 0, var3, var4, var5, 0, var3); 296 297 for (int var7 = 0; var7 < var5.length; ++var7) 298 { 299 int var8 = var5[var7] >> 24 & 255; 300 int var9 = var5[var7] >> 16 & 255; 301 int var10 = var5[var7] >> 8 & 255; 302 int var11 = var5[var7] & 255; 303 304 if (this.options != null && this.options.anaglyph) 305 { 306 int var12 = (var9 * 30 + var10 * 59 + var11 * 11) / 100; 307 int var13 = (var9 * 30 + var10 * 70) / 100; 308 int var14 = (var9 * 30 + var11 * 70) / 100; 309 var9 = var12; 310 var10 = var13; 311 var11 = var14; 312 } 313 314 var6[var7 * 4 + 0] = (byte)var9; 315 var6[var7 * 4 + 1] = (byte)var10; 316 var6[var7 * 4 + 2] = (byte)var11; 317 var6[var7 * 4 + 3] = (byte)var8; 318 } 319 320 this.imageData.clear(); 321 this.imageData.put(var6); 322 this.imageData.position(0).limit(var6.length); 323 GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, var3, var4, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, this.imageData); 324 } 325 326 public void createTextureFromBytes(int[] par1ArrayOfInteger, int par2, int par3, int par4) 327 { 328 GL11.glBindTexture(GL11.GL_TEXTURE_2D, par4); 329 GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); 330 GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); 331 332 if (this.blurTexture) 333 { 334 GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); 335 GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); 336 } 337 338 if (this.clampTexture) 339 { 340 GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP); 341 GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP); 342 } 343 else 344 { 345 GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); 346 GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); 347 } 348 349 byte[] var5 = new byte[par2 * par3 * 4]; 350 351 for (int var6 = 0; var6 < par1ArrayOfInteger.length; ++var6) 352 { 353 int var7 = par1ArrayOfInteger[var6] >> 24 & 255; 354 int var8 = par1ArrayOfInteger[var6] >> 16 & 255; 355 int var9 = par1ArrayOfInteger[var6] >> 8 & 255; 356 int var10 = par1ArrayOfInteger[var6] & 255; 357 358 if (this.options != null && this.options.anaglyph) 359 { 360 int var11 = (var8 * 30 + var9 * 59 + var10 * 11) / 100; 361 int var12 = (var8 * 30 + var9 * 70) / 100; 362 int var13 = (var8 * 30 + var10 * 70) / 100; 363 var8 = var11; 364 var9 = var12; 365 var10 = var13; 366 } 367 368 var5[var6 * 4 + 0] = (byte)var8; 369 var5[var6 * 4 + 1] = (byte)var9; 370 var5[var6 * 4 + 2] = (byte)var10; 371 var5[var6 * 4 + 3] = (byte)var7; 372 } 373 374 this.imageData.clear(); 375 this.imageData.put(var5); 376 this.imageData.position(0).limit(var5.length); 377 GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, par2, par3, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, this.imageData); 378 } 379 380 /** 381 * Deletes a single GL texture 382 */ 383 public void deleteTexture(int par1) 384 { 385 this.textureNameToImageMap.removeObject(par1); 386 this.singleIntBuffer.clear(); 387 this.singleIntBuffer.put(par1); 388 this.singleIntBuffer.flip(); 389 GL11.glDeleteTextures(this.singleIntBuffer); 390 } 391 392 /** 393 * Takes a URL of a downloadable image and the name of the local image to be used as a fallback. If the image has 394 * been downloaded, returns the GL texture of the downloaded image, otherwise returns the GL texture of the fallback 395 * image. 396 */ 397 public int getTextureForDownloadableImage(String par1Str, String par2Str) 398 { 399 ThreadDownloadImageData var3 = (ThreadDownloadImageData)this.urlToImageDataMap.get(par1Str); 400 401 if (var3 != null && var3.image != null && !var3.textureSetupComplete) 402 { 403 if (var3.textureName < 0) 404 { 405 var3.textureName = this.allocateAndSetupTexture(var3.image); 406 } 407 else 408 { 409 this.setupTexture(var3.image, var3.textureName); 410 } 411 412 var3.textureSetupComplete = true; 413 } 414 415 return var3 != null && var3.textureName >= 0 ? var3.textureName : (par2Str == null ? -1 : this.getTexture(par2Str)); 416 } 417 418 public boolean func_82773_c(String par1Str) 419 { 420 return this.urlToImageDataMap.containsKey(par1Str); 421 } 422 423 /** 424 * Return a ThreadDownloadImageData instance for the given URL. If it does not already exist, it is created and 425 * uses the passed ImageBuffer. If it does, its reference count is incremented. 426 */ 427 public ThreadDownloadImageData obtainImageData(String par1Str, IImageBuffer par2IImageBuffer) 428 { 429 ThreadDownloadImageData var3 = (ThreadDownloadImageData)this.urlToImageDataMap.get(par1Str); 430 431 if (var3 == null) 432 { 433 this.urlToImageDataMap.put(par1Str, new ThreadDownloadImageData(par1Str, par2IImageBuffer)); 434 } 435 else 436 { 437 ++var3.referenceCount; 438 } 439 440 return var3; 441 } 442 443 /** 444 * Decrements the reference count for a given URL, deleting the image data if the reference count hits 0 445 */ 446 public void releaseImageData(String par1Str) 447 { 448 ThreadDownloadImageData var2 = (ThreadDownloadImageData)this.urlToImageDataMap.get(par1Str); 449 450 if (var2 != null) 451 { 452 --var2.referenceCount; 453 454 if (var2.referenceCount == 0) 455 { 456 if (var2.textureName >= 0) 457 { 458 this.deleteTexture(var2.textureName); 459 } 460 461 this.urlToImageDataMap.remove(par1Str); 462 } 463 } 464 } 465 466 public void registerTextureFX(TextureFX par1TextureFX) 467 { 468 TextureFXManager.instance().onPreRegisterEffect(par1TextureFX); 469 this.textureList.add(par1TextureFX); 470 par1TextureFX.onTick(); 471 } 472 473 public void updateDynamicTextures() 474 { 475 int var1 = -1; 476 477 for (int var2 = 0; var2 < this.textureList.size(); ++var2) 478 { 479 TextureFX var3 = (TextureFX)this.textureList.get(var2); 480 var3.anaglyphEnabled = this.options.anaglyph; 481 if (TextureFXManager.instance().onUpdateTextureEffect(var3)) 482 { 483 var1 = this.func_82772_a(var3, var1); 484 } 485 } 486 } 487 488 public int func_82772_a(TextureFX par1TextureFX, int par2) 489 { 490 Dimension dim = TextureFXManager.instance().getTextureDimensions(par1TextureFX); 491 int tWidth = dim.width >> 4; 492 int tHeight = dim.height >> 4; 493 int tLen = tWidth * tHeight << 2; 494 495 if (par1TextureFX.imageData.length == tLen) 496 { 497 this.imageData.clear(); 498 this.imageData.put(par1TextureFX.imageData); 499 this.imageData.position(0).limit(par1TextureFX.imageData.length); 500 } 501 else 502 { 503 TextureFXManager.instance().scaleTextureFXData(par1TextureFX.imageData, imageData, tWidth, tLen); 504 } 505 506 if (par1TextureFX.iconIndex != par2) 507 { 508 par1TextureFX.bindImage(this); 509 par2 = par1TextureFX.iconIndex; 510 } 511 512 for (int var3 = 0; var3 < par1TextureFX.tileSize; ++var3) 513 { 514 int xOffset = par1TextureFX.iconIndex % 16 * tWidth + var3 * tWidth; 515 for (int var4 = 0; var4 < par1TextureFX.tileSize; ++var4) 516 { 517 int yOffset = par1TextureFX.iconIndex / 16 * tHeight + var4 * tHeight; 518 GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0, xOffset, yOffset, tWidth, tHeight, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, this.imageData); 519 } 520 } 521 522 return par2; 523 } 524 525 /** 526 * Call setupTexture on all currently-loaded textures again to account for changes in rendering options 527 */ 528 public void refreshTextures() 529 { 530 ITexturePack var1 = this.texturePack.getSelectedTexturePack(); 531 Iterator var2 = this.textureNameToImageMap.getKeySet().iterator(); 532 BufferedImage var4; 533 534 while (var2.hasNext()) 535 { 536 int var3 = ((Integer)var2.next()).intValue(); 537 var4 = (BufferedImage)this.textureNameToImageMap.lookup(var3); 538 this.setupTexture(var4, var3); 539 } 540 541 ThreadDownloadImageData var8; 542 543 for (var2 = this.urlToImageDataMap.values().iterator(); var2.hasNext(); var8.textureSetupComplete = false) 544 { 545 var8 = (ThreadDownloadImageData)var2.next(); 546 } 547 548 var2 = this.textureMap.keySet().iterator(); 549 String var9; 550 551 while (var2.hasNext()) 552 { 553 var9 = (String)var2.next(); 554 555 try 556 { 557 if (var9.startsWith("##")) 558 { 559 var4 = this.unwrapImageByColumns(this.readTextureImage(var1.getResourceAsStream(var9.substring(2)))); 560 } 561 else if (var9.startsWith("%clamp%")) 562 { 563 this.clampTexture = true; 564 var4 = this.readTextureImage(var1.getResourceAsStream(var9.substring(7))); 565 } 566 else if (var9.startsWith("%blur%")) 567 { 568 this.blurTexture = true; 569 var4 = this.readTextureImage(var1.getResourceAsStream(var9.substring(6))); 570 } 571 else if (var9.startsWith("%blurclamp%")) 572 { 573 this.blurTexture = true; 574 this.clampTexture = true; 575 var4 = this.readTextureImage(var1.getResourceAsStream(var9.substring(11))); 576 } 577 else 578 { 579 var4 = this.readTextureImage(var1.getResourceAsStream(var9)); 580 } 581 582 int var5 = ((Integer)this.textureMap.get(var9)).intValue(); 583 this.setupTexture(var4, var5); 584 this.blurTexture = false; 585 this.clampTexture = false; 586 } 587 catch (Exception var7) 588 { 589 log.log(Level.INFO,String.format("An error occured reading texture file %s (refreshTexture)", var9),var7); 590 var7.printStackTrace(); 591 } 592 } 593 594 var2 = this.textureContentsMap.keySet().iterator(); 595 596 while (var2.hasNext()) 597 { 598 var9 = (String)var2.next(); 599 600 try 601 { 602 if (var9.startsWith("##")) 603 { 604 var4 = this.unwrapImageByColumns(this.readTextureImage(var1.getResourceAsStream(var9.substring(2)))); 605 } 606 else if (var9.startsWith("%clamp%")) 607 { 608 this.clampTexture = true; 609 var4 = this.readTextureImage(var1.getResourceAsStream(var9.substring(7))); 610 } 611 else if (var9.startsWith("%blur%")) 612 { 613 this.blurTexture = true; 614 var4 = this.readTextureImage(var1.getResourceAsStream(var9.substring(6))); 615 } 616 else 617 { 618 var4 = this.readTextureImage(var1.getResourceAsStream(var9)); 619 } 620 621 this.getImageContents(var4, (int[])this.textureContentsMap.get(var9)); 622 this.blurTexture = false; 623 this.clampTexture = false; 624 } 625 catch (Exception var6) 626 { 627 log.log(Level.INFO,String.format("An error occured reading texture file data %s (refreshTexture)", var9),var6); 628 var6.printStackTrace(); 629 } 630 } 631 } 632 633 /** 634 * Returns a BufferedImage read off the provided input stream. Args: inputStream 635 */ 636 private BufferedImage readTextureImage(InputStream par1InputStream) throws IOException 637 { 638 BufferedImage var2 = ImageIO.read(par1InputStream); 639 par1InputStream.close(); 640 return var2; 641 } 642 643 public void bindTexture(int par1) 644 { 645 if (par1 >= 0) 646 { 647 GL11.glBindTexture(GL11.GL_TEXTURE_2D, par1); 648 } 649 } 650 }