public static void setup(TextureAtlasSprite icon) {
   if (!fboSupported) {
     return;
   }
   String name = IconAPI.getIconName(icon).replaceFirst("^minecraft:items/", "");
   if (icon instanceof TextureClock && name.equals("compass")) { // 1.5 bug
     name = "clock";
   }
   if ("compass".equals(name)) {
     if (!enableCompass) {
       return;
     }
   } else if ("clock".equals(name)) {
     if (!enableClock) {
       return;
     }
   } else {
     logger.warning("ignoring custom animation for %s not compass or clock", name);
     return;
   }
   ResourceLocation resource =
       TexturePackAPI.newMCPatcherResourceLocation(
           "/misc/" + name + ".properties", "dial/" + name + ".properties");
   if (TexturePackAPI.hasResource(resource)) {
     logger.fine("found custom %s (%s)", name, resource);
     setupInfo.put(icon, resource);
     active = true;
   }
 }
 Layer newLayer(PropertiesFile properties, String suffix) {
   ResourceLocation textureResource = properties.getResourceLocation("source" + suffix, "");
   if (textureResource == null) {
     return null;
   }
   if (!TexturePackAPI.hasResource(textureResource)) {
     properties.error("could not read %s", textureResource);
     return null;
   }
   float scaleX = properties.getFloat("scaleX" + suffix, 1.0f);
   float scaleY = properties.getFloat("scaleY" + suffix, 1.0f);
   float offsetX = properties.getFloat("offsetX" + suffix, 0.0f);
   float offsetY = properties.getFloat("offsetY" + suffix, 0.0f);
   float angleMultiplier = properties.getFloat("rotationSpeed" + suffix, 0.0f);
   float angleOffset = properties.getFloat("rotationOffset" + suffix, 0.0f);
   String blend = properties.getString("blend" + suffix, "alpha");
   BlendMethod blendMethod = BlendMethod.parse(blend);
   if (blendMethod == null) {
     properties.error("unknown blend method %s", blend);
     return null;
   }
   boolean debug = properties.getBoolean("debug" + suffix, false);
   return new Layer(
       textureResource,
       scaleX,
       scaleY,
       offsetX,
       offsetY,
       angleMultiplier,
       angleOffset,
       blendMethod,
       debug);
 }
 static void registerAnimations() {
   TextureObject texture = TexturePackAPI.getTextureObject(TexturePackAPI.ITEMS_PNG);
   if (texture instanceof TextureAtlas) {
     List<TextureAtlasSprite> animations = ((TextureAtlas) texture).animations;
     for (FancyDial instance : instances.values()) {
       instance.registerAnimation(animations);
     }
   }
 }
  private FancyDial(TextureAtlasSprite icon, PropertiesFile properties) {
    this.icon = icon;
    this.properties = properties;
    name = IconAPI.getIconName(icon);
    x0 = IconAPI.getIconX0(icon);
    y0 = IconAPI.getIconY0(icon);
    width = IconAPI.getIconWidth(icon);
    height = IconAPI.getIconHeight(icon);
    scratchBuffer = ByteBuffer.allocateDirect(4 * width * height);

    int itemsTexture = TexturePackAPI.getTextureIfLoaded(TexturePackAPI.ITEMS_PNG);
    if (itemsTexture < 0) {
      logger.severe("could not get items texture");
      return;
    }
    itemsFBO = new FBO(itemsTexture, x0, y0, width, height);

    if (useScratchTexture) {
      logger.fine("rendering %s to %dx%d scratch texture", name, width, height);
      for (int i = 0; i < scratchFBO.length; i++) {
        scratchFBO[i] = new FBO(width, height);
      }
    } else {
      logger.fine("rendering %s directly to atlas", name);
    }

    boolean debug = false;
    for (int i = 0; ; i++) {
      Layer layer = newLayer(properties, "." + i);
      if (layer == null) {
        if (i > 0) {
          break;
        }
        continue;
      }
      layers.add(layer);
      debug |= layer.debug;
      logger.fine("  new %s", layer);
    }
    keyboard = new InputHandler(name, debug);
    if (layers.size() < 2) {
      logger.error("custom %s needs at least two layers defined", name);
      return;
    }

    outputFrames = properties.getInt("outputFrames", 0);

    int glError = GL11.glGetError();
    if (glError != 0) {
      logger.severe("%s during %s setup", GLU.gluErrorString(glError), name);
      return;
    }
    ok = true;
  }
 public static boolean renderEnchantments3D(RenderItemCustom renderItem, IModel model) {
   if (currentItem != null) {
     EnchantmentList enchantments = CITUtils.findEnchantments(currentItem);
     if (!enchantments.isEmpty()) {
       renderingEnchantment = true;
       Enchantment.beginOuter3D();
       for (int i = 0; i < enchantments.size(); i++) {
         Enchantment enchantment = enchantments.getEnchantment(i);
         float intensity = enchantments.getIntensity(i);
         if (intensity > 0.0f && enchantment.bindTexture(null)) {
           enchantment.begin(intensity);
           renderItem.renderItem1(model, -1, null);
           enchantment.end();
         }
       }
       Enchantment.endOuter3D();
       TexturePackAPI.bindTexture(TexturePackAPI.ITEMS_PNG);
       renderingEnchantment = false;
     }
   }
   return !CITUtils.useGlint;
 }
 private void renderImpl(double angle) {
   for (Layer layer : layers) {
     layer.blendMethod.applyBlending();
     GL11.glPushMatrix();
     TexturePackAPI.bindTexture(layer.textureName);
     float offsetX = layer.offsetX;
     float offsetY = layer.offsetY;
     float scaleX = layer.scaleX;
     float scaleY = layer.scaleY;
     if (layer.debug) {
       offsetX += offsetXDelta;
       offsetY += offsetYDelta;
       scaleX += scaleXDelta;
       scaleY += scaleYDelta;
     }
     GL11.glTranslatef(offsetX, offsetY, 0.0f);
     GL11.glScalef(scaleX, scaleY, 1.0f);
     float layerAngle = (float) (angle * layer.rotationMultiplier + layer.rotationOffset);
     GL11.glRotatef(layerAngle, 0.0f, 0.0f, 1.0f);
     GL11.glCallList(drawList);
     GL11.glPopMatrix();
   }
 }
