Model system improvements:
- Port some things I did in 1.14 which I couldn't do in 1.15 due to breaking changes. - Fix multi-layer block models not working (1.16 RenderType doesn't override toString the same way anymore) - Implement multi-layer item rendering. - Improve CompositeModel submodel data passing.
This commit is contained in:
parent
45152c6073
commit
ce3d8b40cf
17 changed files with 749 additions and 202 deletions
|
@ -18,16 +18,30 @@
|
|||
p_229111_4_.func_227861_a_(-0.5D, -0.5D, -0.5D);
|
||||
if (!p_229111_8_.func_188618_c() && (p_229111_1_.func_77973_b() != Items.field_203184_eO || flag)) {
|
||||
boolean flag1;
|
||||
@@ -132,7 +132,7 @@
|
||||
|
||||
@@ -105,7 +105,8 @@
|
||||
} else {
|
||||
flag1 = true;
|
||||
}
|
||||
-
|
||||
+ if (p_229111_8_.isLayered()) { net.minecraftforge.client.ForgeHooksClient.drawItemLayered(this, p_229111_8_, p_229111_1_, p_229111_4_, p_229111_5_, p_229111_6_, p_229111_7_, flag1); }
|
||||
+ else {
|
||||
RenderType rendertype = RenderTypeLookup.func_239219_a_(p_229111_1_, flag1);
|
||||
IVertexBuilder ivertexbuilder;
|
||||
if (p_229111_1_.func_77973_b() == Items.field_151111_aL && p_229111_1_.func_77962_s()) {
|
||||
@@ -129,10 +130,10 @@
|
||||
} else {
|
||||
ivertexbuilder = func_229113_a_(p_229111_5_, rendertype, true, p_229111_1_.func_77962_s());
|
||||
}
|
||||
-
|
||||
this.func_229114_a_(p_229111_8_, p_229111_1_, p_229111_6_, p_229111_7_, p_229111_4_, ivertexbuilder);
|
||||
+ }
|
||||
} else {
|
||||
- ItemStackTileEntityRenderer.field_147719_a.func_239207_a_(p_229111_1_, p_229111_2_, p_229111_4_, p_229111_5_, p_229111_6_, p_229111_7_);
|
||||
+ p_229111_1_.func_77973_b().getItemStackTileEntityRenderer().func_239207_a_(p_229111_1_, p_229111_2_, p_229111_4_, p_229111_5_, p_229111_6_, p_229111_7_);
|
||||
}
|
||||
|
||||
p_229111_4_.func_227865_b_();
|
||||
@@ -172,7 +172,7 @@
|
||||
@@ -172,7 +173,7 @@
|
||||
float f = (float)(i >> 16 & 255) / 255.0F;
|
||||
float f1 = (float)(i >> 8 & 255) / 255.0F;
|
||||
float f2 = (float)(i & 255) / 255.0F;
|
||||
|
@ -36,7 +50,7 @@
|
|||
}
|
||||
|
||||
}
|
||||
@@ -263,6 +263,7 @@
|
||||
@@ -263,6 +264,7 @@
|
||||
crashreportcategory.func_189529_a("Item Type", () -> {
|
||||
return String.valueOf((Object)p_239387_2_.func_77973_b());
|
||||
});
|
||||
|
@ -44,7 +58,7 @@
|
|||
crashreportcategory.func_189529_a("Item Damage", () -> {
|
||||
return String.valueOf(p_239387_2_.func_77952_i());
|
||||
});
|
||||
@@ -294,18 +295,16 @@
|
||||
@@ -294,18 +296,16 @@
|
||||
irendertypebuffer$impl.func_228461_a_();
|
||||
}
|
||||
|
||||
|
@ -67,7 +81,7 @@
|
|||
this.func_181565_a(bufferbuilder, p_180453_3_ + 2, p_180453_4_ + 13, 13, 2, 0, 0, 0, 255);
|
||||
this.func_181565_a(bufferbuilder, p_180453_3_ + 2, p_180453_4_ + 13, i, 1, j >> 16 & 255, j >> 8 & 255, j & 255, 255);
|
||||
RenderSystem.enableBlend();
|
||||
@@ -343,4 +342,9 @@
|
||||
@@ -343,4 +343,9 @@
|
||||
public void func_195410_a(IResourceManager p_195410_1_) {
|
||||
this.field_175059_m.func_178085_b();
|
||||
}
|
||||
|
|
|
@ -810,4 +810,17 @@ public class ForgeHooksClient
|
|||
MinecraftForge.EVENT_BUS.post(event);
|
||||
return event;
|
||||
}
|
||||
|
||||
public static void drawItemLayered(ItemRenderer renderer, IBakedModel modelIn, ItemStack itemStackIn, MatrixStack matrixStackIn, IRenderTypeBuffer bufferIn, int combinedLightIn, int combinedOverlayIn, boolean fabulous)
|
||||
{
|
||||
for(com.mojang.datafixers.util.Pair<IBakedModel,RenderType> layerModel : modelIn.getLayerModels(itemStackIn, fabulous)) {
|
||||
modelIn = layerModel.getFirst();
|
||||
RenderType rendertype = layerModel.getSecond();
|
||||
net.minecraftforge.client.ForgeHooksClient.setRenderLayer(rendertype); // neded for compatibility with MultiLayerModels
|
||||
|
||||
IVertexBuilder ivertexbuilder = ItemRenderer.getBuffer(bufferIn, rendertype, true, itemStackIn.hasEffect());
|
||||
renderer.renderModel(modelIn, itemStackIn, combinedLightIn, combinedOverlayIn, matrixStackIn, ivertexbuilder);
|
||||
}
|
||||
net.minecraftforge.client.ForgeHooksClient.setRenderLayer(null);
|
||||
}
|
||||
}
|
||||
|
|
142
src/main/java/net/minecraftforge/client/ForgeRenderTypes.java
Normal file
142
src/main/java/net/minecraftforge/client/ForgeRenderTypes.java
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
*
|
||||
* 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;
|
||||
|
||||
import net.minecraft.client.renderer.RenderState;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.texture.AtlasTexture;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.common.util.NonNullLazy;
|
||||
import net.minecraftforge.common.util.NonNullSupplier;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public enum ForgeRenderTypes
|
||||
{
|
||||
/**
|
||||
* A cached copy of {@link ForgeRenderTypes#getUnsortedTranslucent(ResourceLocation)}
|
||||
* for use in item models and TileEntityRenderers that use the block/item atlas.
|
||||
*/
|
||||
ITEM_UNSORTED_TRANSLUCENT(()-> getUnsortedTranslucent(AtlasTexture.LOCATION_BLOCKS_TEXTURE)),
|
||||
ITEM_UNLIT_TRANSLUCENT(()-> getUnlitTranslucent(AtlasTexture.LOCATION_BLOCKS_TEXTURE)),
|
||||
ITEM_UNSORTED_UNLIT_TRANSLUCENT(()-> getUnlitTranslucent(AtlasTexture.LOCATION_BLOCKS_TEXTURE, false));
|
||||
|
||||
/**
|
||||
* @return A RenderType fit for translucent item/entity rendering, but with depth sorting disabled.
|
||||
*/
|
||||
public static RenderType getUnsortedTranslucent(ResourceLocation textureLocation)
|
||||
{
|
||||
return Internal.unsortedTranslucent(textureLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A RenderType fit for translucent item/entity rendering, but with diffuse lighting disabled
|
||||
* so that fullbright quads look correct.
|
||||
*/
|
||||
public static RenderType getUnlitTranslucent(ResourceLocation textureLocation)
|
||||
{
|
||||
return getUnlitTranslucent(textureLocation, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A RenderType fit for translucent item/entity rendering, but with diffuse lighting disabled
|
||||
* so that fullbright quads look correct.
|
||||
* @param sortingEnabled If false, depth sorting will not be performed.
|
||||
*/
|
||||
public static RenderType getUnlitTranslucent(ResourceLocation textureLocation, boolean sortingEnabled)
|
||||
{
|
||||
return Internal.unlitTranslucent(textureLocation, sortingEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Same as {@link RenderType#getEntityCutout(ResourceLocation)}, but with mipmapping enabled.
|
||||
*/
|
||||
public static RenderType getEntityCutoutMipped(ResourceLocation textureLocation)
|
||||
{
|
||||
return Internal.entityCutoutMipped(textureLocation);
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
// Implementation details below this line
|
||||
// ----------------------------------------
|
||||
|
||||
private final NonNullSupplier<RenderType> renderTypeSupplier;
|
||||
|
||||
ForgeRenderTypes(NonNullSupplier<RenderType> renderTypeSupplier)
|
||||
{
|
||||
// Wrap in a Lazy<> to avoid running the supplier more than once.
|
||||
this.renderTypeSupplier = NonNullLazy.of(renderTypeSupplier);
|
||||
}
|
||||
|
||||
public RenderType get()
|
||||
{
|
||||
return renderTypeSupplier.get();
|
||||
}
|
||||
|
||||
private static class Internal extends RenderType
|
||||
{
|
||||
private Internal(String name, VertexFormat fmt, int glMode, int size, boolean doCrumbling, boolean depthSorting, Runnable onEnable, Runnable onDisable)
|
||||
{
|
||||
super(name, fmt, glMode, size, doCrumbling, depthSorting, onEnable, onDisable);
|
||||
throw new IllegalStateException("This class must not be instantiated");
|
||||
}
|
||||
|
||||
public static RenderType unsortedTranslucent(ResourceLocation textureLocation)
|
||||
{
|
||||
final boolean sortingEnabled = false;
|
||||
State renderState = State.getBuilder()
|
||||
.texture(new TextureState(textureLocation, false, false))
|
||||
.transparency(TRANSLUCENT_TRANSPARENCY)
|
||||
.diffuseLighting(DIFFUSE_LIGHTING_ENABLED)
|
||||
.alpha(DEFAULT_ALPHA)
|
||||
.cull(CULL_DISABLED)
|
||||
.lightmap(LIGHTMAP_ENABLED)
|
||||
.overlay(OVERLAY_ENABLED)
|
||||
.build(true);
|
||||
return makeType("entity_unsorted_translucent", DefaultVertexFormats.ENTITY, GL11.GL_QUADS, 256, true, sortingEnabled, renderState);
|
||||
}
|
||||
|
||||
public static RenderType unlitTranslucent(ResourceLocation textureLocation, boolean sortingEnabled)
|
||||
{
|
||||
State renderState = State.getBuilder()
|
||||
.texture(new TextureState(textureLocation, false, false))
|
||||
.transparency(TRANSLUCENT_TRANSPARENCY)
|
||||
.alpha(DEFAULT_ALPHA)
|
||||
.cull(CULL_DISABLED)
|
||||
.lightmap(LIGHTMAP_ENABLED)
|
||||
.overlay(OVERLAY_ENABLED)
|
||||
.build(true);
|
||||
return makeType("entity_unlit_translucent", DefaultVertexFormats.ENTITY, GL11.GL_QUADS, 256, true, sortingEnabled, renderState);
|
||||
}
|
||||
|
||||
public static RenderType entityCutoutMipped(ResourceLocation locationIn) {
|
||||
RenderType.State rendertype$state = RenderType.State.getBuilder()
|
||||
.texture(new RenderState.TextureState(locationIn, false, true))
|
||||
.transparency(NO_TRANSPARENCY)
|
||||
.diffuseLighting(DIFFUSE_LIGHTING_ENABLED)
|
||||
.alpha(DEFAULT_ALPHA)
|
||||
.lightmap(LIGHTMAP_ENABLED)
|
||||
.overlay(OVERLAY_ENABLED)
|
||||
.build(true);
|
||||
return makeType("entity_cutout_mipped", DefaultVertexFormats.ENTITY, 7, 256, true, false, rendertype$state);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,19 +19,25 @@
|
|||
|
||||
package net.minecraftforge.client.extensions;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.RenderTypeLookup;
|
||||
import net.minecraft.client.renderer.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.model.ItemCameraTransforms;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockDisplayReader;
|
||||
|
@ -75,4 +81,20 @@ public interface IForgeBakedModel
|
|||
{
|
||||
return getBakedModel().getParticleTexture();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to true, to tell forge to call the getLayerModels method below.
|
||||
*/
|
||||
default boolean isLayered()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If {@see isLayered()} returns true, this is called to get the list of layers to draw.
|
||||
*/
|
||||
default List<Pair<IBakedModel, RenderType>> getLayerModels(ItemStack itemStack, boolean fabulous)
|
||||
{
|
||||
return Collections.singletonList(Pair.of(getBakedModel(), RenderTypeLookup.func_239219_a_(itemStack, fabulous)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,17 +38,17 @@ public interface IForgeVertexBuilder
|
|||
{
|
||||
default IVertexBuilder getVertexBuilder() { return (IVertexBuilder)this; }
|
||||
|
||||
// Copy of func_227889_a_, but enables tinting
|
||||
// Copy of addQuad, but enables tinting and per-vertex alpha
|
||||
default void addVertexData(MatrixStack.Entry matrixStack, BakedQuad bakedQuad, float red, float green, float blue, int lightmapCoord, int overlayColor, boolean readExistingColor) {
|
||||
getVertexBuilder().addQuad(matrixStack, bakedQuad, new float[]{1.0F, 1.0F, 1.0F, 1.0F}, red, green, blue, new int[]{lightmapCoord, lightmapCoord, lightmapCoord, lightmapCoord}, overlayColor, readExistingColor);
|
||||
addVertexData(matrixStack, bakedQuad, red, green, blue, 1.0f, lightmapCoord, overlayColor, readExistingColor);
|
||||
}
|
||||
|
||||
// Copy of func_227889_a_ with alpha support
|
||||
// Copy of addQuad with alpha support
|
||||
default void addVertexData(MatrixStack.Entry matrixEntry, BakedQuad bakedQuad, float red, float green, float blue, float alpha, int lightmapCoord, int overlayColor) {
|
||||
addVertexData(matrixEntry, bakedQuad, new float[]{1.0F, 1.0F, 1.0F, 1.0F}, red, green, blue, alpha, new int[]{lightmapCoord, lightmapCoord, lightmapCoord, lightmapCoord}, overlayColor, false);
|
||||
}
|
||||
|
||||
// Copy of func_227889_a_ with alpha support
|
||||
// Copy of addQuad with alpha support
|
||||
default void addVertexData(MatrixStack.Entry matrixEntry, BakedQuad bakedQuad, float red, float green, float blue, float alpha, int lightmapCoord, int overlayColor, boolean readExistingColor) {
|
||||
addVertexData(matrixEntry, bakedQuad, new float[]{1.0F, 1.0F, 1.0F, 1.0F}, red, green, blue, alpha, new int[]{lightmapCoord, lightmapCoord, lightmapCoord, lightmapCoord}, overlayColor, readExistingColor);
|
||||
}
|
||||
|
|
|
@ -31,10 +31,9 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
|||
import net.minecraft.resources.IResourceManager;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.model.data.EmptyModelData;
|
||||
import net.minecraftforge.client.model.data.IDynamicBakedModel;
|
||||
import net.minecraftforge.client.model.data.IModelData;
|
||||
import net.minecraftforge.client.model.data.ModelProperty;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockDisplayReader;
|
||||
import net.minecraftforge.client.model.data.*;
|
||||
import net.minecraftforge.client.model.geometry.IModelGeometryPart;
|
||||
import net.minecraftforge.client.model.geometry.IMultipartModelGeometry;
|
||||
|
||||
|
@ -45,20 +44,20 @@ import java.util.function.Function;
|
|||
|
||||
public class CompositeModel implements IDynamicBakedModel
|
||||
{
|
||||
public static final ModelProperty<SubmodelModelData> SUBMODEL_DATA = new ModelProperty<>();
|
||||
|
||||
private final ImmutableMap<String, IBakedModel> bakedParts;
|
||||
private final boolean isAmbientOcclusion;
|
||||
private final boolean isGui3d;
|
||||
private final boolean isSideLit;
|
||||
private final TextureAtlasSprite particle;
|
||||
private final ItemOverrideList overrides;
|
||||
private final IModelTransform transforms;
|
||||
|
||||
public CompositeModel(boolean isGui3d, boolean isAmbientOcclusion, TextureAtlasSprite particle, ImmutableMap<String, IBakedModel> bakedParts, IModelTransform combinedTransform, ItemOverrideList overrides)
|
||||
public CompositeModel(boolean isGui3d, boolean isSideLit, boolean isAmbientOcclusion, TextureAtlasSprite particle, ImmutableMap<String, IBakedModel> bakedParts, IModelTransform combinedTransform, ItemOverrideList overrides)
|
||||
{
|
||||
this.bakedParts = bakedParts;
|
||||
this.isAmbientOcclusion = isAmbientOcclusion;
|
||||
this.isGui3d = isGui3d;
|
||||
this.isSideLit = isSideLit;
|
||||
this.particle = particle;
|
||||
this.overrides = overrides;
|
||||
this.transforms = combinedTransform;
|
||||
|
@ -71,12 +70,23 @@ public class CompositeModel implements IDynamicBakedModel
|
|||
List<BakedQuad> quads = new ArrayList<>();
|
||||
for(Map.Entry<String, IBakedModel> entry : bakedParts.entrySet())
|
||||
{
|
||||
// TODO: Some way to provide submodel data?
|
||||
quads.addAll(entry.getValue().getQuads(state, side, rand, getSubmodelData(extraData, entry.getKey())));
|
||||
quads.addAll(entry.getValue().getQuads(state, side, rand, CompositeModelData.get(extraData, entry.getKey())));
|
||||
}
|
||||
return quads;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public IModelData getModelData(@Nonnull IBlockDisplayReader world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nonnull IModelData tileData)
|
||||
{
|
||||
CompositeModelData composite = new CompositeModelData();
|
||||
for(Map.Entry<String, IBakedModel> entry : bakedParts.entrySet())
|
||||
{
|
||||
composite.putSubmodelData(entry.getKey(), entry.getValue().getModelData(world, pos, state, ModelDataWrapper.wrap(tileData)));
|
||||
}
|
||||
return composite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAmbientOcclusion()
|
||||
{
|
||||
|
@ -92,8 +102,7 @@ public class CompositeModel implements IDynamicBakedModel
|
|||
@Override
|
||||
public boolean func_230044_c_()
|
||||
{
|
||||
// TODO: Forge: Auto-generated method stub
|
||||
return false;
|
||||
return isSideLit;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -132,29 +141,6 @@ public class CompositeModel implements IDynamicBakedModel
|
|||
return bakedParts.get(name);
|
||||
}
|
||||
|
||||
private IModelData getSubmodelData(IModelData extraData, String name)
|
||||
{
|
||||
SubmodelModelData data = extraData.getData(SUBMODEL_DATA);
|
||||
if (data == null)
|
||||
return EmptyModelData.INSTANCE;
|
||||
return data.getSubmodelData(name);
|
||||
}
|
||||
|
||||
public static class SubmodelModelData
|
||||
{
|
||||
private final Map<String, IModelData> parts = new HashMap<>();
|
||||
|
||||
public IModelData getSubmodelData(String name)
|
||||
{
|
||||
return parts.getOrDefault(name, EmptyModelData.INSTANCE);
|
||||
}
|
||||
|
||||
public void putSubmodelData(String name, IModelData data)
|
||||
{
|
||||
parts.put(name, data);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Submodel implements IModelGeometryPart
|
||||
{
|
||||
private final String name;
|
||||
|
@ -228,7 +214,7 @@ public class CompositeModel implements IDynamicBakedModel
|
|||
continue;
|
||||
bakedParts.put(part.getKey(), submodel.bakeModel(bakery, spriteGetter, modelTransform, modelLocation));
|
||||
}
|
||||
return new CompositeModel(owner.isShadedInGui(), owner.useSmoothLighting(), particle, bakedParts.build(), owner.getCombinedTransform(), overrides);
|
||||
return new CompositeModel(owner.isShadedInGui(), owner.useSmoothLighting(), owner.isSideLit(), particle, bakedParts.build(), owner.getCombinedTransform(), overrides);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -273,4 +259,116 @@ public class CompositeModel implements IDynamicBakedModel
|
|||
return new Geometry(parts.build());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A model data container which stores data for child components.
|
||||
*/
|
||||
public static class CompositeModelData extends ModelDataMap
|
||||
{
|
||||
public static final ModelProperty<CompositeModelData> SUBMODEL_DATA = new ModelProperty<>();
|
||||
|
||||
/**
|
||||
* Helper to get the CompositeModelData from an unknown IModelData instance.
|
||||
* @param modelData The undetermined instance to get data from
|
||||
* @return An optional representing the composite data, if present.
|
||||
*/
|
||||
public static Optional<CompositeModelData> get(IModelData modelData)
|
||||
{
|
||||
return Optional.ofNullable(modelData.getData(SUBMODEL_DATA));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get child data from an unknown IModelData instance.
|
||||
* @param modelData The undetermined instance to get data from
|
||||
* @param name The name of the child part to get data for.
|
||||
* @return The data for the child, or empty if not available.
|
||||
*/
|
||||
public static IModelData get(IModelData modelData, String name)
|
||||
{
|
||||
return get(modelData).map(data -> data.getSubmodelData(name))
|
||||
.orElse(EmptyModelData.INSTANCE);
|
||||
}
|
||||
|
||||
// Implementation
|
||||
|
||||
private final Map<String, IModelData> parts = new HashMap<>();
|
||||
|
||||
public IModelData getSubmodelData(String name)
|
||||
{
|
||||
if (parts.containsKey(name))
|
||||
return parts.get(name);
|
||||
return EmptyModelData.INSTANCE;
|
||||
}
|
||||
|
||||
public void putSubmodelData(String name, IModelData data)
|
||||
{
|
||||
parts.put(name, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasProperty(ModelProperty<?> prop)
|
||||
{
|
||||
return prop == SUBMODEL_DATA ||super.hasProperty(prop);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
@Override
|
||||
public <T> T getData(ModelProperty<T> prop)
|
||||
{
|
||||
if (prop == SUBMODEL_DATA)
|
||||
return (T)this;
|
||||
return super.getData(prop);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
@Override
|
||||
public <T> T setData(ModelProperty<T> prop, T data)
|
||||
{
|
||||
if (prop == SUBMODEL_DATA)
|
||||
return (T)this;
|
||||
return super.setData(prop, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for an IModelData instance which allows forwarding queries to the parent,
|
||||
* but stores any new/modified values itself, avoiding modifications to the parent.
|
||||
*/
|
||||
private static class ModelDataWrapper extends ModelDataMap
|
||||
{
|
||||
private final IModelData parent;
|
||||
|
||||
public static IModelData wrap(IModelData parent)
|
||||
{
|
||||
return new ModelDataWrapper(parent);
|
||||
}
|
||||
|
||||
private ModelDataWrapper(IModelData parent)
|
||||
{
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasProperty(ModelProperty<?> prop)
|
||||
{
|
||||
return super.hasProperty(prop) || parent.hasProperty(prop);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public <T> T getData(ModelProperty<T> prop)
|
||||
{
|
||||
return super.hasProperty(prop) ? super.getData(prop) : parent.getData(prop);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public <T> T setData(ModelProperty<T> prop, T data)
|
||||
{
|
||||
// We do not want to delegate setting to the parent
|
||||
return super.setData(prop, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,7 @@
|
|||
|
||||
package net.minecraftforge.client.model;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.*;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
|
@ -31,7 +28,6 @@ import net.minecraft.util.math.vector.Quaternion;
|
|||
import net.minecraft.util.math.vector.TransformationMatrix;
|
||||
import net.minecraft.client.renderer.model.*;
|
||||
import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType;
|
||||
import net.minecraft.client.renderer.texture.MissingTextureSprite;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
|
@ -40,29 +36,24 @@ import net.minecraft.item.ItemStack;
|
|||
import net.minecraft.resources.IResourceManager;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.ForgeHooksClient;
|
||||
import net.minecraftforge.client.model.geometry.IModelGeometry;
|
||||
import net.minecraftforge.fluids.FluidUtil;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import net.minecraftforge.resource.IResourceType;
|
||||
import net.minecraftforge.resource.VanillaResourceType;
|
||||
import net.minecraftforge.versions.forge.ForgeVersion;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public final class DynamicBucketModel implements IModelGeometry<DynamicBucketModel>
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
public static final ModelResourceLocation LOCATION = new ModelResourceLocation(new ResourceLocation(ForgeVersion.MOD_ID, "dynbucket"), "inventory");
|
||||
|
||||
// minimal Z offset to prevent depth-fighting
|
||||
private static final float NORTH_Z_COVER = 7.496f / 16f;
|
||||
|
@ -76,13 +67,21 @@ public final class DynamicBucketModel implements IModelGeometry<DynamicBucketMod
|
|||
private final boolean flipGas;
|
||||
private final boolean tint;
|
||||
private final boolean coverIsMask;
|
||||
private final boolean applyFluidLuminosity;
|
||||
|
||||
@Deprecated
|
||||
public DynamicBucketModel(Fluid fluid, boolean flipGas, boolean tint, boolean coverIsMask)
|
||||
{
|
||||
this(fluid, flipGas, tint, coverIsMask, true);
|
||||
}
|
||||
|
||||
public DynamicBucketModel(Fluid fluid, boolean flipGas, boolean tint, boolean coverIsMask, boolean applyFluidLuminosity)
|
||||
{
|
||||
this.fluid = fluid;
|
||||
this.flipGas = flipGas;
|
||||
this.tint = tint;
|
||||
this.coverIsMask = coverIsMask;
|
||||
this.applyFluidLuminosity = applyFluidLuminosity;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,63 +90,46 @@ public final class DynamicBucketModel implements IModelGeometry<DynamicBucketMod
|
|||
*/
|
||||
public DynamicBucketModel withFluid(Fluid newFluid)
|
||||
{
|
||||
return new DynamicBucketModel(newFluid, flipGas, tint, coverIsMask);
|
||||
return new DynamicBucketModel(newFluid, flipGas, tint, coverIsMask, applyFluidLuminosity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<RenderMaterial, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ItemOverrideList overrides, ResourceLocation modelLocation)
|
||||
{
|
||||
RenderMaterial particleLocation = owner.resolveTexture("particle");
|
||||
if (MissingTextureSprite.getLocation().equals(particleLocation.getTextureLocation()))
|
||||
{
|
||||
particleLocation = null;
|
||||
}
|
||||
|
||||
RenderMaterial baseLocation = owner.resolveTexture("base");
|
||||
if (MissingTextureSprite.getLocation().equals(baseLocation.getTextureLocation()))
|
||||
{
|
||||
baseLocation = null;
|
||||
}
|
||||
|
||||
RenderMaterial fluidMaskLocation = owner.resolveTexture("fluid");
|
||||
if (MissingTextureSprite.getLocation().equals(fluidMaskLocation.getTextureLocation()))
|
||||
{
|
||||
fluidMaskLocation = null;
|
||||
}
|
||||
|
||||
RenderMaterial coverLocation = owner.resolveTexture("cover");
|
||||
if (!MissingTextureSprite.getLocation().equals(coverLocation.getTextureLocation()))
|
||||
{
|
||||
// cover (the actual item around the other two)
|
||||
coverLocation = null;
|
||||
}
|
||||
RenderMaterial particleLocation = owner.isTexturePresent("particle") ? owner.resolveTexture("particle") : null;
|
||||
RenderMaterial baseLocation = owner.isTexturePresent("base") ? owner.resolveTexture("base") : null;
|
||||
RenderMaterial fluidMaskLocation = owner.isTexturePresent("fluid") ? owner.resolveTexture("fluid") : null;
|
||||
RenderMaterial coverLocation = owner.isTexturePresent("fluid") ? owner.resolveTexture("cover") : null;
|
||||
|
||||
IModelTransform transformsFromModel = owner.getCombinedTransform();
|
||||
|
||||
ImmutableMap<TransformType, TransformationMatrix> transformMap = transformsFromModel != null ?
|
||||
PerspectiveMapWrapper.getTransforms(new ModelTransformComposition(transformsFromModel, modelTransform)) :
|
||||
PerspectiveMapWrapper.getTransforms(modelTransform);
|
||||
TextureAtlasSprite fluidSprite = fluid != Fluids.EMPTY ? spriteGetter.apply(ForgeHooksClient.getBlockMaterial(fluid.getAttributes().getStillTexture())) : null;
|
||||
TextureAtlasSprite coverSprite = (coverLocation != null && (!coverIsMask || baseLocation != null)) ? spriteGetter.apply(coverLocation) : null;
|
||||
|
||||
ImmutableMap<TransformType, TransformationMatrix> transformMap =
|
||||
PerspectiveMapWrapper.getTransforms(new ModelTransformComposition(transformsFromModel, modelTransform));
|
||||
|
||||
TextureAtlasSprite particleSprite = particleLocation != null ? spriteGetter.apply(particleLocation) : null;
|
||||
|
||||
if (particleSprite == null) particleSprite = fluidSprite;
|
||||
if (particleSprite == null && !coverIsMask) particleSprite = coverSprite;
|
||||
|
||||
// if the fluid is lighter than air, will manipulate the initial state to be rotated 180deg to turn it upside down
|
||||
if (flipGas && fluid != Fluids.EMPTY && fluid.getAttributes().isLighterThanAir())
|
||||
{
|
||||
modelTransform = new ModelTransformComposition(modelTransform, new SimpleModelTransform(new TransformationMatrix(null, new Quaternion(0, 0, 1, 0), null, null)));
|
||||
modelTransform = new SimpleModelTransform(
|
||||
modelTransform.getRotation().blockCornerToCenter().composeVanilla(
|
||||
new TransformationMatrix(null, new Quaternion(0, 0, 1, 0), null, null)).blockCenterToCorner());
|
||||
}
|
||||
|
||||
TransformationMatrix transform = modelTransform.getRotation();
|
||||
|
||||
TextureAtlasSprite fluidSprite = fluid != Fluids.EMPTY ? spriteGetter.apply(ForgeHooksClient.getBlockMaterial(fluid.getAttributes().getStillTexture())) : null;
|
||||
|
||||
if (particleSprite == null) particleSprite = fluidSprite;
|
||||
|
||||
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
|
||||
ItemMultiLayerBakedModel.Builder builder = ItemMultiLayerBakedModel.builder(owner, particleSprite, new ContainedFluidOverrideHandler(overrides, bakery, owner, this), transformMap);
|
||||
|
||||
if (baseLocation != null)
|
||||
{
|
||||
// build base (insidest)
|
||||
builder.addAll(ItemLayerModel.getQuadsForSprites(ImmutableList.of(baseLocation), transform, spriteGetter));
|
||||
builder.addQuads(ItemLayerModel.getLayerRenderType(false), ItemLayerModel.getQuadsForSprites(ImmutableList.of(baseLocation), transform, spriteGetter));
|
||||
}
|
||||
|
||||
if (fluidMaskLocation != null && fluidSprite != null)
|
||||
|
@ -156,36 +138,34 @@ public final class DynamicBucketModel implements IModelGeometry<DynamicBucketMod
|
|||
if (templateSprite != null)
|
||||
{
|
||||
// build liquid layer (inside)
|
||||
builder.addAll(ItemTextureQuadConverter.convertTexture(transform, templateSprite, fluidSprite, NORTH_Z_FLUID, Direction.NORTH, tint ? fluid.getAttributes().getColor() : 0xFFFFFFFF, 1));
|
||||
builder.addAll(ItemTextureQuadConverter.convertTexture(transform, templateSprite, fluidSprite, SOUTH_Z_FLUID, Direction.SOUTH, tint ? fluid.getAttributes().getColor() : 0xFFFFFFFF, 1));
|
||||
int luminosity = applyFluidLuminosity ? fluid.getAttributes().getLuminosity() : 0;
|
||||
int color = tint ? fluid.getAttributes().getColor() : 0xFFFFFFFF;
|
||||
builder.addQuads(ItemLayerModel.getLayerRenderType(luminosity > 0), ItemTextureQuadConverter.convertTexture(transform, templateSprite, fluidSprite, NORTH_Z_FLUID, Direction.NORTH, color, 1, luminosity));
|
||||
builder.addQuads(ItemLayerModel.getLayerRenderType(luminosity > 0), ItemTextureQuadConverter.convertTexture(transform, templateSprite, fluidSprite, SOUTH_Z_FLUID, Direction.SOUTH, color, 1, luminosity));
|
||||
}
|
||||
}
|
||||
|
||||
if (coverLocation != null && (!coverIsMask || baseLocation != null))
|
||||
{
|
||||
// cover (the actual item around the other two)
|
||||
TextureAtlasSprite coverSprite = spriteGetter.apply(coverLocation);
|
||||
if (coverSprite != null)
|
||||
{
|
||||
if (coverIsMask)
|
||||
{
|
||||
if (coverSprite != null && baseLocation != null)
|
||||
{
|
||||
TextureAtlasSprite baseSprite = spriteGetter.apply(baseLocation);
|
||||
builder.addAll(ItemTextureQuadConverter.convertTexture(transform, coverSprite, baseSprite, NORTH_Z_COVER, Direction.NORTH, 0xFFFFFFFF, 1));
|
||||
builder.addAll(ItemTextureQuadConverter.convertTexture(transform, coverSprite, baseSprite, SOUTH_Z_COVER, Direction.SOUTH, 0xFFFFFFFF, 1));
|
||||
builder.addQuads(ItemLayerModel.getLayerRenderType(false), ItemTextureQuadConverter.convertTexture(transform, coverSprite, baseSprite, NORTH_Z_COVER, Direction.NORTH, 0xFFFFFFFF, 2));
|
||||
builder.addQuads(ItemLayerModel.getLayerRenderType(false), ItemTextureQuadConverter.convertTexture(transform, coverSprite, baseSprite, SOUTH_Z_COVER, Direction.SOUTH, 0xFFFFFFFF, 2));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.add(ItemTextureQuadConverter.genQuad(transform, 0, 0, 16, 16, NORTH_Z_COVER, coverSprite, Direction.NORTH, 0xFFFFFFFF, 2));
|
||||
builder.add(ItemTextureQuadConverter.genQuad(transform, 0, 0, 16, 16, SOUTH_Z_COVER, coverSprite, Direction.SOUTH, 0xFFFFFFFF, 2));
|
||||
if (particleSprite == null)
|
||||
if (coverSprite != null)
|
||||
{
|
||||
particleSprite = coverSprite;
|
||||
}
|
||||
}
|
||||
builder.addQuads(ItemLayerModel.getLayerRenderType(false), ItemTextureQuadConverter.genQuad(transform, 0, 0, 16, 16, NORTH_Z_COVER, coverSprite, Direction.NORTH, 0xFFFFFFFF, 2));
|
||||
builder.addQuads(ItemLayerModel.getLayerRenderType(false), ItemTextureQuadConverter.genQuad(transform, 0, 0, 16, 16, SOUTH_Z_COVER, coverSprite, Direction.SOUTH, 0xFFFFFFFF, 2));
|
||||
}
|
||||
}
|
||||
|
||||
return new BakedModel(bakery, owner, this, builder.build(), particleSprite, Maps.immutableEnumMap(transformMap), Maps.newHashMap(), transform.isIdentity(), modelTransform, owner.isSideLit());
|
||||
builder.setParticle(particleSprite);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -193,10 +173,10 @@ public final class DynamicBucketModel implements IModelGeometry<DynamicBucketMod
|
|||
{
|
||||
Set<RenderMaterial> texs = Sets.newHashSet();
|
||||
|
||||
texs.add(owner.resolveTexture("particle"));
|
||||
texs.add(owner.resolveTexture("base"));
|
||||
texs.add(owner.resolveTexture("fluid"));
|
||||
texs.add(owner.resolveTexture("cover"));
|
||||
if (owner.isTexturePresent("particle")) texs.add(owner.resolveTexture("particle"));
|
||||
if (owner.isTexturePresent("base")) texs.add(owner.resolveTexture("base"));
|
||||
if (owner.isTexturePresent("fluid")) texs.add(owner.resolveTexture("fluid"));
|
||||
if (owner.isTexturePresent("cover")) texs.add(owner.resolveTexture("cover"));
|
||||
|
||||
return texs;
|
||||
}
|
||||
|
@ -251,70 +231,55 @@ public final class DynamicBucketModel implements IModelGeometry<DynamicBucketMod
|
|||
coverIsMask = modelContents.get("coverIsMask").getAsBoolean();
|
||||
}
|
||||
|
||||
boolean applyFluidLuminosity = true;
|
||||
if (modelContents.has("applyFluidLuminosity"))
|
||||
{
|
||||
applyFluidLuminosity = modelContents.get("applyFluidLuminosity").getAsBoolean();
|
||||
}
|
||||
|
||||
// create new model with correct liquid
|
||||
return new DynamicBucketModel(fluid, flip, tint, coverIsMask);
|
||||
return new DynamicBucketModel(fluid, flip, tint, coverIsMask, applyFluidLuminosity);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ContainedFluidOverrideHandler extends ItemOverrideList
|
||||
{
|
||||
private final Map<String, IBakedModel> cache = Maps.newHashMap(); // contains all the baked models since they'll never change
|
||||
private final ItemOverrideList nested;
|
||||
private final ModelBakery bakery;
|
||||
private final IModelConfiguration owner;
|
||||
private final DynamicBucketModel parent;
|
||||
|
||||
private ContainedFluidOverrideHandler(ModelBakery bakery)
|
||||
private ContainedFluidOverrideHandler(ItemOverrideList nested, ModelBakery bakery, IModelConfiguration owner, DynamicBucketModel parent)
|
||||
{
|
||||
this.nested = nested;
|
||||
this.bakery = bakery;
|
||||
this.owner = owner;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel func_239290_a_(IBakedModel originalModel, ItemStack stack, @Nullable ClientWorld world, @Nullable LivingEntity entity)
|
||||
{
|
||||
IBakedModel overriden = nested.func_239290_a_(originalModel, stack, world, entity);
|
||||
if (overriden != originalModel) return overriden;
|
||||
return FluidUtil.getFluidContained(stack)
|
||||
.map(fluidStack -> {
|
||||
BakedModel model = (BakedModel)originalModel;
|
||||
|
||||
Fluid fluid = fluidStack.getFluid();
|
||||
String name = fluid.getRegistryName().toString();
|
||||
|
||||
if (!model.cache.containsKey(name))
|
||||
if (!cache.containsKey(name))
|
||||
{
|
||||
DynamicBucketModel parent = model.parent.withFluid(fluid);
|
||||
IBakedModel bakedModel = parent.bake(model.owner, bakery, ModelLoader.defaultTextureGetter(), model.originalTransform, model.getOverrides(), new ResourceLocation("forge:bucket_override"));
|
||||
model.cache.put(name, bakedModel);
|
||||
DynamicBucketModel unbaked = this.parent.withFluid(fluid);
|
||||
IBakedModel bakedModel = unbaked.bake(owner, bakery, ModelLoader.defaultTextureGetter(), ModelRotation.X0_Y0, this, new ResourceLocation("forge:bucket_override"));
|
||||
cache.put(name, bakedModel);
|
||||
return bakedModel;
|
||||
}
|
||||
|
||||
return model.cache.get(name);
|
||||
return cache.get(name);
|
||||
})
|
||||
// not a fluid item apparently
|
||||
.orElse(originalModel); // empty bucket
|
||||
}
|
||||
}
|
||||
|
||||
// the dynamic bucket is based on the empty bucket
|
||||
private static final class BakedModel extends BakedItemModel
|
||||
{
|
||||
private final IModelConfiguration owner;
|
||||
private final DynamicBucketModel parent;
|
||||
private final Map<String, IBakedModel> cache; // contains all the baked models since they'll never change
|
||||
private final IModelTransform originalTransform;
|
||||
private final boolean isSideLit;
|
||||
|
||||
BakedModel(ModelBakery bakery,
|
||||
IModelConfiguration owner, DynamicBucketModel parent,
|
||||
ImmutableList<BakedQuad> quads,
|
||||
TextureAtlasSprite particle,
|
||||
ImmutableMap<TransformType, TransformationMatrix> transforms,
|
||||
Map<String, IBakedModel> cache,
|
||||
boolean untransformed,
|
||||
IModelTransform originalTransform, boolean isSideLit)
|
||||
{
|
||||
super(quads, particle, transforms, new ContainedFluidOverrideHandler(bakery), untransformed, isSideLit);
|
||||
this.owner = owner;
|
||||
this.parent = parent;
|
||||
this.cache = cache;
|
||||
this.originalTransform = originalTransform;
|
||||
this.isSideLit = isSideLit;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ import com.google.common.collect.ImmutableMap;
|
|||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
// TODO: Write a model loader and test/fix as needed
|
||||
public final class FluidModel implements IModelGeometry<FluidModel>
|
||||
{
|
||||
public static final FluidModel WATER = new FluidModel(Fluids.WATER);
|
||||
|
|
|
@ -76,7 +76,6 @@ public interface IModelConfiguration {
|
|||
* Gets the vanilla camera transforms data.
|
||||
* Do not use for non-vanilla code. For general usage, prefer getCombinedState.
|
||||
*/
|
||||
@Deprecated
|
||||
ItemCameraTransforms getCameraTransforms();
|
||||
|
||||
/**
|
||||
|
|
|
@ -19,18 +19,13 @@
|
|||
|
||||
package net.minecraftforge.client.model;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.*;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import net.minecraft.util.math.vector.TransformationMatrix;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.model.*;
|
||||
import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormatElement;
|
||||
|
@ -38,6 +33,8 @@ import net.minecraft.resources.IResourceManager;
|
|||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.JSONUtils;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.vector.TransformationMatrix;
|
||||
import net.minecraftforge.client.ForgeRenderTypes;
|
||||
import net.minecraftforge.client.model.geometry.IModelGeometry;
|
||||
import net.minecraftforge.client.model.pipeline.BakedQuadBuilder;
|
||||
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
|
||||
|
@ -55,7 +52,6 @@ import java.util.function.Function;
|
|||
* - Various fixes in the baking logic.
|
||||
* - Not limited to 4 layers maximum.
|
||||
*/
|
||||
// TODO: Implement as new model loader
|
||||
public final class ItemLayerModel implements IModelGeometry<ItemLayerModel>
|
||||
{
|
||||
public static final ItemLayerModel INSTANCE = new ItemLayerModel(ImmutableList.of());
|
||||
|
@ -93,16 +89,31 @@ public final class ItemLayerModel implements IModelGeometry<ItemLayerModel>
|
|||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<RenderMaterial, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ItemOverrideList overrides, ResourceLocation modelLocation)
|
||||
public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery,
|
||||
Function<RenderMaterial, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform,
|
||||
ItemOverrideList overrides, ResourceLocation modelLocation)
|
||||
{
|
||||
//TODO: Verify
|
||||
ImmutableMap<ItemCameraTransforms.TransformType, TransformationMatrix> transformMap =
|
||||
PerspectiveMapWrapper.getTransforms(new ModelTransformComposition(owner.getCombinedTransform(), modelTransform));
|
||||
TransformationMatrix transform = modelTransform.getRotation();
|
||||
ImmutableList<BakedQuad> quads = getQuadsForSprites(textures, transform, spriteGetter, fullbrightLayers);
|
||||
TextureAtlasSprite particle = spriteGetter.apply(
|
||||
owner.isTexturePresent("particle") ? owner.resolveTexture("particle") : textures.get(0)
|
||||
);
|
||||
ImmutableMap<TransformType, TransformationMatrix> map = PerspectiveMapWrapper.getTransforms(modelTransform);
|
||||
return new BakedItemModel(quads, particle, map, overrides, transform.isIdentity(), owner.isSideLit());
|
||||
|
||||
ItemMultiLayerBakedModel.Builder builder = ItemMultiLayerBakedModel.builder(owner, particle, overrides, transformMap);
|
||||
for(int i = 0; i < textures.size(); i++)
|
||||
{
|
||||
TextureAtlasSprite tas = spriteGetter.apply(textures.get(i));
|
||||
RenderType rt = getLayerRenderType(fullbrightLayers.contains(i));
|
||||
builder.addQuads(rt, getQuadsForSprite(i, tas, transform, true));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static RenderType getLayerRenderType(boolean isFullbright)
|
||||
{
|
||||
return isFullbright ? ForgeRenderTypes.ITEM_UNSORTED_UNLIT_TRANSLUCENT.get() : ForgeRenderTypes.ITEM_UNSORTED_TRANSLUCENT.get();
|
||||
}
|
||||
|
||||
public static ImmutableList<BakedQuad> getQuadsForSprites(List<RenderMaterial> textures, TransformationMatrix transform, Function<RenderMaterial, TextureAtlasSprite> spriteGetter)
|
||||
|
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
*
|
||||
* 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 com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.model.ItemCameraTransforms;
|
||||
import net.minecraft.client.renderer.model.ItemOverrideList;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.vector.TransformationMatrix;
|
||||
import net.minecraftforge.client.model.data.EmptyModelData;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class ItemMultiLayerBakedModel implements IBakedModel
|
||||
{
|
||||
private final boolean smoothLighting;
|
||||
private final boolean shadedInGui;
|
||||
private final boolean sideLit;
|
||||
private final TextureAtlasSprite particle;
|
||||
private final ItemOverrideList overrides;
|
||||
private final ImmutableList<Pair<IBakedModel, RenderType>> layerModels;
|
||||
private final ImmutableMap<ItemCameraTransforms.TransformType, TransformationMatrix> cameraTransforms;
|
||||
|
||||
public ItemMultiLayerBakedModel(boolean smoothLighting, boolean shadedInGui, boolean sideLit,
|
||||
TextureAtlasSprite particle, ItemOverrideList overrides,
|
||||
ImmutableMap<ItemCameraTransforms.TransformType, TransformationMatrix> cameraTransforms,
|
||||
ImmutableList<Pair<IBakedModel, RenderType>> layerModels)
|
||||
{
|
||||
this.smoothLighting = smoothLighting;
|
||||
this.shadedInGui = shadedInGui;
|
||||
this.sideLit = sideLit;
|
||||
this.particle = particle;
|
||||
this.overrides = overrides;
|
||||
this.layerModels = layerModels;
|
||||
this.cameraTransforms = cameraTransforms;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand)
|
||||
{
|
||||
List<BakedQuad> quads = Lists.newArrayList();
|
||||
layerModels.forEach(lm -> quads.addAll(lm.getFirst().getQuads(state, side, rand, EmptyModelData.INSTANCE)));
|
||||
return quads;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAmbientOcclusion()
|
||||
{
|
||||
return smoothLighting;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGui3d()
|
||||
{
|
||||
return shadedInGui;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean func_230044_c_()
|
||||
{
|
||||
return sideLit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltInRenderer()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureAtlasSprite getParticleTexture()
|
||||
{
|
||||
return particle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemOverrideList getOverrides()
|
||||
{
|
||||
return overrides;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesHandlePerspectives()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel handlePerspective(ItemCameraTransforms.TransformType cameraTransformType, MatrixStack mat)
|
||||
{
|
||||
return PerspectiveMapWrapper.handlePerspective(this, cameraTransforms, cameraTransformType, mat);
|
||||
}
|
||||
|
||||
//@Override
|
||||
public boolean isLayered()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//@Override
|
||||
public List<Pair<IBakedModel, RenderType>> getLayerModels(ItemStack itemStack, boolean fabulous)
|
||||
{
|
||||
return layerModels;
|
||||
}
|
||||
|
||||
public static Builder builder(IModelConfiguration owner, TextureAtlasSprite particle, ItemOverrideList overrides,
|
||||
ImmutableMap<ItemCameraTransforms.TransformType, TransformationMatrix> cameraTransforms)
|
||||
{
|
||||
return new Builder(owner, particle, overrides, cameraTransforms);
|
||||
}
|
||||
|
||||
public static class Builder
|
||||
{
|
||||
private final ImmutableList.Builder<Pair<IBakedModel, RenderType>> builder = ImmutableList.builder();
|
||||
private final List<BakedQuad> quads = Lists.newArrayList();
|
||||
private final ItemOverrideList overrides;
|
||||
private final ImmutableMap<ItemCameraTransforms.TransformType, TransformationMatrix> cameraTransforms;
|
||||
private final IModelConfiguration owner;
|
||||
private TextureAtlasSprite particle;
|
||||
private RenderType lastRt = null;
|
||||
|
||||
private Builder(IModelConfiguration owner, TextureAtlasSprite particle, ItemOverrideList overrides,
|
||||
ImmutableMap<ItemCameraTransforms.TransformType, TransformationMatrix> cameraTransforms)
|
||||
{
|
||||
this.owner = owner;
|
||||
this.particle = particle;
|
||||
this.overrides = overrides;
|
||||
this.cameraTransforms = cameraTransforms;
|
||||
}
|
||||
|
||||
private void addLayer(ImmutableList.Builder<Pair<IBakedModel, RenderType>> builder, List<BakedQuad> quads, RenderType rt)
|
||||
{
|
||||
IBakedModel model = new BakedItemModel(ImmutableList.copyOf(quads), particle, ImmutableMap.of(), ItemOverrideList.EMPTY, true, owner.isSideLit());
|
||||
builder.add(Pair.of(model, rt));
|
||||
}
|
||||
|
||||
private void flushQuads(RenderType rt)
|
||||
{
|
||||
if (rt != lastRt)
|
||||
{
|
||||
if (quads.size() > 0)
|
||||
{
|
||||
addLayer(builder, quads, lastRt);
|
||||
quads.clear();
|
||||
}
|
||||
lastRt = rt;
|
||||
}
|
||||
}
|
||||
|
||||
public Builder setParticle(TextureAtlasSprite particleSprite)
|
||||
{
|
||||
this.particle = particleSprite;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addQuads(RenderType rt, BakedQuad... quadsToAdd)
|
||||
{
|
||||
flushQuads(rt);
|
||||
Collections.addAll(quads, quadsToAdd);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addQuads(RenderType rt, Collection<BakedQuad> quadsToAdd)
|
||||
{
|
||||
flushQuads(rt);
|
||||
quads.addAll(quadsToAdd);
|
||||
return this;
|
||||
}
|
||||
|
||||
public IBakedModel build()
|
||||
{
|
||||
if (quads.size() > 0)
|
||||
{
|
||||
addLayer(builder, quads, lastRt);
|
||||
}
|
||||
return new ItemMultiLayerBakedModel(owner.useSmoothLighting(), owner.isShadedInGui(), owner.isSideLit(),
|
||||
particle, overrides, cameraTransforms, builder.build());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,11 +21,12 @@ package net.minecraftforge.client.model;
|
|||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import net.minecraft.util.math.vector.TransformationMatrix;
|
||||
import net.minecraft.client.renderer.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormatElement;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.vector.TransformationMatrix;
|
||||
import net.minecraftforge.client.model.pipeline.BakedQuadBuilder;
|
||||
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
|
||||
import net.minecraftforge.client.model.pipeline.TRSRTransformer;
|
||||
|
@ -47,15 +48,18 @@ public final class ItemTextureQuadConverter
|
|||
* The resulting list of quads is the texture represented as a list of horizontal OR vertical quads,
|
||||
* depending on which creates less quads. If the amount of quads is equal, horizontal is preferred.
|
||||
*
|
||||
* @param format
|
||||
* @param template The input texture to convert
|
||||
* @param sprite The texture whose UVs shall be used
|
||||
* @return The generated quads.
|
||||
*/
|
||||
public static List<BakedQuad> convertTexture(TransformationMatrix transform, TextureAtlasSprite template, TextureAtlasSprite sprite, float z, Direction facing, int color, int tint)
|
||||
{
|
||||
List<BakedQuad> horizontal = convertTextureHorizontal(transform, template, sprite, z, facing, color, tint);
|
||||
List<BakedQuad> vertical = convertTextureVertical(transform, template, sprite, z, facing, color, tint);
|
||||
return convertTexture(transform, template, sprite, z, facing, color, tint, 0);
|
||||
}
|
||||
public static List<BakedQuad> convertTexture(TransformationMatrix transform, TextureAtlasSprite template, TextureAtlasSprite sprite, float z, Direction facing, int color, int tint, int luminosity)
|
||||
{
|
||||
List<BakedQuad> horizontal = convertTextureHorizontal(transform, template, sprite, z, facing, color, tint, luminosity);
|
||||
List<BakedQuad> vertical = convertTextureVertical(transform, template, sprite, z, facing, color, tint, luminosity);
|
||||
|
||||
return horizontal.size() <= vertical.size() ? horizontal : vertical;
|
||||
}
|
||||
|
@ -65,6 +69,10 @@ public final class ItemTextureQuadConverter
|
|||
* The height of the strips is as big as possible.
|
||||
*/
|
||||
public static List<BakedQuad> convertTextureHorizontal(TransformationMatrix transform, TextureAtlasSprite template, TextureAtlasSprite sprite, float z, Direction facing, int color, int tint)
|
||||
{
|
||||
return convertTextureHorizontal(transform, template, sprite, z, facing, color, tint, 0);
|
||||
}
|
||||
public static List<BakedQuad> convertTextureHorizontal(TransformationMatrix transform, TextureAtlasSprite template, TextureAtlasSprite sprite, float z, Direction facing, int color, int tint, int luminosity)
|
||||
{
|
||||
int w = template.getWidth();
|
||||
int h = template.getHeight();
|
||||
|
@ -115,7 +123,7 @@ public final class ItemTextureQuadConverter
|
|||
(float)y * hScale,
|
||||
(float)x * wScale,
|
||||
(float)endY * hScale,
|
||||
z, sprite, facing, color, tint));
|
||||
z, sprite, facing, color, tint, luminosity));
|
||||
|
||||
// update Y if all the rows match. no need to rescan
|
||||
if (endY - y > 1)
|
||||
|
@ -136,6 +144,10 @@ public final class ItemTextureQuadConverter
|
|||
* The width of the strips is as big as possible.
|
||||
*/
|
||||
public static List<BakedQuad> convertTextureVertical(TransformationMatrix transform, TextureAtlasSprite template, TextureAtlasSprite sprite, float z, Direction facing, int color, int tint)
|
||||
{
|
||||
return convertTextureVertical(transform, template, sprite, z, facing, color, tint, 0);
|
||||
}
|
||||
public static List<BakedQuad> convertTextureVertical(TransformationMatrix transform, TextureAtlasSprite template, TextureAtlasSprite sprite, float z, Direction facing, int color, int tint, int luminosity)
|
||||
{
|
||||
int w = template.getWidth();
|
||||
int h = template.getHeight();
|
||||
|
@ -186,7 +198,7 @@ public final class ItemTextureQuadConverter
|
|||
(float)start * hScale,
|
||||
(float)endX * wScale,
|
||||
(float)y * hScale,
|
||||
z, sprite, facing, color, tint));
|
||||
z, sprite, facing, color, tint, luminosity));
|
||||
|
||||
// update X if all the columns match. no need to rescan
|
||||
if (endX - x > 1)
|
||||
|
@ -212,6 +224,10 @@ public final class ItemTextureQuadConverter
|
|||
* Coordinates are [0,16] to match the usual coordinates used in TextureAtlasSprites
|
||||
*/
|
||||
public static BakedQuad genQuad(TransformationMatrix transform, float x1, float y1, float x2, float y2, float z, TextureAtlasSprite sprite, Direction facing, int color, int tint)
|
||||
{
|
||||
return genQuad(transform, x1, y1, x2, y2, z, sprite, facing, color, tint, 0);
|
||||
}
|
||||
public static BakedQuad genQuad(TransformationMatrix transform, float x1, float y1, float x2, float y2, float z, TextureAtlasSprite sprite, Direction facing, int color, int tint, int luminosity)
|
||||
{
|
||||
float u1 = sprite.getInterpolatedU(x1);
|
||||
float v1 = sprite.getInterpolatedV(y1);
|
||||
|
@ -227,17 +243,18 @@ public final class ItemTextureQuadConverter
|
|||
y1 = 1f - y2;
|
||||
y2 = 1f - tmp;
|
||||
|
||||
return putQuad(transform, facing, sprite, color, tint, x1, y1, x2, y2, z, u1, v1, u2, v2);
|
||||
return putQuad(transform, facing, sprite, color, tint, x1, y1, x2, y2, z, u1, v1, u2, v2, luminosity);
|
||||
}
|
||||
|
||||
private static BakedQuad putQuad(TransformationMatrix transform, Direction side, TextureAtlasSprite sprite, int color, int tint,
|
||||
float x1, float y1, float x2, float y2, float z,
|
||||
float u1, float v1, float u2, float v2)
|
||||
float u1, float v1, float u2, float v2, int luminosity)
|
||||
{
|
||||
BakedQuadBuilder builder = new BakedQuadBuilder(sprite);
|
||||
|
||||
builder.setQuadTint(tint);
|
||||
builder.setQuadOrientation(side);
|
||||
builder.setApplyDiffuseLighting(luminosity == 0);
|
||||
|
||||
// only apply the transform if it's not identity
|
||||
boolean hasTransform = !transform.isIdentity();
|
||||
|
@ -245,28 +262,29 @@ public final class ItemTextureQuadConverter
|
|||
|
||||
if (side == Direction.SOUTH)
|
||||
{
|
||||
putVertex(consumer, side, x1, y1, z, u1, v2, color);
|
||||
putVertex(consumer, side, x2, y1, z, u2, v2, color);
|
||||
putVertex(consumer, side, x2, y2, z, u2, v1, color);
|
||||
putVertex(consumer, side, x1, y2, z, u1, v1, color);
|
||||
putVertex(consumer, side, x1, y1, z, u1, v2, color, luminosity);
|
||||
putVertex(consumer, side, x2, y1, z, u2, v2, color, luminosity);
|
||||
putVertex(consumer, side, x2, y2, z, u2, v1, color, luminosity);
|
||||
putVertex(consumer, side, x1, y2, z, u1, v1, color, luminosity);
|
||||
}
|
||||
else
|
||||
{
|
||||
putVertex(consumer, side, x1, y1, z, u1, v2, color);
|
||||
putVertex(consumer, side, x1, y2, z, u1, v1, color);
|
||||
putVertex(consumer, side, x2, y2, z, u2, v1, color);
|
||||
putVertex(consumer, side, x2, y1, z, u2, v2, color);
|
||||
putVertex(consumer, side, x1, y1, z, u1, v2, color, luminosity);
|
||||
putVertex(consumer, side, x1, y2, z, u1, v1, color, luminosity);
|
||||
putVertex(consumer, side, x2, y2, z, u2, v1, color, luminosity);
|
||||
putVertex(consumer, side, x2, y1, z, u2, v2, color, luminosity);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static void putVertex(IVertexConsumer consumer, Direction side,
|
||||
float x, float y, float z, float u, float v, int color)
|
||||
float x, float y, float z, float u, float v, int color, int luminosity)
|
||||
{
|
||||
VertexFormat format = consumer.getVertexFormat();
|
||||
for (int e = 0; e < format.getElements().size(); e++)
|
||||
{
|
||||
switch (format.getElements().get(e).getUsage())
|
||||
VertexFormatElement element = format.getElements().get(e);
|
||||
switch (element.getUsage())
|
||||
{
|
||||
case POSITION:
|
||||
consumer.put(e, x, y, z, 1f);
|
||||
|
@ -285,11 +303,16 @@ public final class ItemTextureQuadConverter
|
|||
consumer.put(e, offX, offY, offZ, 0f);
|
||||
break;
|
||||
case UV:
|
||||
if (format.getElements().get(e).getIndex() == 0)
|
||||
if (element.getIndex() == 0)
|
||||
{
|
||||
consumer.put(e, u, v, 0f, 1f);
|
||||
break;
|
||||
}
|
||||
else if (element.getIndex() == 2)
|
||||
{
|
||||
consumer.put(e, (luminosity<<4)/32768.0f, (luminosity<<4)/32768.0f, 0f, 1f);
|
||||
break;
|
||||
}
|
||||
// else fallthrough to default
|
||||
default:
|
||||
consumer.put(e);
|
||||
|
|
|
@ -24,7 +24,7 @@ import java.util.*;
|
|||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.*;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
|
@ -34,11 +34,14 @@ import net.minecraft.client.renderer.RenderType;
|
|||
import net.minecraft.util.math.vector.TransformationMatrix;
|
||||
import net.minecraft.client.renderer.model.*;
|
||||
import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType;
|
||||
import net.minecraft.client.renderer.texture.AtlasTexture;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.resources.IResourceManager;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.JSONUtils;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.ForgeRenderTypes;
|
||||
import net.minecraftforge.client.MinecraftForgeClient;
|
||||
|
||||
import net.minecraftforge.client.model.data.EmptyModelData;
|
||||
|
@ -48,9 +51,7 @@ import org.apache.logging.log4j.LogManager;
|
|||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A model that can be rendered in multiple {@link RenderType}.
|
||||
|
@ -92,11 +93,12 @@ public final class MultiLayerModel implements IModelGeometry<MultiLayerModel>
|
|||
IUnbakedModel missing = ModelLoader.instance().getMissingModel();
|
||||
|
||||
return new MultiLayerBakedModel(
|
||||
owner.useSmoothLighting(), owner.isShadedInGui(),
|
||||
owner.isSideLit(), spriteGetter.apply(owner.resolveTexture("particle")), overrides,
|
||||
buildModels(models, modelTransform, bakery, spriteGetter, modelLocation),
|
||||
owner.useSmoothLighting(), owner.isShadedInGui(), owner.isSideLit(),
|
||||
spriteGetter.apply(owner.resolveTexture("particle")), overrides, true,
|
||||
missing.bakeModel(bakery, spriteGetter, modelTransform, modelLocation),
|
||||
PerspectiveMapWrapper.getTransforms(new ModelTransformComposition(owner.getCombinedTransform(), modelTransform)));
|
||||
buildModels(models, modelTransform, bakery, spriteGetter, modelLocation),
|
||||
PerspectiveMapWrapper.getTransforms(new ModelTransformComposition(owner.getCombinedTransform(), modelTransform))
|
||||
);
|
||||
}
|
||||
|
||||
private static final class MultiLayerBakedModel implements IBakedModel
|
||||
|
@ -109,10 +111,13 @@ public final class MultiLayerModel implements IModelGeometry<MultiLayerModel>
|
|||
protected final TextureAtlasSprite particle;
|
||||
protected final ItemOverrideList overrides;
|
||||
private final IBakedModel missing;
|
||||
private final boolean convertRenderTypes;
|
||||
private final List<Pair<IBakedModel, RenderType>> itemLayers;
|
||||
|
||||
public MultiLayerBakedModel(
|
||||
boolean ambientOcclusion, boolean isGui3d, boolean isSideLit, TextureAtlasSprite particle, ItemOverrideList overrides,
|
||||
ImmutableMap<RenderType, IBakedModel> models, IBakedModel missing, ImmutableMap<TransformType, TransformationMatrix> cameraTransforms)
|
||||
boolean convertRenderTypes, IBakedModel missing, ImmutableMap<RenderType, IBakedModel> models,
|
||||
ImmutableMap<TransformType, TransformationMatrix> cameraTransforms)
|
||||
{
|
||||
this.isSideLit = isSideLit;
|
||||
this.models = models;
|
||||
|
@ -122,6 +127,12 @@ public final class MultiLayerModel implements IModelGeometry<MultiLayerModel>
|
|||
this.gui3d = isGui3d;
|
||||
this.particle = particle;
|
||||
this.overrides = overrides;
|
||||
this.convertRenderTypes = convertRenderTypes;
|
||||
this.itemLayers = models.entrySet().stream().map(kv -> {
|
||||
RenderType rt = kv.getKey();
|
||||
if (convertRenderTypes) rt = ITEM_RENDER_TYPE_MAPPING.getOrDefault(rt, rt);
|
||||
return Pair.of(kv.getValue(), rt);
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -144,6 +155,9 @@ public final class MultiLayerModel implements IModelGeometry<MultiLayerModel>
|
|||
}
|
||||
return builder.build();
|
||||
}
|
||||
// support for item layer rendering
|
||||
if (state == null && convertRenderTypes)
|
||||
layer = ITEM_RENDER_TYPE_MAPPING.inverse().getOrDefault(layer, layer);
|
||||
// assumes that child model will handle this state properly. FIXME?
|
||||
return models.getOrDefault(layer, missing).getQuads(state, side, rand, extraData);
|
||||
}
|
||||
|
@ -201,10 +215,38 @@ public final class MultiLayerModel implements IModelGeometry<MultiLayerModel>
|
|||
{
|
||||
return ItemOverrideList.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLayered()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Pair<IBakedModel, RenderType>> getLayerModels(ItemStack itemStack, boolean fabulous)
|
||||
{
|
||||
return itemLayers;
|
||||
}
|
||||
|
||||
public static BiMap<RenderType, RenderType> ITEM_RENDER_TYPE_MAPPING = HashBiMap.create();
|
||||
static {
|
||||
ITEM_RENDER_TYPE_MAPPING.put(RenderType.getSolid(), RenderType.getEntitySolid(AtlasTexture.LOCATION_BLOCKS_TEXTURE));
|
||||
ITEM_RENDER_TYPE_MAPPING.put(RenderType.getCutout(), RenderType.getEntityCutout(AtlasTexture.LOCATION_BLOCKS_TEXTURE));
|
||||
ITEM_RENDER_TYPE_MAPPING.put(RenderType.getCutoutMipped(), ForgeRenderTypes.getEntityCutoutMipped(AtlasTexture.LOCATION_BLOCKS_TEXTURE));
|
||||
ITEM_RENDER_TYPE_MAPPING.put(RenderType.getTranslucent(), RenderType.getEntityTranslucent(AtlasTexture.LOCATION_BLOCKS_TEXTURE));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Loader implements IModelLoader<MultiLayerModel>
|
||||
{
|
||||
public static final Map<String, RenderType> BLOCK_LAYERS = ImmutableMap.<String,RenderType>builder()
|
||||
.put("solid", RenderType.getSolid())
|
||||
.put("cutout", RenderType.getCutout())
|
||||
.put("cutout_mipped", RenderType.getCutoutMipped())
|
||||
.put("translucent", RenderType.getTranslucent())
|
||||
.put("tripwire", RenderType.func_241715_r_())
|
||||
.build();
|
||||
|
||||
public static final Loader INSTANCE = new Loader();
|
||||
|
||||
private Loader() {}
|
||||
|
@ -220,12 +262,12 @@ public final class MultiLayerModel implements IModelGeometry<MultiLayerModel>
|
|||
{
|
||||
ImmutableMap.Builder<RenderType, IUnbakedModel> builder = ImmutableMap.builder();
|
||||
JsonObject layersObject = JSONUtils.getJsonObject(modelContents, "layers");
|
||||
for(RenderType layer : RenderType.getBlockRenderTypes()) // block layers
|
||||
for(Map.Entry<String, RenderType> layer : BLOCK_LAYERS.entrySet()) // block layers
|
||||
{
|
||||
String layerName = layer.toString(); // mc overrides toString to return the ID for the layer
|
||||
String layerName = layer.getKey(); // mc overrides toString to return the ID for the layer
|
||||
if(layersObject.has(layerName))
|
||||
{
|
||||
builder.put(layer, deserializationContext.deserialize(JSONUtils.getJsonObject(layersObject, layerName), BlockModel.class));
|
||||
builder.put(layer.getValue(), deserializationContext.deserialize(JSONUtils.getJsonObject(layersObject, layerName), BlockModel.class));
|
||||
}
|
||||
}
|
||||
ImmutableMap<RenderType, IUnbakedModel> models = builder.build();
|
||||
|
|
|
@ -31,7 +31,7 @@ import net.minecraft.client.renderer.model.IBakedModel;
|
|||
import net.minecraft.util.Direction;
|
||||
|
||||
/**
|
||||
* Convenience interface with default implementation of {@link IBakedModel#getQuads(net.minecraft.block.state.IBlockState, net.minecraft.util.EnumFacing, java.util.Random)}.
|
||||
* Convenience interface with default implementation of {@link IBakedModel#getQuads(net.minecraft.block.BlockState, net.minecraft.util.Direction, java.util.Random)}.
|
||||
*/
|
||||
public interface IDynamicBakedModel extends IBakedModel
|
||||
{
|
||||
|
|
|
@ -33,6 +33,11 @@ public class ModelDataMap implements IModelData
|
|||
this.backingMap = new IdentityHashMap<>(map);
|
||||
}
|
||||
|
||||
protected ModelDataMap()
|
||||
{
|
||||
this.backingMap = new IdentityHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasProperty(ModelProperty<?> prop)
|
||||
{
|
||||
|
|
|
@ -150,6 +150,7 @@ public net.minecraft.client.particle.ParticleManager$IParticleMetaFactory
|
|||
public net.minecraft.client.renderer.GameRenderer func_175069_a(Lnet/minecraft/util/ResourceLocation;)V #loadShader
|
||||
private net.minecraft.client.renderer.ItemModelMesher field_199313_a #force public -> private
|
||||
public net.minecraft.client.renderer.ItemRenderer func_229112_a_(Lcom/mojang/blaze3d/matrix/MatrixStack;Lcom/mojang/blaze3d/vertex/IVertexBuilder;Ljava/util/List;Lnet/minecraft/item/ItemStack;II)V # renderQuads
|
||||
public net.minecraft.client.renderer.ItemRenderer func_229114_a_(Lnet/minecraft/client/renderer/model/IBakedModel;Lnet/minecraft/item/ItemStack;IILcom/mojang/blaze3d/matrix/MatrixStack;Lcom/mojang/blaze3d/vertex/IVertexBuilder;)V # renderModel
|
||||
public net.minecraft.client.renderer.entity.EntityRendererManager field_78729_o #renderers
|
||||
public net.minecraft.client.renderer.entity.EntityRendererManager func_229087_a_(Lnet/minecraft/entity/EntityType;Lnet/minecraft/client/renderer/entity/EntityRenderer;)V # addRenderer
|
||||
protected net.minecraft.client.renderer.entity.ItemRenderer func_177078_a(Lnet/minecraft/item/ItemStack;)I # getMiniItemCount
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"solid": {
|
||||
"parent": "block/cube_all",
|
||||
"textures": { "all": "block/slime_block" },
|
||||
"transform": { "scale": 0.5, "translation": [-0.25,-0.25,-0.25] }
|
||||
"transform": { "origin":"center", "scale": 0.625 }
|
||||
},
|
||||
"translucent": {
|
||||
"parent": "block/cube_all",
|
||||
|
|
Loading…
Reference in a new issue