More model/rendering fixes:

- Breaking change: Change ClientRegistry.bindTileEntityRenderer to a factory, so mods don't have to manually specify the dispatcher.
- Breaking change: Delete obsolete SimpleModelState (the class was duplicated by mistake, see SimpleModelTransform) and ICustomModelState (part of the old loader API).
- Breaking change: Rename getTextureDependencies to getTextures, for consistency.
- Reinstate the getRenderLayer method, fixed appropriately to return the new RenderType value.
- Fix OBJ loader applying the model transform in the wrong reference frame.
- Fix vanilla bug in TransformationMatrix#func_227986_a_
- Fix QuadTransformer logic.
- Added new method to IModelConfiguration to retrieve the owner IUnbakedModel, needed in order to construct ItemOverrideLists when baking custom models.
- Reintroduce multi-layer model through the new model loader system.
This commit is contained in:
David Quintana 2019-12-27 22:30:16 +01:00
parent e8ce61d4cd
commit fc189c9aaf
29 changed files with 325 additions and 344 deletions

View File

@ -25,7 +25,7 @@
} }
- p_229111_8_.func_177552_f().func_181688_b(p_229111_2_).func_228830_a_(p_229111_3_, p_229111_4_); - p_229111_8_.func_177552_f().func_181688_b(p_229111_2_).func_228830_a_(p_229111_3_, p_229111_4_);
+ net.minecraftforge.client.ForgeHooksClient.handleCameraTransforms(p_229111_4_, p_229111_8_, p_229111_2_, p_229111_3_); + p_229111_8_ = net.minecraftforge.client.ForgeHooksClient.handleCameraTransforms(p_229111_4_, p_229111_8_, p_229111_2_, p_229111_3_);
p_229111_4_.func_227861_a_(-0.5D, -0.5D, -0.5D); 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 || flag1)) { if (!p_229111_8_.func_188618_c() && (p_229111_1_.func_77973_b() != Items.field_203184_eO || flag1)) {
RenderType rendertype = RenderTypeLookup.func_228389_a_(p_229111_1_); RenderType rendertype = RenderTypeLookup.func_228389_a_(p_229111_1_);

View File

@ -9,6 +9,15 @@
private final Matrix4f field_227976_a_; private final Matrix4f field_227976_a_;
private boolean field_227977_b_; private boolean field_227977_b_;
@Nullable @Nullable
@@ -97,7 +97,7 @@
if (p_227986_0_ != null) {
matrix4f.field_226578_d_ = p_227986_0_.func_195899_a();
matrix4f.field_226582_h_ = p_227986_0_.func_195900_b();
- matrix4f.field_226589_o_ = p_227986_0_.func_195902_c();
+ matrix4f.field_226586_l_ = p_227986_0_.func_195902_c();
}
return matrix4f;
@@ -133,4 +133,32 @@ @@ -133,4 +133,32 @@
public int hashCode() { public int hashCode() {
return Objects.hash(this.field_227976_a_); return Objects.hash(this.field_227976_a_);

View File

@ -34,6 +34,7 @@ import java.util.function.Supplier;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import net.minecraft.client.renderer.RenderType;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import com.google.common.cache.Cache; import com.google.common.cache.Cache;
@ -52,11 +53,10 @@ import net.minecraft.world.World;
public class MinecraftForgeClient public class MinecraftForgeClient
{ {
/* TODO: reimplement public static RenderType getRenderLayer()
public static BlockRenderLayer getRenderLayer()
{ {
return ForgeHooksClient.renderLayer.get(); return ForgeHooksClient.renderLayer.get();
}*/ }
/** /**
* returns the Locale set by the player in Minecraft. * returns the Locale set by the player in Minecraft.

View File

@ -44,6 +44,13 @@ public class BlockModelConfiguration implements IModelConfiguration
this.owner = owner; this.owner = owner;
} }
@Nullable
@Override
public IUnbakedModel getOwnerModel()
{
return owner;
}
@Override @Override
public String getModelName() public String getModelName()
{ {
@ -138,12 +145,12 @@ public class BlockModelConfiguration implements IModelConfiguration
geometry.getTextures(this, modelGetter, missingTextureErrors); geometry.getTextures(this, modelGetter, missingTextureErrors);
} }
public IBakedModel bake(ModelBakery bakery, Function<Material, TextureAtlasSprite> bakedTextureGetter, IModelTransform sprite, ItemOverrideList overrides, ResourceLocation modelLocation) public IBakedModel bake(ModelBakery bakery, Function<Material, TextureAtlasSprite> bakedTextureGetter, IModelTransform modelTransform, ItemOverrideList overrides, ResourceLocation modelLocation)
{ {
IModelGeometry<?> geometry = getCustomGeometry(); IModelGeometry<?> geometry = getCustomGeometry();
if (geometry == null) if (geometry == null)
throw new IllegalStateException("Can not use custom baking without custom geometry"); throw new IllegalStateException("Can not use custom baking without custom geometry");
return geometry.bake(this, bakery, bakedTextureGetter, sprite, overrides, modelLocation); return geometry.bake(this, bakery, bakedTextureGetter, modelTransform, overrides, modelLocation);
} }
public static class VisibilityData public static class VisibilityData

View File

@ -109,10 +109,10 @@ final class FancyMissingModel implements IUnbakedModel
@Nullable @Nullable
@Override @Override
public IBakedModel func_225613_a_(ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform sprite, ResourceLocation modelLocation) public IBakedModel func_225613_a_(ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ResourceLocation modelLocation)
{ {
IBakedModel bigMissing = missingModel.func_225613_a_(bakery, spriteGetter, sprite, modelLocation); IBakedModel bigMissing = missingModel.func_225613_a_(bakery, spriteGetter, modelTransform, modelLocation);
ModelTransformComposition smallState = new ModelTransformComposition(sprite, new SimpleModelTransform(smallTransformation)); ModelTransformComposition smallState = new ModelTransformComposition(modelTransform, new SimpleModelTransform(smallTransformation));
IBakedModel smallMissing = missingModel.func_225613_a_(bakery, spriteGetter, smallState, modelLocation); IBakedModel smallMissing = missingModel.func_225613_a_(bakery, spriteGetter, smallState, modelLocation);
return new BakedModel(bigMissing, smallMissing, fontCache.getUnchecked(DefaultVertexFormats.BLOCK), message, spriteGetter.apply(font2)); return new BakedModel(bigMissing, smallMissing, fontCache.getUnchecked(DefaultVertexFormats.BLOCK), message, spriteGetter.apply(font2));
} }

View File

@ -1,64 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* 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.function.Predicate;
import net.minecraft.client.renderer.model.IUnbakedModel;
import net.minecraft.resources.IResourceManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.resource.IResourceType;
import net.minecraftforge.resource.ISelectiveResourceReloadListener;
import net.minecraftforge.resource.VanillaResourceType;
public interface ICustomModelLoader extends ISelectiveResourceReloadListener
{
@Override
void onResourceManagerReload(IResourceManager resourceManager);
@Override
default void onResourceManagerReload(IResourceManager resourceManager, Predicate<IResourceType> resourcePredicate)
{
if (resourcePredicate.test(VanillaResourceType.MODELS))
{
onResourceManagerReload(resourceManager);
}
}
/**
* Checks if given model should be loaded by this loader.
* Reading file contents is inadvisable, if possible decision should be made based on the location alone.
* @param modelLocation The path, either to an actual file or a {@link net.minecraft.client.renderer.model.ModelResourceLocation}.
*/
boolean accepts(ResourceLocation modelLocation);
/**
* @param modelLocation The model to (re)load, either path to an
* actual file or a {@link net.minecraft.client.renderer.model.ModelResourceLocation}.
*/
IUnbakedModel loadModel(ResourceLocation modelLocation) throws Exception;
@Override
default IResourceType getResourceType()
{
return VanillaResourceType.MODELS;
}
}

View File

@ -20,15 +20,25 @@
package net.minecraftforge.client.model; package net.minecraftforge.client.model;
import net.minecraft.client.renderer.model.IModelTransform; import net.minecraft.client.renderer.model.IModelTransform;
import net.minecraft.client.renderer.model.IUnbakedModel;
import net.minecraft.client.renderer.model.ItemCameraTransforms; import net.minecraft.client.renderer.model.ItemCameraTransforms;
import net.minecraft.client.renderer.model.Material; import net.minecraft.client.renderer.model.Material;
import net.minecraftforge.client.model.geometry.IModelGeometryPart; import net.minecraftforge.client.model.geometry.IModelGeometryPart;
import javax.annotation.Nullable;
/* /*
* Interface that provides generic access to the data within BlockModel, * Interface that provides generic access to the data within BlockModel,
* while allowing non-blockmodel usage of models * while allowing non-blockmodel usage of models
*/ */
public interface IModelConfiguration { public interface IModelConfiguration {
/**
* If available, gets the owning model (usually BlockModel) of this configuration
*/
@Nullable
IUnbakedModel getOwnerModel();
/** /**
* @return The name of the model being baked, for logging and cache purposes. * @return The name of the model being baked, for logging and cache purposes.
*/ */

View File

@ -82,15 +82,15 @@ public final class ItemLayerModel implements IModelGeometry<ItemLayerModel>
} }
@Override @Override
public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform sprite, ItemOverrideList overrides, ResourceLocation modelLocation) public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ItemOverrideList overrides, ResourceLocation modelLocation)
{ {
//TODO: Verify //TODO: Verify
TransformationMatrix transform = sprite.func_225615_b_(); TransformationMatrix transform = modelTransform.func_225615_b_();
ImmutableList<BakedQuad> quads = getQuadsForSprites(textures, DefaultVertexFormats.BLOCK, transform, spriteGetter); ImmutableList<BakedQuad> quads = getQuadsForSprites(textures, DefaultVertexFormats.BLOCK, transform, spriteGetter);
TextureAtlasSprite particle = spriteGetter.apply( TextureAtlasSprite particle = spriteGetter.apply(
owner.isTexturePresent("particle") ? owner.resolveTexture("particle") : textures.get(0) owner.isTexturePresent("particle") ? owner.resolveTexture("particle") : textures.get(0)
); );
ImmutableMap<TransformType, TransformationMatrix> map = PerspectiveMapWrapper.getTransforms(sprite); ImmutableMap<TransformType, TransformationMatrix> map = PerspectiveMapWrapper.getTransforms(modelTransform);
return new BakedItemModel(quads, particle, map, overrides, transform.isIdentity()); return new BakedItemModel(quads, particle, map, overrides, transform.isIdentity());
} }

View File

@ -80,12 +80,12 @@ public final class ModelFluid implements IModelGeometry<ModelFluid>
} }
@Override @Override
public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform sprite, ItemOverrideList overrides, ResourceLocation modelLocation) public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ItemOverrideList overrides, ResourceLocation modelLocation)
{ {
FluidAttributes attrs = fluid.getAttributes(); FluidAttributes attrs = fluid.getAttributes();
return new CachingBakedFluid( return new CachingBakedFluid(
sprite.func_225615_b_(), modelTransform.func_225615_b_(),
PerspectiveMapWrapper.getTransforms(sprite), PerspectiveMapWrapper.getTransforms(modelTransform),
modelLocation, modelLocation,
attrs.getColor(), attrs.getColor(),
spriteGetter.apply(ForgeHooksClient.getBlockMaterial(attrs.getStillTexture())), spriteGetter.apply(ForgeHooksClient.getBlockMaterial(attrs.getStillTexture())),

View File

@ -63,11 +63,11 @@ public class ModelLoaderRegistry
registerLoader(new ResourceLocation("forge:bucket"), ModelDynBucket.LoaderDynBucket2.INSTANCE); registerLoader(new ResourceLocation("forge:bucket"), ModelDynBucket.LoaderDynBucket2.INSTANCE);
registerLoader(new ResourceLocation("forge:composite"), CompositeModel.Loader.INSTANCE); registerLoader(new ResourceLocation("forge:composite"), CompositeModel.Loader.INSTANCE);
registerLoader(new ResourceLocation("minecraft:elements"), VanillaProxy.Loader.INSTANCE); registerLoader(new ResourceLocation("minecraft:elements"), VanillaProxy.Loader.INSTANCE);
registerLoader(new ResourceLocation("forge:multi-layer"), MultiLayerModel.Loader.INSTANCE);
// TODO: Implement as new model loaders // TODO: Implement as new model loaders
//registerLoader(new ResourceLocation("forge:b3d"), new ModelLoaderAdapter(B3DLoader.INSTANCE)); //registerLoader(new ResourceLocation("forge:b3d"), new ModelLoaderAdapter(B3DLoader.INSTANCE));
//registerLoader(new ResourceLocation("forge:fluid"), new ModelLoaderAdapter(ModelFluid.FluidLoader.INSTANCE)); //registerLoader(new ResourceLocation("forge:fluid"), new ModelLoaderAdapter(ModelFluid.FluidLoader.INSTANCE));
//registerLoader(new ResourceLocation("forge:multi-layer"), new ModelLoaderAdapter(MultiLayerModel.Loader.INSTANCE));
} }
/** /**
@ -212,22 +212,22 @@ public class ModelLoaderRegistry
} }
} }
public static IBakedModel bakeHelper(BlockModel blockModel, ModelBakery modelBakery, BlockModel otherModel, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform sprite, ResourceLocation modelLocation) public static IBakedModel bakeHelper(BlockModel blockModel, ModelBakery modelBakery, BlockModel otherModel, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ResourceLocation modelLocation)
{ {
IBakedModel model; IBakedModel model;
IModelGeometry<?> customModel = blockModel.customData.getCustomGeometry(); IModelGeometry<?> customModel = blockModel.customData.getCustomGeometry();
IModelTransform customModelState = blockModel.customData.getCustomModelState(); IModelTransform customModelState = blockModel.customData.getCustomModelState();
if (customModelState != null) if (customModelState != null)
{ {
sprite = new ModelTransformComposition(customModelState, sprite, sprite.isUvLock()); modelTransform = new ModelTransformComposition(customModelState, modelTransform, modelTransform.isUvLock());
} }
if (customModel != null) if (customModel != null)
{ {
model = customModel.bake(blockModel.customData, modelBakery, spriteGetter, sprite, blockModel.getOverrides(modelBakery, otherModel, spriteGetter), modelLocation); model = customModel.bake(blockModel.customData, modelBakery, spriteGetter, modelTransform, blockModel.getOverrides(modelBakery, otherModel, spriteGetter), modelLocation);
} }
else else
{ {
model = blockModel.bakeVanilla(modelBakery, otherModel, spriteGetter, sprite, modelLocation); model = blockModel.bakeVanilla(modelBakery, otherModel, spriteGetter, modelTransform, modelLocation);
} }
if (customModelState != null && !model.doesHandlePerspectives()) if (customModelState != null && !model.doesHandlePerspectives())
@ -248,18 +248,18 @@ public class ModelLoaderRegistry
} }
@Override @Override
public void addQuads(IModelConfiguration owner, IModelBuilder<?> modelBuilder, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform sprite, ResourceLocation modelLocation) public void addQuads(IModelConfiguration owner, IModelBuilder<?> modelBuilder, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ResourceLocation modelLocation)
{ {
for(BlockPart blockpart : elements) { for(BlockPart blockpart : elements) {
for(Direction direction : blockpart.mapFaces.keySet()) { for(Direction direction : blockpart.mapFaces.keySet()) {
BlockPartFace blockpartface = blockpart.mapFaces.get(direction); BlockPartFace blockpartface = blockpart.mapFaces.get(direction);
TextureAtlasSprite textureatlassprite1 = spriteGetter.apply(owner.resolveTexture(blockpartface.texture)); TextureAtlasSprite textureatlassprite1 = spriteGetter.apply(owner.resolveTexture(blockpartface.texture));
if (blockpartface.cullFace == null) { if (blockpartface.cullFace == null) {
modelBuilder.addGeneralQuad(BlockModel.makeBakedQuad(blockpart, blockpartface, textureatlassprite1, direction, sprite, modelLocation)); modelBuilder.addGeneralQuad(BlockModel.makeBakedQuad(blockpart, blockpartface, textureatlassprite1, direction, modelTransform, modelLocation));
} else { } else {
modelBuilder.addFaceQuad( modelBuilder.addFaceQuad(
sprite.func_225615_b_().rotateTransform(blockpartface.cullFace), modelTransform.func_225615_b_().rotateTransform(blockpartface.cullFace),
BlockModel.makeBakedQuad(blockpart, blockpartface, textureatlassprite1, direction, sprite, modelLocation)); BlockModel.makeBakedQuad(blockpart, blockpartface, textureatlassprite1, direction, modelTransform, modelLocation));
} }
} }
} }

View File

@ -19,138 +19,115 @@
package net.minecraftforge.client.model; package net.minecraftforge.client.model;
import java.util.Collection; import java.util.*;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.google.common.collect.Sets;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.datafixers.util.Pair;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.TransformationMatrix; import net.minecraft.client.renderer.TransformationMatrix;
import net.minecraft.client.renderer.model.*; import net.minecraft.client.renderer.model.*;
import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.resources.IResourceManager;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.JSONUtils;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.MinecraftForgeClient; import net.minecraftforge.client.MinecraftForgeClient;
import net.minecraftforge.client.model.data.EmptyModelData;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.geometry.IModelGeometry;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.util.function.Function; import java.util.function.Function;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
/** /**
* A model that can be rendered in multiple {@link BlockRenderLayer}. * A model that can be rendered in multiple {@link RenderType}.
*/ */
/* TODO: reimplement public final class MultiLayerModel implements IModelGeometry<MultiLayerModel>
public final class MultiLayerModel implements IUnbakedModel
{ {
private static final Logger LOGGER = LogManager.getLogger(); private static final Logger LOGGER = LogManager.getLogger();
public static final MultiLayerModel INSTANCE = new MultiLayerModel(ImmutableMap.of());
private final ImmutableMap<Optional<BlockRenderLayer>, ResourceLocation> models; private final ImmutableMap<RenderType, IUnbakedModel> models;
@Nullable
private final IUnbakedModel base;
public MultiLayerModel(ImmutableMap<Optional<BlockRenderLayer>, ResourceLocation> models) public MultiLayerModel(@Nullable IUnbakedModel base, ImmutableMap<RenderType, IUnbakedModel> models)
{ {
this.base = base;
this.models = models; this.models = models;
} }
@Override
public Collection<ResourceLocation> getDependencies()
{
return ImmutableList.copyOf(models.values());
}
@Override @Override
public Collection<Material> func_225614_a_(Function<ResourceLocation, IUnbakedModel> p_225614_1_, Set<com.mojang.datafixers.util.Pair<String, String>> p_225614_2_) public Collection<Material> getTextures(IModelConfiguration owner, Function<ResourceLocation, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors)
{ {
Set<Material> materials = Sets.newHashSet();
if (base != null)
materials.addAll(base.func_225614_a_(modelGetter, missingTextureErrors));
for (IUnbakedModel m : models.values())
materials.addAll(m.func_225614_a_(modelGetter, missingTextureErrors));
return Collections.emptyList(); return Collections.emptyList();
} }
private static ImmutableMap<RenderType, IBakedModel> buildModels(ImmutableMap<RenderType, IUnbakedModel> models, IModelTransform modelTransform, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, ResourceLocation modelLocation)
private static ImmutableMap<Optional<BlockRenderLayer>, IBakedModel> buildModels(ImmutableMap<Optional<BlockRenderLayer>, ResourceLocation> models, IModelTransform sprite, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, ResourceLocation p_225613_4_)
{ {
ImmutableMap.Builder<Optional<BlockRenderLayer>, IBakedModel> builder = ImmutableMap.builder(); ImmutableMap.Builder<RenderType, IBakedModel> builder = ImmutableMap.builder();
for(Optional<BlockRenderLayer> key : models.keySet()) for(Map.Entry<RenderType, IUnbakedModel> entry : models.entrySet())
{ {
IUnbakedModel model = ModelLoader.defaultModelGetter().apply(models.get(key)); builder.put(entry.getKey(), entry.getValue().func_225613_a_(bakery, spriteGetter, modelTransform, modelLocation));
builder.put(key, model.func_225613_a_(bakery, spriteGetter, sprite, p_225613_4_));
} }
return builder.build(); return builder.build();
} }
@Nullable
@Override @Override
public IBakedModel func_225613_a_(ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform sprite, ResourceLocation p_225613_4_) public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ItemOverrideList overrides, ResourceLocation modelLocation)
{ {
IUnbakedModel missing = ModelLoader.instance().getMissingModel(); IUnbakedModel missing = ModelLoader.instance().getMissingModel();
return new MultiLayerBakedModel( return new MultiLayerBakedModel(
buildModels(models, sprite, bakery, spriteGetter, p_225613_4_), base != null ? base.func_225613_a_(bakery, spriteGetter, modelTransform, modelLocation) : null,
missing.func_225613_a_(bakery, spriteGetter, sprite, p_225613_4_), buildModels(models, modelTransform, bakery, spriteGetter, modelLocation),
PerspectiveMapWrapper.getTransforms(sprite) missing.func_225613_a_(bakery, spriteGetter, modelTransform, modelLocation),
PerspectiveMapWrapper.getTransforms(modelTransform)
); );
} }
public MultiLayerModel process(ImmutableMap<String, String> customData)
{
ImmutableMap.Builder<Optional<BlockRenderLayer>, ResourceLocation> builder = ImmutableMap.builder();
for(String key : customData.keySet())
{
if("base".equals(key))
{
builder.put(Optional.empty(), 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>, ResourceLocation> models = builder.build();
if(models.isEmpty()) return INSTANCE;
return new MultiLayerModel(models);
}
private ResourceLocation getLocation(String json)
{
JsonElement e = new JsonParser().parse(json);
if(e.isJsonPrimitive() && e.getAsJsonPrimitive().isString())
{
return new ModelResourceLocation(e.getAsString());
}
LOGGER.fatal("Expect ModelResourceLocation, got: {}", json);
return new ModelResourceLocation("builtin/missing", "missing");
}
private static final class MultiLayerBakedModel implements IBakedModel private static final class MultiLayerBakedModel implements IBakedModel
{ {
private final ImmutableMap<Optional<BlockRenderLayer>, IBakedModel> models; private final ImmutableMap<RenderType, IBakedModel> models;
private final ImmutableMap<TransformType, TransformationMatrix> cameraTransforms; private final ImmutableMap<TransformType, TransformationMatrix> cameraTransforms;
private final IBakedModel base; private final IBakedModel base;
private final IBakedModel missing; private final IBakedModel missing;
public MultiLayerBakedModel(ImmutableMap<Optional<BlockRenderLayer>, IBakedModel> models, IBakedModel missing, ImmutableMap<TransformType, TransformationMatrix> cameraTransforms) public MultiLayerBakedModel(@Nullable IBakedModel base, ImmutableMap<RenderType, IBakedModel> models, IBakedModel missing, ImmutableMap<TransformType, TransformationMatrix> cameraTransforms)
{ {
this.models = models; this.models = models;
this.cameraTransforms = cameraTransforms; this.cameraTransforms = cameraTransforms;
this.missing = missing; this.missing = missing;
this.base = models.getOrDefault(Optional.empty(), missing); this.base = base != null ? base : missing;
} }
@Override @Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand) public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand)
{ {
BlockRenderLayer layer = MinecraftForgeClient.getRenderLayer(); return getQuads(state, side, rand, EmptyModelData.INSTANCE);
}
@Nonnull
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, @Nonnull Random rand, @Nonnull IModelData extraData)
{
RenderType layer = MinecraftForgeClient.getRenderLayer();
if (layer == null) if (layer == null)
{ {
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder(); ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
@ -161,7 +138,8 @@ public final class MultiLayerModel implements IUnbakedModel
return builder.build(); return builder.build();
} }
// assumes that child model will handle this state properly. FIXME? // assumes that child model will handle this state properly. FIXME?
return models.getOrDefault(Optional.of(layer), missing).getQuads(state, side, rand); List<BakedQuad> quads = models.getOrDefault(layer, missing).getQuads(state, side, rand, extraData);
return quads;
} }
@Override @Override
@ -201,9 +179,9 @@ public final class MultiLayerModel implements IUnbakedModel
} }
@Override @Override
public Pair<? extends IBakedModel, Matrix4f> handlePerspective(TransformType cameraTransformType) public IBakedModel handlePerspective(TransformType cameraTransformType, MatrixStack mat)
{ {
return PerspectiveMapWrapper.handlePerspective(this, cameraTransforms, cameraTransformType); return PerspectiveMapWrapper.handlePerspective(this, cameraTransforms, cameraTransformType, mat);
} }
@Override @Override
@ -212,5 +190,39 @@ public final class MultiLayerModel implements IUnbakedModel
return ItemOverrideList.EMPTY; return ItemOverrideList.EMPTY;
} }
} }
}
*/ public static final class Loader implements IModelLoader<MultiLayerModel>
{
public static final Loader INSTANCE = new Loader();
private Loader() {}
@Override
public void onResourceManagerReload(IResourceManager resourceManager)
{
}
@Override
public MultiLayerModel read(JsonDeserializationContext deserializationContext, JsonObject modelContents)
{
ImmutableMap.Builder<RenderType, IUnbakedModel> builder = ImmutableMap.builder();
JsonObject layersObject = JSONUtils.getJsonObject(modelContents, "layers");
BlockModel base = null;
if(layersObject.has("base"))
{
base = deserializationContext.deserialize(JSONUtils.getJsonObject(layersObject, "base"), BlockModel.class);
}
for(RenderType layer : RenderType.func_228661_n_()) // block layers
{
String layerName = layer.toString(); // 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));
}
}
ImmutableMap<RenderType, IUnbakedModel> models = builder.build();
return new MultiLayerModel(base, models);
}
}
}