public class ColorizeBlock18 {
  private static final MCLogger logger = MCLogger.getLogger(MCPatcherUtils.CUSTOM_COLORS);

  private static final ResourceLocation COLOR_PROPERTIES =
      TexturePackAPI.newMCPatcherResourceLocation("color.properties");

  private static Block grassBlock;
  private static Block mycelBlock;

  private final CTMUtils18 ctm;
  private boolean useCM;
  private IColorMap colorMap;
  private boolean isSmooth;
  private final float[][] vertexColors = new float[4][3];
  public final float[] vertexColor = new float[3];

  private static final int[][][] FACE_VERTICES =
      new int[][][] {
        // bottom face (y=0)
        {
          {0, 0, 1}, // top left
          {0, 0, 0}, // bottom left
          {1, 0, 0}, // bottom right
          {1, 0, 1}, // top right
        },
        // top face (y=1)
        {
          {0, 1, 0},
          {0, 1, 1},
          {1, 1, 1},
          {1, 1, 0},
        },
        // north face (z=0)
        {
          {1, 1, 0},
          {1, 0, 0},
          {0, 0, 0},
          {0, 1, 0},
        },
        // south face (z=1)
        {
          {0, 1, 1},
          {0, 0, 1},
          {1, 0, 1},
          {1, 1, 1},
        },
        // west face (x=0)
        {
          {0, 1, 0},
          {0, 0, 0},
          {0, 0, 1},
          {0, 1, 1},
        },
        // east face (x=1)
        {
          {1, 1, 1},
          {1, 0, 1},
          {1, 0, 0},
          {1, 1, 0},
        }
      };

  private static final int[][][] FACE_VERTICES_WATER =
      new int[][][] {
        // bottom face (y=0)
        {
          {0, 0, 1}, // top left
          {0, 0, 0}, // bottom left
          {1, 0, 0}, // bottom right
          {1, 0, 1}, // top right
        },
        // top face (y=1)
        {
          {0, 1, 0},
          {0, 1, 1},
          {1, 1, 1},
          {1, 1, 0},
        },
        // north face (z=0)
        {
          {0, 1, 0},
          {1, 1, 0},
          {1, 0, 0},
          {0, 0, 0},
        },
        // south face (z=1)
        {
          {1, 1, 1},
          {0, 1, 1},
          {0, 0, 1},
          {1, 0, 1},
        },
        // west face (x=0)
        {
          {0, 1, 1},
          {0, 1, 0},
          {0, 0, 0},
          {0, 0, 1},
        },
        // east face (x=1)
        {
          {1, 1, 0},
          {1, 1, 1},
          {1, 0, 1},
          {1, 0, 0},
        }
      };

  static {
    TexturePackChangeHandler.register(
        new TexturePackChangeHandler(MCPatcherUtils.CUSTOM_COLORS, 2) {
          @Override
          public void beforeChange() {
            reset();
          }

          @Override
          public void afterChange() {
            PropertiesFile properties = PropertiesFile.getNonNull(logger, COLOR_PROPERTIES);
            ColorizeBlock.reloadAll(properties);
          }
        });
  }

  public static void reset() {
    try {
      grassBlock = BlockAPI.getFixedBlock("minecraft:grass");
      mycelBlock = BlockAPI.getFixedBlock("minecraft:mycelium");
      ColorizeBlock.reset();
    } catch (Throwable e) {
      e.printStackTrace();
    }
  }

  public ColorizeBlock18(CTMUtils18 ctm) {
    this.ctm = ctm;
  }

  public void preRender(
      IBlockAccess blockAccess,
      IModel model,
      IBlockState blockState,
      Position position,
      Block block,
      boolean useAO) {
    colorMap = null;
    useCM = RenderPassAPI.instance.useColorMultiplierThisPass(block);
    if (useCM) {
      List<BlockStateMatcher> maps = ColorizeBlock.findColorMaps(block);
      if (maps != null) {
        for (BlockStateMatcher matcher : maps) {
          if (matcher.matchBlockState(blockState)) {
            colorMap = ColorizeBlock.getThreadLocal(matcher);
            break;
          }
        }
      }
    }
    isSmooth = false;
  }

