@Override
 public Pair<IBakedModel, Matrix4f> handlePerspective(TransformType cameraTransformType) {
   TRSRTransformation tr = transforms.get(cameraTransformType);
   Matrix4f mat = null;
   if (tr != null && tr != TRSRTransformation.identity())
     mat = TRSRTransformation.blockCornerToCenter(tr).getMatrix();
   return Pair.of((IBakedModel) this, mat);
 }
    private IFlexibleBakedModel bakeNormal(
        ModelBlock model,
        IModelState perState,
        final TRSRTransformation modelState,
        List<TRSRTransformation> newTransforms,
        VertexFormat format,
        Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter,
        boolean uvLocked) {
      TextureAtlasSprite particle =
          bakedTextureGetter.apply(new ResourceLocation(model.resolveTextureName("particle")));
      SimpleBakedModel.Builder builder = (new SimpleBakedModel.Builder(model)).setTexture(particle);
      for (int i = 0; i < model.getElements().size(); i++) {
        BlockPart part = model.getElements().get(i);
        TRSRTransformation transformation = modelState;
        if (newTransforms.get(i) != null) {
          transformation = transformation.compose(newTransforms.get(i));
        }
        for (Map.Entry<EnumFacing, BlockPartFace> e :
            (Iterable<Map.Entry<EnumFacing, BlockPartFace>>) part.mapFaces.entrySet()) {
          TextureAtlasSprite textureatlassprite1 =
              bakedTextureGetter.apply(
                  new ResourceLocation(model.resolveTextureName(e.getValue().texture)));

          if (e.getValue().cullFace == null
              || !TRSRTransformation.isInteger(transformation.getMatrix())) {
            builder.addGeneralQuad(
                makeBakedQuad(
                    part, e.getValue(), textureatlassprite1, e.getKey(), transformation, uvLocked));
          } else {
            builder.addFaceQuad(
                modelState.rotate(e.getValue().cullFace),
                makeBakedQuad(
                    part, e.getValue(), textureatlassprite1, e.getKey(), transformation, uvLocked));
          }
        }
      }

      return new ISmartBlockModel.PerspectiveWrapper(
          new IPerspectiveAwareModel.MapWrapper(
              new IFlexibleBakedModel.Wrapper(builder.makeBakedModel(), format), perState)) {
        public IBakedModel handleBlockState(IBlockState state) {
          return VanillaModelWrapper.this.handleBlockState(parent, modelState, state);
        }
      };
    }
    public WeightedRandomModel(ModelResourceLocation parent, Variants variants) {
      this.variants = variants.getVariants();
      ImmutableList.Builder<Pair<IModel, IModelState>> builder = ImmutableList.builder();
      for (Variant v : (List<Variant>) variants.getVariants()) {
        ResourceLocation loc = v.getModelLocation();
        locations.add(loc);

        IModel model = null;
        try {
          model = getModel(loc);
        } catch (Exception e) {
          /*
           * Vanilla eats this, which makes it only show variants that have models.
           * But that doesn't help debugging, so we maintain the missing model
           * so that resource pack makers have a hint that their states are broken.
           */
          FMLLog.warning(
              "Unable to load block model: \'"
                  + loc
                  + "\' for variant: \'"
                  + parent
                  + "\': "
                  + e.toString());
          model = getMissingModel();
        }

        if (v instanceof ISmartVariant) {
          model = ((ISmartVariant) v).process(model, ModelLoader.this);
          try {
            resolveDependencies(model);
          } catch (IOException e) {
            FMLLog.getLogger()
                .error("Exception resolving indirect dependencies for model" + loc, e);
          }
          textures.addAll(model.getTextures()); // Kick this, just in case.
        }

        models.add(model);
        builder.add(Pair.of(model, v.getState()));
      }

      if (models.size()
          == 0) // If all variants are missing, add one with the missing model and default rotation.
      {
        IModel missing = getMissingModel();
        models.add(missing);
        builder.add(Pair.<IModel, IModelState>of(missing, TRSRTransformation.identity()));
      }

      defaultState = new MultiModelState(builder.build());
    }
    public IFlexibleBakedModel bake(
        IModelState state,
        VertexFormat format,
        Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter) {
      if (!Attributes.moreSpecific(format, Attributes.DEFAULT_BAKED_FORMAT)) {
        throw new IllegalArgumentException(
            "can't bake vanilla models to the format that doesn't fit into the default one: "
                + format);
      }
      ModelBlock model = this.model;
      if (model == null)
        return getMissingModel()
            .bake(getMissingModel().getDefaultState(), format, bakedTextureGetter);

      List<TRSRTransformation> newTransforms = Lists.newArrayList();
      for (int i = 0; i < model.getElements().size(); i++) {
        newTransforms.add(null);
      }

      ItemCameraTransforms transforms = model.func_181682_g();
      boolean uvlock = false;
      if (state instanceof UVLock) {
        uvlock = true;
        state = ((UVLock) state).getParent();
      }
      Map<TransformType, TRSRTransformation> tMap = Maps.newHashMap();
      tMap.putAll(IPerspectiveAwareModel.MapWrapper.getTransforms(transforms));
      tMap.putAll(IPerspectiveAwareModel.MapWrapper.getTransforms(state));
      IModelState perState = new SimpleModelState(ImmutableMap.copyOf(tMap));

      if (hasItemModel(model)) {
        return new ItemLayerModel(model).bake(perState, format, bakedTextureGetter);
      }
      if (isCustomRenderer(model))
        return new IFlexibleBakedModel.Wrapper(new BuiltInModel(transforms), format);
      return bakeNormal(
          model,
          perState,
          state.apply(Optional.<IModelPart>absent()).or(TRSRTransformation.identity()),
          newTransforms,
          format,
          bakedTextureGetter,
          uvlock);
    }
 public static BakedQuad transform(
     TRSRTransformation transform, BakedQuad quad, VertexFormat format) {
   for (VertexFormatElement e : (List<VertexFormatElement>) format.getElements()) {
     if (e.getUsage() == VertexFormatElement.EnumUsage.POSITION) {
       if (e.getType() != VertexFormatElement.EnumType.FLOAT) {
         throw new IllegalArgumentException("can only transform float position");
       }
       int[] data = Arrays.copyOf(quad.getVertexData(), quad.getVertexData().length);
       float[] pos = new float[] {0f, 0f, 0f, 1f};
       for (int i = 0; i < Math.min(4, e.getElementCount()); i++) {
         pos[i] = Float.intBitsToFloat(data[e.getOffset() / 4 + i]);
       }
       Vector4f vec = new Vector4f(pos);
       transform.getMatrix().transform(vec);
       vec.get(pos);
       for (int i = 0; i < Math.min(4, e.getElementCount()); i++) {
         data[e.getOffset() / 4 + i] = Float.floatToRawIntBits(pos[i]);
       }
       return new BakedQuad(data, quad.getTintIndex(), quad.getFace());
     }
   }
   return quad;
 }