View File

@ -48,22 +48,22 @@ public class QuadTransformer
private void processVertices(int[] inData, int[] outData) private void processVertices(int[] inData, int[] outData)
{ {
int stride = format.getIntegerSize(); int stride = format.getSize();
int count = inData.length / stride; int count = (inData.length * 4) / stride;
for (int i=0;i<count;i++) for (int i=0;i<count;i++)
{ {
int offset = positionOffset + i * stride; int offset = positionOffset + i * stride;
float x = Float.intBitsToFloat(inData[offset ]); float x = Float.intBitsToFloat(getAtByteOffset(inData, offset ));
float y = Float.intBitsToFloat(inData[offset + 1]); float y = Float.intBitsToFloat(getAtByteOffset(inData, offset + 4));
float z = Float.intBitsToFloat(inData[offset + 2]); float z = Float.intBitsToFloat(getAtByteOffset(inData, offset + 8));
Vector4f pos = new Vector4f(x, y, z, 1); Vector4f pos = new Vector4f(x, y, z, 1);
transform.transformPosition(pos); transform.transformPosition(pos);
pos.func_229374_e_(); pos.func_229375_f_();
outData[offset] = Float.floatToRawIntBits(pos.getX()); putAtByteOffset(outData, offset, Float.floatToRawIntBits(pos.getX()));
outData[offset + 1] = Float.floatToRawIntBits(pos.getY()); putAtByteOffset(outData,offset + 4, Float.floatToRawIntBits(pos.getY()));
outData[offset + 2] = Float.floatToRawIntBits(pos.getZ()); putAtByteOffset(outData,offset + 8, Float.floatToRawIntBits(pos.getZ()));
} }
if (normalOffset >= 0) if (normalOffset >= 0)
@ -71,25 +71,57 @@ public class QuadTransformer
for (int i=0;i<count;i++) for (int i=0;i<count;i++)
{ {
int offset = normalOffset + i * stride; int offset = normalOffset + i * stride;
int normalIn = inData[offset]; int normalIn = getAtByteOffset(inData,offset);
float x = (((normalIn)>>24)&0xFF)/255.0f; if (normalIn != 0)
float y = (((normalIn<<8)>>24)&0xFF)/255.0f; {
float z = (((normalIn<<16)>>24)&0xFF)/255.0f; float x = (((normalIn) >> 24) & 0xFF) / 255.0f;
float y = (((normalIn << 8) >> 24) & 0xFF) / 255.0f;
float z = (((normalIn << 16) >> 24) & 0xFF) / 255.0f;
Vector3f pos = new Vector3f(x, y, z); Vector3f pos = new Vector3f(x, y, z);
transform.transformNormal(pos); transform.transformNormal(pos);
pos.func_229194_d_();
int normalOut = int normalOut = (((int) (x / 255.0) & 0xFF) << 24) |
(((int)(x/255.0)&0xFF)<<24) | (((int) (y / 255.0) & 0xFF) << 16) |
(((int)(y/255.0)&0xFF)<<16) | (((int) (z / 255.0) & 0xFF) << 8) |
(((int)(z/255.0)&0xFF)<<8) | (normalIn & 0xFF);
(normalIn&0xFF);
outData[offset] = normalOut; putAtByteOffset(outData, offset, normalOut);
}
} }
} }
} }
private static int getAtByteOffset(int[] inData, int offset)
{
int index = offset / 4;
int lsb = inData[index];
int shift = (offset % 4) * 8;
if (shift == 0)
return inData[index];
int msb = inData[index+1];
return (lsb >>> shift) | (msb << (32-shift));
}
private static void putAtByteOffset(int[] outData, int offset, int value)
{
int index = offset / 4;
int shift = (offset % 4) * 8;
if (shift == 0)
outData[index] = value;
int lsbMask = 0xFFFFFFFF >>> (32-shift);
int msbMask = 0xFFFFFFFF << shift;
outData[index] = (outData[index] & lsbMask) | (value << shift);
outData[index+1] = (outData[index+1] & msbMask) | (value >>> (32-shift));
}
private static int findPositionOffset(VertexFormat fmt) private static int findPositionOffset(VertexFormat fmt)
{ {
int index; int index;

View File

@ -1,57 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* 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 net.minecraft.client.renderer.TransformationMatrix;
import net.minecraft.client.renderer.model.IModelTransform;
import com.google.common.collect.ImmutableMap;
/**
* Simple implementation of IModelState via a map and a default value.
*/
public final class SimpleModelState implements IModelTransform
{
private final ImmutableMap<? extends Object, TransformationMatrix> map;
private final TransformationMatrix def;
public SimpleModelState(ImmutableMap<? extends Object, TransformationMatrix> map)
{
this(map, TransformationMatrix.func_227983_a_());
}
public SimpleModelState(ImmutableMap<? extends Object, TransformationMatrix> map, TransformationMatrix def)
{
this.map = map;
this.def = def;
}
@Override
public TransformationMatrix func_225615_b_()
{
return def;
}
@Override
public TransformationMatrix getPartTransformation(Object part)
{
return map.getOrDefault(part, TransformationMatrix.func_227983_a_());
}
}

View File

@ -460,7 +460,7 @@ public enum B3DLoader implements ISelectiveResourceReloadListener
@Nullable @Nullable
@Override @Override
public IBakedModel func_225613_a_(ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform sprite, ResourceLocation modelLocation) public IBakedModel func_225613_a_(ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ResourceLocation modelLocation)
{ {
ImmutableMap.Builder<String, TextureAtlasSprite> builder = ImmutableMap.builder(); ImmutableMap.Builder<String, TextureAtlasSprite> builder = ImmutableMap.builder();
TextureAtlasSprite missing = spriteGetter.apply(new Material(AtlasTexture.LOCATION_BLOCKS_TEXTURE, MissingTextureSprite.getLocation())); TextureAtlasSprite missing = spriteGetter.apply(new Material(AtlasTexture.LOCATION_BLOCKS_TEXTURE, MissingTextureSprite.getLocation()));
@ -477,7 +477,7 @@ public enum B3DLoader implements ISelectiveResourceReloadListener
} }
} }
builder.put("missingno", missing); builder.put("missingno", missing);
return new BakedWrapper(model.getRoot(), sprite, smooth, gui3d, DefaultVertexFormats.BLOCK, meshes, builder.build()); return new BakedWrapper(model.getRoot(), modelTransform, smooth, gui3d, DefaultVertexFormats.BLOCK, meshes, builder.build());
} }
public ModelWrapper retexture(ImmutableMap<String, String> textures) public ModelWrapper retexture(ImmutableMap<String, String> textures)