  public void preRenderHeld(IModel model, IBlockState blockState, Block block) {
    colorMap = null;
    isSmooth = false;
    List<BlockStateMatcher> maps = ColorizeBlock.findColorMaps(block);
    if (maps != null) {
      for (BlockStateMatcher matcher : maps) {
        if (matcher.matchBlockState(blockState)) {
          colorMap = ColorizeBlock.getThreadLocal(matcher);
          break;
        }
      }
    }
  }

  public void clear() {
    colorMap = null;
    isSmooth = false;
  }

  public void setDirection(Direction direction) {
    setDirection(direction, FACE_VERTICES);
  }

  public void setDirectionWater(Direction direction) {
    setDirection(direction, FACE_VERTICES_WATER);
  }

  private void setDirection(Direction direction, int[][][] faceVertices) {
    if (ColorizeBlock.enableSmoothBiomes
        && direction != null
        && colorMap != null
        && ctm.isInWorld()) {
      isSmooth = true;
      int[][] offsets = faceVertices[direction.ordinal()];
      computeVertexColor(offsets[0], vertexColors[0]);
      computeVertexColor(offsets[1], vertexColors[1]);
      computeVertexColor(offsets[2], vertexColors[2]);
      computeVertexColor(offsets[3], vertexColors[3]);
    } else {
      isSmooth = false;
    }
  }

  private void computeVertexColor(int[] offsets, float[] color) {
    int i = ctm.getI() + offsets[0];
    int j = ctm.getJ() + offsets[1];
    int k = ctm.getK() + offsets[2];
    if (ColorizeBlock.enableTestColorSmoothing) {
      int rgb = 0;
      if (i % 2 == 0) {
        rgb |= 0xff0000;
      }
      if (j % 2 == 0) {
        rgb |= 0x00ff00;
      }
      if (k % 2 == 0) {
        rgb |= 0x0000ff;
      }
      ColorUtils.intToFloat3(rgb, color);
    } else {
      float[] tmp = colorMap.getColorMultiplierF(ctm.getBlockAccess(), i, j, k);
      color[0] = tmp[0];
      color[1] = tmp[1];
      color[2] = tmp[2];
    }
  }

  public boolean useColormap(ModelFace face) {
    return useCM
        && (face.useColormap()
            || (colorMap != null && ctm.getBlock() != grassBlock && ctm.getBlock() != mycelBlock));
  }

  public int colorMultiplier(int color) {
    if (colorMap == null) {
      return color;
    } else if (ctm.isInWorld()) {
      return colorMap.getColorMultiplier(ctm.getBlockAccess(), ctm.getI(), ctm.getJ(), ctm.getK());
    } else {
      return colorMap.getColorMultiplier();
    }
  }

  public float getVertexColor(float color, int vertex, int channel) {
    if (isSmooth) {
      return vertexColors[vertex][channel];
    } else {
      return color;
    }
  }

  public void applyVertexColor(Tessellator tessellator, float base, int vertex) {
    if (isSmooth) {
      float[] rgb = vertexColors[vertex];
      TessellatorAPI.setColorOpaque_F(tessellator, base * rgb[0], base * rgb[1], base * rgb[2]);
    }
  }

  public float applyVertexColor(float base, int vertex, float r, float g, float b) {
    if (isSmooth) {
      float[] rgb = vertexColors[vertex];
      vertexColor[0] = base * rgb[0];
      vertexColor[1] = base * rgb[1];
      vertexColor[2] = base * rgb[2];
    } else {
      vertexColor[0] = r;
      vertexColor[1] = g;
      vertexColor[2] = b;
    }
    return vertexColor[0];
  }

  public float getVertexColor(int index) {
    return vertexColor[index];
  }

  public int getParticleColor(
      IBlockAccess blockAccess, IBlockState blockState, Position position, int defaultColor) {
    return getColorMultiplier(blockAccess, blockState, position, defaultColor);
  }

  // public static methods requested by MamiyaOtaru for VoxelMap
  public static int getColorMultiplier(
      IBlockAccess blockAccess, IBlockState blockState, Position position, int defaultColor) {
    List<BlockStateMatcher> maps = ColorizeBlock.findColorMaps(blockState.getBlock());
    if (maps != null) {
      for (BlockStateMatcher matcher : maps) {
        if (matcher.matchBlockState(blockState)) {
          IColorMap colorMap = ColorizeBlock.getThreadLocal(matcher);
          return colorMap.getColorMultiplier(
              blockAccess, position.getI(), position.getJ(), position.getK());
        }
      }
    }
    return defaultColor;
  }

  public static int getColorMultiplier(
      IBlockAccess blockAccess, IBlockState blockState, Position position) {
    return getColorMultiplier(blockAccess, blockState, position, 0xffffff);
  }
}