package slimeknights.tconstruct.library.client.model;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import gnu.trove.map.hash.THashMap;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.IPerspectiveAwareModel;
import net.minecraftforge.client.model.ItemLayerModel;
import net.minecraftforge.client.model.ModelStateComposition;
import net.minecraftforge.common.model.IModelState;
import net.minecraftforge.common.model.TRSRTransformation;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import slimeknights.tconstruct.library.client.model.format.AmmoPosition;
import slimeknights.tconstruct.library.client.model.format.ToolModelOverride;
public class ToolModel implements IModel {
private final List<MaterialModel> partBlocks;
private final List<MaterialModel> brokenPartBlocks;
private final Float[] layerRotations;
private final ModifierModel modifiers;
private final ImmutableMap<TransformType, TRSRTransformation> transforms;
private final ImmutableList<ToolModelOverride> overrides;
private final ImmutableList<ResourceLocation> textures;
private final AmmoPosition ammoPosition;
public ToolModel(ImmutableList<ResourceLocation> defaultTextures,
List<MaterialModel> parts,
List<MaterialModel> brokenPartBlocks,
Float[] layerRotations,
ModifierModel modifiers,
ImmutableMap<TransformType, TRSRTransformation> transforms,
ImmutableList<ToolModelOverride> overrides, AmmoPosition ammoPosition) {
this.partBlocks = parts;
this.brokenPartBlocks = brokenPartBlocks;
this.layerRotations = layerRotations;
this.modifiers = modifiers;
this.transforms = transforms;
this.overrides = overrides;
this.textures = defaultTextures;
this.ammoPosition = ammoPosition;
}
@Override
public Collection<ResourceLocation> getDependencies() {
return ImmutableList.of();
}
@Override
public Collection<ResourceLocation> getTextures() {
ImmutableSet.Builder<ResourceLocation> builder = ImmutableSet.builder();
builder.addAll(textures);
// modifier textures
if(modifiers != null) {
builder.addAll(modifiers.getTextures());
}
for(ToolModelOverride override : overrides) {
for(MaterialModel model : override.partModelReplacement.valueCollection()) {
builder.addAll(model.getTextures());
}
for(MaterialModel model : override.brokenPartModelReplacement.valueCollection()) {
builder.addAll(model.getTextures());
}
}
return builder.build();
}
@Override
public IBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter) {
IBakedModel base = new ItemLayerModel(textures).bake(state, format, bakedTextureGetter);
BakedMaterialModel[] partModels = new BakedMaterialModel[partBlocks.size()];
BakedMaterialModel[] brokenPartModels = new BakedMaterialModel[partBlocks.size()]; // has to be same size
// we build simple models for the parts, so we can extract the UV information AND have depth
for(int i = 0; i < partBlocks.size(); i++) {
MaterialModel materialModel = partBlocks.get(i);
partModels[i] = materialModel.bakeIt(getStateForPart(i, state), format, bakedTextureGetter);
}
for(int i = 0; i < brokenPartBlocks.size(); i++) {
if(brokenPartBlocks.get(i) != null) {
brokenPartModels[i] = brokenPartBlocks.get(i).bakeIt(getStateForPart(i, state), format, bakedTextureGetter);
}
}
Map<String, IBakedModel> modifierModels;
if(modifiers != null) {
modifierModels = modifiers.bakeModels(state, format, bakedTextureGetter);
}
else {
modifierModels = new THashMap<String, IBakedModel>();
}
Map<TransformType, TRSRTransformation> builder = Maps.newHashMap();
builder.putAll(IPerspectiveAwareModel.MapWrapper.getTransforms(state));
builder.putAll(transforms); // only contains actual entries, so we override default values
// calculate all the overrides
ImmutableList.Builder<BakedToolModelOverride> overrideBuilder = ImmutableList.builder();
for(ToolModelOverride override : overrides) {
// create a new BakedToolModel representing the new state
BakedMaterialModel[] overridenPartModels = new BakedMaterialModel[partBlocks.size()];
BakedMaterialModel[] overridenBrokenPartModels = new BakedMaterialModel[partBlocks.size()];
for(int i = 0; i < partBlocks.size(); i++) {
if(override.partModelReplacement.containsKey(i)) {
overridenPartModels[i] = override.partModelReplacement.get(i).bakeIt(getStateForPart(i, state), format, bakedTextureGetter);
}
else {
overridenPartModels[i] = partModels[i];
}
if(override.brokenPartModelReplacement.containsKey(i)) {
overridenBrokenPartModels[i] = override.brokenPartModelReplacement.get(i).bakeIt(getStateForPart(i, state), format, bakedTextureGetter);
}
else {
overridenBrokenPartModels[i] = brokenPartModels[i];
}
}
Map<TransformType, TRSRTransformation> builder2 = Maps.newHashMap();
builder2.putAll(IPerspectiveAwareModel.MapWrapper.getTransforms(state));
builder2.putAll(transforms);
builder2.putAll(override.transforms); // only contains actual entries, so we override default values
Map<String, IBakedModel> overriddenModifierModels;
if(override.overrideModifierModel != null) {
overriddenModifierModels = override.overrideModifierModel.bakeModels(state, format, bakedTextureGetter);
}
else {
overriddenModifierModels = modifierModels;
}
BakedToolModel bakedToolModel = getBakedToolModel(base, overridenPartModels, overridenBrokenPartModels, overriddenModifierModels, ImmutableMap.copyOf(builder2), ImmutableList.<BakedToolModelOverride>of(), override.ammoPosition);
overrideBuilder.add(new BakedToolModelOverride(override.predicates, bakedToolModel));
}
return getBakedToolModel(base, partModels, brokenPartModels, modifierModels, ImmutableMap.copyOf(builder), overrideBuilder.build(), ammoPosition);
}
private BakedToolModel getBakedToolModel(IBakedModel base, BakedMaterialModel[] partModels, BakedMaterialModel[] brokenPartModels, Map<String, IBakedModel> modifierModels, ImmutableMap<TransformType, TRSRTransformation> transform, ImmutableList<BakedToolModelOverride> build, AmmoPosition ammoPosition) {
if(ammoPosition != null) {
// combine ammopositions
AmmoPosition combined = ammoPosition.combine(this.ammoPosition);
return new BakedBowModel(base, partModels, brokenPartModels, modifierModels, transform, build, combined);
}
return new BakedToolModel(base, partModels, brokenPartModels, modifierModels, transform, build);
}
private IModelState getStateForPart(int i, IModelState originalState) {
if(layerRotations.length > i) {
return new ModelStateComposition(originalState, TRSRTransformation.blockCenterToCorner(new TRSRTransformation(null, TRSRTransformation.quatFromXYZ(0, 0, (float) (layerRotations[i] * Math.PI / 180)), null, null)));
}
return originalState;
}
@Override
public IModelState getDefaultState() {
return ModelHelper.DEFAULT_TOOL_STATE;
}
}