View File

@ -149,13 +149,13 @@ public class CompositeModel implements IBakedModel
{ {
private final String name; private final String name;
private final BlockModel model; private final BlockModel model;
private final IModelTransform sprite; private final IModelTransform modelTransform;
private Submodel(String name, BlockModel model, IModelTransform sprite) private Submodel(String name, BlockModel model, IModelTransform modelTransform)
{ {
this.name = name; this.name = name;
this.model = model; this.model = model;
this.sprite = sprite; this.modelTransform = modelTransform;
} }
@Override @Override
@ -165,19 +165,19 @@ public class CompositeModel implements IBakedModel
} }
@Override @Override
public void addQuads(IModelConfiguration owner, IModelBuilder<?> modelBuilder, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform sprite, ResourceLocation modelLocation) public void addQuads(IModelConfiguration owner, IModelBuilder<?> modelBuilder, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ResourceLocation modelLocation)
{ {
throw new UnsupportedOperationException("Attempted to call adQuads on a Submodel instance. Please don't."); throw new UnsupportedOperationException("Attempted to call adQuads on a Submodel instance. Please don't.");
} }
public IBakedModel func_225613_a_(ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform sprite, ResourceLocation modelLocation) public IBakedModel func_225613_a_(ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ResourceLocation modelLocation)
{ {
return model.func_225613_a_(bakery, spriteGetter, new ModelTransformComposition(this.sprite, sprite, return model.func_225613_a_(bakery, spriteGetter, new ModelTransformComposition(this.modelTransform, modelTransform,
this.sprite.isUvLock() || sprite.isUvLock()), modelLocation); this.modelTransform.isUvLock() || modelTransform.isUvLock()), modelLocation);
} }
@Override @Override
public Collection<Material> getTextureDependencies(IModelConfiguration owner, Function<ResourceLocation, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors) public Collection<Material> getTextures(IModelConfiguration owner, Function<ResourceLocation, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors)
{ {
return model.func_225614_a_(modelGetter, missingTextureErrors); return model.func_225614_a_(modelGetter, missingTextureErrors);
} }
@ -205,7 +205,7 @@ public class CompositeModel implements IBakedModel
} }
@Override @Override
public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform sprite, ItemOverrideList overrides, ResourceLocation modelLocation) public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ItemOverrideList overrides, ResourceLocation modelLocation)
{ {
Material particleLocation = owner.resolveTexture("particle"); Material particleLocation = owner.resolveTexture("particle");
TextureAtlasSprite particle = spriteGetter.apply(particleLocation); TextureAtlasSprite particle = spriteGetter.apply(particleLocation);
@ -216,7 +216,7 @@ public class CompositeModel implements IBakedModel
Submodel submodel = part.getValue(); Submodel submodel = part.getValue();
if (!owner.getPartVisibility(submodel)) if (!owner.getPartVisibility(submodel))
continue; continue;
bakedParts.put(part.getKey(), submodel.func_225613_a_(bakery, spriteGetter, sprite, modelLocation)); bakedParts.put(part.getKey(), submodel.func_225613_a_(bakery, spriteGetter, modelTransform, modelLocation));
} }
return new CompositeModel(owner.isShadedInGui(), owner.useSmoothLighting(), particle, bakedParts.build(), overrides); return new CompositeModel(owner.isShadedInGui(), owner.useSmoothLighting(), particle, bakedParts.build(), overrides);
} }
@ -227,7 +227,7 @@ public class CompositeModel implements IBakedModel
Set<Material> textures = new HashSet<>(); Set<Material> textures = new HashSet<>();
for(Submodel part : parts.values()) for(Submodel part : parts.values())
{ {
textures.addAll(part.getTextureDependencies(owner, modelGetter, missingTextureErrors)); textures.addAll(part.getTextures(owner, modelGetter, missingTextureErrors));
} }
return textures; return textures;
} }
@ -254,11 +254,11 @@ public class CompositeModel implements IBakedModel
for(Map.Entry<String, JsonElement> part : modelContents.get("parts").getAsJsonObject().entrySet()) for(Map.Entry<String, JsonElement> part : modelContents.get("parts").getAsJsonObject().entrySet())
{ {
// TODO: Allow customizing state? If so, how? // TODO: Allow customizing state? If so, how?
IModelTransform sprite = SimpleModelTransform.IDENTITY; IModelTransform modelTransform = SimpleModelTransform.IDENTITY;
parts.put(part.getKey(), new Submodel( parts.put(part.getKey(), new Submodel(
part.getKey(), part.getKey(),
ModelLoaderRegistry.ExpandedBlockModelDeserializer.INSTANCE.fromJson(part.getValue(), BlockModel.class), deserializationContext.deserialize(part.getValue(), BlockModel.class),
sprite)); modelTransform));
} }
return new Geometry(parts.build()); return new Geometry(parts.build());
} }

