// Path: src/main/java/com/github/worldsender/mcanm/client/model/IRenderPassInformation.java
// public interface IRenderPassInformation extends IModelStateInformation {
// 	/**
// 	 * Retrieves the texture that should go into the texture slot slot
// 	 * 
// 	 * @param slot
// 	 *            the name of the texture slot getting polled
// 	 * @return the resource location of the texture to stick
// 	 */
// 	ResourceLocation getActualResourceLocation(String slot);
// }
// 
// Path: src/main/java/com/github/worldsender/mcanm/common/animation/IAnimation.java
// public interface IAnimation {
// 	/**
// 	 * Describes a BoneTransformation, including rotation, translation and scaling. This class is opaque i.e. all
// 	 * getters and setters don't make defensive copies and states can be manipulated from the outside.
// 	 *
// 	 * @author WorldSEnder
// 	 *
// 	 */
// 	public static class BoneTransformation {
// 		public static final BoneTransformation identity = new BoneTransformation();
// 
// 		private static Vector3f identityScale() {
// 			return new Vector3f(1.0F, 1.0F, 1.0F);
// 		}
// 
// 		public final Matrix4f matrix;
// 
// 		public BoneTransformation() {
// 			this(null, null, null);
// 		}
// 
// 		public BoneTransformation(Vector3f translation, Quat4f quat) {
// 			this(translation, quat, identityScale());
// 		}
// 
// 		public BoneTransformation(Vector3f translation, Quat4f quat, Vector3f scale) {
// 			if (quat == null)
// 				quat = new Quat4f();
// 			if (translation == null)
// 				translation = new Vector3f();
// 			if (scale == null)
// 				scale = identityScale();
// 			this.matrix = Utils.fromRTS(quat, translation, scale, new Matrix4f());
// 		}
// 
// 		public Matrix4f getMatrix() {
// 			return matrix;
// 		}
// 	}
// 
// 	/**
// 	 * Stores the bone's current {@link BoneTransformation} in transform(identified by name). <br>
// 	 * If the requested bone is not known to the animation transform is left untouched and this return
// 	 * <code>false</code>. Otherwise transform is set to the bone's current transform state.
// 	 *
// 	 * @param bone
// 	 *            the name of the bone the matrix is requested
// 	 * @param frame
// 	 *            the current frame in the animation
// 	 * @param transform
// 	 *            the transform to set
// 	 * @return if a transformation has been set
// 	 */
// 	public boolean storeCurrentTransformation(String bone, float frame, BoneTransformation transform);
// }


import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import com.github.worldsender.mcanm.client.model.IRenderPassInformation;
import com.github.worldsender.mcanm.common.animation.IAnimation;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import net.minecraft.util.ResourceLocation;

package com.github.worldsender.mcanm.client.model.util;




/**
 * Used to simplify the pre-render callback process. This class is an aggregate of all needed information for one render
 * pass (aka. rendering one object). You may use the setter methods or simply extend the class and override the getter
 * methods to return what you need.<br>
 * You should not call new RenderPassInformation(...) every time one is needed but reuse instances you used before. The
 * internal API doesn't keep custom instances around after the render-pass is over, only its own.
 *
 * @author WorldSEnder
 *
 */
public class RenderPassInformation extends ModelStateInformation implements IRenderPassInformation {
	public static final Function<String, ResourceLocation> makeCachingTransform(
			Function<String, ResourceLocation> cacheLoader) {
		LoadingCache<String, ResourceLocation> cachedResourceLoc = CacheBuilder.newBuilder().maximumSize(100)
				.build(new CacheLoader<String, ResourceLocation>() {
					@Override
					public ResourceLocation load(String key) {
						return cacheLoader.apply(key);
					}
				});
		return cachedResourceLoc::getUnchecked;
	}

	public static final Function<String, ResourceLocation> TRANSFORM_DIRECT = makeCachingTransform(
			ResourceLocation::new);
	/**
	 * This is the default texture rebinding, it just returns the given resource-location and as such does not change
	 * the bound texture.
	 */
	public static final Function<ResourceLocation, ResourceLocation> IDENTITY = Function.identity();

	private Function<String, ResourceLocation> textureRemap;

	public RenderPassInformation() {
		this.reset();
	}

