ForgePatch/src/main/java/net/minecraftforge/client/model/MultiLayerModel.java

269 lines
9.8 KiB
Java
Raw Normal View History

/*
* Minecraft Forge
* Copyright (c) 2016.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.client.model;
import java.util.Collection;
import java.util.List;
import javax.annotation.Nonnull;
import javax.vecmath.Matrix4f;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.model.BakedQuad;
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.block.model.ItemOverrideList;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.MinecraftForgeClient;
import net.minecraftforge.common.ForgeVersion;
import net.minecraftforge.common.model.IModelState;
import net.minecraftforge.common.model.TRSRTransformation;
import net.minecraftforge.fml.common.FMLLog;
2015-12-30 04:15:03 +00:00
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
public final class MultiLayerModel implements IModelCustomData
{
2016-03-21 07:23:27 +00:00
public static final MultiLayerModel INSTANCE = new MultiLayerModel(ImmutableMap.<Optional<BlockRenderLayer>, ModelResourceLocation>of());
private final ImmutableMap<Optional<BlockRenderLayer>, ModelResourceLocation> models;
public MultiLayerModel(ImmutableMap<Optional<BlockRenderLayer>, ModelResourceLocation> models)
{
this.models = models;
}
@Override
public Collection<ResourceLocation> getDependencies()
{
return ImmutableList.<ResourceLocation>copyOf(models.values());
}
@Override
public Collection<ResourceLocation> getTextures()
{
return ImmutableList.of();
}
private static ImmutableMap<Optional<BlockRenderLayer>, IBakedModel> buildModels(ImmutableMap<Optional<BlockRenderLayer>, ModelResourceLocation> models, IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
{
ImmutableMap.Builder<Optional<BlockRenderLayer>, IBakedModel> builder = ImmutableMap.builder();
for(Optional<BlockRenderLayer> key : models.keySet())
{
IModel model = ModelLoaderRegistry.getModelOrLogError(models.get(key), "Couldn't load MultiLayerModel dependency: " + models.get(key));
builder.put(key, model.bake(new ModelStateComposition(state, model.getDefaultState()), format, bakedTextureGetter));
}
return builder.build();
}
@Override
public IBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
{
IModel missing = ModelLoaderRegistry.getMissingModel();
return new MultiLayerBakedModel(
buildModels(models, state, format, bakedTextureGetter),
missing.bake(missing.getDefaultState(), format, bakedTextureGetter),
IPerspectiveAwareModel.MapWrapper.getTransforms(state)
);
}
@Override
public IModelState getDefaultState()
{
return TRSRTransformation.identity();
}
@Override
public MultiLayerModel process(ImmutableMap<String, String> customData)
{
ImmutableMap.Builder<Optional<BlockRenderLayer>, ModelResourceLocation> builder = ImmutableMap.builder();
for(String key : customData.keySet())
{
if("base".equals(key))
{
builder.put(Optional.<BlockRenderLayer>absent(), getLocation(customData.get(key)));
}
for(BlockRenderLayer layer : BlockRenderLayer.values())
{
if(layer.toString().equals(key))
{
builder.put(Optional.of(layer), getLocation(customData.get(key)));
}
}
}
ImmutableMap<Optional<BlockRenderLayer>, ModelResourceLocation> models = builder.build();
2016-03-21 07:23:27 +00:00
if(models.isEmpty()) return INSTANCE;
return new MultiLayerModel(models);
}
private ModelResourceLocation getLocation(String json)
{
JsonElement e = new JsonParser().parse(json);
if(e.isJsonPrimitive() && e.getAsJsonPrimitive().isString())
{
return new ModelResourceLocation(e.getAsString());
}
FMLLog.log.fatal("Expect ModelResourceLocation, got: {}", json);
return new ModelResourceLocation("builtin/missing", "missing");
}
private static final class MultiLayerBakedModel implements IPerspectiveAwareModel
{
private final ImmutableMap<Optional<BlockRenderLayer>, IBakedModel> models;
private final ImmutableMap<TransformType, TRSRTransformation> cameraTransforms;;
private final IBakedModel base;
private final IBakedModel missing;
private final ImmutableMap<Optional<EnumFacing>, ImmutableList<BakedQuad>> quads;
public MultiLayerBakedModel(ImmutableMap<Optional<BlockRenderLayer>, IBakedModel> models, IBakedModel missing, ImmutableMap<TransformType, TRSRTransformation> cameraTransforms)
{
this.models = models;
this.cameraTransforms = cameraTransforms;
this.missing = missing;
if(models.containsKey(Optional.absent()))
{
base = models.get(Optional.absent());
}
else
{
base = missing;
}
ImmutableMap.Builder<Optional<EnumFacing>, ImmutableList<BakedQuad>> quadBuilder = ImmutableMap.builder();
quadBuilder.put(Optional.<EnumFacing>absent(), buildQuads(models, Optional.<EnumFacing>absent()));
for(EnumFacing side: EnumFacing.values())
{
quadBuilder.put(Optional.of(side), buildQuads(models, Optional.of(side)));
}
quads = quadBuilder.build();
}
private static ImmutableList<BakedQuad> buildQuads(ImmutableMap<Optional<BlockRenderLayer>, IBakedModel> models, Optional<EnumFacing> side)
{
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
for(IBakedModel model : models.values())
{
builder.addAll(model.getQuads(null, side.orNull(), 0));
}
return builder.build();
}
@Nonnull
@Override
public List<BakedQuad> getQuads(IBlockState state, EnumFacing side, long rand)
{
IBakedModel model;
BlockRenderLayer layer = MinecraftForgeClient.getRenderLayer();
if(layer == null)
{
return quads.get(Optional.fromNullable(side));
}
else if(!models.containsKey(Optional.of(layer)))
{
model = missing;
}
else
{
model = models.get(Optional.of(layer));
}
// assumes that child model will handle this state properly. FIXME?
return model.getQuads(state, side, rand);
}
@Override
public boolean isAmbientOcclusion()
{
return base.isAmbientOcclusion();
}
@Override
public boolean isGui3d()
{
return base.isGui3d();
}
@Override
public boolean isBuiltInRenderer()
{
return base.isBuiltInRenderer();
}
@Override
2015-12-30 04:15:03 +00:00
public TextureAtlasSprite getParticleTexture()
{
2015-12-30 04:15:03 +00:00
return base.getParticleTexture();
}
@Override
public ItemCameraTransforms getItemCameraTransforms()
{
return ItemCameraTransforms.DEFAULT;
}
@Override
public Pair<? extends IBakedModel, Matrix4f> handlePerspective(TransformType cameraTransformType)
{
return IPerspectiveAwareModel.MapWrapper.handlePerspective(this, cameraTransforms, cameraTransformType);
}
@Override
public ItemOverrideList getOverrides()
{
return ItemOverrideList.NONE;
}
}
public static enum Loader implements ICustomModelLoader
{
2016-03-21 07:23:27 +00:00
INSTANCE;
2017-06-18 01:24:17 +00:00
@Override
public void onResourceManagerReload(IResourceManager resourceManager) {}
2017-06-18 01:24:17 +00:00
@Override
public boolean accepts(ResourceLocation modelLocation)
{
return modelLocation.getResourceDomain().equals(ForgeVersion.MOD_ID) && (
modelLocation.getResourcePath().equals("multi-layer") ||
modelLocation.getResourcePath().equals("models/block/multi-layer") ||
modelLocation.getResourcePath().equals("models/item/multi-layer"));
}
2017-06-18 01:24:17 +00:00
@Override
public IModel loadModel(ResourceLocation modelLocation)
{
2016-03-21 07:23:27 +00:00
return MultiLayerModel.INSTANCE;
}
}
}