View File

@ -45,7 +45,7 @@ public interface IModelGeometry<T extends IModelGeometry<T>>
return Optional.empty(); return Optional.empty();
} }
IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform sprite, ItemOverrideList overrides, ResourceLocation modelLocation); IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ItemOverrideList overrides, ResourceLocation modelLocation);
Collection<Material> getTextures(IModelConfiguration owner, Function<ResourceLocation, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors); Collection<Material> getTextures(IModelConfiguration owner, Function<ResourceLocation, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors);
} }

View File

@ -39,9 +39,9 @@ public interface IModelGeometryPart
{ {
String name(); String name();
void addQuads(IModelConfiguration owner, IModelBuilder<?> modelBuilder, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform sprite, ResourceLocation modelLocation); void addQuads(IModelConfiguration owner, IModelBuilder<?> modelBuilder, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ResourceLocation modelLocation);
default Collection<Material> getTextureDependencies(IModelConfiguration owner, Function<ResourceLocation, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors) { default Collection<Material> getTextures(IModelConfiguration owner, Function<ResourceLocation, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors) {
// No texture dependencies // No texture dependencies
return Collections.emptyList(); return Collections.emptyList();
} }

View File

@ -43,10 +43,10 @@ public interface IMultipartModelGeometry<T extends IMultipartModelGeometry<T>> e
Optional<? extends IModelGeometryPart> getPart(String name); Optional<? extends IModelGeometryPart> getPart(String name);
@Override @Override
default void addQuads(IModelConfiguration owner, IModelBuilder<?> modelBuilder, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform sprite, ResourceLocation modelLocation) default void addQuads(IModelConfiguration owner, IModelBuilder<?> modelBuilder, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ResourceLocation modelLocation)
{ {
getParts().stream().filter(part -> owner.getPartVisibility(part)) getParts().stream().filter(part -> owner.getPartVisibility(part))
.forEach(part -> part.addQuads(owner, modelBuilder, bakery, spriteGetter, sprite, modelLocation)); .forEach(part -> part.addQuads(owner, modelBuilder, bakery, spriteGetter, modelTransform, modelLocation));
} }
@Override @Override
@ -54,7 +54,7 @@ public interface IMultipartModelGeometry<T extends IMultipartModelGeometry<T>> e
{ {
Set<Material> combined = Sets.newHashSet(); Set<Material> combined = Sets.newHashSet();
for (IModelGeometryPart part : getParts()) for (IModelGeometryPart part : getParts())
combined.addAll(part.getTextureDependencies(owner, modelGetter, missingTextureErrors)); combined.addAll(part.getTextures(owner, modelGetter, missingTextureErrors));
return combined; return combined;
} }
} }