	public RenderPassInformation(
			float frame,

// Path: src/main/java/com/github/worldsender/mcanm/client/model/IRenderPassInformation.java
// public interface IRenderPassInformation extends IModelStateInformation {
// 	/**
// 	 * Retrieves the texture that should go into the texture slot slot
// 	 * 
// 	 * @param slot
// 	 *            the name of the texture slot getting polled
// 	 * @return the resource location of the texture to stick
// 	 */
// 	ResourceLocation getActualResourceLocation(String slot);
// }
// 
// Path: src/main/java/com/github/worldsender/mcanm/common/animation/IAnimation.java
// public interface IAnimation {
// 	/**
// 	 * Describes a BoneTransformation, including rotation, translation and scaling. This class is opaque i.e. all
// 	 * getters and setters don't make defensive copies and states can be manipulated from the outside.
// 	 *
// 	 * @author WorldSEnder
// 	 *
// 	 */
// 	public static class BoneTransformation {
// 		public static final BoneTransformation identity = new BoneTransformation();
// 
// 		private static Vector3f identityScale() {
// 			return new Vector3f(1.0F, 1.0F, 1.0F);
// 		}
// 
// 		public final Matrix4f matrix;
// 
// 		public BoneTransformation() {
// 			this(null, null, null);
// 		}
// 
// 		public BoneTransformation(Vector3f translation, Quat4f quat) {
// 			this(translation, quat, identityScale());
// 		}
// 
// 		public BoneTransformation(Vector3f translation, Quat4f quat, Vector3f scale) {
// 			if (quat == null)
// 				quat = new Quat4f();
// 			if (translation == null)
// 				translation = new Vector3f();
// 			if (scale == null)
// 				scale = identityScale();
// 			this.matrix = Utils.fromRTS(quat, translation, scale, new Matrix4f());
// 		}
// 
// 		public Matrix4f getMatrix() {
// 			return matrix;
// 		}
// 	}
// 
// 	/**
// 	 * Stores the bone's current {@link BoneTransformation} in transform(identified by name). <br>
// 	 * If the requested bone is not known to the animation transform is left untouched and this return
// 	 * <code>false</code>. Otherwise transform is set to the bone's current transform state.
// 	 *
// 	 * @param bone
// 	 *            the name of the bone the matrix is requested
// 	 * @param frame
// 	 *            the current frame in the animation
// 	 * @param transform
// 	 *            the transform to set
// 	 * @return if a transformation has been set
// 	 */
// 	public boolean storeCurrentTransformation(String bone, float frame, BoneTransformation transform);
// }


// Path: src/main/java/com/github/worldsender/mcanm/client/model/util/RenderPassInformation.java
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import com.github.worldsender.mcanm.client.model.IRenderPassInformation;
import com.github.worldsender.mcanm.common.animation.IAnimation;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import net.minecraft.util.ResourceLocation;

package com.github.worldsender.mcanm.client.model.util;




/**
 * Used to simplify the pre-render callback process. This class is an aggregate of all needed information for one render
 * pass (aka. rendering one object). You may use the setter methods or simply extend the class and override the getter
 * methods to return what you need.<br>
 * You should not call new RenderPassInformation(...) every time one is needed but reuse instances you used before. The
 * internal API doesn't keep custom instances around after the render-pass is over, only its own.
 *
 * @author WorldSEnder
 *
 */
public class RenderPassInformation extends ModelStateInformation implements IRenderPassInformation {
	public static final Function<String, ResourceLocation> makeCachingTransform(
			Function<String, ResourceLocation> cacheLoader) {
		LoadingCache<String, ResourceLocation> cachedResourceLoc = CacheBuilder.newBuilder().maximumSize(100)
				.build(new CacheLoader<String, ResourceLocation>() {
					@Override
					public ResourceLocation load(String key) {
						return cacheLoader.apply(key);
					}
				});
		return cachedResourceLoc::getUnchecked;
	}

	public static final Function<String, ResourceLocation> TRANSFORM_DIRECT = makeCachingTransform(
			ResourceLocation::new);
	/**
	 * This is the default texture rebinding, it just returns the given resource-location and as such does not change
	 * the bound texture.
	 */
	public static final Function<ResourceLocation, ResourceLocation> IDENTITY = Function.identity();

	private Function<String, ResourceLocation> textureRemap;

	public RenderPassInformation() {
		this.reset();
	}

	public RenderPassInformation(
			float frame,

			Optional<IAnimation> animation,
