gt:         if (this.spriteSingle != null)
context: package net.minecraft.client.renderer.texture;
  
  import java.awt.image.BufferedImage;
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
  import java.util.concurrent.Callable;
  
  import com.google.common.collect.Lists;
  
  import net.minecraft.client.resources.IResourceManager;
  import net.minecraft.client.resources.data.AnimationFrame;
  import net.minecraft.client.resources.data.AnimationMetadataSection;
  import net.minecraft.crash.CrashReport;
  import net.minecraft.crash.CrashReportCategory;
  import net.minecraft.util.ReportedException;
  import net.minecraft.util.ResourceLocation;
  import optfine.Config;
  import optfine.TextureUtils;
  import shadersmod.client.ShadersTex;
  
  public class TextureAtlasSprite
  {
      private final String iconName;
      protected List framesTextureData = Lists.newArrayList();
      protected int[][] interpolatedFrameData;
      private AnimationMetadataSection animationMetadata;
      protected boolean rotated;
      protected int originX;
      protected int originY;
      protected int width;
      protected int height;
      private float minU;
      private float maxU;
      private float minV;
      private float maxV;
      protected int frameCounter;
      protected int tickCounter;
      private static String locationNameClock = "builtin/clock";
      private static String locationNameCompass = "builtin/compass";
      private static final String __OBFID = "CL_00001062";
      private int indexInMap = -1;
      public float baseU;
      public float baseV;
      public int sheetWidth;
      public int sheetHeight;
      public int glSpriteTextureId = -1;
      public TextureAtlasSprite spriteSingle = null;
      public boolean isSpriteSingle = false;
      public int mipmapLevels = 0;
  
      private TextureAtlasSprite(TextureAtlasSprite p_i18_1_)
      {
          this.iconName = p_i18_1_.iconName;
          this.isSpriteSingle = true;
      }
  
      protected TextureAtlasSprite(String spriteName)
      {
          this.iconName = spriteName;
  
          if (Config.isMultiTexture())
          {
              this.spriteSingle = new TextureAtlasSprite(this);
          }
      }
  
      protected static TextureAtlasSprite makeAtlasSprite(ResourceLocation spriteResourceLocation)
      {
          String s = spriteResourceLocation.toString();
          return (TextureAtlasSprite)(locationNameClock.equals(s) ? new TextureClock(s) : (locationNameCompass.equals(s) ? new TextureCompass(s) : new TextureAtlasSprite(s)));
      }
  
      public static void setLocationNameClock(String clockName)
      {
          locationNameClock = clockName;
      }
  
      public static void setLocationNameCompass(String compassName)
      {
          locationNameCompass = compassName;
      }
  
      public void initSprite(int inX, int inY, int originInX, int originInY, boolean rotatedIn)
      {
          this.originX = originInX;
          this.originY = originInY;
          this.rotated = rotatedIn;
          float f = (float)(0.009999999776482582D / (double)inX);
          float f1 = (float)(0.009999999776482582D / (double)inY);
          this.minU = (float)originInX / (float)((double)inX) + f;
          this.maxU = (float)(originInX + this.width) / (float)((double)inX) - f;
          this.minV = (float)originInY / (float)inY + f1;
          this.maxV = (float)(originInY + this.height) / (float)inY - f1;
          this.baseU = Math.min(this.minU, this.maxU);
          this.baseV = Math.min(this.minV, this.maxV);
  
          if (this.spriteSingle != null)
          {
              this.spriteSingle.initSprite(this.width, this.height, 0, 0, false);
          }
      }
  
      public void copyFrom(TextureAtlasSprite atlasSpirit)
      {
          this.originX = atlasSpirit.originX;
          this.originY = atlasSpirit.originY;
          this.width = atlasSpirit.width;
          this.height = atlasSpirit.height;
          this.rotated = atlasSpirit.rotated;
          this.minU = atlasSpirit.minU;
          this.maxU = atlasSpirit.maxU;
          this.minV = atlasSpirit.minV;
          this.maxV = atlasSpirit.maxV;
  
          if (this.spriteSingle != null)
          {
              this.spriteSingle.initSprite(this.width, this.height, 0, 0, false);
          }
      }
  
      /**
       * Returns the X position of this icon on its texture sheet, in pixels.
       */
      public int getOriginX()
      {
          return this.originX;
      }
  
      /**
       * Returns the Y position of this icon on its texture sheet, in pixels.
       */
      public int getOriginY()
      {
          return this.originY;
      }
  
      /**
       * Returns the width of the icon, in pixels.
       */
      public int getIconWidth()
      {
          return this.width;
      }
  
      /**
       * Returns the height of the icon, in pixels.
       */
      public int getIconHeight()
      {
          return this.height;
      }
  
      /**
       * Returns the minimum U coordinate to use when rendering with this icon.
       */
      public float getMinU()
      {
          return this.minU;
      }
  
      /**
       * Returns the maximum U coordinate to use when rendering with this icon.
       */
      public float getMaxU()
      {
          return this.maxU;
      }
  
      /**
       * Gets a U coordinate on the icon. 0 returns uMin and 16 returns uMax. Other arguments return in-between values.
       */
      public float getInterpolatedU(double u)
      {
          float f = this.maxU - this.minU;
          return this.minU + f * (float)u / 16.0F;
      }
  
      /**
       * Returns the minimum V coordinate to use when rendering with this icon.
       */
      public float getMinV()
      {
          return this.minV;
      }
  
      /**
       * Returns the maximum V coordinate to use when rendering with this icon.
       */
      public float getMaxV()
      {
          return this.maxV;
      }
  
      /**
       * Gets a V coordinate on the icon. 0 returns vMin and 16 returns vMax. Other arguments return in-between values.
       */
      public float getInterpolatedV(double v)
      {
          float f = this.maxV - this.minV;
          return this.minV + f * ((float)v / 16.0F);
      }
  
      public String getIconName()
      {
          return this.iconName;
      }
  
      public void updateAnimation()
      {
          ++this.tickCounter;
  
          if (this.tickCounter >= this.animationMetadata.getFrameTimeSingle(this.frameCounter))
          {
              int i = this.animationMetadata.getFrameIndex(this.frameCounter);
              int j = this.animationMetadata.getFrameCount() == 0 ? this.framesTextureData.size() : this.animationMetadata.getFrameCount();
              this.frameCounter = (this.frameCounter + 1) % j;
              this.tickCounter = 0;
              int k = this.animationMetadata.getFrameIndex(this.frameCounter);
              boolean flag = false;
              boolean flag1 = this.isSpriteSingle;
  
              if (i != k && k >= 0 && k < this.framesTextureData.size())
              {
                  if (Config.isShaders())
                  {
                      ShadersTex.uploadTexSub((int[][])((int[][])this.framesTextureData.get(k)), this.width, this.height, this.originX, this.originY, flag, flag1);
                  }
                  else
                  {
                      TextureUtil.uploadTextureMipmap((int[][])((int[][])this.framesTextureData.get(k)), this.width, this.height, this.originX, this.originY, flag, flag1);
                  }
              }
          }
          else if (this.animationMetadata.isInterpolate())
          {
              this.updateAnimationInterpolated();
          }
      }
  
      private void updateAnimationInterpolated()
      {
          double d0 = 1.0D - (double)this.tickCounter / (double)this.animationMetadata.getFrameTimeSingle(this.frameCounter);
          int i = this.animationMetadata.getFrameIndex(this.frameCounter);
          int j = this.animationMetadata.getFrameCount() == 0 ? this.framesTextureData.size() : this.animationMetadata.getFrameCount();
          int k = this.animationMetadata.getFrameIndex((this.frameCounter + 1) % j);
  
          if (i != k && k >= 0 && k < this.framesTextureData.size())
          {
              int[][] aint = (int[][])((int[][])this.framesTextureData.get(i));
              int[][] aint1 = (int[][])((int[][])this.framesTextureData.get(k));
  
              if (this.interpolatedFrameData == null || this.interpolatedFrameData.length != aint.length)
              {
                  this.interpolatedFrameData = new int[aint.length][];
              }
  
              for (int l = 0; l < aint.length; ++l)
              {
                  if (this.interpolatedFrameData[l] == null)
                  {
                      this.interpolatedFrameData[l] = new int[aint[l].length];
                  }
  
                  if (l < aint1.length && aint1[l].length == aint[l].length)
                  {
                      for (int i1 = 0; i1 < aint[l].length; ++i1)
                      {
                          int j1 = aint[l][i1];
                          int k1 = aint1[l][i1];
                          int l1 = (int)((double)((j1 & 16711680) >> 16) * d0 + (double)((k1 & 16711680) >> 16) * (1.0D - d0));
                          int i2 = (int)((double)((j1 & 65280) >> 8) * d0 + (double)((k1 & 65280) >> 8) * (1.0D - d0));
                          int j2 = (int)((double)(j1 & 255) * d0 + (double)(k1 & 255) * (1.0D - d0));
                          this.interpolatedFrameData[l][i1] = j1 & -16777216 | l1 << 16 | i2 << 8 | j2;
                      }
                  }
              }
  
              TextureUtil.uploadTextureMipmap(this.interpolatedFrameData, this.width, this.height, this.originX, this.originY, false, false);
          }
      }
  
      public int[][] getFrameTextureData(int index)
      {
          return (int[][])((int[][])this.framesTextureData.get(index));
      }
  
      public int getFrameCount()
      {
          return this.framesTextureData.size();
      }
  
      public void setIconWidth(int newWidth)
      {
          this.width = newWidth;
  
          if (this.spriteSingle != null)
          {
              this.spriteSingle.setIconWidth(this.width);
          }
      }
  
      public void setIconHeight(int newHeight)
      {
          this.height = newHeight;
  
          if (this.spriteSingle != null)
          {
              this.spriteSingle.setIconHeight(this.height);
          }
      }
  
      public void loadSprite(BufferedImage[] images, AnimationMetadataSection meta) throws IOException
      {
          this.resetSprite();
          int i = images[0].getWidth();
          int j = images[0].getHeight();
          this.width = i;
          this.height = j;
          int[][] aint = new int[images.length][];
  
          for (int k = 0; k < images.length; ++k)
          {
              BufferedImage bufferedimage = images[k];
  
              if (bufferedimage != null)
              {
                  if (k > 0 && (bufferedimage.getWidth() != i >> k || bufferedimage.getHeight() != j >> k))
                  {
                      throw new RuntimeException(String.format("Unable to load miplevel: %d, image is size: %dx%d, expected %dx%d", new Object[] {Integer.valueOf(k), Integer.valueOf(bufferedimage.getWidth()), Integer.valueOf(bufferedimage.getHeight()), Integer.valueOf(i >> k), Integer.valueOf(j >> k)}));
                  }
  
                  aint[k] = new int[bufferedimage.getWidth() * bufferedimage.getHeight()];
                  bufferedimage.getRGB(0, 0, bufferedimage.getWidth(), bufferedimage.getHeight(), aint[k], 0, bufferedimage.getWidth());
              }
          }
  
          if (meta == null)
          {
              if (j != i)
              {
                  throw new RuntimeException("broken aspect ratio and not an animation");
              }
  
              this.framesTextureData.add(aint);
          }
          else
          {
              int j1 = j / i;
              int k1 = i;
              int l = i;
              this.height = this.width;
  
              if (meta.getFrameCount() > 0)
              {
                  Iterator iterator = meta.getFrameIndexSet().iterator();
  
                  while (iterator.hasNext())
                  {
                      int i1 = ((Integer)iterator.next()).intValue();
  
                      if (i1 >= j1)
                      {
                          throw new RuntimeException("invalid frameindex " + i1);
                      }
  
                      this.allocateFrameTextureData(i1);
                      this.framesTextureData.set(i1, getFrameTextureData(aint, k1, l, i1));
                  }
  
                  this.animationMetadata = meta;
              }
              else
              {
                  ArrayList arraylist = Lists.newArrayList();
  
                  for (int i2 = 0; i2 < j1; ++i2)
                  {
                      this.framesTextureData.add(getFrameTextureData(aint, k1, l, i2));
                      arraylist.add(new AnimationFrame(i2, -1));
                  }
  
                  this.animationMetadata = new AnimationMetadataSection(arraylist, this.width, this.height, meta.getFrameTime(), meta.isInterpolate());
              }
          }
  
          for (int l1 = 0; l1 < this.framesTextureData.size(); ++l1)
          {
              int[][] aint1 = (int[][])((int[][])this.framesTextureData.get(l1));
  
              if (aint1 != null && !this.iconName.startsWith("minecraft:blocks/leaves_"))
              {
                  for (int j2 = 0; j2 < aint1.length; ++j2)
                  {
                      int[] aint2 = aint1[j2];
                      this.fixTransparentColor(aint2);
                  }
              }
          }
  
  