View File

@ -33,18 +33,18 @@ import java.util.function.Function;
public interface ISimpleModelGeometry<T extends ISimpleModelGeometry<T>> extends IModelGeometry<T> public interface ISimpleModelGeometry<T extends ISimpleModelGeometry<T>> extends IModelGeometry<T>
{ {
@Override @Override
default IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform sprite, ItemOverrideList overrides, ResourceLocation modelLocation) default IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ItemOverrideList overrides, ResourceLocation modelLocation)
{ {
TextureAtlasSprite particle = spriteGetter.apply(owner.resolveTexture("particle")); TextureAtlasSprite particle = spriteGetter.apply(owner.resolveTexture("particle"));
IModelBuilder<?> builder = IModelBuilder.of(owner, overrides, particle); IModelBuilder<?> builder = IModelBuilder.of(owner, overrides, particle);
addQuads(owner, builder, bakery, spriteGetter, sprite, modelLocation); addQuads(owner, builder, bakery, spriteGetter, modelTransform, modelLocation);
return builder.build(); return builder.build();
} }
void addQuads(IModelConfiguration owner, IModelBuilder<?> modelBuilder, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform sprite, ResourceLocation modelLocation); void addQuads(IModelConfiguration owner, IModelBuilder<?> modelBuilder, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ResourceLocation modelLocation);
@Override @Override
Collection<Material> getTextures(IModelConfiguration owner, Function<ResourceLocation, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors); Collection<Material> getTextures(IModelConfiguration owner, Function<ResourceLocation, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors);

View File

@ -395,7 +395,8 @@ public class OBJModel implements IMultipartModelGeometry<OBJModel>
Vec2f uv2 = new Vec2f(((float) fakeLight * 0x20) / 0xFFFF, ((float) fakeLight * 0x20) / 0xFFFF); Vec2f uv2 = new Vec2f(((float) fakeLight * 0x20) / 0xFFFF, ((float) fakeLight * 0x20) / 0xFFFF);
boolean hasTransform = !transform.isIdentity(); boolean hasTransform = !transform.isIdentity();
TransformationMatrix transformation = hasTransform ? transform : null; // The incoming transform is referenced on the center of the block, but our coords are referenced on the corner
TransformationMatrix transformation = hasTransform ? transform.blockCenterToCorner() : transform;
for(int i=0;i<4;i++) for(int i=0;i<4;i++)
{ {
@ -556,7 +557,7 @@ public class OBJModel implements IMultipartModelGeometry<OBJModel>
} }
@Override @Override
public void addQuads(IModelConfiguration owner, IModelBuilder<?> modelBuilder, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform sprite, ResourceLocation modelLocation) public void addQuads(IModelConfiguration owner, IModelBuilder<?> modelBuilder, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ResourceLocation modelLocation)
{ {
for(ModelMesh mesh : meshes) for(ModelMesh mesh : meshes)
{ {
@ -570,7 +571,7 @@ public class OBJModel implements IMultipartModelGeometry<OBJModel>
for (int[][] face : mesh.faces) for (int[][] face : mesh.faces)
{ {
Pair<BakedQuad, Direction> quad = makeQuad(face, tintIndex, colorTint, mat.ambientColor, isFullbright, texture, DefaultVertexFormats.BLOCK, sprite.func_225615_b_()); Pair<BakedQuad, Direction> quad = makeQuad(face, tintIndex, colorTint, mat.ambientColor, isFullbright, texture, DefaultVertexFormats.BLOCK, modelTransform.func_225615_b_());
if (quad.getRight() == null) if (quad.getRight() == null)
modelBuilder.addGeneralQuad(quad.getLeft()); modelBuilder.addGeneralQuad(quad.getLeft());
else else
@ -580,7 +581,7 @@ public class OBJModel implements IMultipartModelGeometry<OBJModel>
} }
@Override @Override
public Collection<Material> getTextureDependencies(IModelConfiguration owner, Function<ResourceLocation, IUnbakedModel> modelGetter, Set<com.mojang.datafixers.util.Pair<String, String>> missingTextureErrors) public Collection<Material> getTextures(IModelConfiguration owner, Function<ResourceLocation, IUnbakedModel> modelGetter, Set<com.mojang.datafixers.util.Pair<String, String>> missingTextureErrors)
{ {
return meshes.stream().map(mesh -> ModelLoaderRegistry.resolveTexture(mesh.mat.diffuseColorMap, owner)).collect(Collectors.toSet()); return meshes.stream().map(mesh -> ModelLoaderRegistry.resolveTexture(mesh.mat.diffuseColorMap, owner)).collect(Collectors.toSet());
} }
@ -606,21 +607,21 @@ public class OBJModel implements IMultipartModelGeometry<OBJModel>
} }
@Override @Override
public void addQuads(IModelConfiguration owner, IModelBuilder<?> modelBuilder, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform sprite, ResourceLocation modelLocation) public void addQuads(IModelConfiguration owner, IModelBuilder<?> modelBuilder, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ResourceLocation modelLocation)
{ {
super.addQuads(owner, modelBuilder, bakery, spriteGetter, sprite, modelLocation); super.addQuads(owner, modelBuilder, bakery, spriteGetter, modelTransform, modelLocation);
getParts().stream().filter(part -> owner.getPartVisibility(part)) getParts().stream().filter(part -> owner.getPartVisibility(part))
.forEach(part -> part.addQuads(owner, modelBuilder, bakery, spriteGetter, sprite, modelLocation)); .forEach(part -> part.addQuads(owner, modelBuilder, bakery, spriteGetter, modelTransform, modelLocation));
} }
@Override @Override
public Collection<Material> getTextureDependencies(IModelConfiguration owner, Function<ResourceLocation, IUnbakedModel> modelGetter, Set<com.mojang.datafixers.util.Pair<String, String>> missingTextureErrors) public Collection<Material> getTextures(IModelConfiguration owner, Function<ResourceLocation, IUnbakedModel> modelGetter, Set<com.mojang.datafixers.util.Pair<String, String>> missingTextureErrors)
{ {
Set<Material> combined = Sets.newHashSet(); Set<Material> combined = Sets.newHashSet();
combined.addAll(super.getTextureDependencies(owner, modelGetter, missingTextureErrors)); combined.addAll(super.getTextures(owner, modelGetter, missingTextureErrors));
for (IModelGeometryPart part : getParts()) for (IModelGeometryPart part : getParts())
combined.addAll(part.getTextureDependencies(owner, modelGetter, missingTextureErrors)); combined.addAll(part.getTextures(owner, modelGetter, missingTextureErrors));
return combined; return combined;
} }

View File

@ -32,6 +32,7 @@ import net.minecraft.tileentity.TileEntity;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
public class ClientRegistry public class ClientRegistry
{ {
@ -42,9 +43,9 @@ public class ClientRegistry
* Call this during {@link net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent}. * Call this during {@link net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent}.
* This method is safe to call during parallel mod loading. * This method is safe to call during parallel mod loading.
*/ */
public static synchronized <T extends TileEntity> void bindTileEntityRenderer(TileEntityType<T> tileEntityType, TileEntityRenderer<? super T> specialRenderer) public static synchronized <T extends TileEntity> void bindTileEntityRenderer(TileEntityType<T> tileEntityType, Function<TileEntityRendererDispatcher, TileEntityRenderer<? super T>> rendererFactory)
{ {
TileEntityRendererDispatcher.instance.setSpecialRendererInternal(tileEntityType, specialRenderer); TileEntityRendererDispatcher.instance.setSpecialRendererInternal(tileEntityType, rendererFactory.apply(TileEntityRendererDispatcher.instance));
} }
/** /**

View File

@ -17,28 +17,22 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
/*
package net.minecraftforge.debug.client.model; package net.minecraftforge.debug.client.model;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.material.Material; import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState; import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.model.ModelResourceLocation; import net.minecraft.client.renderer.RenderTypeLookup;
import net.minecraft.creativetab.CreativeTabs; import net.minecraft.item.BlockItem;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemGroup;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.common.registry.GameRegistry.ObjectHolder; import net.minecraftforge.registries.ObjectHolder;
//@Mod(modid = MultiLayerModelTest.MODID, name = "ForgeDebugMultiLayerModel", version = MultiLayerModelTest.VERSION, acceptableRemoteVersions = "*") @Mod(MultiLayerModelTest.MODID)
public class MultiLayerModelTest public class MultiLayerModelTest
{ {
private static final boolean ENABLED = true; private static final boolean ENABLED = true;
@ -50,7 +44,7 @@ public class MultiLayerModelTest
@ObjectHolder(blockName) @ObjectHolder(blockName)
public static final Block TEST_BLOCK = null; public static final Block TEST_BLOCK = null;
//@Mod.EventBusSubscriber(modid = MODID) @Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.MOD)
public static class Registration public static class Registration
{ {
@net.minecraftforge.eventbus.api.SubscribeEvent @net.minecraftforge.eventbus.api.SubscribeEvent
@ -59,48 +53,28 @@ public class MultiLayerModelTest
if (!ENABLED) if (!ENABLED)
return; return;
event.getRegistry().register( event.getRegistry().register(
new Block(Material.WOOD) new Block(Block.Properties.create(Material.WOOD))
{ {
{ }.setRegistryName(blockId)
setCreativeTab(CreativeTabs.BUILDING_BLOCKS);
setUnlocalizedName(MODID + "." + blockName);
setRegistryName(blockId);
}
@Override
public boolean isOpaqueCube(IBlockState state)
{
return false;
}
@Override
public boolean isFullCube(IBlockState state)
{
return false;
}
@Override
public boolean canRenderInLayer(IBlockState state, BlockRenderLayer layer)
{
return layer == BlockRenderLayer.SOLID || layer == BlockRenderLayer.TRANSLUCENT;
}
}
); );
} }
@net.minecraftforge.eventbus.api.SubscribeEvent @net.minecraftforge.eventbus.api.SubscribeEvent
public static void registerItems(RegistryEvent.Register<Item> event) public static void registerItems(RegistryEvent.Register<Item> event)
{ {
event.getRegistry().register(new ItemBlock(TEST_BLOCK).setRegistryName(TEST_BLOCK.getRegistryName())); if (!ENABLED)
return;
event.getRegistry().register(new BlockItem(TEST_BLOCK, new Item.Properties().group(ItemGroup.MISC)).setRegistryName(TEST_BLOCK.getRegistryName()));
} }
@SubscribeEvent @net.minecraftforge.eventbus.api.SubscribeEvent
public static void registerModels(ModelRegistryEvent event) public static void clientSetup(FMLClientSetupEvent event)
{ {
if (!ENABLED) if (!ENABLED)
return; return;
ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(TEST_BLOCK), 0, new ModelResourceLocation(blockId, "inventory")); RenderTypeLookup.setRenderLayer(TEST_BLOCK, (layer) -> {
return layer == RenderType.func_228639_c_() || layer == RenderType.func_228645_f_();
});
} }
} }
} }
*/

View File

@ -23,12 +23,17 @@ import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.FourWayBlock;
import net.minecraft.block.material.Material;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.model.ItemCameraTransforms; import net.minecraft.client.renderer.model.ItemCameraTransforms;
import net.minecraft.client.renderer.texture.AtlasTexture; import net.minecraft.client.renderer.texture.AtlasTexture;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.inventory.EquipmentSlotType; import net.minecraft.inventory.EquipmentSlotType;
import net.minecraft.item.*; import net.minecraft.item.*;
import net.minecraft.state.StateContainer;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.client.event.RenderGameOverlayEvent;
@ -45,6 +50,8 @@ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ForgeRegistries;
import javax.annotation.Nullable;
@Mod(NewModelLoaderTest.MODID) @Mod(NewModelLoaderTest.MODID)
public class NewModelLoaderTest public class NewModelLoaderTest
{ {
@ -52,8 +59,27 @@ public class NewModelLoaderTest
public static final DeferredRegister<Block> BLOCKS = new DeferredRegister<>(ForgeRegistries.BLOCKS, MODID); public static final DeferredRegister<Block> BLOCKS = new DeferredRegister<>(ForgeRegistries.BLOCKS, MODID);
public static final DeferredRegister<Item> ITEMS = new DeferredRegister<>(ForgeRegistries.ITEMS, MODID); public static final DeferredRegister<Item> ITEMS = new DeferredRegister<>(ForgeRegistries.ITEMS, MODID);
public static RegistryObject<Block> obj_block = BLOCKS.register("obj_block", () ->
new Block(Block.Properties.create(Material.WOOD)) {
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{
builder.add(BlockStateProperties.HORIZONTAL_FACING);
}
@Nullable
@Override
public BlockState getStateForPlacement(BlockItemUseContext context)
{
return getDefaultState().with(
BlockStateProperties.HORIZONTAL_FACING, context.getPlacementHorizontalFacing()
);
}
}
);
public static RegistryObject<Item> obj_item = ITEMS.register("obj_item", () -> public static RegistryObject<Item> obj_item = ITEMS.register("obj_item", () ->
new Item(new Item.Properties().group(ItemGroup.MISC)) { new BlockItem(obj_block.get(), new Item.Properties().group(ItemGroup.MISC)) {
@Override @Override
public boolean canEquip(ItemStack stack, EquipmentSlotType armorType, Entity entity) public boolean canEquip(ItemStack stack, EquipmentSlotType armorType, Entity entity)
{ {

View File

@ -51,3 +51,5 @@ loaderVersion="[28,)"
## modId="custom_tnt_test" ## modId="custom_tnt_test"
[[mods]] [[mods]]
modId="new_model_loader_test" modId="new_model_loader_test"
[[mods]]
modId="forgedebugmultilayermodel"

View File

@ -1,26 +1,5 @@
{ {
"forge_marker": 1,
"defaults": {
"model": "forge:multi-layer",
"custom": {
// base is used for model properties - camera transforms, isGui3d, e.t.c.
"base": "forgedebugmultilayermodel:test_layer_block#aux",
// per-layer models
"Solid": "forgedebugmultilayermodel:test_layer_block#aux",
"Translucent": "forgedebugmultilayermodel:test_layer_block#pane"
},
"transform": "forge:default-block"
},
"variants": { "variants": {
"normal": [{}], "": { "model": "forgedebugmultilayermodel:block/test_layer_block"}
"inventory": [{}],
"pane": [{
"model": "minecraft:pink_stained_glass_pane_noside"
}],
"aux": [{
"model": "cube_all",
"textures": { "all": "blocks/slime" },
"transform": { "scale": 0.5 }
}]
} }
} }

View File

@ -0,0 +1,21 @@
{
"parent": "block/block",
"loader": "forge:multi-layer",
"layers": {
"__comment": "base is used for model properties - camera transforms, isGui3d, e.t.c.",
"base": {
"parent": "block/cube_all",
"textures": { "all": "block/slime_block" }
},
"__comment": "per-layer models",
"solid": {
"parent": "block/cube_all",
"textures": { "all": "block/slime_block" },
"transform": { "scale": 0.5 }
},
"translucent": {
"parent": "minecraft:block/pink_stained_glass_pane_noside"
}
}
}

View File

@ -0,0 +1,3 @@
{
"parent": "forgedebugmultilayermodel:block/test_layer_block"
}

View File

@ -0,0 +1,8 @@
{
"variants": {
"facing=east": { "model": "new_model_loader_test:block/obj_block", "y": 90 },
"facing=west": { "model": "new_model_loader_test:block/obj_block", "y": 270 },
"facing=north": { "model": "new_model_loader_test:block/obj_block", "y": 0 },
"facing=south": { "model": "new_model_loader_test:block/obj_block", "y": 180 }
}
}

View File

@ -0,0 +1,17 @@
{
"parent": "forge:item/default",
"loader": "forge:composite",
"parts": {
"part1": {
"loader": "forge:obj",
"model": "new_model_loader_test:models/item/sugar_glider.obj",
"ambientToFullbright": true,
"textures": {
"qr": "minecraft:block/oak_planks"
}
}
},
"textures": {
"particle": "block/oak_planks"
}
}