From dc145a3dfc5345b3a059020a1ef5720e416ef7ed Mon Sep 17 00:00:00 2001 From: David Quintana Date: Fri, 28 Feb 2020 18:26:59 +0100 Subject: [PATCH] Backport implementation of the new model system from 1.15: (#6180) - Extended block model format to support a "loader" value, as an alternative to "elements. - Extended block model format to support "gui_3d":false as a way to mark a model as being intended to be flat and lit from the front. (No this is not equivalent to the "gui_light" flag in 1.15.2. It changes more than just the light direction) - Added a new OBJ loader designed from the ground up to work with the new model system. - Added stock models to serve as parent models when using custom loaders (forge:item/default, forge:item/default-tool, and forge:block/default). - Added stock white texture (forge:white) for use in loaders that want to draw untextured geometry. - Deprecated the old loader components, since they are gone in 1.15 already. --- .../renderer/model/BlockModel.java.patch | 63 +- .../model/ItemModelGenerator.java.patch | 10 + .../renderer/model/ModelManager.java.patch | 17 +- .../model/SimpleBakedModel.java.patch | 7 +- .../texture/TextureAtlasSprite.java.patch | 19 +- .../client/ForgeHooksClient.java | 1 - .../client/extensions/IForgeBakedModel.java | 9 +- .../client/model/BakedItemModel.java | 6 + .../client/model/BakedModelWrapper.java | 7 +- .../client/model/BlockModelConfiguration.java | 183 +++++ .../client/model/BlockStateLoader.java | 5 +- .../client/model/CompositeModel.java | 340 +++++++++ .../client/model/FancyMissingModel.java | 6 + .../client/model/ForgeBlockStateV1.java | 123 +--- .../client/model/ICustomModelLoader.java | 1 + .../client/model/IForgeUnbakedModel.java | 52 ++ .../minecraftforge/client/model/IModel.java | 14 +- .../client/model/IModelBuilder.java | 70 ++ .../client/model/IModelConfiguration.java | 99 +++ .../client/model/IModelLoader.java | 53 ++ .../client/model/ModelDynBucket.java | 332 ++++++--- .../client/model/ModelFluid.java | 6 + .../client/model/ModelLoader.java | 120 ++-- .../client/model/ModelLoaderRegistry.java | 22 + .../client/model/ModelLoaderRegistry2.java | 559 +++++++++++++++ .../client/model/MultiLayerModel.java | 18 +- .../client/model/MultiModel.java | 6 + .../client/model/PerspectiveMapWrapper.java | 74 +- .../client/model/QuadTransformer.java | 234 ++++++ .../model/animation/ModelBlockAnimation.java | 6 + .../client/model/b3d/B3DLoader.java | 40 +- .../client/model/data/ModelDataMap.java | 7 +- .../model/generators/BlockModelProvider.java | 19 + .../model/generators/ConfiguredModel.java | 19 + .../model/generators/ExistingFileHelper.java | 19 + .../generators/IGeneratedBlockstate.java | 19 + .../model/generators/ItemModelProvider.java | 19 + .../MultiPartBlockStateBuilder.java | 19 + .../client/model/geometry/IModelGeometry.java | 52 ++ .../model/geometry/IModelGeometryPart.java | 46 ++ .../geometry/IMultipartModelGeometry.java | 59 ++ .../model/geometry/ISimpleModelGeometry.java | 54 ++ .../client/model/obj/LineReader.java | 97 +++ .../client/model/obj/MaterialLibrary2.java | 133 ++++ .../client/model/obj/OBJLoader.java | 1 + .../client/model/obj/OBJLoader2.java | 118 +++ .../client/model/obj/OBJModel.java | 7 + .../client/model/obj/OBJModel2.java | 671 ++++++++++++++++++ .../common/data/LanguageProvider.java | 1 + .../net/minecraftforge/common/util/Lazy.java | 108 +++ .../common/util/NonNullLazy.java | 109 +++ .../fml/client/ClientModLoader.java | 3 + .../fml/packs/DelegatableResourcePack.java | 19 + .../fml/packs/DelegatingResourcePack.java | 19 + .../resources/META-INF/accesstransformer.cfg | 1 + .../assets/forge/models/block/default.json | 3 + .../assets/forge/models/item/bucket.json | 5 +- .../assets/forge/models/item/bucket_drip.json | 7 + .../forge/models/item/default-tool.json | 24 + .../assets/forge/models/item/default.json | 28 + .../forge/textures/item/mask/bucket_fluid.png | Bin 0 -> 158 bytes .../textures/item/mask/bucket_fluid_cover.png | Bin 0 -> 168 bytes .../item/mask/bucket_fluid_cover_drip.png | Bin 0 -> 181 bytes .../textures/item/mask/bucket_fluid_drip.png | Bin 0 -> 172 bytes .../resources/assets/forge/textures/white.png | Bin 0 -> 139 bytes .../client/model/NewModelLoaderTest.java | 193 +++++ .../entity/player/PlayerXpEventTest.java | 19 + src/test/resources/META-INF/mods.toml | 4 +- .../blockstates/test_fluid_block.json | 5 + .../models/block/test_fluid.json | 5 + .../models/item/test_fluid_bucket.json | 31 + .../blockstates/obj_block.json | 8 + .../models/block/obj_block.json | 10 + .../models/item/custom_loader.json | 8 + .../models/item/custom_transforms.json | 13 + .../models/item/custom_vanilla_loader.json | 56 ++ .../models/item/item_direction.mtl | 7 + .../models/item/item_direction.obj | 650 +++++++++++++++++ .../models/item/obj_block.json | 59 ++ .../models/item/sugar_glider.mtl | 46 ++ .../models/item/sugar_glider.obj | 579 +++++++++++++++ .../textures/item/qr.png | Bin 0 -> 237 bytes 82 files changed, 5576 insertions(+), 305 deletions(-) create mode 100644 patches/minecraft/net/minecraft/client/renderer/model/ItemModelGenerator.java.patch create mode 100644 src/main/java/net/minecraftforge/client/model/BlockModelConfiguration.java create mode 100644 src/main/java/net/minecraftforge/client/model/CompositeModel.java create mode 100644 src/main/java/net/minecraftforge/client/model/IForgeUnbakedModel.java create mode 100644 src/main/java/net/minecraftforge/client/model/IModelBuilder.java create mode 100644 src/main/java/net/minecraftforge/client/model/IModelConfiguration.java create mode 100644 src/main/java/net/minecraftforge/client/model/IModelLoader.java create mode 100644 src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry2.java create mode 100644 src/main/java/net/minecraftforge/client/model/QuadTransformer.java create mode 100644 src/main/java/net/minecraftforge/client/model/geometry/IModelGeometry.java create mode 100644 src/main/java/net/minecraftforge/client/model/geometry/IModelGeometryPart.java create mode 100644 src/main/java/net/minecraftforge/client/model/geometry/IMultipartModelGeometry.java create mode 100644 src/main/java/net/minecraftforge/client/model/geometry/ISimpleModelGeometry.java create mode 100644 src/main/java/net/minecraftforge/client/model/obj/LineReader.java create mode 100644 src/main/java/net/minecraftforge/client/model/obj/MaterialLibrary2.java create mode 100644 src/main/java/net/minecraftforge/client/model/obj/OBJLoader2.java create mode 100644 src/main/java/net/minecraftforge/client/model/obj/OBJModel2.java create mode 100644 src/main/java/net/minecraftforge/common/util/Lazy.java create mode 100644 src/main/java/net/minecraftforge/common/util/NonNullLazy.java create mode 100644 src/main/resources/assets/forge/models/block/default.json create mode 100644 src/main/resources/assets/forge/models/item/bucket_drip.json create mode 100644 src/main/resources/assets/forge/models/item/default-tool.json create mode 100644 src/main/resources/assets/forge/models/item/default.json create mode 100644 src/main/resources/assets/forge/textures/item/mask/bucket_fluid.png create mode 100644 src/main/resources/assets/forge/textures/item/mask/bucket_fluid_cover.png create mode 100644 src/main/resources/assets/forge/textures/item/mask/bucket_fluid_cover_drip.png create mode 100644 src/main/resources/assets/forge/textures/item/mask/bucket_fluid_drip.png create mode 100644 src/main/resources/assets/forge/textures/white.png create mode 100644 src/test/java/net/minecraftforge/debug/client/model/NewModelLoaderTest.java create mode 100644 src/test/resources/assets/new_fluid_test/blockstates/test_fluid_block.json create mode 100644 src/test/resources/assets/new_fluid_test/models/block/test_fluid.json create mode 100644 src/test/resources/assets/new_fluid_test/models/item/test_fluid_bucket.json create mode 100644 src/test/resources/assets/new_model_loader_test/blockstates/obj_block.json create mode 100644 src/test/resources/assets/new_model_loader_test/models/block/obj_block.json create mode 100644 src/test/resources/assets/new_model_loader_test/models/item/custom_loader.json create mode 100644 src/test/resources/assets/new_model_loader_test/models/item/custom_transforms.json create mode 100644 src/test/resources/assets/new_model_loader_test/models/item/custom_vanilla_loader.json create mode 100644 src/test/resources/assets/new_model_loader_test/models/item/item_direction.mtl create mode 100644 src/test/resources/assets/new_model_loader_test/models/item/item_direction.obj create mode 100644 src/test/resources/assets/new_model_loader_test/models/item/obj_block.json create mode 100644 src/test/resources/assets/new_model_loader_test/models/item/sugar_glider.mtl create mode 100644 src/test/resources/assets/new_model_loader_test/models/item/sugar_glider.obj create mode 100644 src/test/resources/assets/new_model_loader_test/textures/item/qr.png diff --git a/patches/minecraft/net/minecraft/client/renderer/model/BlockModel.java.patch b/patches/minecraft/net/minecraft/client/renderer/model/BlockModel.java.patch index ffa77d3000..1faf51f66f 100644 --- a/patches/minecraft/net/minecraft/client/renderer/model/BlockModel.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/model/BlockModel.java.patch @@ -1,6 +1,32 @@ --- a/net/minecraft/client/renderer/model/BlockModel.java +++ b/net/minecraft/client/renderer/model/BlockModel.java -@@ -75,6 +75,9 @@ +@@ -38,6 +38,7 @@ + public class BlockModel implements IUnbakedModel { + private static final Logger field_178313_f = LogManager.getLogger(); + private static final FaceBakery field_217647_g = new FaceBakery(); ++ @Deprecated + @VisibleForTesting + static final Gson field_178319_a = (new GsonBuilder()).registerTypeAdapter(BlockModel.class, new BlockModel.Deserializer()).registerTypeAdapter(BlockPart.class, new BlockPart.Deserializer()).registerTypeAdapter(BlockPartFace.class, new BlockPartFace.Deserializer()).registerTypeAdapter(BlockFaceUV.class, new BlockFaceUV.Deserializer()).registerTypeAdapter(ItemTransformVec3f.class, new ItemTransformVec3f.Deserializer()).registerTypeAdapter(ItemCameraTransforms.class, new ItemCameraTransforms.Deserializer()).registerTypeAdapter(ItemOverride.class, new ItemOverride.Deserializer()).create(); + private final List field_178314_g; +@@ -52,9 +53,10 @@ + public BlockModel field_178315_d; + @Nullable + protected ResourceLocation field_178316_e; ++ public final net.minecraftforge.client.model.BlockModelConfiguration customData = new net.minecraftforge.client.model.BlockModelConfiguration(this); + + public static BlockModel func_178307_a(Reader p_178307_0_) { +- return JSONUtils.func_193839_a(field_178319_a, p_178307_0_, BlockModel.class); ++ return JSONUtils.func_193839_a(net.minecraftforge.client.model.ModelLoaderRegistry2.ExpandedBlockModelDeserializer.INSTANCE, p_178307_0_, BlockModel.class); + } + + public static BlockModel func_178294_a(String p_178294_0_) { +@@ -71,10 +73,15 @@ + this.field_187968_k = p_i46573_7_; + } + ++ @Deprecated + public List func_178298_a() { ++ if (customData.hasCustomGeometry()) return java.util.Collections.emptyList(); return this.field_178314_g.isEmpty() && this.field_178315_d != null ? this.field_178315_d.func_178298_a() : this.field_178314_g; } @@ -10,7 +36,7 @@ public boolean func_178309_b() { return this.field_178315_d != null ? this.field_178315_d.func_178309_b() : this.field_178322_i; } -@@ -91,6 +94,10 @@ +@@ -91,6 +98,10 @@ return this.field_187968_k.isEmpty() ? ItemOverrideList.field_188022_a : new ItemOverrideList(p_217646_1_, p_217646_2_, p_217646_1_::func_209597_a, this.field_187968_k); } @@ -21,7 +47,17 @@ public Collection func_187965_e() { Set set = Sets.newHashSet(); -@@ -160,25 +167,33 @@ +@@ -134,6 +145,9 @@ + + Set set1 = Sets.newHashSet(new ResourceLocation(this.func_178308_c("particle"))); + ++ if(customData.hasCustomGeometry()) ++ set1.addAll(customData.getTextureDependencies(p_209559_1_, p_209559_2_)); ++ else + for(BlockPart blockpart : this.func_178298_a()) { + for(BlockPartFace blockpartface : blockpart.field_178240_c.values()) { + String s = this.func_178308_c(blockpartface.field_178242_d); +@@ -160,25 +174,36 @@ return set1; } @@ -29,8 +65,6 @@ - return this.func_217644_a(p_217641_1_, this, p_217641_2_, p_217641_3_); + // FORGE: Override our interface method, binary compatible + public IBakedModel bake(ModelBakery bakery, Function spriteGetter, ISprite sprite, net.minecraft.client.renderer.vertex.VertexFormat format) { -+ if (!net.minecraftforge.client.model.Attributes.moreSpecific(format, net.minecraftforge.client.model.Attributes.DEFAULT_BAKED_FORMAT)) -+ throw new IllegalArgumentException("Cannot bake vanilla model to format other than BLOCK"); + return this.bake(bakery, this, spriteGetter, sprite, format); } @@ -39,7 +73,12 @@ + return bake(p_217644_1_, p_217644_2_, p_217644_3_, p_217644_4_, net.minecraft.client.renderer.vertex.DefaultVertexFormats.field_176599_b); + } + -+ public IBakedModel bake(ModelBakery p_217644_1_, BlockModel p_217644_2_, Function p_217644_3_, ISprite p_217644_4_, net.minecraft.client.renderer.vertex.VertexFormat format) { ++ public IBakedModel bake(ModelBakery p_217644_1_, BlockModel p_217644_2_, Function p_217644_3_, ISprite p_217644_4_, net.minecraft.client.renderer.vertex.VertexFormat format) ++ { ++ return net.minecraftforge.client.model.ModelLoaderRegistry2.bakeHelper(this, p_217644_1_, p_217644_2_, p_217644_3_, p_217644_4_, format); ++ } ++ ++ public IBakedModel bakeVanilla(ModelBakery p_217644_1_, BlockModel p_217644_2_, Function p_217644_3_, ISprite p_217644_4_, net.minecraft.client.renderer.vertex.VertexFormat format) { TextureAtlasSprite textureatlassprite = p_217644_3_.apply(new ResourceLocation(this.func_178308_c("particle"))); if (this.func_178310_f() == ModelBakery.field_177616_r) { - return new BuiltInModel(this.func_181682_g(), this.func_217646_a(p_217644_1_, p_217644_2_), textureatlassprite); @@ -61,7 +100,7 @@ } } } -@@ -191,6 +206,10 @@ +@@ -191,6 +216,10 @@ return field_217647_g.func_217648_a(p_217645_0_.field_178241_a, p_217645_0_.field_178239_b, p_217645_1_, p_217645_2_, p_217645_3_, p_217645_4_, p_217645_0_.field_178237_d, p_217645_0_.field_178238_e); } @@ -72,3 +111,13 @@ public boolean func_178300_b(String p_178300_1_) { return !MissingTextureSprite.func_195675_b().toString().equals(this.func_178308_c(p_178300_1_)); } +@@ -280,7 +309,8 @@ + + List list1 = this.func_187964_a(p_deserialize_3_, jsonobject); + ResourceLocation resourcelocation = s.isEmpty() ? null : new ResourceLocation(s); +- return new BlockModel(resourcelocation, list, map, flag, true, itemcameratransforms, list1); ++ boolean gui3d = JSONUtils.func_151209_a(jsonobject, "gui_3d", true); ++ return new BlockModel(resourcelocation, list, map, flag, gui3d, itemcameratransforms, list1); + } + + protected List func_187964_a(JsonDeserializationContext p_187964_1_, JsonObject p_187964_2_) { diff --git a/patches/minecraft/net/minecraft/client/renderer/model/ItemModelGenerator.java.patch b/patches/minecraft/net/minecraft/client/renderer/model/ItemModelGenerator.java.patch new file mode 100644 index 0000000000..796df50456 --- /dev/null +++ b/patches/minecraft/net/minecraft/client/renderer/model/ItemModelGenerator.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/client/renderer/model/ItemModelGenerator.java ++++ b/net/minecraft/client/renderer/model/ItemModelGenerator.java +@@ -35,6 +35,7 @@ + map.put("particle", p_209579_2_.func_178300_b("particle") ? p_209579_2_.func_178308_c("particle") : map.get("layer0")); + BlockModel blockmodel = new BlockModel((ResourceLocation)null, list, map, false, false, p_209579_2_.func_181682_g(), p_209579_2_.func_187966_f()); + blockmodel.field_178317_b = p_209579_2_.field_178317_b; ++ blockmodel.customData.copyFrom(p_209579_2_.customData); + return blockmodel; + } + diff --git a/patches/minecraft/net/minecraft/client/renderer/model/ModelManager.java.patch b/patches/minecraft/net/minecraft/client/renderer/model/ModelManager.java.patch index 7372c957be..c36c2e9725 100644 --- a/patches/minecraft/net/minecraft/client/renderer/model/ModelManager.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/model/ModelManager.java.patch @@ -9,7 +9,18 @@ private final AtlasTexture field_174956_b; private final BlockModelShapes field_174957_c; private final BlockColors field_224743_d; -@@ -43,7 +43,7 @@ +@@ -29,6 +29,10 @@ + this.field_174957_c = new BlockModelShapes(this); + } + ++ public IBakedModel getModel(ResourceLocation modelLocation) { ++ return this.field_174958_a.getOrDefault(modelLocation, this.field_174955_d); ++ } ++ + public IBakedModel func_174953_a(ModelResourceLocation p_174953_1_) { + return this.field_174958_a.getOrDefault(p_174953_1_, this.field_174955_d); + } +@@ -43,7 +47,7 @@ protected ModelBakery func_212854_a_(IResourceManager p_212854_1_, IProfiler p_212854_2_) { p_212854_2_.func_219894_a(); @@ -18,7 +29,7 @@ p_212854_2_.func_219897_b(); return modelbakery; } -@@ -55,6 +55,7 @@ +@@ -55,6 +59,7 @@ this.field_174958_a = p_212853_1_.func_217846_a(); this.field_224744_f = p_212853_1_.func_225354_b(); this.field_174955_d = this.field_174958_a.get(ModelBakery.field_177604_a); @@ -26,7 +37,7 @@ p_212853_3_.func_219895_b("cache"); this.field_174957_c.func_178124_c(); p_212853_3_.func_76319_b(); -@@ -78,4 +79,10 @@ +@@ -78,4 +83,10 @@ return true; } } diff --git a/patches/minecraft/net/minecraft/client/renderer/model/SimpleBakedModel.java.patch b/patches/minecraft/net/minecraft/client/renderer/model/SimpleBakedModel.java.patch index 2eeaa712e0..d665fa0426 100644 --- a/patches/minecraft/net/minecraft/client/renderer/model/SimpleBakedModel.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/model/SimpleBakedModel.java.patch @@ -1,8 +1,13 @@ --- a/net/minecraft/client/renderer/model/SimpleBakedModel.java +++ b/net/minecraft/client/renderer/model/SimpleBakedModel.java -@@ -75,7 +75,7 @@ +@@ -74,8 +74,12 @@ + this(p_i46988_1_.func_178309_b(), p_i46988_1_.func_178311_c(), p_i46988_1_.func_181682_g(), p_i46988_2_); } ++ public Builder(net.minecraftforge.client.model.IModelConfiguration model, ItemOverrideList overrides) { ++ this(model.useSmoothLighting(), model.isShadedInGui(), model.getCameraTransforms(), overrides); ++ } ++ public Builder(BlockState p_i48189_1_, IBakedModel p_i48189_2_, TextureAtlasSprite p_i48189_3_, Random p_i48189_4_, long p_i48189_5_) { - this(p_i48189_2_.func_177555_b(), p_i48189_2_.func_177556_c(), p_i48189_2_.func_177552_f(), p_i48189_2_.func_188617_f()); + this(p_i48189_2_.isAmbientOcclusion(p_i48189_1_), p_i48189_2_.func_177556_c(), p_i48189_2_.func_177552_f(), p_i48189_2_.func_188617_f()); diff --git a/patches/minecraft/net/minecraft/client/renderer/texture/TextureAtlasSprite.java.patch b/patches/minecraft/net/minecraft/client/renderer/texture/TextureAtlasSprite.java.patch index 61e65aa99b..e15e91a6af 100644 --- a/patches/minecraft/net/minecraft/client/renderer/texture/TextureAtlasSprite.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/texture/TextureAtlasSprite.java.patch @@ -42,14 +42,25 @@ p_195667_3_[i].func_195706_a(i, this.field_110975_c >> i, this.field_110974_d >> i, p_195667_1_ >> i, p_195667_2_ >> i, this.field_130223_c >> i, this.field_130224_d >> i, this.field_195670_c.length > 1); } -@@ -464,4 +471,10 @@ +@@ -454,14 +461,21 @@ + } + + public int func_195665_a(int p_195665_1_, int p_195665_2_, int p_195665_3_, int p_195665_4_) { ++ if (this.field_195671_d == null || this.field_195672_e == null) return this.field_195670_c[p_195665_2_].func_195709_a(p_195665_3_, p_195665_4_); // FORGE: Avoid crash if the texture is not animated + return this.field_195670_c[p_195665_2_].func_195709_a(p_195665_3_ + (this.field_195671_d[p_195665_1_] * this.field_130223_c >> p_195665_2_), p_195665_4_ + (this.field_195672_e[p_195665_1_] * this.field_130224_d >> p_195665_2_)); + } + + public boolean func_195662_a(int p_195662_1_, int p_195662_2_, int p_195662_3_) { ++ if (this.field_195671_d == null || this.field_195672_e == null) return (this.field_195670_c[0].func_195709_a(p_195662_2_, p_195662_3_) >> 24 & 255) == 0; // FORGE: Avoid crash if the texture is not animated + return (this.field_195670_c[0].func_195709_a(p_195662_2_ + this.field_195671_d[p_195662_1_] * this.field_130223_c, p_195662_3_ + this.field_195672_e[p_195662_1_] * this.field_130224_d) >> 24 & 255) == 0; + } + public void func_195663_q() { this.func_195659_d(0); } -+ ++ + // Forge Start -+ + public int getPixelRGBA(int frameIndex, int x, int y) { -+ return this.field_195670_c[frameIndex].func_195709_a(x + this.field_195671_d[frameIndex] * this.field_130223_c, y + this.field_195672_e[frameIndex] * this.field_130224_d); ++ return this.func_195665_a(frameIndex, 0, x, y); + } } diff --git a/src/main/java/net/minecraftforge/client/ForgeHooksClient.java b/src/main/java/net/minecraftforge/client/ForgeHooksClient.java index a1cf9d94fd..77fb5703e7 100644 --- a/src/main/java/net/minecraftforge/client/ForgeHooksClient.java +++ b/src/main/java/net/minecraftforge/client/ForgeHooksClient.java @@ -181,7 +181,6 @@ public class ForgeHooksClient { ModLoader.get().postEvent(new TextureStitchEvent.Pre(map, resourceLocations)); // ModelLoader.White.INSTANCE.register(map); // TODO Custom TAS - ModelDynBucket.LoaderDynBucket.INSTANCE.register(map); } public static void onTextureStitchedPost(AtlasTexture map) diff --git a/src/main/java/net/minecraftforge/client/extensions/IForgeBakedModel.java b/src/main/java/net/minecraftforge/client/extensions/IForgeBakedModel.java index 4300baa2de..96cb971cbb 100644 --- a/src/main/java/net/minecraftforge/client/extensions/IForgeBakedModel.java +++ b/src/main/java/net/minecraftforge/client/extensions/IForgeBakedModel.java @@ -24,6 +24,7 @@ import java.util.Random; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import javax.vecmath.Matrix4f; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.model.BakedQuad; @@ -34,6 +35,7 @@ import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IEnviromentBlockReader; import net.minecraftforge.client.model.data.IModelData; +import org.apache.commons.lang3.tuple.Pair; public interface IForgeBakedModel { @@ -50,11 +52,16 @@ public interface IForgeBakedModel default boolean isAmbientOcclusion(BlockState state) { return getBakedModel().isAmbientOcclusion(); } + /** + * Override to tell the new model loader that it shouldn't wrap this model + */ + default boolean doesHandlePerspectives() { return false; } + /* * Returns the pair of the model for the given perspective, and the matrix that * should be applied to the GL state before rendering it (matrix may be null). */ - default org.apache.commons.lang3.tuple.Pair handlePerspective(ItemCameraTransforms.TransformType cameraTransformType) + default Pair handlePerspective(ItemCameraTransforms.TransformType cameraTransformType) { return net.minecraftforge.client.ForgeHooksClient.handlePerspective(getBakedModel(), cameraTransformType); } diff --git a/src/main/java/net/minecraftforge/client/model/BakedItemModel.java b/src/main/java/net/minecraftforge/client/model/BakedItemModel.java index 4304a3ff0f..75491adeb7 100644 --- a/src/main/java/net/minecraftforge/client/model/BakedItemModel.java +++ b/src/main/java/net/minecraftforge/client/model/BakedItemModel.java @@ -121,6 +121,12 @@ public class BakedItemModel implements IBakedModel return ImmutableList.of(); } + @Override + public boolean doesHandlePerspectives() + { + return true; + } + @Override public Pair handlePerspective(TransformType type) { diff --git a/src/main/java/net/minecraftforge/client/model/BakedModelWrapper.java b/src/main/java/net/minecraftforge/client/model/BakedModelWrapper.java index 61784bf00a..0ba6817784 100644 --- a/src/main/java/net/minecraftforge/client/model/BakedModelWrapper.java +++ b/src/main/java/net/minecraftforge/client/model/BakedModelWrapper.java @@ -34,7 +34,6 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IEnviromentBlockReader; -import net.minecraft.world.IWorldReader; import net.minecraftforge.client.model.data.IModelData; import org.apache.commons.lang3.tuple.Pair; @@ -95,6 +94,12 @@ public abstract class BakedModelWrapper implements IBaked return originalModel.getOverrides(); } + @Override + public boolean doesHandlePerspectives() + { + return originalModel.doesHandlePerspectives(); + } + @Override public Pair handlePerspective(ItemCameraTransforms.TransformType cameraTransformType) { diff --git a/src/main/java/net/minecraftforge/client/model/BlockModelConfiguration.java b/src/main/java/net/minecraftforge/client/model/BlockModelConfiguration.java new file mode 100644 index 0000000000..25024fdb01 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/BlockModelConfiguration.java @@ -0,0 +1,183 @@ +/* + * 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.model.*; +import net.minecraft.client.renderer.texture.ISprite; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.model.geometry.IModelGeometry; +import net.minecraftforge.client.model.geometry.IModelGeometryPart; +import net.minecraftforge.common.model.IModelState; + +import javax.annotation.Nullable; +import java.util.*; +import java.util.function.Function; + +public class BlockModelConfiguration implements IModelConfiguration +{ + public final BlockModel owner; + public final VisibilityData visibilityData = new VisibilityData(); + @Nullable + private IModelGeometry customGeometry; + @Nullable + private IModelState customModelState; + + public BlockModelConfiguration(BlockModel owner) + { + this.owner = owner; + } + + @Nullable + @Override + public IUnbakedModel getOwnerModel() + { + return owner; + } + + @Override + public String getModelName() + { + return owner.name; + } + + public boolean hasCustomGeometry() + { + return getCustomGeometry() != null; + } + + @Nullable + public IModelGeometry getCustomGeometry() + { + return owner.parent != null && customGeometry == null ? owner.parent.customData.getCustomGeometry() : customGeometry; + } + + public void setCustomGeometry(IModelGeometry geometry) + { + this.customGeometry = geometry; + } + + @Nullable + public IModelState getCustomModelState() + { + return owner.parent != null && customModelState == null ? owner.parent.customData.getCustomModelState() : customModelState; + } + + public void setCustomModelState(IModelState modelState) + { + this.customModelState = modelState; + } + + @Override + public boolean getPartVisibility(IModelGeometryPart part, boolean fallback) + { + return owner.parent != null && !visibilityData.hasCustomVisibility(part) ? + owner.parent.customData.getPartVisibility(part, fallback): + visibilityData.isVisible(part, fallback); + } + + @Override + public boolean isTexturePresent(String name) + { + return owner.isTexturePresent(name); + } + + @Override + public String resolveTexture(String name) + { + return owner.resolveTextureName(name); + } + + @Override + public boolean isShadedInGui() { + return owner.isGui3d(); + } + + @Override + public boolean useSmoothLighting() + { + return owner.isAmbientOcclusion(); + } + + @Override + public ItemCameraTransforms getCameraTransforms() + { + return owner.getAllTransforms(); + } + + @Override + public IModelState getCombinedState() + { + IModelState state = getCustomModelState(); + + return state != null + ? new SimpleModelState(PerspectiveMapWrapper.getTransformsWithFallback(state, getCameraTransforms()), state.apply(Optional.empty())) + : new SimpleModelState(PerspectiveMapWrapper.getTransforms(getCameraTransforms())); + } + + public void copyFrom(BlockModelConfiguration other) + { + this.customGeometry = other.customGeometry; + this.customModelState = other.customModelState; + this.visibilityData.copyFrom(other.visibilityData); + } + + public Collection getTextureDependencies(Function modelGetter, Set missingTextureErrors) + { + IModelGeometry geometry = getCustomGeometry(); + return geometry == null ? Collections.emptySet() : + geometry.getTextureDependencies(this, modelGetter, missingTextureErrors); + } + + public IBakedModel bake(ModelBakery bakery, Function bakedTextureGetter, ISprite sprite, VertexFormat format, ItemOverrideList overrides) + { + IModelGeometry geometry = getCustomGeometry(); + if (geometry == null) + throw new IllegalStateException("Can not use custom baking without custom geometry"); + return geometry.bake(this, bakery, bakedTextureGetter, sprite, format, overrides); + } + + public static class VisibilityData + { + private final Map data = new HashMap<>(); + + public boolean hasCustomVisibility(IModelGeometryPart part) + { + return data.containsKey(part.name()); + } + + public boolean isVisible(IModelGeometryPart part, boolean fallback) + { + return data.getOrDefault(part.name(), fallback); + } + + public void setVisibilityState(String partName, boolean type) + { + data.put(partName, type); + } + + public void copyFrom(VisibilityData visibilityData) + { + data.clear(); + data.putAll(visibilityData.data); + } + } +} diff --git a/src/main/java/net/minecraftforge/client/model/BlockStateLoader.java b/src/main/java/net/minecraftforge/client/model/BlockStateLoader.java index 69d4fbe778..44014fadc9 100644 --- a/src/main/java/net/minecraftforge/client/model/BlockStateLoader.java +++ b/src/main/java/net/minecraftforge/client/model/BlockStateLoader.java @@ -46,6 +46,7 @@ import com.google.gson.GsonBuilder; import javax.annotation.Nullable; +@Deprecated // Use the new model loading system and data generators instead. public class BlockStateLoader { private static final Gson GSON = (new GsonBuilder()) @@ -103,7 +104,7 @@ public class BlockStateLoader entry.getKey().replace("=","_").replace(",","_")) ); - IUnbakedModel model = ForgeVariantHelper.prepareInjectedModel((ModelLoader)bakery, modelLocation, var.getModel(), var.getSmooth(), var.getGui3d(), var.getTextures(), var.getOnlyPartsVariant(), var.getCustomData()); + IUnbakedModel model = ForgeVariantHelper.prepareInjectedModel(modelLocation, var.getModel(), var.getSmooth(), var.getGui3d(), var.getTextures(), var.getOnlyPartsVariant(), var.getCustomData()); modelConsumer.accept(modelLocation, model); } @@ -185,7 +186,7 @@ public class BlockStateLoader private static class ForgeVariantHelper { - public static IUnbakedModel prepareInjectedModel(ModelLoader bakery, ResourceLocation blockstateLocation, @Nullable ResourceLocation modelLocation, Optional smooth, Optional gui3d, ImmutableMap textures, ImmutableMap parts, ImmutableMap customData) + public static IUnbakedModel prepareInjectedModel(ResourceLocation blockstateLocation, @Nullable ResourceLocation modelLocation, Optional smooth, Optional gui3d, ImmutableMap textures, ImmutableMap parts, ImmutableMap customData) { int size = parts.size(); diff --git a/src/main/java/net/minecraftforge/client/model/CompositeModel.java b/src/main/java/net/minecraftforge/client/model/CompositeModel.java new file mode 100644 index 0000000000..79f3bda9df --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/CompositeModel.java @@ -0,0 +1,340 @@ +/* + * 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 com.google.common.collect.ImmutableMap; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import net.minecraft.block.BlockState; +import net.minecraft.client.renderer.model.*; +import net.minecraft.client.renderer.texture.ISprite; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.resources.IResourceManager; +import net.minecraft.util.Direction; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IEnviromentBlockReader; +import net.minecraftforge.client.model.data.*; +import net.minecraftforge.client.model.geometry.IModelGeometryPart; +import net.minecraftforge.client.model.geometry.IMultipartModelGeometry; +import net.minecraftforge.common.model.IModelState; +import org.apache.commons.lang3.tuple.Pair; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.vecmath.Matrix4f; +import java.util.*; +import java.util.function.Function; + +public class CompositeModel implements IDynamicBakedModel +{ + private final ImmutableMap bakedParts; + private final boolean isAmbientOcclusion; + private final boolean isGui3d; + private final TextureAtlasSprite particle; + private final ItemOverrideList overrides; + private final IModelState transforms; + + public CompositeModel(boolean isGui3d, boolean isAmbientOcclusion, TextureAtlasSprite particle, ImmutableMap bakedParts, IModelState combinedState, ItemOverrideList overrides) + { + this.bakedParts = bakedParts; + this.isAmbientOcclusion = isAmbientOcclusion; + this.isGui3d = isGui3d; + this.particle = particle; + this.overrides = overrides; + this.transforms = combinedState; + } + + @Nonnull + @Override + public List getQuads(@Nullable BlockState state, @Nullable Direction side, @Nonnull Random rand, @Nonnull IModelData extraData) + { + List quads = new ArrayList<>(); + for(Map.Entry entry : bakedParts.entrySet()) + { + quads.addAll(entry.getValue().getQuads(state, side, rand, CompositeModelData.get(extraData, entry.getKey()))); + } + return quads; + } + + @Nonnull + @Override + public IModelData getModelData(@Nonnull IEnviromentBlockReader world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nonnull IModelData tileData) + { + CompositeModelData composite = new CompositeModelData(); + for(Map.Entry entry : bakedParts.entrySet()) + { + composite.putSubmodelData(entry.getKey(), entry.getValue().getModelData(world, pos, state, new ModelDataWrapper(tileData))); + } + return composite; + } + + @Override + public boolean isAmbientOcclusion() + { + return isAmbientOcclusion; + } + + @Override + public boolean isGui3d() + { + return isGui3d; + } + + @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 Pair handlePerspective(ItemCameraTransforms.TransformType cameraTransformType) + { + return PerspectiveMapWrapper.handlePerspective(this, transforms, cameraTransformType); + } + + @Nullable + public IBakedModel getPart(String name) + { + return bakedParts.get(name); + } + + private static class Submodel implements IModelGeometryPart + { + private final String name; + private final BlockModel model; + private final ISprite sprite; + + private Submodel(String name, BlockModel model, ISprite sprite) + { + this.name = name; + this.model = model; + this.sprite = sprite; + } + + @Override + public String name() + { + return name; + } + + @Override + public void addQuads(IModelConfiguration owner, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ISprite sprite, VertexFormat format) + { + throw new UnsupportedOperationException("Attempted to call adQuads on a Submodel instance. Please don't."); + } + + public IBakedModel bake(ModelBakery bakery, Function spriteGetter, ISprite sprite, VertexFormat format) + { + return model.bake(bakery, spriteGetter, new ModelStateComposition(this.sprite.getState(), sprite.getState(), + this.sprite.isUvLock() || sprite.isUvLock()), format); + } + + @Override + public Collection getTextureDependencies(IModelConfiguration owner, Function modelGetter, Set missingTextureErrors) + { + return model.getTextures(modelGetter, missingTextureErrors); + } + } + + public static class Geometry implements IMultipartModelGeometry + { + private final ImmutableMap parts; + + Geometry(ImmutableMap parts) + { + this.parts = parts; + } + + @Override + public Collection getParts() + { + return parts.values(); + } + + @Override + public Optional getPart(String name) + { + return Optional.ofNullable(parts.get(name)); + } + + @Override + public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, ISprite sprite, VertexFormat format, ItemOverrideList overrides) + { + String particleLocation = owner.resolveTexture("particle"); + TextureAtlasSprite particle = spriteGetter.apply(new ResourceLocation(particleLocation)); + + ImmutableMap.Builder bakedParts = ImmutableMap.builder(); + for(Map.Entry part : parts.entrySet()) + { + Submodel submodel = part.getValue(); + if (!owner.getPartVisibility(submodel)) + continue; + bakedParts.put(part.getKey(), submodel.bake(bakery, spriteGetter, sprite, format)); + } + return new CompositeModel(owner.isShadedInGui(), owner.useSmoothLighting(), particle, bakedParts.build(), owner.getCombinedState(), overrides); + } + + @Override + public Collection getTextureDependencies(IModelConfiguration owner, Function modelGetter, Set missingTextureErrors) + { + Set textures = new HashSet<>(); + for(Submodel part : parts.values()) + { + textures.addAll(part.getTextureDependencies(owner, modelGetter, missingTextureErrors)); + } + return textures; + } + } + + public static class Loader implements IModelLoader + { + public static final Loader INSTANCE = new Loader(); + + private Loader() {} + + @Override + public void onResourceManagerReload(IResourceManager resourceManager) + { + + } + + @Override + public Geometry read(JsonDeserializationContext deserializationContext, JsonObject modelContents) + { + if (!modelContents.has("parts")) + throw new RuntimeException("Composite model requires a \"parts\" element."); + ImmutableMap.Builder parts = ImmutableMap.builder(); + for(Map.Entry part : modelContents.get("parts").getAsJsonObject().entrySet()) + { + ISprite sprite = ModelRotation.X0_Y0; + parts.put(part.getKey(), new Submodel( + part.getKey(), + deserializationContext.deserialize(part.getValue(), BlockModel.class), + sprite)); + } + return new Geometry(parts.build()); + } + } + + private static class CompositeModelData implements IModelData + { + public static final ModelProperty SUBMODEL_DATA = new ModelProperty<>(); + + public static Optional get(IModelData modelData) + { + return Optional.ofNullable(modelData.getData(SUBMODEL_DATA)); + } + + public static IModelData get(IModelData modelData, String name) + { + return get(modelData).map(data -> data.getSubmodelData(name)) + .orElse(EmptyModelData.INSTANCE); + } + + private final Map 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; + } + + @SuppressWarnings("unchecked") + @Nullable + @Override + public T getData(ModelProperty prop) + { + if (prop == SUBMODEL_DATA) + return (T)this; + return null; + } + + @Nullable + @Override + public T setData(ModelProperty prop, T data) + { + return null; + } + } + + private static class ModelDataWrapper extends ModelDataMap + { + private final IModelData parent; + + public ModelDataWrapper(IModelData parent) + { + this.parent = parent; + } + + @Override + public boolean hasProperty(ModelProperty prop) + { + return super.hasProperty(prop) || parent.hasProperty(prop); + } + + @Nullable + @Override + public T getData(ModelProperty prop) + { + return super.hasProperty(prop) ? super.getData(prop) : parent.getData(prop); + } + + @Nullable + @Override + public T setData(ModelProperty prop, T data) + { + // We do not want to delegate setting to the parent + return super.setData(prop, data); + } + } +} diff --git a/src/main/java/net/minecraftforge/client/model/FancyMissingModel.java b/src/main/java/net/minecraftforge/client/model/FancyMissingModel.java index 974fccea5a..6501723bb3 100644 --- a/src/main/java/net/minecraftforge/client/model/FancyMissingModel.java +++ b/src/main/java/net/minecraftforge/client/model/FancyMissingModel.java @@ -187,6 +187,12 @@ final class FancyMissingModel implements IUnbakedModel @Override public ItemOverrideList getOverrides() { return ItemOverrideList.EMPTY; } + @Override + public boolean doesHandlePerspectives() + { + return true; + } + @Override public Pair handlePerspective(ItemCameraTransforms.TransformType cameraTransformType) { diff --git a/src/main/java/net/minecraftforge/client/model/ForgeBlockStateV1.java b/src/main/java/net/minecraftforge/client/model/ForgeBlockStateV1.java index 8f39668cb9..992aaeeaaa 100644 --- a/src/main/java/net/minecraftforge/client/model/ForgeBlockStateV1.java +++ b/src/main/java/net/minecraftforge/client/model/ForgeBlockStateV1.java @@ -35,6 +35,7 @@ import javax.vecmath.Matrix4f; import javax.vecmath.Quat4f; import javax.vecmath.Vector3f; +import net.minecraft.client.renderer.model.ItemCameraTransforms; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -62,6 +63,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; +@Deprecated // Use the new model loading system and data generators instead. public class ForgeBlockStateV1 extends Marker { private static final Logger LOGGER = LogManager.getLogger(); @@ -390,7 +392,11 @@ public class ForgeBlockStateV1 extends Marker boolean isVanillaCompatible() { - return model != null && submodels.isEmpty() && textures.isEmpty() && customData.isEmpty() && !smooth.isPresent() && !gui3d.isPresent() && state.orElse(ModelRotation.X0_Y0) instanceof ModelRotation; + return model != null && !ModelLoaderRegistry.isCustomModel(model) + && submodels.isEmpty() + && textures.isEmpty() && customData.isEmpty() + && !smooth.isPresent() && !gui3d.isPresent() + && state.orElse(ModelRotation.X0_Y0) instanceof ModelRotation; } protected SubModel asGenericSubModel() @@ -495,118 +501,8 @@ public class ForgeBlockStateV1 extends Marker if (json.has("transform")) { - if (json.get("transform").isJsonPrimitive() && json.get("transform").getAsJsonPrimitive().isString()) - { - String transform = json.get("transform").getAsString(); - ret.state = Transforms.get(transform); - if (!ret.state.isPresent()) - { - throw new JsonParseException("transform: unknown default string: " + transform); - } - } - else if (!json.get("transform").isJsonObject()) - { - try - { - TRSRTransformation base = context.deserialize(json.get("transform"), TRSRTransformation.class); - ret.state = Optional.of(TRSRTransformation.blockCenterToCorner(base)); - } - catch (JsonParseException e) - { - throw new JsonParseException("transform: expected a string, object or valid base transformation, got: " + json.get("transform")); - } - } - else - { - JsonObject transform = json.get("transform").getAsJsonObject(); - EnumMap transforms = Maps.newEnumMap(TransformType.class); - if(transform.has("thirdperson")) - { - TRSRTransformation t = context.deserialize(transform.get("thirdperson"), TRSRTransformation.class); - transform.remove("thirdperson"); - transforms.put(TransformType.THIRD_PERSON_RIGHT_HAND, TRSRTransformation.blockCenterToCorner(t)); - } - if(transform.has("thirdperson_righthand")) - { - TRSRTransformation t = context.deserialize(transform.get("thirdperson_righthand"), TRSRTransformation.class); - transform.remove("thirdperson_righthand"); - transforms.put(TransformType.THIRD_PERSON_RIGHT_HAND, TRSRTransformation.blockCenterToCorner(t)); - } - if(transform.has("thirdperson_lefthand")) - { - TRSRTransformation t = context.deserialize(transform.get("thirdperson_lefthand"), TRSRTransformation.class); - transform.remove("thirdperson_lefthand"); - transforms.put(TransformType.THIRD_PERSON_LEFT_HAND, TRSRTransformation.blockCenterToCorner(t)); - } - if(transform.has("firstperson")) - { - TRSRTransformation t = context.deserialize(transform.get("firstperson"), TRSRTransformation.class); - transform.remove("firstperson"); - transforms.put(TransformType.FIRST_PERSON_RIGHT_HAND, TRSRTransformation.blockCenterToCorner(t)); - } - if(transform.has("firstperson_righthand")) - { - TRSRTransformation t = context.deserialize(transform.get("firstperson_righthand"), TRSRTransformation.class); - transform.remove("firstperson_righthand"); - transforms.put(TransformType.FIRST_PERSON_RIGHT_HAND, TRSRTransformation.blockCenterToCorner(t)); - } - if(transform.has("firstperson_lefthand")) - { - TRSRTransformation t = context.deserialize(transform.get("firstperson_lefthand"), TRSRTransformation.class); - transform.remove("firstperson_lefthand"); - transforms.put(TransformType.FIRST_PERSON_LEFT_HAND, TRSRTransformation.blockCenterToCorner(t)); - } - if(transform.has("head")) - { - TRSRTransformation t = context.deserialize(transform.get("head"), TRSRTransformation.class); - transform.remove("head"); - transforms.put(TransformType.HEAD, TRSRTransformation.blockCenterToCorner(t)); - } - if(transform.has("gui")) - { - TRSRTransformation t = context.deserialize(transform.get("gui"), TRSRTransformation.class); - transform.remove("gui"); - transforms.put(TransformType.GUI, TRSRTransformation.blockCenterToCorner(t)); - } - if(transform.has("ground")) - { - TRSRTransformation t = context.deserialize(transform.get("ground"), TRSRTransformation.class); - transform.remove("ground"); - transforms.put(TransformType.GROUND, TRSRTransformation.blockCenterToCorner(t)); - } - if(transform.has("fixed")) - { - TRSRTransformation t = context.deserialize(transform.get("fixed"), TRSRTransformation.class); - transform.remove("fixed"); - transforms.put(TransformType.FIXED, TRSRTransformation.blockCenterToCorner(t)); - } - int k = transform.entrySet().size(); - if(transform.has("matrix")) k--; - if(transform.has("translation")) k--; - if(transform.has("rotation")) k--; - if(transform.has("scale")) k--; - if(transform.has("post-rotation")) k--; - if(k > 0) - { - throw new JsonParseException("transform: allowed keys: 'thirdperson', 'firstperson', 'gui', 'head', 'matrix', 'translation', 'rotation', 'scale', 'post-rotation'"); - } - TRSRTransformation base = TRSRTransformation.identity(); - if(!transform.entrySet().isEmpty()) - { - base = context.deserialize(transform, TRSRTransformation.class); - base = TRSRTransformation.blockCenterToCorner(base); - } - IModelState state; - if(transforms.isEmpty()) - { - state = base; - } - else - { - state = new SimpleModelState(Maps.immutableEnumMap(transforms), Optional.of(base)); - } - ret.state = Optional.of(state); - } + JsonElement transformData = json.get("transform"); + ret.state = ModelLoaderRegistry2.deserializeTransform(context, transformData); } if (json.has("uvlock")) @@ -923,6 +819,7 @@ public class ForgeBlockStateV1 extends Marker return TRSRTransformation.blockCenterToCorner(flipX.compose(TRSRTransformation.blockCornerToCenter(transform)).compose(flipX)); } + @Deprecated public static Optional get(String name) { return Optional.ofNullable(transforms.get(name)); diff --git a/src/main/java/net/minecraftforge/client/model/ICustomModelLoader.java b/src/main/java/net/minecraftforge/client/model/ICustomModelLoader.java index 5042507429..b33fefcb55 100644 --- a/src/main/java/net/minecraftforge/client/model/ICustomModelLoader.java +++ b/src/main/java/net/minecraftforge/client/model/ICustomModelLoader.java @@ -28,6 +28,7 @@ import net.minecraftforge.resource.IResourceType; import net.minecraftforge.resource.ISelectiveResourceReloadListener; import net.minecraftforge.resource.VanillaResourceType; +@Deprecated // Use the new model loading system and data generators instead. public interface ICustomModelLoader extends ISelectiveResourceReloadListener { @Override diff --git a/src/main/java/net/minecraftforge/client/model/IForgeUnbakedModel.java b/src/main/java/net/minecraftforge/client/model/IForgeUnbakedModel.java new file mode 100644 index 0000000000..c6318dfdc0 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/IForgeUnbakedModel.java @@ -0,0 +1,52 @@ +/* + * 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.model.IBakedModel; +import net.minecraft.client.renderer.model.ModelBakery; +import net.minecraft.client.renderer.texture.ISprite; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.model.IModelState; +import net.minecraftforge.common.model.animation.IClip; + +import javax.annotation.Nullable; +import java.util.Optional; +import java.util.function.Function; + +public interface IForgeUnbakedModel +{ + /** + * @param spriteGetter Where textures will be looked up when baking + * @param sprite Transforms to apply while baking. Usually will be an instance of {@link IModelState}. + */ + @Nullable + IBakedModel bake(ModelBakery bakery, Function spriteGetter, ISprite sprite, VertexFormat format); + + /** + * Retrieves information about an animation clip in the model. + * @param name The clip name + * @return + */ + default Optional getClip(String name) { + return Optional.empty(); + } +} diff --git a/src/main/java/net/minecraftforge/client/model/IModel.java b/src/main/java/net/minecraftforge/client/model/IModel.java index 3d83012fcb..90474e58c6 100644 --- a/src/main/java/net/minecraftforge/client/model/IModel.java +++ b/src/main/java/net/minecraftforge/client/model/IModel.java @@ -41,15 +41,9 @@ import net.minecraftforge.common.model.animation.IClip; * Models can be baked to different vertex formats and with different state. */ @SuppressWarnings("unchecked") -public interface IModel> +@Deprecated // Use the new model loading system and data generators instead. +public interface IModel> extends IForgeUnbakedModel { - /** - * @param spriteGetter Where textures will be looked up when baking - * @param sprite Transforms to apply while baking. Usually will be an instance of {@link IModelState}. - */ - @Nullable - IBakedModel bake(ModelBakery bakery, Function spriteGetter, ISprite sprite, VertexFormat format); - /** * Default state this model will be baked with. * @see IModelState @@ -58,10 +52,6 @@ public interface IModel> return TRSRTransformation.identity(); } - default Optional getClip(String name) { - return Optional.empty(); - } - /** * Allows the model to process custom data from the variant definition. * If unknown data is encountered it should be skipped. diff --git a/src/main/java/net/minecraftforge/client/model/IModelBuilder.java b/src/main/java/net/minecraftforge/client/model/IModelBuilder.java new file mode 100644 index 0000000000..79607a41d5 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/IModelBuilder.java @@ -0,0 +1,70 @@ +/* + * 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.model.BakedQuad; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.model.ItemOverrideList; +import net.minecraft.client.renderer.model.SimpleBakedModel; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.util.Direction; + +public interface IModelBuilder> +{ + static IModelBuilder of(IModelConfiguration owner, ItemOverrideList overrides, TextureAtlasSprite particle) + { + return new Simple(new SimpleBakedModel.Builder(owner, overrides).setTexture(particle)); + } + + T addFaceQuad(Direction facing, BakedQuad quad); + T addGeneralQuad(BakedQuad quad); + + IBakedModel build(); + + class Simple implements IModelBuilder { + final SimpleBakedModel.Builder builder; + + Simple(SimpleBakedModel.Builder builder) + { + this.builder = builder; + } + + @Override + public Simple addFaceQuad(Direction facing, BakedQuad quad) + { + builder.addFaceQuad(facing, quad); + return this; + } + + @Override + public Simple addGeneralQuad(BakedQuad quad) + { + builder.addGeneralQuad(quad); + return this; + } + + @Override + public IBakedModel build() + { + return builder.build(); + } + } +} + diff --git a/src/main/java/net/minecraftforge/client/model/IModelConfiguration.java b/src/main/java/net/minecraftforge/client/model/IModelConfiguration.java new file mode 100644 index 0000000000..65ef70645b --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/IModelConfiguration.java @@ -0,0 +1,99 @@ +/* + * 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.model.IUnbakedModel; +import net.minecraft.client.renderer.model.ItemCameraTransforms; +import net.minecraftforge.client.model.geometry.IModelGeometryPart; +import net.minecraftforge.common.model.IModelState; + +import javax.annotation.Nullable; + +/* + * Interface that provides generic access to the data within BlockModel, + * while allowing non-blockmodel usage of models + */ +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. + */ + String getModelName(); + + /** + * Checks if a texture is present in the model. + * @param name The name of a texture channel. + */ + boolean isTexturePresent(String name); + + /** + * Resolves the final texture name, taking into account texture aliases and replacements. + * @param name The name of a texture channel. + * @return The location of the texture, or the missing texture if not found. + */ + String resolveTexture(String name); + + /** + * @return True if the item uses 3D lighting. + */ + boolean isShadedInGui(); + + /** + * @return True if the item requires per-vertex lighting. + */ + boolean useSmoothLighting(); + + /** + * Gets the vanilla camera transforms data. + * Do not use for non-vanilla code. For general usage, prefer getCombinedState. + */ + @Deprecated + ItemCameraTransforms getCameraTransforms(); + + /** + * @return The combined transformation state including vanilla and forge transforms data. + */ + IModelState getCombinedState(); + + /** + * Queries the visibility information for the model parts. + * @param part A part for which to query visibility. + * @param fallback A boolean specifying the default visibility if an override isn't found in the model data. + * @return The final computed visibility. + */ + default boolean getPartVisibility(IModelGeometryPart part, boolean fallback) { + return fallback; + } + + /** + * Queries the visibility information for the model parts. Same as above, but defaulting to visible. + * @param part A part for which to query visibility. + * @return The final computed visibility. + */ + default boolean getPartVisibility(IModelGeometryPart part) { + return getPartVisibility(part, true); + } +} diff --git a/src/main/java/net/minecraftforge/client/model/IModelLoader.java b/src/main/java/net/minecraftforge/client/model/IModelLoader.java new file mode 100644 index 0000000000..86a5aaccf7 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/IModelLoader.java @@ -0,0 +1,53 @@ +/* + * 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 com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import net.minecraft.resources.IResourceManager; +import net.minecraftforge.client.model.geometry.IModelGeometry; +import net.minecraftforge.resource.IResourceType; +import net.minecraftforge.resource.ISelectiveResourceReloadListener; +import net.minecraftforge.resource.VanillaResourceType; + +import java.util.function.Predicate; + +public interface IModelLoader> extends ISelectiveResourceReloadListener +{ + @Override + default IResourceType getResourceType() + { + return VanillaResourceType.MODELS; + } + + @Override + void onResourceManagerReload(IResourceManager resourceManager); + + @Override + default void onResourceManagerReload(IResourceManager resourceManager, Predicate resourcePredicate) + { + if (resourcePredicate.test(getResourceType())) + { + onResourceManagerReload(resourceManager); + } + } + + T read(JsonDeserializationContext deserializationContext, JsonObject modelContents); +} diff --git a/src/main/java/net/minecraftforge/client/model/ModelDynBucket.java b/src/main/java/net/minecraftforge/client/model/ModelDynBucket.java index 981fb77552..dca6f98fb6 100644 --- a/src/main/java/net/minecraftforge/client/model/ModelDynBucket.java +++ b/src/main/java/net/minecraftforge/client/model/ModelDynBucket.java @@ -20,49 +20,46 @@ package net.minecraftforge.client.model; import java.io.IOException; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; +import java.util.*; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.vecmath.Quat4f; +import com.google.common.collect.*; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.model.*; import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; -import net.minecraft.client.renderer.texture.ISprite; -import net.minecraft.client.renderer.texture.PngSizeInfo; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.renderer.texture.AtlasTexture; +import net.minecraft.client.renderer.texture.*; import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.client.resources.data.AnimationMetadataSection; import net.minecraft.entity.LivingEntity; import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.Fluids; import net.minecraft.item.ItemStack; import net.minecraft.resources.IResource; import net.minecraft.resources.IResourceManager; import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; +import net.minecraftforge.client.model.geometry.IModelGeometry; import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.resource.IResourceType; +import net.minecraftforge.resource.VanillaResourceType; import net.minecraftforge.versions.forge.ForgeVersion; import net.minecraftforge.common.model.IModelState; import net.minecraftforge.common.model.TRSRTransformation; import net.minecraftforge.fluids.FluidUtil; import java.util.function.Function; -import java.util.Optional; -import java.util.Random; -import java.util.Set; +import java.util.function.Predicate; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Maps; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -public final class ModelDynBucket implements IUnbakedModel +public final class ModelDynBucket implements IUnbakedModel, IModelGeometry { private static final Logger LOGGER = LogManager.getLogger(); public static final ModelResourceLocation LOCATION = new ModelResourceLocation(new ResourceLocation(ForgeVersion.MOD_ID, "dynbucket"), "inventory"); @@ -73,111 +70,88 @@ public final class ModelDynBucket implements IUnbakedModel private static final float NORTH_Z_FLUID = 7.498f / 16f; private static final float SOUTH_Z_FLUID = 8.502f / 16f; - public static final IUnbakedModel MODEL = new ModelDynBucket(); + @Deprecated + public static final ModelDynBucket MODEL = new ModelDynBucket(); + @Deprecated @Nullable - private final ResourceLocation baseLocation; + private ResourceLocation particleLocation; + + @Deprecated @Nullable - private final ResourceLocation liquidLocation; + private ResourceLocation baseLocation; + + @Deprecated @Nullable - private final ResourceLocation coverLocation; + private ResourceLocation fluidMaskLocation; + + @Deprecated @Nullable + private ResourceLocation coverLocation; + + @Nonnull private final Fluid fluid; private final boolean flipGas; private final boolean tint; + private final boolean coverIsMask; + @Deprecated public ModelDynBucket() { - this(null, null, null, null, false, true); + this(Fluids.EMPTY, false, true, false); } - public ModelDynBucket(@Nullable ResourceLocation baseLocation, @Nullable ResourceLocation liquidLocation, @Nullable ResourceLocation coverLocation, @Nullable Fluid fluid, boolean flipGas, boolean tint) + @Deprecated + public ModelDynBucket(@Nullable ResourceLocation baseLocation, @Nullable ResourceLocation fluidMaskLocation, @Nullable ResourceLocation coverLocation, @Nullable Fluid fluid, boolean flipGas, boolean tint) { + this(fluid != null ? fluid : Fluids.EMPTY, flipGas, tint, false); this.baseLocation = baseLocation; - this.liquidLocation = liquidLocation; + this.fluidMaskLocation = fluidMaskLocation; this.coverLocation = coverLocation; + } + + public ModelDynBucket(Fluid fluid, boolean flipGas, boolean tint, boolean coverIsMask) + { this.fluid = fluid; this.flipGas = flipGas; this.tint = tint; + this.coverIsMask = coverIsMask; } - + + @Deprecated @Override public Collection getTextures(Function modelGetter, Set missingTextureErrors) { ImmutableSet.Builder builder = ImmutableSet.builder(); + if (particleLocation != null) + builder.add(particleLocation); if (baseLocation != null) builder.add(baseLocation); - if (liquidLocation != null) - builder.add(liquidLocation); + if (fluidMaskLocation != null) + builder.add(fluidMaskLocation); if (coverLocation != null) builder.add(coverLocation); - if (fluid != null) + if (fluid != Fluids.EMPTY) builder.add(fluid.getAttributes().getStillTexture()); return builder.build(); } - + + @Deprecated @Override public Collection getDependencies() { return Collections.emptyList(); } + @Deprecated @Nullable @Override public IBakedModel bake(ModelBakery bakery, Function spriteGetter, ISprite sprite, VertexFormat format) { - IModelState state = sprite.getState(); - ImmutableMap transformMap = PerspectiveMapWrapper.getTransforms(state); - - // if the fluid is lighter than air, will manipulate the initial state to be rotated 180° to turn it upside down - if (flipGas && fluid != null && fluid.getAttributes().isLighterThanAir()) - { - sprite = new ModelStateComposition(state, TRSRTransformation.blockCenterToCorner(new TRSRTransformation(null, new Quat4f(0, 0, 1, 0), null, null))); - state = sprite.getState(); - } - - TRSRTransformation transform = state.apply(Optional.empty()).orElse(TRSRTransformation.identity()); - TextureAtlasSprite fluidSprite = null; - TextureAtlasSprite particleSprite = null; - ImmutableList.Builder builder = ImmutableList.builder(); - - if(fluid != null) { - fluidSprite = spriteGetter.apply(fluid.getAttributes().getStillTexture()); - } - - Random random = new Random(); - if (baseLocation != null) - { - // build base (insidest) - IBakedModel model = (new ItemLayerModel(ImmutableList.of(baseLocation))).bake(bakery, spriteGetter, sprite, format); - random.setSeed(42); - builder.addAll(model.getQuads(null, null, random)); - particleSprite = model.getParticleTexture(); - } - if (liquidLocation != null && fluidSprite != null) - { - TextureAtlasSprite liquid = spriteGetter.apply(liquidLocation); - // build liquid layer (inside) - builder.addAll(ItemTextureQuadConverter.convertTexture(format, transform, liquid, fluidSprite, NORTH_Z_FLUID, Direction.NORTH, tint ? fluid.getAttributes().getColor() : 0xFFFFFFFF, 1)); - builder.addAll(ItemTextureQuadConverter.convertTexture(format, transform, liquid, fluidSprite, SOUTH_Z_FLUID, Direction.SOUTH, tint ? fluid.getAttributes().getColor() : 0xFFFFFFFF, 1)); - particleSprite = fluidSprite; - } - if (coverLocation != null) - { - // cover (the actual item around the other two) - TextureAtlasSprite cover = spriteGetter.apply(coverLocation); - builder.add(ItemTextureQuadConverter.genQuad(format, transform, 0, 0, 16, 16, NORTH_Z_COVER, cover, Direction.NORTH, 0xFFFFFFFF, 2)); - builder.add(ItemTextureQuadConverter.genQuad(format, transform, 0, 0, 16, 16, SOUTH_Z_COVER, cover, Direction.SOUTH, 0xFFFFFFFF, 2)); - if (particleSprite == null) - { - particleSprite = cover; - } - } - - return new BakedDynBucket(bakery, this, builder.build(), particleSprite, format, Maps.immutableEnumMap(transformMap), Maps.newHashMap(), transform.isIdentity()); + return bakeInternal(bakery, spriteGetter, sprite, format, null, particleLocation, baseLocation, fluidMaskLocation, coverLocation); } /** @@ -188,6 +162,7 @@ public final class ModelDynBucket implements IUnbakedModel *

* If the fluid can't be found, water is used. */ + @Deprecated @Override public ModelDynBucket process(ImmutableMap customData) { @@ -219,7 +194,7 @@ public final class ModelDynBucket implements IUnbakedModel } // create new model with correct liquid - return new ModelDynBucket(baseLocation, liquidLocation, coverLocation, fluid, flip, tint); + return new ModelDynBucket(baseLocation, fluidMaskLocation, coverLocation, fluid, flip, tint); } /** @@ -231,12 +206,12 @@ public final class ModelDynBucket implements IUnbakedModel *

* If no liquid is given a hardcoded variant for the bucket is used. */ + @Deprecated @Override public ModelDynBucket retexture(ImmutableMap textures) { - ResourceLocation base = baseLocation; - ResourceLocation liquid = liquidLocation; + ResourceLocation liquid = fluidMaskLocation; ResourceLocation cover = coverLocation; if (textures.containsKey("base")) @@ -248,7 +223,8 @@ public final class ModelDynBucket implements IUnbakedModel return new ModelDynBucket(base, liquid, cover, fluid, flipGas, tint); } - + + @Deprecated @Nullable protected static IResource getResource(ResourceLocation resourceLocation) { @@ -261,7 +237,8 @@ public final class ModelDynBucket implements IUnbakedModel return null; } } - + + @Deprecated @Nullable protected static PngSizeInfo getSizeInfo(IResource resource) { @@ -274,7 +251,128 @@ public final class ModelDynBucket implements IUnbakedModel throw new RuntimeException(e); } } - + + @Override + public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, ISprite sprite, VertexFormat format, ItemOverrideList overrides) + { + String particle = owner.resolveTexture("particle"); + if (!MissingTextureSprite.getLocation().toString().equals(particle)) + { + particleLocation = new ResourceLocation(particle); + } + + String base = owner.resolveTexture("base"); + if (!MissingTextureSprite.getLocation().toString().equals(base)) + { + baseLocation = new ResourceLocation(base); + } + + String template = owner.resolveTexture("fluid"); + if (!MissingTextureSprite.getLocation().toString().equals(template)) + { + fluidMaskLocation = new ResourceLocation(template); + } + + String cover = owner.resolveTexture("cover"); + if (!MissingTextureSprite.getLocation().toString().equals(cover)) + { + // cover (the actual item around the other two) + coverLocation = new ResourceLocation(cover); + } + + return bakeInternal(bakery, spriteGetter, sprite, format, owner.getCombinedState(), particleLocation, baseLocation, fluidMaskLocation, coverLocation); + } + + private IBakedModel bakeInternal( + ModelBakery bakery, Function spriteGetter, ISprite sprite, VertexFormat format, + @Nullable IModelState transformsFromModel, + @Nullable ResourceLocation particleLocation, @Nullable ResourceLocation baseLocation, + @Nullable ResourceLocation fluidMaskLocation, @Nullable ResourceLocation coverLocation) + { + IModelState state = sprite.getState(); + ImmutableMap transformMap = transformsFromModel != null ? + PerspectiveMapWrapper.getTransforms(new ModelStateComposition(transformsFromModel, state)) : + PerspectiveMapWrapper.getTransforms(state); + + TextureAtlasSprite particle = particleLocation != null ? spriteGetter.apply(particleLocation) : null; + + // if the fluid is lighter than air, will manipulate the initial state to be rotated 180° to turn it upside down + if (flipGas && fluid != Fluids.EMPTY && fluid.getAttributes().isLighterThanAir()) + { + sprite = new ModelStateComposition(state, TRSRTransformation.blockCenterToCorner(new TRSRTransformation(null, new Quat4f(0, 0, 1, 0), null, null))); + state = sprite.getState(); + } + + TRSRTransformation transform = state.apply(Optional.empty()).orElse(TRSRTransformation.identity()); + + ResourceLocation fluidLocation = fluid != Fluids.EMPTY ? fluid.getAttributes().getStillTexture() : null; + TextureAtlasSprite fluidSprite = fluidLocation != null ? spriteGetter.apply(fluidLocation) : null; + + if (particle == null) particle = fluidSprite; + + Random random = new Random(); + ImmutableList.Builder builder = ImmutableList.builder(); + + if (baseLocation != null) + { + // build base (insidest) + IBakedModel model = new ItemLayerModel(ImmutableList.of(baseLocation)).bake(bakery, spriteGetter, sprite, format); + random.setSeed(42); + builder.addAll(model.getQuads(null, null, random)); + } + + if (fluidMaskLocation != null && fluidSprite != null) + { + TextureAtlasSprite templateSprite = spriteGetter.apply(fluidMaskLocation); + if (templateSprite != null) + { + // build liquid layer (inside) + builder.addAll(ItemTextureQuadConverter.convertTexture(format, transform, templateSprite, fluidSprite, NORTH_Z_FLUID, Direction.NORTH, tint ? fluid.getAttributes().getColor() : 0xFFFFFFFF, 1)); + builder.addAll(ItemTextureQuadConverter.convertTexture(format, transform, templateSprite, fluidSprite, SOUTH_Z_FLUID, Direction.SOUTH, tint ? fluid.getAttributes().getColor() : 0xFFFFFFFF, 1)); + } + } + + if (coverLocation != null && (!coverIsMask || baseLocation != null)) + { + // cover (the actual item around the other two) + TextureAtlasSprite coverSprite = spriteGetter.apply(coverLocation); + if (coverSprite != null) + { + if (coverIsMask) + { + TextureAtlasSprite baseSprite = spriteGetter.apply(baseLocation); + builder.addAll(ItemTextureQuadConverter.convertTexture(format, transform, coverSprite, baseSprite, NORTH_Z_COVER, Direction.NORTH, 0xFFFFFFFF, 1)); + builder.addAll(ItemTextureQuadConverter.convertTexture(format, transform, coverSprite, baseSprite, SOUTH_Z_COVER, Direction.SOUTH, 0xFFFFFFFF, 1)); + } + else + { + builder.add(ItemTextureQuadConverter.genQuad(format, transform, 0, 0, 16, 16, NORTH_Z_COVER, coverSprite, Direction.NORTH, 0xFFFFFFFF, 2)); + builder.add(ItemTextureQuadConverter.genQuad(format, transform, 0, 0, 16, 16, SOUTH_Z_COVER, coverSprite, Direction.SOUTH, 0xFFFFFFFF, 2)); + if (particle == null) + { + particle = coverSprite; + } + } + } + } + + return new BakedDynBucket(bakery, this, builder.build(), particle, format, Maps.immutableEnumMap(transformMap), Maps.newHashMap(), transform.isIdentity()); + } + + @Override + public Collection getTextureDependencies(IModelConfiguration owner, Function modelGetter, Set missingTextureErrors) + { + Set texs = Sets.newHashSet(); + + texs.add(new ResourceLocation(owner.resolveTexture("particle"))); + texs.add(new ResourceLocation(owner.resolveTexture("base"))); + texs.add(new ResourceLocation(owner.resolveTexture("fluid"))); + texs.add(new ResourceLocation(owner.resolveTexture("cover"))); + + return texs; + } + + @Deprecated public enum LoaderDynBucket implements ICustomModelLoader { INSTANCE; @@ -291,12 +389,25 @@ public final class ModelDynBucket implements IUnbakedModel return MODEL; } + @Override + public IResourceType getResourceType() + { + return VanillaResourceType.MODELS; + } + @Override public void onResourceManagerReload(IResourceManager resourceManager) { // no need to clear cache since we create a new model instance } + @Override + public void onResourceManagerReload(IResourceManager resourceManager, Predicate resourcePredicate) + { + // no need to clear cache since we create a new model instance + } + + @Deprecated public void register(AtlasTexture map) { // only create these textures if they are not added by a resource pack @@ -318,6 +429,62 @@ public final class ModelDynBucket implements IUnbakedModel } } + public enum Loader implements IModelLoader + { + INSTANCE; + + @Override + public IResourceType getResourceType() + { + return VanillaResourceType.MODELS; + } + + @Override + public void onResourceManagerReload(IResourceManager resourceManager) + { + // no need to clear cache since we create a new model instance + } + + @Override + public void onResourceManagerReload(IResourceManager resourceManager, Predicate resourcePredicate) + { + // no need to clear cache since we create a new model instance + } + + @Override + public ModelDynBucket read(JsonDeserializationContext deserializationContext, JsonObject modelContents) + { + if (!modelContents.has("fluid")) + throw new RuntimeException("Bucket model requires 'fluid' value."); + + ResourceLocation fluidName = new ResourceLocation(modelContents.get("fluid").getAsString()); + + Fluid fluid = ForgeRegistries.FLUIDS.getValue(fluidName); + + boolean flip = false; + if (modelContents.has("flipGas")) + { + flip = modelContents.get("flipGas").getAsBoolean(); + } + + boolean tint = true; + if (modelContents.has("applyTint")) + { + tint = modelContents.get("applyTint").getAsBoolean(); + } + + boolean coverIsMask = true; + if (modelContents.has("coverIsMask")) + { + coverIsMask = modelContents.get("coverIsMask").getAsBoolean(); + } + + // create new model with correct liquid + return new ModelDynBucket(fluid, flip, tint, coverIsMask); + } + } + + @Deprecated private static final class BucketBaseSprite extends TextureAtlasSprite { private final ResourceLocation bucket = new ResourceLocation("item/bucket"); @@ -359,6 +526,7 @@ public final class ModelDynBucket implements IUnbakedModel /** * Creates a bucket cover sprite from the vanilla resource. */ + @Deprecated private static final class BucketCoverSprite extends TextureAtlasSprite { private final ResourceLocation bucket = new ResourceLocation("item/bucket"); diff --git a/src/main/java/net/minecraftforge/client/model/ModelFluid.java b/src/main/java/net/minecraftforge/client/model/ModelFluid.java index f56ca6da59..48820d70d2 100644 --- a/src/main/java/net/minecraftforge/client/model/ModelFluid.java +++ b/src/main/java/net/minecraftforge/client/model/ModelFluid.java @@ -499,6 +499,12 @@ public final class ModelFluid implements IUnbakedModel return ItemOverrideList.EMPTY; } + @Override + public boolean doesHandlePerspectives() + { + return true; + } + @Override public Pair handlePerspective(TransformType type) { diff --git a/src/main/java/net/minecraftforge/client/model/ModelLoader.java b/src/main/java/net/minecraftforge/client/model/ModelLoader.java index 2a0636a26c..2e96130265 100644 --- a/src/main/java/net/minecraftforge/client/model/ModelLoader.java +++ b/src/main/java/net/minecraftforge/client/model/ModelLoader.java @@ -19,25 +19,17 @@ package net.minecraftforge.client.model; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; -import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.TimeUnit; -import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.BlockModelShapes; -import net.minecraft.client.renderer.ItemModelMesher; import net.minecraft.client.renderer.Vector3f; import net.minecraft.client.renderer.color.BlockColors; import net.minecraft.client.renderer.model.BakedQuad; @@ -45,76 +37,61 @@ import net.minecraft.client.renderer.model.BlockPart; import net.minecraft.client.renderer.model.BlockPartFace; import net.minecraft.client.renderer.model.BlockPartRotation; import net.minecraft.client.renderer.model.BuiltInModel; -import net.minecraft.client.renderer.model.FaceBakery; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.IUnbakedModel; import net.minecraft.client.renderer.model.ItemCameraTransforms; -import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; import net.minecraft.client.renderer.model.ItemModelGenerator; import net.minecraft.client.renderer.model.ItemOverrideList; import net.minecraft.client.renderer.model.ModelBakery; import net.minecraft.client.renderer.model.BlockModel; import net.minecraft.client.renderer.model.BlockModelDefinition; import net.minecraft.client.renderer.model.ModelResourceLocation; -import net.minecraft.client.renderer.model.ModelRotation; -import net.minecraft.client.renderer.model.MultipartBakedModel; import net.minecraft.client.renderer.model.SimpleBakedModel; import net.minecraft.client.renderer.model.Variant; import net.minecraft.client.renderer.model.VariantList; import net.minecraft.client.renderer.model.WeightedBakedModel; -import net.minecraft.client.renderer.model.multipart.Multipart; -import net.minecraft.client.renderer.model.multipart.Selector; import net.minecraft.client.renderer.texture.ISprite; import net.minecraft.client.renderer.texture.MissingTextureSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.AtlasTexture; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.VertexFormat; -import net.minecraft.item.Item; import net.minecraft.profiler.IProfiler; import net.minecraft.resources.IResourceManager; -import net.minecraft.state.StateContainer; import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraftforge.client.model.animation.AnimationItemOverrideList; import net.minecraftforge.client.model.animation.ModelBlockAnimation; import net.minecraftforge.client.model.data.IModelData; -import net.minecraftforge.common.ForgeMod; +import net.minecraftforge.client.model.geometry.IModelGeometry; +import net.minecraftforge.client.model.geometry.IModelGeometryPart; import net.minecraftforge.common.model.IModelState; import net.minecraftforge.common.model.Models; import net.minecraftforge.common.model.TRSRTransformation; import net.minecraftforge.common.model.animation.IClip; import net.minecraftforge.common.property.Properties; -import net.minecraftforge.fml.client.ClientModLoader; import net.minecraftforge.logging.ModelLoaderErrorMessage; -import net.minecraftforge.registries.IRegistryDelegate; import org.apache.commons.lang3.tuple.Pair; import java.util.function.Function; -import com.google.common.base.Joiner; + import com.google.common.base.Objects; import com.google.common.base.Preconditions; import java.util.Optional; import java.util.Random; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; -import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.google.common.collect.Multimaps; import com.google.common.collect.Sets; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import static net.minecraftforge.fml.Logging.MODELLOADING; @@ -274,25 +251,35 @@ public final class ModelLoader extends ModelBakery public IBakedModel bakeImpl(ModelBakery bakery, Function bakedTextureGetter, IModelState state, boolean uvlock, VertexFormat format) { - if(!Attributes.moreSpecific(format, Attributes.DEFAULT_BAKED_FORMAT)) - { - throw new IllegalArgumentException("can't bake vanilla models to the format that doesn't fit into the default one: " + format); - } BlockModel model = this.model; if(model == null) return getMissingModel().bake(bakery, bakedTextureGetter, new BasicState(getMissingModel().getDefaultState(), uvlock), format); List newTransforms = Lists.newArrayList(); - for(int i = 0; i < model.getElements().size(); i++) + IModelGeometry customGeometry = model.customData.getCustomGeometry(); + if (customGeometry != null) { - BlockPart part = model.getElements().get(i); - newTransforms.add(animation.getPartTransform(state, part, i)); + Collection parts = customGeometry.getParts(); + for (int i = 0; i < parts.size(); i++) + { + newTransforms.add(animation.getPartTransform(state, i)); + } + } + else + { + List elements = model.getElements(); + for (int i = 0; i < elements.size(); i++) + { + BlockPart part = elements.get(i); + newTransforms.add(animation.getPartTransform(state, part, i)); + } } ItemCameraTransforms transforms = model.getAllTransforms(); - Map tMap = Maps.newEnumMap(TransformType.class); - tMap.putAll(PerspectiveMapWrapper.getTransforms(transforms)); - tMap.putAll(PerspectiveMapWrapper.getTransforms(state)); - IModelState perState = new SimpleModelState(ImmutableMap.copyOf(tMap), state.apply(Optional.empty())); + IModelState perState = model.customData.getCustomModelState(); + if (perState == null) + { + perState = new SimpleModelState(PerspectiveMapWrapper.getTransformsWithFallback(state, transforms), state.apply(Optional.empty())); + } if(model == ModelBakery.MODEL_GENERATED) { @@ -300,7 +287,39 @@ public final class ModelLoader extends ModelBakery } TextureAtlasSprite textureatlassprite = bakedTextureGetter.apply(new ResourceLocation(model.resolveTextureName("particle"))); if(model == ModelBakery.MODEL_ENTITY) return new BuiltInModel(transforms, model.getOverrides(bakery, model, bakedTextureGetter, format), textureatlassprite); - return bakeNormal(bakery, model, perState, state, newTransforms, format, bakedTextureGetter, uvlock); + if(model.customData.hasCustomGeometry()) + return bakeNew(bakery, model, perState, state, newTransforms, format, bakedTextureGetter, uvlock); + else + return bakeNormal(bakery, model, perState, state, newTransforms, format, bakedTextureGetter, uvlock); + } + + private IBakedModel bakeNew(ModelBakery bakery, BlockModel model, IModelState perState, final IModelState modelState, List newTransforms, final VertexFormat format, final Function bakedTextureGetter, boolean uvLocked) + { + final TRSRTransformation baseState = modelState.apply(Optional.empty()).orElse(TRSRTransformation.identity()); + + IBakedModel baked = model.customData.bake(bakery, bakedTextureGetter, new BasicState(baseState, uvLocked), format, model.getOverrides(bakery, model, bakedTextureGetter, format)); + + return new PerspectiveMapWrapper(baked, perState) + { + private final ItemOverrideList overrides = new AnimationItemOverrideList(bakery, VanillaModelWrapper.this, modelState, format, bakedTextureGetter, super.getOverrides()); + + @Override + public List getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand, IModelData modelData) + { + IModelState newState = modelData.getData(Properties.AnimationProperty); + if(newState != null) + { + return VanillaModelWrapper.this.bake(bakery, bakedTextureGetter, new ModelStateComposition(modelState, newState, uvlock), format).getQuads(state, side, rand, modelData); + } + return super.getQuads(state, side, rand, modelData); + } + + @Override + public ItemOverrideList getOverrides() + { + return overrides; + } + }; } private IBakedModel bakeNormal(ModelBakery bakery, BlockModel model, IModelState perState, final IModelState modelState, List newTransforms, final VertexFormat format, final Function bakedTextureGetter, boolean uvLocked) @@ -308,13 +327,14 @@ public final class ModelLoader extends ModelBakery final TRSRTransformation baseState = modelState.apply(Optional.empty()).orElse(TRSRTransformation.identity()); TextureAtlasSprite particle = bakedTextureGetter.apply(new ResourceLocation(model.resolveTextureName("particle"))); SimpleBakedModel.Builder builder = (new SimpleBakedModel.Builder(model, model.getOverrides(bakery, model, bakedTextureGetter, format))).setTexture(particle); - for(int i = 0; i < model.getElements().size(); i++) + List elements = model.getElements(); + for(int i = 0; i < elements.size(); i++) { if(modelState.apply(Optional.of(Models.getHiddenModelPart(ImmutableList.of(Integer.toString(i))))).isPresent()) { continue; } - BlockPart part = model.getElements().get(i); + BlockPart part = elements.get(i); TRSRTransformation transformation = baseState; if(newTransforms.get(i) != null) { @@ -350,7 +370,7 @@ public final class ModelLoader extends ModelBakery { return VanillaModelWrapper.this.bake(bakery, bakedTextureGetter, new ModelStateComposition(modelState, newState, uvlock), format).getQuads(state, side, rand, modelData); } - return super.getQuads(state, side, rand); + return super.getQuads(state, side, rand, modelData); } @Override @@ -368,16 +388,19 @@ public final class ModelLoader extends ModelBakery return this; List elements = Lists.newArrayList(); //We have to duplicate this so we can edit it below. - for (BlockPart part : this.model.getElements()) + if (!model.customData.hasCustomGeometry()) { - elements.add(new BlockPart(part.positionFrom, part.positionTo, Maps.newHashMap(part.mapFaces), part.partRotation, part.shade)); + for (BlockPart part : this.model.getElements()) + { + elements.add(new BlockPart(part.positionFrom, part.positionTo, Maps.newHashMap(part.mapFaces), part.partRotation, part.shade)); + } } - BlockModel newModel = new BlockModel(this.model.getParentLocation(), elements, Maps.newHashMap(this.model.textures), this.model.isAmbientOcclusion(), this.model.isGui3d(), //New Textures man VERY IMPORTANT model.getAllTransforms(), Lists.newArrayList(model.getOverrides())); newModel.name = this.model.name; newModel.parent = this.model.parent; + newModel.customData.copyFrom(this.model.customData); Set removed = Sets.newHashSet(); @@ -408,9 +431,12 @@ public final class ModelLoader extends ModelBakery newModel.textures.putAll(remapped); //Remove any faces that use a null texture, this is for performance reasons, also allows some cool layering stuff. - for (BlockPart part : newModel.getElements()) + if (!newModel.customData.hasCustomGeometry()) { - part.mapFaces.entrySet().removeIf(entry -> removed.contains(entry.getValue().texture)); + for (BlockPart part : newModel.getElements()) + { + part.mapFaces.entrySet().removeIf(entry -> removed.contains(entry.getValue().texture)); + } } return new VanillaModelWrapper(location, newModel, uvlock, animation); @@ -436,6 +462,7 @@ public final class ModelLoader extends ModelBakery BlockModel newModel = new BlockModel(model.getParentLocation(), model.getElements(), model.textures, value, model.isGui3d(), model.getAllTransforms(), Lists.newArrayList(model.getOverrides())); newModel.parent = model.parent; newModel.name = model.name; + newModel.customData.copyFrom(model.customData); return new VanillaModelWrapper(location, newModel, uvlock, animation); } @@ -449,6 +476,7 @@ public final class ModelLoader extends ModelBakery BlockModel newModel = new BlockModel(model.getParentLocation(), model.getElements(), model.textures, model.ambientOcclusion, value, model.getAllTransforms(), Lists.newArrayList(model.getOverrides())); newModel.parent = model.parent; newModel.name = model.name; + newModel.customData.copyFrom(model.customData); return new VanillaModelWrapper(location, newModel, uvlock, animation); } } diff --git a/src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry.java b/src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry.java index 763e242063..ab5f7555df 100644 --- a/src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry.java +++ b/src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry.java @@ -50,6 +50,7 @@ import net.minecraftforge.common.model.animation.IAnimationStateMachine; /** * Central hub for custom model loaders. */ +@Deprecated // Use the new model loading system and data generators instead. public class ModelLoaderRegistry { private static final Logger LOGGER = LogManager.getLogger(); @@ -193,6 +194,27 @@ public class ModelLoaderRegistry return model; } + public static boolean isCustomModel(ResourceLocation location) + { + ResourceLocation actual = getActualLocation(location); + for(ICustomModelLoader loader : loaders) + { + try + { + if(loader.accepts(actual)) + { + return true; + } + } + catch(Exception e) + { + LOGGER.warn("Exception checking if model {} can be loaded with loader {}", location, loader, e); + } + } + + return false; + } + /** * Use this if you don't care about the exception and want some model anyway. */ diff --git a/src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry2.java b/src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry2.java new file mode 100644 index 0000000000..112fb79354 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry2.java @@ -0,0 +1,559 @@ +/* + * 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 com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.gson.*; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.model.*; +import net.minecraft.client.renderer.texture.ISprite; +import net.minecraft.client.renderer.texture.MissingTextureSprite; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.resources.IReloadableResourceManager; +import net.minecraft.resources.IResourceManager; +import net.minecraft.util.Direction; +import net.minecraft.util.JSONUtils; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.model.b3d.B3DLoader; +import net.minecraftforge.client.model.geometry.IModelGeometry; +import net.minecraftforge.client.model.geometry.ISimpleModelGeometry; +import net.minecraftforge.client.model.obj.OBJLoader2; +import net.minecraftforge.common.model.IModelState; +import net.minecraftforge.common.model.TRSRTransformation; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.annotation.Nullable; +import java.lang.reflect.Type; +import java.util.*; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * Central hub for custom model loaders. + */ +public class ModelLoaderRegistry2 +{ + private static final Logger LOGGER = LogManager.getLogger(); + + public static final String WHITE_TEXTURE = "forge:white"; + + private static final Map> loaders = Maps.newHashMap(); + private static volatile boolean registryFrozen = false; + + // Forge built-in loaders + public static void init() + { + registerLoader(new ResourceLocation("minecraft","elements"), VanillaProxy.Loader.INSTANCE); + registerLoader(new ResourceLocation("forge","obj"), OBJLoader2.INSTANCE); + registerLoader(new ResourceLocation("forge","bucket"), ModelDynBucket.Loader.INSTANCE); + registerLoader(new ResourceLocation("forge","composite"), CompositeModel.Loader.INSTANCE); + + // Model adapters from the old loading system + registerLoader(new ResourceLocation("forge","b3d"), new ModelLoaderAdapter(B3DLoader.INSTANCE)); + registerLoader(new ResourceLocation("forge","fluid"), new ModelLoaderAdapter(ModelFluid.FluidLoader.INSTANCE)); + registerLoader(new ResourceLocation("forge","multi-layer"), new ModelLoaderAdapter(MultiLayerModel.Loader.INSTANCE)); + } + + public static void initComplete() + { + registryFrozen = true; + } + + /** + * Makes system aware of your loader. + */ + public static void registerLoader(ResourceLocation id, IModelLoader loader) + { + if (registryFrozen) + throw new IllegalStateException("Can not register model loaders after models have started loading. Please use FMLClientSetupEvent or ModelRegistryEvent to register your loaders."); + synchronized(loaders) + { + loaders.put(id, loader); + ((IReloadableResourceManager) Minecraft.getInstance().getResourceManager()).addReloadListener(loader); + } + } + + public static IModelGeometry getModel(ResourceLocation loaderId, JsonDeserializationContext deserializationContext, JsonObject data) + { + try + { + if (!loaders.containsKey(loaderId)) + { + throw new IllegalStateException(String.format("Model loader '%s' not found. Registered loaders: %s", loaderId, + loaders.keySet().stream().map(ResourceLocation::toString).collect(Collectors.joining(", ")))); + } + + IModelLoader loader = loaders.get(loaderId); + + return loader.read(deserializationContext, data); + } + catch(Exception e) + { + e.printStackTrace(); + throw e; + } + } + + @Nullable + public static IModelGeometry deserializeGeometry(JsonDeserializationContext deserializationContext, JsonObject object) { + if (!object.has("loader")) { + return null; + } + + ResourceLocation loader = new ResourceLocation(JSONUtils.getString(object,"loader")); + return getModel(loader, deserializationContext, object); + } + + /* Explanation: + * This takes anything that looks like a valid resourcepack texture location, and tries to extract a resourcelocation out of it. + * 1. it will ignore anything up to and including an /assets/ folder, + * 2. it will take the next path component as a namespace, + * 3. it will match but skip the /textures/ part of the path, + * 4. it will take the rest of the path up to but excluding the .png extension as the resource path + * It's a best-effort situation, to allow model files exported by modelling software to be used without post-processing. + * Example: + * C:\Something\Or Other\src\main\resources\assets\mymodid\textures\item\my_thing.png + * ........................................--------_______----------_____________---- + * + * Result after replacing '\' to '/': mymodid:item/my_thing + */ + private static final Pattern FILESYSTEM_PATH_TO_RESLOC = + Pattern.compile("(?:.*[\\\\/]assets[\\\\/](?[a-z_-]+)[\\\\/]textures[\\\\/])?(?[a-z_\\\\/-]+)\\.png"); + + public static ResourceLocation resolveTexture(@Nullable String tex, IModelConfiguration owner) + { + if (tex == null) + return new ResourceLocation(WHITE_TEXTURE); + if (tex.startsWith("#")) + return new ResourceLocation(owner.resolveTexture(tex)); + + // Attempt to convert a common (windows/linux/mac) filesystem path to a ResourceLocation. + // This makes no promises, if it doesn't work, too bad, fix your mtl file. + Matcher match = FILESYSTEM_PATH_TO_RESLOC.matcher(tex); + if (match.matches()) + { + String namespace = match.group("namespace"); + String path = match.group("path").replace("\\", "/"); + if (namespace != null) + return new ResourceLocation(namespace, path); + return new ResourceLocation(path); + } + + return new ResourceLocation(tex); + } + + @Nullable + public static IModelState deserializeModelTransforms(JsonDeserializationContext deserializationContext, JsonObject modelData) + { + if (!modelData.has("transform")) + return null; + + return deserializeTransform(deserializationContext, modelData.get("transform")).orElse(null); + } + + public static Optional deserializeTransform(JsonDeserializationContext context, JsonElement transformData) + { + // TODO: remove the default string option, in favor of the base models + // "forge:default-item" --> "parent": "forge:item/default" + // "forge:default-tool" --> "parent": "forge:item/default-tool" + // "forge:default-block" --> "parent": "minecraft:block/block" + if (transformData.isJsonPrimitive() && transformData.getAsJsonPrimitive().isString()) + { + String transform = transformData.getAsString(); + Optional state = ForgeBlockStateV1.Transforms.get(transform); + if (!state.isPresent()) + { + throw new JsonParseException("transform: unknown default string: " + transform); + } + return state; + } + else if (!transformData.isJsonObject()) + { + try + { + TRSRTransformation base = context.deserialize(transformData, TRSRTransformation.class); + return Optional.of(TRSRTransformation.blockCenterToCorner(base)); + } + catch (JsonParseException e) + { + throw new JsonParseException("transform: expected a string, object or valid base transformation, got: " + transformData); + } + } + else + { + JsonObject transform = transformData.getAsJsonObject(); + EnumMap transforms = Maps.newEnumMap(ItemCameraTransforms.TransformType.class); + + deserializeTRSR(context, transforms, transform, "thirdperson", ItemCameraTransforms.TransformType.THIRD_PERSON_RIGHT_HAND); + deserializeTRSR(context, transforms, transform, "thirdperson_righthand", ItemCameraTransforms.TransformType.THIRD_PERSON_RIGHT_HAND); + deserializeTRSR(context, transforms, transform, "thirdperson_lefthand", ItemCameraTransforms.TransformType.THIRD_PERSON_LEFT_HAND); + + deserializeTRSR(context, transforms, transform, "firstperson", ItemCameraTransforms.TransformType.FIRST_PERSON_RIGHT_HAND); + deserializeTRSR(context, transforms, transform, "firstperson_righthand", ItemCameraTransforms.TransformType.FIRST_PERSON_RIGHT_HAND); + deserializeTRSR(context, transforms, transform, "firstperson_lefthand", ItemCameraTransforms.TransformType.FIRST_PERSON_LEFT_HAND); + + deserializeTRSR(context, transforms, transform, "head", ItemCameraTransforms.TransformType.HEAD); + deserializeTRSR(context, transforms, transform, "gui", ItemCameraTransforms.TransformType.GUI); + deserializeTRSR(context, transforms, transform, "ground", ItemCameraTransforms.TransformType.GROUND); + deserializeTRSR(context, transforms, transform, "fixed", ItemCameraTransforms.TransformType.FIXED); + + int k = transform.entrySet().size(); + if(transform.has("matrix")) k--; + if(transform.has("translation")) k--; + if(transform.has("rotation")) k--; + if(transform.has("scale")) k--; + if(transform.has("post-rotation")) k--; + if(k > 0) + { + throw new JsonParseException("transform: allowed keys: 'thirdperson', 'firstperson', 'gui', 'head', 'matrix', 'translation', 'rotation', 'scale', 'post-rotation'"); + } + TRSRTransformation base = TRSRTransformation.identity(); + if(!transform.entrySet().isEmpty()) + { + base = context.deserialize(transform, TRSRTransformation.class); + base = TRSRTransformation.blockCenterToCorner(base); + } + IModelState state; + if(transforms.isEmpty()) + { + state = base; + } + else + { + state = new SimpleModelState(Maps.immutableEnumMap(transforms), Optional.of(base)); + } + return Optional.of(state); + } + } + + private static void deserializeTRSR(JsonDeserializationContext context, EnumMap transforms, JsonObject transform, String name, ItemCameraTransforms.TransformType itemCameraTransform) + { + if(transform.has(name)) + { + TRSRTransformation t = context.deserialize(transform.remove(name), TRSRTransformation.class); + transforms.put(itemCameraTransform, TRSRTransformation.blockCenterToCorner(t)); + } + } + + public static IBakedModel bakeHelper(BlockModel blockModel, ModelBakery modelBakery, BlockModel otherModel, Function spriteGetter, ISprite sprite, VertexFormat format) + { + try + { + IBakedModel model; + IModelGeometry customModel = blockModel.customData.getCustomGeometry(); + IModelState customModelState = blockModel.customData.getCustomModelState(); + if (customModelState != null) + { + sprite = new ModelStateComposition(customModelState.apply(Optional.empty()).orElse(TRSRTransformation.identity()), sprite.getState(), sprite.isUvLock()); + } + if (customModel != null) + { + model = customModel.bake(blockModel.customData, modelBakery, spriteGetter, sprite, format, blockModel.getOverrides(modelBakery, otherModel, spriteGetter, format)); + } + else + { + if (!Attributes.moreSpecific(format, Attributes.DEFAULT_BAKED_FORMAT)) + { + // TODO: Provide custom vanilla baking handler for special formats. + throw new IllegalArgumentException("can't bake vanilla models to the format that doesn't fit into the default one: " + format); + } + model = blockModel.bakeVanilla(modelBakery, otherModel, spriteGetter, sprite, format); + } + + if (customModelState != null && !model.doesHandlePerspectives()) + { + model = new PerspectiveMapWrapper(model, customModelState); + } + + return model; + } + catch(Exception e) + { + // Minecraft eats the stack trace, so print it first. + LOGGER.error("Error baking model", e); + throw e; + } + } + + public static class ModelLoaderAdapter implements IModelLoader + { + private final ICustomModelLoader parent; + + public ModelLoaderAdapter(ICustomModelLoader parent) + { + this.parent = parent; + } + + @Override + public void onResourceManagerReload(IResourceManager resourceManager) + { + + } + + @Override + public ModelAdapter read(JsonDeserializationContext deserializationContext, JsonObject modelContents) + { + if (!modelContents.has("model")) + throw new RuntimeException("ModelLoaderAdapter requires a 'model' key that points to a model file."); + + String modelLocation = modelContents.get("model").getAsString(); + + boolean forceLoad = JSONUtils.getBoolean(modelContents,"force", false); + + try + { + ResourceLocation loc = new ResourceLocation(modelLocation); + + if (!forceLoad && !parent.accepts(loc)) + throw new IllegalStateException("The loader does not accept the requested model."); + + IUnbakedModel model = parent.loadModel(loc); + + ImmutableMap.Builder builder = ImmutableMap.builder(); + + if (modelContents.has("custom")) + { + for (Map.Entry e : modelContents.get("custom").getAsJsonObject().entrySet()) + { + if (e.getValue().isJsonNull()) + builder.put(e.getKey(), null); + else + builder.put(e.getKey(), e.getValue().toString()); + } + } + + return new ModelAdapter(model, builder.build()); + } + catch (Exception e) + { + throw new RuntimeException("Error loading model from legacy model loader", e); + } + } + } + + public static class ModelAdapter implements IModelGeometry + { + private final ImmutableMap customData; + private IUnbakedModel wrappedModel; + private boolean processed; + + public ModelAdapter(IUnbakedModel wrappedModel, ImmutableMap customData) + { + this.wrappedModel = wrappedModel; + this.customData = customData; + } + + private void process(IModelConfiguration owner, @Nullable TextureAtlasSprite particle) + { + if (!processed) + { + processed = true; + wrappedModel = wrappedModel.process(customData); + if (owner instanceof BlockModel) + { + Map replacements = Maps.newHashMap(); + BlockModel src = (BlockModel)owner; + while (src != null) + { + for (Map.Entry entry : src.textures.entrySet()) + { + replacements.putIfAbsent(entry.getKey(), entry.getValue()); + } + src = src.parent; + } + + for (String key : replacements.keySet()) + { + String value = replacements.get(key); + boolean replaced = value.startsWith("#"); + while (value.startsWith("#")) + { + String newkey = value.substring(1); + value = replacements.get(newkey); + } + if (replaced) + { + replacements.put(key, value); + } + } + + wrappedModel = wrappedModel.retexture(ImmutableMap.copyOf(replacements)); + } + if (owner.useSmoothLighting()) wrappedModel = wrappedModel.smoothLighting(true); + if (owner.isShadedInGui()) wrappedModel = wrappedModel.gui3d(true); + } + } + + @Override + public Collection getTextureDependencies(IModelConfiguration owner, Function modelGetter, Set missingTextureErrors) + { + process(owner, null); + return wrappedModel.getTextures(modelGetter, missingTextureErrors); + } + + @Override + public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, ISprite sprite, VertexFormat format, ItemOverrideList overrides) + { + TextureAtlasSprite particle = spriteGetter.apply(new ResourceLocation(owner.resolveTexture("particle"))); + process(owner, particle); + + sprite = new ModelStateComposition(owner.getCombinedState(), sprite.getState(), sprite.isUvLock()); + + return wrappedModel.bake(bakery, spriteGetter, sprite, format); + } + } + + public static class VanillaProxy implements ISimpleModelGeometry + { + private final List elements; + + public VanillaProxy(List list) + { + this.elements = list; + } + + @Override + public void addQuads(IModelConfiguration owner, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ISprite sprite, VertexFormat format) + { + if(!Attributes.moreSpecific(format, Attributes.DEFAULT_BAKED_FORMAT)) + { + // TODO: Provide custom handler for special formats. + throw new IllegalArgumentException("can't bake vanilla models to the format that doesn't fit into the default one: " + format); + } + + for(BlockPart blockpart : elements) { + for(Direction direction : blockpart.mapFaces.keySet()) { + BlockPartFace blockpartface = blockpart.mapFaces.get(direction); + TextureAtlasSprite textureatlassprite1 = spriteGetter.apply(new ResourceLocation(owner.resolveTexture(blockpartface.texture))); + if (blockpartface.cullFace == null) { + modelBuilder.addGeneralQuad(BlockModel.makeBakedQuad(blockpart, blockpartface, textureatlassprite1, direction, sprite)); + } else { + modelBuilder.addFaceQuad( + sprite.getState().apply(Optional.empty()) + .map(trsr -> trsr.rotateTransform(blockpartface.cullFace)).orElse(blockpartface.cullFace), + BlockModel.makeBakedQuad(blockpart, blockpartface, textureatlassprite1, direction, sprite)); + } + } + } + } + + @Override + public Collection getTextureDependencies(IModelConfiguration owner, Function modelGetter, Set missingTextureErrors) + { + Set textures = Sets.newHashSet(); + + for(BlockPart part : elements) { + for(BlockPartFace face : part.mapFaces.values()) { + String texture = owner.resolveTexture(face.texture); + if (Objects.equals(texture, MissingTextureSprite.getLocation().toString())) { + missingTextureErrors.add(String.format("%s in %s", face.texture, owner.getModelName())); + } + + textures.add(new ResourceLocation(texture)); + } + } + + return textures; + } + + public static class Loader implements IModelLoader + { + public static final Loader INSTANCE = new Loader(); + + private Loader() + { + } + + @Override + public void onResourceManagerReload(IResourceManager resourceManager) + { + + } + + @Override + public VanillaProxy read(JsonDeserializationContext deserializationContext, JsonObject modelContents) + { + List list = this.getModelElements(deserializationContext, modelContents); + return new VanillaProxy(list); + } + + private List getModelElements(JsonDeserializationContext deserializationContext, JsonObject object) { + List list = Lists.newArrayList(); + if (object.has("elements")) { + for(JsonElement jsonelement : JSONUtils.getJsonArray(object, "elements")) { + list.add(deserializationContext.deserialize(jsonelement, BlockPart.class)); + } + } + + return list; + } + } + } + + public static class ExpandedBlockModelDeserializer extends BlockModel.Deserializer + { + public static final Gson INSTANCE = (new GsonBuilder()) + .registerTypeAdapter(BlockModel.class, new ExpandedBlockModelDeserializer()) + .registerTypeAdapter(BlockPart.class, new BlockPart.Deserializer()) + .registerTypeAdapter(BlockPartFace.class, new BlockPartFace.Deserializer()) + .registerTypeAdapter(BlockFaceUV.class, new BlockFaceUV.Deserializer()) + .registerTypeAdapter(ItemTransformVec3f.class, new ItemTransformVec3f.Deserializer()) + .registerTypeAdapter(ItemCameraTransforms.class, new ItemCameraTransforms.Deserializer()) + .registerTypeAdapter(ItemOverride.class, new ItemOverride.Deserializer()) + .registerTypeAdapter(TRSRTransformation.class, ForgeBlockStateV1.TRSRDeserializer.INSTANCE) + .create(); + + public BlockModel deserialize(JsonElement element, Type targetType, JsonDeserializationContext deserializationContext) throws JsonParseException { + BlockModel model = super.deserialize(element, targetType, deserializationContext); + JsonObject jsonobject = element.getAsJsonObject(); + IModelGeometry geometry = deserializeGeometry(deserializationContext, jsonobject); + + List elements = model.getElements(); + if (geometry != null) { + elements.clear(); + model.customData.setCustomGeometry(geometry); + } + + IModelState modelState = deserializeModelTransforms(deserializationContext, jsonobject); + if (modelState != null) + { + model.customData.setCustomModelState(modelState); + } + + if (jsonobject.has("visibility")) + { + JsonObject visibility = JSONUtils.getJsonObject(jsonobject, "visibility"); + for(Map.Entry part : visibility.entrySet()) + { + model.customData.visibilityData.setVisibilityState(part.getKey(), part.getValue().getAsBoolean()); + } + } + + return model; + } + } +} diff --git a/src/main/java/net/minecraftforge/client/model/MultiLayerModel.java b/src/main/java/net/minecraftforge/client/model/MultiLayerModel.java index c8f7c359ab..bdbe0463a3 100644 --- a/src/main/java/net/minecraftforge/client/model/MultiLayerModel.java +++ b/src/main/java/net/minecraftforge/client/model/MultiLayerModel.java @@ -63,9 +63,9 @@ public final class MultiLayerModel implements IUnbakedModel private static final Logger LOGGER = LogManager.getLogger(); public static final MultiLayerModel INSTANCE = new MultiLayerModel(ImmutableMap.of()); - private final ImmutableMap, ModelResourceLocation> models; + private final ImmutableMap, ? extends ResourceLocation> models; - public MultiLayerModel(ImmutableMap, ModelResourceLocation> models) + public MultiLayerModel(ImmutableMap, ? extends ResourceLocation> models) { this.models = models; } @@ -82,7 +82,7 @@ public final class MultiLayerModel implements IUnbakedModel return Collections.emptyList(); } - private static ImmutableMap, IBakedModel> buildModels(ImmutableMap, ModelResourceLocation> models, ISprite sprite, VertexFormat format, ModelBakery bakery, Function spriteGetter) + private static ImmutableMap, IBakedModel> buildModels(ImmutableMap, ? extends ResourceLocation> models, ISprite sprite, VertexFormat format, ModelBakery bakery, Function spriteGetter) { ImmutableMap.Builder, IBakedModel> builder = ImmutableMap.builder(); for(Optional key : models.keySet()) @@ -108,7 +108,7 @@ public final class MultiLayerModel implements IUnbakedModel @Override public MultiLayerModel process(ImmutableMap customData) { - ImmutableMap.Builder, ModelResourceLocation> builder = ImmutableMap.builder(); + ImmutableMap.Builder, ResourceLocation> builder = ImmutableMap.builder(); for(String key : customData.keySet()) { if("base".equals(key)) @@ -123,12 +123,12 @@ public final class MultiLayerModel implements IUnbakedModel } } } - ImmutableMap, ModelResourceLocation> models = builder.build(); + ImmutableMap, ResourceLocation> models = builder.build(); if(models.isEmpty()) return INSTANCE; return new MultiLayerModel(models); } - private ModelResourceLocation getLocation(String json) + private ResourceLocation getLocation(String json) { JsonElement e = new JsonParser().parse(json); if(e.isJsonPrimitive() && e.getAsJsonPrimitive().isString()) @@ -201,6 +201,12 @@ public final class MultiLayerModel implements IUnbakedModel return base.getParticleTexture(); } + @Override + public boolean doesHandlePerspectives() + { + return true; + } + @Override public Pair handlePerspective(TransformType cameraTransformType) { diff --git a/src/main/java/net/minecraftforge/client/model/MultiModel.java b/src/main/java/net/minecraftforge/client/model/MultiModel.java index 7babfb4667..8610ef765f 100644 --- a/src/main/java/net/minecraftforge/client/model/MultiModel.java +++ b/src/main/java/net/minecraftforge/client/model/MultiModel.java @@ -199,6 +199,12 @@ public final class MultiModel implements IUnbakedModel return quads.build(); } + @Override + public boolean doesHandlePerspectives() + { + return true; + } + @Override public Pair handlePerspective(TransformType cameraTransformType) { diff --git a/src/main/java/net/minecraftforge/client/model/PerspectiveMapWrapper.java b/src/main/java/net/minecraftforge/client/model/PerspectiveMapWrapper.java index bfd99ea509..5a0de1ea52 100644 --- a/src/main/java/net/minecraftforge/client/model/PerspectiveMapWrapper.java +++ b/src/main/java/net/minecraftforge/client/model/PerspectiveMapWrapper.java @@ -23,26 +23,31 @@ import java.util.EnumMap; import java.util.Optional; import java.util.Random; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import net.minecraft.block.BlockState; -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.model.*; import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.entity.LivingEntity; +import net.minecraft.item.ItemStack; import net.minecraft.util.Direction; +import net.minecraft.world.World; +import net.minecraftforge.client.model.data.IDynamicBakedModel; +import net.minecraftforge.client.model.data.IModelData; import net.minecraftforge.common.model.IModelState; import net.minecraftforge.common.model.TRSRTransformation; import org.apache.commons.lang3.tuple.Pair; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.vecmath.Matrix4f; import java.util.List; -public class PerspectiveMapWrapper implements IBakedModel +public class PerspectiveMapWrapper implements IDynamicBakedModel { private final IBakedModel parent; private final ImmutableMap transforms; + private final OverrideListWrapper overrides = new OverrideListWrapper(); public PerspectiveMapWrapper(IBakedModel parent, ImmutableMap transforms) { @@ -83,6 +88,25 @@ public class PerspectiveMapWrapper implements IBakedModel return ImmutableMap.copyOf(map); } + @SuppressWarnings("deprecation") + public static ImmutableMap getTransformsWithFallback(IModelState state, ItemCameraTransforms transforms) + { + EnumMap map = new EnumMap<>(ItemCameraTransforms.TransformType.class); + for(ItemCameraTransforms.TransformType type : ItemCameraTransforms.TransformType.values()) + { + Optional tr = state.apply(Optional.of(type)); + if(tr.isPresent()) + { + map.put(type, tr.get()); + } + else if (transforms.hasCustomTransform(type)) + { + map.put(type, TRSRTransformation.blockCenterToCorner(TRSRTransformation.from(transforms.getTransform(type)))); + } + } + return ImmutableMap.copyOf(map); + } + public static Pair handlePerspective(IBakedModel model, ImmutableMap transforms, ItemCameraTransforms.TransformType cameraTransformType) { TRSRTransformation tr = transforms.getOrDefault(cameraTransformType, TRSRTransformation.identity()); @@ -110,12 +134,48 @@ public class PerspectiveMapWrapper implements IBakedModel @Override public TextureAtlasSprite getParticleTexture() { return parent.getParticleTexture(); } @SuppressWarnings("deprecation") @Override public ItemCameraTransforms getItemCameraTransforms() { return parent.getItemCameraTransforms(); } - @Override public List getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand) { return parent.getQuads(state, side, rand); } - @Override public ItemOverrideList getOverrides() { return parent.getOverrides(); } + @Override public List getQuads(@Nullable BlockState state, @Nullable Direction side, @Nonnull Random rand, @Nonnull IModelData extraData) + { + return parent.getQuads(state, side, rand, extraData); + } + + @Override + public ItemOverrideList getOverrides() + { + return overrides; + } + + @Override + public boolean doesHandlePerspectives() + { + return true; + } @Override public Pair handlePerspective(ItemCameraTransforms.TransformType cameraTransformType) { return handlePerspective(this, transforms, cameraTransformType); } + + private class OverrideListWrapper extends ItemOverrideList + { + public OverrideListWrapper() + { + super(); + } + + @Nullable + @Override + public IBakedModel getModelWithOverrides(IBakedModel model, ItemStack stack, @Nullable World worldIn, @Nullable LivingEntity entityIn) + { + model = parent.getOverrides().getModelWithOverrides(parent, stack, worldIn, entityIn); + return new PerspectiveMapWrapper(model, transforms); + } + + @Override + public ImmutableList getOverrides() + { + return parent.getOverrides().getOverrides(); + } + } } diff --git a/src/main/java/net/minecraftforge/client/model/QuadTransformer.java b/src/main/java/net/minecraftforge/client/model/QuadTransformer.java new file mode 100644 index 0000000000..f079eec57f --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/QuadTransformer.java @@ -0,0 +1,234 @@ +/* + * 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 com.google.common.collect.Lists; +import net.minecraft.client.renderer.model.BakedQuad; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.client.renderer.vertex.VertexFormatElement; +import net.minecraftforge.common.model.TRSRTransformation; + +import javax.vecmath.Matrix4f; +import javax.vecmath.Vector3f; +import javax.vecmath.Vector4f; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class QuadTransformer +{ + private final VertexFormat format; + private final int positionOffset; + private final int normalOffset; + private final TRSRTransformation transform; + + public QuadTransformer(VertexFormat format, TRSRTransformation transform) + { + this.format = format; + this.positionOffset = findPositionOffset(format); + this.normalOffset = findNormalOffset(format); + this.transform = transform; + } + + private void processVertices(int[] inData, int[] outData) + { + int stride = format.getSize(); + int count = (inData.length * 4) / stride; + for (int i=0;i= 0) + { + for (int i=0;i> 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); + transform.transformNormal(pos); + pos.normalize(); + + int normalOut = (((int) (x / 255.0) & 0xFF) << 24) | + (((int) (y / 255.0) & 0xFF) << 16) | + (((int) (z / 255.0) & 0xFF) << 8) | + (normalIn & 0xFF); + + 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) + { + int index; + VertexFormatElement element = null; + for (index = 0; index < fmt.getElementCount(); index++) + { + VertexFormatElement el = fmt.getElement(index); + if (el.getUsage() == VertexFormatElement.Usage.POSITION) + { + element = el; + break; + } + } + if (index == fmt.getElementCount() || element == null) + throw new RuntimeException("Expected vertex format to have a POSITION attribute"); + if (element.getType() != VertexFormatElement.Type.FLOAT) + throw new RuntimeException("Expected POSITION attribute to have data type FLOAT"); + if (element.getSize() < 3) + throw new RuntimeException("Expected POSITION attribute to have at least 3 dimensions"); + return fmt.getOffset(index); + } + + private static int findNormalOffset(VertexFormat fmt) + { + int index; + VertexFormatElement element = null; + for (index = 0; index < fmt.getElementCount(); index++) + { + VertexFormatElement el = fmt.getElement(index); + if (el.getUsage() == VertexFormatElement.Usage.NORMAL) + { + element = el; + break; + } + } + if (index == fmt.getElementCount() || element == null) + return -1; + if (element.getType() != VertexFormatElement.Type.BYTE) + throw new RuntimeException("Expected NORMAL attribute to have data type BYTE"); + if (element.getSize() < 3) + throw new RuntimeException("Expected NORMAL attribute to have at least 3 dimensions"); + return fmt.getOffset(index); + } + + /** + * Processes a single quad, producing a new quad. + * @param input A single quad to transform. + * @return A new BakedQuad object with the new position. + */ + public BakedQuad processOne(BakedQuad input) + { + int[] inData = input.getVertexData(); + int[] outData = Arrays.copyOf(inData, inData.length); + processVertices(inData, outData); + + return new BakedQuad(outData, input.getTintIndex(), input.getFace(), input.getSprite(), input.shouldApplyDiffuseLighting(), format); + } + + /** + * Processes a single quad, modifying the input quad. + * @param input A single quad to transform. + * @return The input BakedQuad object with the new position applied. + */ + public BakedQuad processOneInPlace(BakedQuad input) + { + int[] data = input.getVertexData(); + processVertices(data, data); + return input; + } + + /** + * Processes multiple quads, producing a new array of new quads. + * @param inputs The list of quads to transform + * @return A new array of new BakedQuad objects. + */ + public List processMany(List inputs) + { + if(inputs.size() == 0) + return Collections.emptyList(); + + List outputs = Lists.newArrayList(); + for(BakedQuad input : inputs) + { + int[] inData = input.getVertexData(); + int[] outData = Arrays.copyOf(inData, inData.length); + processVertices(inData, outData); + + outputs.add(new BakedQuad(outData, input.getTintIndex(), input.getFace(), input.getSprite(), input.shouldApplyDiffuseLighting(), format)); + } + return outputs; + } + + /** + * Processes multiple quads in place, modifying the input quads. + * @param inputs The list of quads to transform + */ + public void processManyInPlace(List inputs) + { + if(inputs.size() == 0) + return; + + for(BakedQuad input : inputs) + { + int[] data = input.getVertexData(); + processVertices(data, data); + } + } +} diff --git a/src/main/java/net/minecraftforge/client/model/animation/ModelBlockAnimation.java b/src/main/java/net/minecraftforge/client/model/animation/ModelBlockAnimation.java index 22050f1ed0..f340827755 100644 --- a/src/main/java/net/minecraftforge/client/model/animation/ModelBlockAnimation.java +++ b/src/main/java/net/minecraftforge/client/model/animation/ModelBlockAnimation.java @@ -519,6 +519,12 @@ public class ModelBlockAnimation @Nullable public TRSRTransformation getPartTransform(IModelState state, BlockPart part, int i) + { + return getPartTransform(state, i); + } + + @Nullable + public TRSRTransformation getPartTransform(IModelState state, int i) { ImmutableCollection infos = getJoint(i); if(!infos.isEmpty()) diff --git a/src/main/java/net/minecraftforge/client/model/b3d/B3DLoader.java b/src/main/java/net/minecraftforge/client/model/b3d/B3DLoader.java index fda550780c..2dbfeb6d22 100644 --- a/src/main/java/net/minecraftforge/client/model/b3d/B3DLoader.java +++ b/src/main/java/net/minecraftforge/client/model/b3d/B3DLoader.java @@ -32,6 +32,7 @@ import java.util.Random; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.function.Function; +import java.util.stream.Collectors; import javax.annotation.Nullable; import javax.vecmath.Matrix4f; @@ -410,7 +411,7 @@ public enum B3DLoader implements ICustomModelLoader private final ResourceLocation modelLocation; private final B3DModel model; private final ImmutableSet meshes; - private final ImmutableMap textures; + private final ImmutableMap textures; private final boolean smooth; private final boolean gui3d; private final int defaultKey; @@ -420,7 +421,7 @@ public enum B3DLoader implements ICustomModelLoader this(modelLocation, model, meshes, smooth, gui3d, defaultKey, buildTextures(model.getTextures())); } - public ModelWrapper(ResourceLocation modelLocation, B3DModel model, ImmutableSet meshes, boolean smooth, boolean gui3d, int defaultKey, ImmutableMap textures) + public ModelWrapper(ResourceLocation modelLocation, B3DModel model, ImmutableSet meshes, boolean smooth, boolean gui3d, int defaultKey, ImmutableMap textures) { this.modelLocation = modelLocation; this.model = model; @@ -431,16 +432,16 @@ public enum B3DLoader implements ICustomModelLoader this.defaultKey = defaultKey; } - private static ImmutableMap buildTextures(List textures) + private static ImmutableMap buildTextures(List textures) { - ImmutableMap.Builder builder = ImmutableMap.builder(); + ImmutableMap.Builder builder = ImmutableMap.builder(); for(Texture t : textures) { String path = t.getPath(); String location = getLocation(path); if(!location.startsWith("#")) location = "#" + location; - builder.put(path, new ResourceLocation(location)); + builder.put(path, location); } return builder.build(); } @@ -454,7 +455,7 @@ public enum B3DLoader implements ICustomModelLoader @Override public Collection getTextures(Function modelGetter, Set missingTextureErrors) { - return Collections2.filter(textures.values(), loc -> !loc.getPath().startsWith("#")); + return textures.values().stream().filter(loc -> !loc.startsWith("#")).map(ResourceLocation::new).collect(Collectors.toList()); } @Override @@ -469,16 +470,16 @@ public enum B3DLoader implements ICustomModelLoader { ImmutableMap.Builder builder = ImmutableMap.builder(); TextureAtlasSprite missing = spriteGetter.apply(new ResourceLocation("missingno")); - for(Map.Entry e : textures.entrySet()) + for(Map.Entry e : textures.entrySet()) { - if(e.getValue().getPath().startsWith("#")) + if(e.getValue().startsWith("#")) { - LOGGER.fatal("unresolved texture '{}' for b3d model '{}'", e.getValue().getPath(), modelLocation); + LOGGER.fatal("unresolved texture '{}' for b3d model '{}'", e.getValue(), modelLocation); builder.put(e.getKey(), missing); } else { - builder.put(e.getKey(), spriteGetter.apply(e.getValue())); + builder.put(e.getKey(), spriteGetter.apply(new ResourceLocation(e.getValue()))); } } builder.put("missingno", missing); @@ -488,16 +489,19 @@ public enum B3DLoader implements ICustomModelLoader @Override public ModelWrapper retexture(ImmutableMap textures) { - ImmutableMap.Builder builder = ImmutableMap.builder(); - for(Map.Entry e : this.textures.entrySet()) + ImmutableMap.Builder builder = ImmutableMap.builder(); + for(Map.Entry e : this.textures.entrySet()) { String path = e.getKey(); String loc = getLocation(path); - if(textures.containsKey(loc)) + // FIXME: Backward compatibilty: support finding textures that start with #, even though this is not how vanilla works + if(loc.startsWith("#") && (textures.containsKey(loc) || textures.containsKey(loc.substring(1)))) { + String alt = loc.substring(1); String newLoc = textures.get(loc); - if(newLoc == null) newLoc = getLocation(path); - builder.put(e.getKey(), new ResourceLocation(newLoc)); + if(newLoc == null) newLoc = textures.get(alt); + if(newLoc == null) newLoc = path.substring(1); + builder.put(e.getKey(), newLoc); } else { @@ -816,6 +820,12 @@ public enum B3DLoader implements ICustomModelLoader return textures.values().asList().get(0); } + @Override + public boolean doesHandlePerspectives() + { + return true; + } + @Override public Pair handlePerspective(TransformType cameraTransformType) { diff --git a/src/main/java/net/minecraftforge/client/model/data/ModelDataMap.java b/src/main/java/net/minecraftforge/client/model/data/ModelDataMap.java index 67222c8b7d..9d23a3eecd 100644 --- a/src/main/java/net/minecraftforge/client/model/data/ModelDataMap.java +++ b/src/main/java/net/minecraftforge/client/model/data/ModelDataMap.java @@ -32,7 +32,12 @@ public class ModelDataMap implements IModelData { this.backingMap = new IdentityHashMap<>(map); } - + + protected ModelDataMap() + { + this.backingMap = new IdentityHashMap<>(); + } + @Override public boolean hasProperty(ModelProperty prop) { diff --git a/src/main/java/net/minecraftforge/client/model/generators/BlockModelProvider.java b/src/main/java/net/minecraftforge/client/model/generators/BlockModelProvider.java index bbb964eaa2..c262ef8578 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/BlockModelProvider.java +++ b/src/main/java/net/minecraftforge/client/model/generators/BlockModelProvider.java @@ -1,3 +1,22 @@ +/* + * 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.generators; import net.minecraft.data.DataGenerator; diff --git a/src/main/java/net/minecraftforge/client/model/generators/ConfiguredModel.java b/src/main/java/net/minecraftforge/client/model/generators/ConfiguredModel.java index a90ea96ee8..c7999ffa37 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/ConfiguredModel.java +++ b/src/main/java/net/minecraftforge/client/model/generators/ConfiguredModel.java @@ -1,3 +1,22 @@ +/* + * 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.generators; import java.util.Arrays; diff --git a/src/main/java/net/minecraftforge/client/model/generators/ExistingFileHelper.java b/src/main/java/net/minecraftforge/client/model/generators/ExistingFileHelper.java index 13f152613d..a7a5a807d7 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/ExistingFileHelper.java +++ b/src/main/java/net/minecraftforge/client/model/generators/ExistingFileHelper.java @@ -1,3 +1,22 @@ +/* + * 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.generators; import java.io.File; diff --git a/src/main/java/net/minecraftforge/client/model/generators/IGeneratedBlockstate.java b/src/main/java/net/minecraftforge/client/model/generators/IGeneratedBlockstate.java index 3fb2389ddd..7a8237d200 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/IGeneratedBlockstate.java +++ b/src/main/java/net/minecraftforge/client/model/generators/IGeneratedBlockstate.java @@ -1,3 +1,22 @@ +/* + * 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.generators; import com.google.common.annotations.VisibleForTesting; diff --git a/src/main/java/net/minecraftforge/client/model/generators/ItemModelProvider.java b/src/main/java/net/minecraftforge/client/model/generators/ItemModelProvider.java index 1c9e8f5e5c..7463acf83c 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/ItemModelProvider.java +++ b/src/main/java/net/minecraftforge/client/model/generators/ItemModelProvider.java @@ -1,3 +1,22 @@ +/* + * 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.generators; import net.minecraft.data.DataGenerator; diff --git a/src/main/java/net/minecraftforge/client/model/generators/MultiPartBlockStateBuilder.java b/src/main/java/net/minecraftforge/client/model/generators/MultiPartBlockStateBuilder.java index 7a78013204..4b65545590 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/MultiPartBlockStateBuilder.java +++ b/src/main/java/net/minecraftforge/client/model/generators/MultiPartBlockStateBuilder.java @@ -1,3 +1,22 @@ +/* + * 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.generators; import java.util.ArrayList; diff --git a/src/main/java/net/minecraftforge/client/model/geometry/IModelGeometry.java b/src/main/java/net/minecraftforge/client/model/geometry/IModelGeometry.java new file mode 100644 index 0000000000..af837d4e4b --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/geometry/IModelGeometry.java @@ -0,0 +1,52 @@ +/* + * 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.geometry; + +import net.minecraft.client.renderer.model.*; +import net.minecraft.client.renderer.texture.ISprite; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.model.IModelConfiguration; + +import java.util.Collection; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; + +/** + * General interface for any model that can be baked, superset of vanilla {@link net.minecraft.client.renderer.model.IUnbakedModel}. + * Models can be baked to different vertex formats and with different state. + */ +public interface IModelGeometry> +{ + default Collection getParts() { + return Collections.emptyList(); + } + + default Optional getPart(String name) { + return Optional.empty(); + } + + IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, ISprite sprite, VertexFormat format, ItemOverrideList overrides); + + Collection getTextureDependencies(IModelConfiguration owner, Function modelGetter, Set missingTextureErrors); +} diff --git a/src/main/java/net/minecraftforge/client/model/geometry/IModelGeometryPart.java b/src/main/java/net/minecraftforge/client/model/geometry/IModelGeometryPart.java new file mode 100644 index 0000000000..5f312326dc --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/geometry/IModelGeometryPart.java @@ -0,0 +1,46 @@ +/* + * 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.geometry; + +import net.minecraft.client.renderer.model.IUnbakedModel; +import net.minecraft.client.renderer.model.ModelBakery; +import net.minecraft.client.renderer.texture.ISprite; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.model.IModelBuilder; +import net.minecraftforge.client.model.IModelConfiguration; + +import java.util.Collection; +import java.util.Collections; +import java.util.Set; +import java.util.function.Function; + +public interface IModelGeometryPart +{ + String name(); + + void addQuads(IModelConfiguration owner, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ISprite sprite, VertexFormat format); + + default Collection getTextureDependencies(IModelConfiguration owner, Function modelGetter, Set missingTextureErrors) { + // No texture dependencies + return Collections.emptyList(); + } +} diff --git a/src/main/java/net/minecraftforge/client/model/geometry/IMultipartModelGeometry.java b/src/main/java/net/minecraftforge/client/model/geometry/IMultipartModelGeometry.java new file mode 100644 index 0000000000..9037664b9b --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/geometry/IMultipartModelGeometry.java @@ -0,0 +1,59 @@ +/* + * 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.geometry; + +import com.google.common.collect.Sets; +import net.minecraft.client.renderer.model.IUnbakedModel; +import net.minecraft.client.renderer.model.ModelBakery; +import net.minecraft.client.renderer.texture.ISprite; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.model.IModelBuilder; +import net.minecraftforge.client.model.IModelConfiguration; + +import java.util.Collection; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; + +public interface IMultipartModelGeometry> extends ISimpleModelGeometry +{ + @Override + Collection getParts(); + + Optional getPart(String name); + + @Override + default void addQuads(IModelConfiguration owner, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ISprite sprite, VertexFormat format) + { + getParts().stream().filter(part -> owner.getPartVisibility(part)) + .forEach(part -> part.addQuads(owner, modelBuilder, bakery, spriteGetter, sprite, format)); + } + + @Override + default Collection getTextureDependencies(IModelConfiguration owner, Function modelGetter, Set missingTextureErrors) + { + Set combined = Sets.newHashSet(); + for (IModelGeometryPart part : getParts()) + combined.addAll(part.getTextureDependencies(owner, modelGetter, missingTextureErrors)); + return combined; + } +} diff --git a/src/main/java/net/minecraftforge/client/model/geometry/ISimpleModelGeometry.java b/src/main/java/net/minecraftforge/client/model/geometry/ISimpleModelGeometry.java new file mode 100644 index 0000000000..3abd322d69 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/geometry/ISimpleModelGeometry.java @@ -0,0 +1,54 @@ +/* + * 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.geometry; + +import net.minecraft.client.renderer.model.*; +import net.minecraft.client.renderer.texture.ISprite; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.model.IModelBuilder; +import net.minecraftforge.client.model.IModelConfiguration; + +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; + +public interface ISimpleModelGeometry> extends IModelGeometry +{ + @Override + default IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, ISprite sprite, VertexFormat format, ItemOverrideList overrides) + { + TextureAtlasSprite particle = spriteGetter.apply(new ResourceLocation(owner.resolveTexture("particle"))); + + IModelBuilder builder = IModelBuilder.of(owner, overrides, particle); + + addQuads(owner, builder, bakery, spriteGetter, sprite, format); + + return builder.build(); + } + + void addQuads(IModelConfiguration owner, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ISprite sprite, VertexFormat format); + + @Override + Collection getTextureDependencies(IModelConfiguration owner, Function modelGetter, Set missingTextureErrors); +} diff --git a/src/main/java/net/minecraftforge/client/model/obj/LineReader.java b/src/main/java/net/minecraftforge/client/model/obj/LineReader.java new file mode 100644 index 0000000000..ceafa14d1f --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/obj/LineReader.java @@ -0,0 +1,97 @@ +/* + * 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.obj; + +import com.google.common.base.Charsets; +import joptsimple.internal.Strings; +import net.minecraft.resources.IResource; + +import javax.annotation.Nullable; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class LineReader implements AutoCloseable +{ + InputStreamReader lineStream; + BufferedReader lineReader; + + public LineReader(IResource resource) + { + this.lineStream = new InputStreamReader(resource.getInputStream(), Charsets.UTF_8); + this.lineReader = new BufferedReader(lineStream); + } + + @Nullable + public String[] readAndSplitLine(boolean ignoreEmptyLines) throws IOException + { + //noinspection LoopConditionNotUpdatedInsideLoop + do + { + String currentLine = lineReader.readLine(); + if (currentLine == null) + return null; + + List lineParts = new ArrayList<>(); + + if (currentLine.startsWith("#")) + currentLine = ""; + + if (currentLine.length() > 0) + { + + boolean hasContinuation; + do + { + hasContinuation = currentLine.endsWith("\\"); + String tmp = hasContinuation ? currentLine.substring(0, currentLine.length() - 1) : currentLine; + + Arrays.stream(tmp.split("[\t ]+")).filter(s -> !Strings.isNullOrEmpty(s)).forEach(lineParts::add); + + if (hasContinuation) + { + currentLine = lineReader.readLine(); + if (currentLine == null) + break; + + if (currentLine.length() == 0 || currentLine.startsWith("#")) + break; + } + } while (hasContinuation); + } + + if (lineParts.size() > 0) + return lineParts.toArray(new String[0]); + } + while (ignoreEmptyLines); + + return new String[0]; + } + + @Override + public void close() throws Exception + { + lineReader.close(); + lineStream.close(); + } +} diff --git a/src/main/java/net/minecraftforge/client/model/obj/MaterialLibrary2.java b/src/main/java/net/minecraftforge/client/model/obj/MaterialLibrary2.java new file mode 100644 index 0000000000..7a22381870 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/obj/MaterialLibrary2.java @@ -0,0 +1,133 @@ +/* + * 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.obj; + +import com.google.common.collect.Maps; +import joptsimple.internal.Strings; + +import javax.vecmath.Vector4f; +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; +import java.util.NoSuchElementException; + +public class MaterialLibrary2 +{ + public static final MaterialLibrary2 EMPTY = new MaterialLibrary2(); + final Map materials = Maps.newHashMap(); + + private MaterialLibrary2() + { + } + + public MaterialLibrary2(LineReader reader) throws IOException + { + Material currentMaterial = null; + + String[] line; + while((line = reader.readAndSplitLine(true)) != null) + { + switch(line[0]) + { + case "newmtl": + { + String name = Strings.join(Arrays.copyOfRange(line, 1, line.length), " "); + currentMaterial = new Material(name); + materials.put(name, currentMaterial); + break; + } + + case "Ka": + currentMaterial.ambientColor = OBJModel2.parseVector4(line); + break; + + case "map_Ka": + // Ignores all options params + currentMaterial.ambientColorMap = line[line.length-1]; + break; + + case "Kd": + currentMaterial.diffuseColor = OBJModel2.parseVector4(line); + break; + + case "forge_TintIndex": + currentMaterial.diffuseTintIndex = Integer.parseInt(line[1]); + break; + + case "map_Kd": + // Ignores all options params + currentMaterial.diffuseColorMap = line[line.length-1]; + break; + + case "Ks": + currentMaterial.specularColor = OBJModel2.parseVector4(line); + break; + + case "Ns": + currentMaterial.specularHighlight = Float.parseFloat(line[1]); + break; + + case "map_Ks": + // Ignores all options params + currentMaterial.specularColorMap = line[line.length-1]; + break; + + case "d": + // Ignores all options params + currentMaterial.dissolve = Float.parseFloat(line[1]); + break; + case "Tr": + // Ignores all options params + currentMaterial.transparency = Float.parseFloat(line[1]); + break; + } + } + } + + public Material getMaterial(String mat) + { + if (!materials.containsKey(mat)) + throw new NoSuchElementException("The material was not found in the library: " + mat); + return materials.get(mat); + } + + public class Material + { + public final String name; + public Vector4f ambientColor = new Vector4f(0,0,0,1); + public String ambientColorMap; + public Vector4f diffuseColor = new Vector4f(1,1,1,1); + public String diffuseColorMap; + public Vector4f specularColor = new Vector4f(0,0,0,1); + public float specularHighlight = 0; + public String specularColorMap; + + public float dissolve = 1.0f; + public float transparency = 0.0f; + + // non-standard + public int diffuseTintIndex = 0; + + public Material(String name) + { + this.name = name; + } + } +} diff --git a/src/main/java/net/minecraftforge/client/model/obj/OBJLoader.java b/src/main/java/net/minecraftforge/client/model/obj/OBJLoader.java index 0250aa0447..24a0e244a0 100644 --- a/src/main/java/net/minecraftforge/client/model/obj/OBJLoader.java +++ b/src/main/java/net/minecraftforge/client/model/obj/OBJLoader.java @@ -42,6 +42,7 @@ import org.apache.logging.log4j.Logger; * To enable your mod call instance.addDomain(modid). * If you need more control over accepted resources - extend the class, and register a new instance with ModelLoaderRegistry. */ +@Deprecated // Use the new model loading system and data generators instead. public enum OBJLoader implements ICustomModelLoader { INSTANCE; diff --git a/src/main/java/net/minecraftforge/client/model/obj/OBJLoader2.java b/src/main/java/net/minecraftforge/client/model/obj/OBJLoader2.java new file mode 100644 index 0000000000..57e2c91fc3 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/obj/OBJLoader2.java @@ -0,0 +1,118 @@ +/* + * 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.obj; + +import com.google.common.collect.Maps; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.IResource; +import net.minecraft.resources.IResourceManager; +import net.minecraft.util.JSONUtils; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.model.IModelLoader; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.util.*; + +public class OBJLoader2 implements IModelLoader +{ + public static OBJLoader2 INSTANCE = new OBJLoader2(); + + private final Map modelCache = Maps.newHashMap(); + private final Map materialCache = Maps.newHashMap(); + + private IResourceManager manager = Minecraft.getInstance().getResourceManager(); + + @Override + public void onResourceManagerReload(IResourceManager resourceManager) + { + modelCache.clear(); + materialCache.clear(); + manager = resourceManager; + } + + @Override + public OBJModel2 read(JsonDeserializationContext deserializationContext, JsonObject modelContents) + { + if (!modelContents.has("model")) + throw new RuntimeException("OBJ Loader requires a 'model' key that points to a valid .OBJ model."); + + String modelLocation = modelContents.get("model").getAsString(); + + boolean detectCullableFaces = JSONUtils.getBoolean(modelContents, "detectCullableFaces", true); + boolean diffuseLighting = JSONUtils.getBoolean(modelContents, "diffuseLighting", false); + boolean flipV = JSONUtils.getBoolean(modelContents, "flip-v", false); + boolean ambientToFullbright = JSONUtils.getBoolean(modelContents, "ambientToFullbright", true); + @Nullable + String materialLibraryOverrideLocation = modelContents.has("materialLibraryOverride") ? JSONUtils.getString(modelContents, "materialLibraryOverride") : null; + + return loadModel(new OBJModel2.ModelSettings(new ResourceLocation(modelLocation), detectCullableFaces, diffuseLighting, flipV, ambientToFullbright, materialLibraryOverrideLocation)); + } + + public OBJModel2 loadModel(OBJModel2.ModelSettings settings) + { + return modelCache.computeIfAbsent(settings, (data) -> { + IResource resource; + try + { + resource = manager.getResource(settings.modelLocation); + } + catch (IOException e) + { + throw new RuntimeException("Could not find OBJ model", e); + } + + try(LineReader rdr = new LineReader(resource)) + { + return new OBJModel2(rdr, settings); + } + catch (Exception e) + { + throw new RuntimeException("Could not read OBJ model", e); + } + }); + } + + public MaterialLibrary2 loadMaterialLibrary(ResourceLocation materialLocation) + { + return materialCache.computeIfAbsent(materialLocation, (location) -> { + IResource resource; + try + { + resource = manager.getResource(location); + } + catch (IOException e) + { + throw new RuntimeException("Could not find OBJ material library", e); + } + + try(LineReader rdr = new LineReader(resource)) + { + return new MaterialLibrary2(rdr); + } + catch (Exception e) + { + throw new RuntimeException("Could not read OBJ material library", e); + } + }); + } +} diff --git a/src/main/java/net/minecraftforge/client/model/obj/OBJModel.java b/src/main/java/net/minecraftforge/client/model/obj/OBJModel.java index fcc0d53176..b2d0b1f7cd 100644 --- a/src/main/java/net/minecraftforge/client/model/obj/OBJModel.java +++ b/src/main/java/net/minecraftforge/client/model/obj/OBJModel.java @@ -79,6 +79,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +@Deprecated // Use the new model loading system and data generators instead. public class OBJModel implements IUnbakedModel { private static final Logger LOGGER = LogManager.getLogger(); @@ -1535,6 +1536,12 @@ public class OBJModel implements IUnbakedModel return new OBJBakedModel(this.model, this.state, this.format, this.textures); } + @Override + public boolean doesHandlePerspectives() + { + return true; + } + @Override public Pair handlePerspective(TransformType cameraTransformType) { diff --git a/src/main/java/net/minecraftforge/client/model/obj/OBJModel2.java b/src/main/java/net/minecraftforge/client/model/obj/OBJModel2.java new file mode 100644 index 0000000000..e864731f47 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/obj/OBJModel2.java @@ -0,0 +1,671 @@ +/* + * 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.obj; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import joptsimple.internal.Strings; +import net.minecraft.client.renderer.model.*; +import net.minecraft.client.renderer.texture.ISprite; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.client.renderer.vertex.VertexFormatElement; +import net.minecraft.util.Direction; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.MathHelper; +import net.minecraftforge.client.model.*; +import net.minecraftforge.client.model.geometry.IModelGeometryPart; +import net.minecraftforge.client.model.geometry.IMultipartModelGeometry; +import net.minecraftforge.client.model.pipeline.IVertexConsumer; +import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad; +import net.minecraftforge.common.model.TRSRTransformation; +import org.apache.commons.lang3.tuple.Pair; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.vecmath.Vector2f; +import javax.vecmath.Vector3f; +import javax.vecmath.Vector4f; +import java.io.IOException; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class OBJModel2 implements IMultipartModelGeometry +{ + private static Vector2f[] DEFAULT_COORDS = { + new Vector2f(0, 0), + new Vector2f(0, 1), + new Vector2f(1, 1), + new Vector2f(1, 0), + }; + + private final Map parts = Maps.newHashMap(); + + private final List positions = Lists.newArrayList(); + private final List texCoords = Lists.newArrayList(); + private final List normals = Lists.newArrayList(); + private final List colors = Lists.newArrayList(); + + public final boolean detectCullableFaces; + public final boolean diffuseLighting; + public final boolean flipV; + public final boolean ambientToFullbright; + + public final ResourceLocation modelLocation; + + @Nullable + public final String materialLibraryOverrideLocation; + + + OBJModel2(LineReader reader, ModelSettings settings) throws IOException + { + this.modelLocation = settings.modelLocation; + this.detectCullableFaces = settings.detectCullableFaces; + this.diffuseLighting = settings.diffuseLighting; + this.flipV = settings.flipV; + this.ambientToFullbright = settings.ambientToFullbright; + this.materialLibraryOverrideLocation = settings.materialLibraryOverrideLocation; + + // for relative references to material libraries + String modelDomain = modelLocation.getNamespace(); + String modelPath = modelLocation.getPath(); + int lastSlash = modelPath.lastIndexOf('/'); + if (lastSlash >= 0) + modelPath = modelPath.substring(0,lastSlash+1); // include the '/' + else + modelPath = ""; + + MaterialLibrary2 mtllib = MaterialLibrary2.EMPTY; + MaterialLibrary2.Material currentMat = null; + String currentSmoothingGroup = null; + ModelGroup currentGroup = null; + ModelObject currentObject = null; + ModelMesh currentMesh = null; + + boolean objAboveGroup = false; + + if (materialLibraryOverrideLocation != null) + { + String lib = materialLibraryOverrideLocation; + if (lib.contains(":")) + mtllib = OBJLoader2.INSTANCE.loadMaterialLibrary(new ResourceLocation(lib)); + else + mtllib = OBJLoader2.INSTANCE.loadMaterialLibrary(new ResourceLocation(modelDomain, modelPath + lib)); + } + + String[] line; + while((line = reader.readAndSplitLine(true)) != null) + { + switch(line[0]) + { + case "mtllib": // Loads material library + { + if (materialLibraryOverrideLocation != null) + break; + + String lib = line[1]; + if (lib.contains(":")) + mtllib = OBJLoader2.INSTANCE.loadMaterialLibrary(new ResourceLocation(lib)); + else + mtllib = OBJLoader2.INSTANCE.loadMaterialLibrary(new ResourceLocation(modelDomain, modelPath + lib)); + break; + } + + case "usemtl": // Sets the current material (starts new mesh) + { + String mat = Strings.join(Arrays.copyOfRange(line, 1, line.length), " "); + MaterialLibrary2.Material newMat = mtllib.getMaterial(mat); + if (!Objects.equals(newMat, currentMat)) + { + currentMat = newMat; + if (currentMesh != null && currentMesh.mat == null && currentMesh.faces.size() == 0) + { + currentMesh.mat = currentMat; + } + else + { + // Start new mesh + currentMesh = null; + } + } + break; + } + + case "v": // Vertex + positions.add(parseVector4To3(line)); + break; + case "vt": // Vertex texcoord + texCoords.add(parseVector2(line)); + break; + case "vn": // Vertex normal + normals.add(parseVector3(line)); + break; + case "vc": // Vertex color (non-standard) + colors.add(parseVector4(line)); + break; + + case "f": // Face + { + if (currentMesh == null) + { + currentMesh = new ModelMesh(currentMat, currentSmoothingGroup); + if (currentObject != null) + { + currentObject.meshes.add(currentMesh); + } + else + { + if (currentGroup == null) + { + currentGroup = new ModelGroup(""); + parts.put("", currentGroup); + } + currentGroup.meshes.add(currentMesh); + } + } + + int[][] vertices = new int[line.length-1][]; + for(int i=0;i Strings.isNullOrEmpty(num) ? 0 : Integer.parseInt(num)).toArray(); + if (vertex[0] < 0) vertex[0] = positions.size() + vertex[0]; + else vertex[0]--; + if (vertex.length > 1) + { + if (vertex[1] < 0) vertex[1] = texCoords.size() + vertex[1]; + else vertex[1]--; + if (vertex.length > 2) + { + if (vertex[2] < 0) vertex[2] = normals.size() + vertex[2]; + else vertex[2]--; + if (vertex.length > 3) + { + if (vertex[3] < 0) vertex[3] = colors.size() + vertex[3]; + else vertex[3]--; + } + } + } + vertices[i] = vertex; + } + + currentMesh.faces.add(vertices); + + break; + } + + case "s": // Smoothing group (starts new mesh) + { + String smoothingGroup = "off".equals(line[1]) ? null : line[1]; + if (!Objects.equals(currentSmoothingGroup, smoothingGroup)) + { + currentSmoothingGroup = smoothingGroup; + if (currentMesh != null && currentMesh.smoothingGroup == null && currentMesh.faces.size() == 0) + { + currentMesh.smoothingGroup = currentSmoothingGroup; + } + else + { + // Start new mesh + currentMesh = null; + } + } + break; + } + + case "g": + { + String name = line[1]; + if (objAboveGroup) + { + currentObject = new ModelObject(currentGroup.name() + "/" + name); + currentGroup.parts.put(name, currentObject); + } + else + { + currentGroup = new ModelGroup(name); + parts.put(name, currentGroup); + currentObject = null; + } + // Start new mesh + currentMesh = null; + break; + } + + case "o": + { + String name = line[1]; + if (objAboveGroup || currentGroup == null) + { + objAboveGroup = true; + + currentGroup = new ModelGroup(name); + parts.put(name, currentGroup); + currentObject = null; + } + else + { + currentObject = new ModelObject(currentGroup.name() + "/" + name); + currentGroup.parts.put(name, currentObject); + } + // Start new mesh + currentMesh = null; + break; + } + } + } + } + + public static Vector3f parseVector4To3(String[] line) + { + switch (line.length) { + case 1: return new Vector3f(0,0,0); + case 2: return new Vector3f(Float.parseFloat(line[1]), 0, 0); + case 3: return new Vector3f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), 0); + case 4: return new Vector3f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), Float.parseFloat(line[3])); + default: + { + Vector4f vec4 = parseVector4(line); + return new Vector3f( + vec4.getX() / vec4.getW(), + vec4.getY() / vec4.getW(), + vec4.getZ() / vec4.getW() + ); + } + } + } + + public static Vector2f parseVector2(String[] line) + { + switch (line.length) { + case 1: return new Vector2f(0,0); + case 2: return new Vector2f(Float.parseFloat(line[1]), 0); + default: return new Vector2f(Float.parseFloat(line[1]), Float.parseFloat(line[2])); + } + } + + public static Vector3f parseVector3(String[] line) + { + switch (line.length) { + case 1: return new Vector3f(0,0,0); + case 2: return new Vector3f(Float.parseFloat(line[1]), 0, 0); + case 3: return new Vector3f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), 0); + default: return new Vector3f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), Float.parseFloat(line[3])); + } + } + + public static Vector4f parseVector4(String[] line) + { + switch (line.length) { + case 1: return new Vector4f(0,0,0,1); + case 2: return new Vector4f(Float.parseFloat(line[1]), 0, 0,1); + case 3: return new Vector4f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), 0,1); + case 4: return new Vector4f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), Float.parseFloat(line[3]),1); + default: return new Vector4f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), Float.parseFloat(line[3]), Float.parseFloat(line[4])); + } + } + + @Override + public Collection getParts() + { + return parts.values(); + } + + @Override + public Optional getPart(String name) + { + return Optional.ofNullable(parts.get(name)); + } + + private Pair makeQuad(int[][] indices, int tintIndex, Vector4f colorTint, Vector4f ambientColor, boolean isFullbright, TextureAtlasSprite texture, VertexFormat format, Optional transform) + { + boolean needsNormalRecalculation = false; + for (int[] ints : indices) + { + needsNormalRecalculation |= ints.length < 3; + } + Vector3f faceNormal = new Vector3f(0,0,0); + if (needsNormalRecalculation) { + Vector3f a = positions.get(indices[0][0]); + Vector3f ab = positions.get(indices[1][0]); + Vector3f ac = positions.get(indices[2][0]); + Vector3f abs = new Vector3f(ab); + abs.sub(a); + Vector3f acs = new Vector3f(ac); + acs.sub(a); + abs.cross(abs,acs); + abs.normalize(); + faceNormal = abs; + } + + Vector4f[] pos = new Vector4f[4]; + Vector3f[] norm = new Vector3f[4]; + + UnpackedBakedQuad.Builder builder = new UnpackedBakedQuad.Builder(format); + + builder.setQuadTint(tintIndex); + builder.setTexture(texture); + builder.setApplyDiffuseLighting(!isFullbright); + + Vector2f uv2 = new Vector2f(0, 0); + if (ambientToFullbright) + { + int fakeLight = (int) ((ambientColor.getX() + ambientColor.getY() + ambientColor.getZ()) * 15 / 3.0f); + uv2 = new Vector2f((fakeLight << 4) / 32767.0f, (fakeLight << 4) / 32767.0f); + builder.setApplyDiffuseLighting(fakeLight == 0); + } + + TRSRTransformation transformation = transform.orElse(null); + boolean hasTransform = transform.isPresent() && !transform.get().isIdentity(); + + for(int i=0;i<4;i++) + { + int[] index = indices[Math.min(i,indices.length-1)]; + Vector3f pos0 = positions.get(index[0]); + Vector4f position = new Vector4f(pos0.x, pos0.y, pos0.z, 1); + Vector2f texCoord = index.length >= 2 && texCoords.size() > 0 ? texCoords.get(index[1]) : DEFAULT_COORDS[i]; + Vector3f norm0 = !needsNormalRecalculation && index.length >= 3 && normals.size() > 0 ? normals.get(index[2]) : faceNormal; + Vector3f normal = norm0; + Vector4f color = index.length >= 4 && colors.size() > 0 ? colors.get(index[3]) : new Vector4f(1, 1, 1, 1); + if (hasTransform) + { + normal = new Vector3f(norm0); + transformation.transformPosition(position); + transformation.transformNormal(normal); + }; + Vector4f tintedColor = new Vector4f( + color.getX() * colorTint.getX(), + color.getY() * colorTint.getY(), + color.getZ() * colorTint.getZ(), + color.getW() * colorTint.getW()); + putVertexData(builder, format, position, texCoord, normal, tintedColor, uv2, texture); + pos[i] = position; + norm[i] = normal; + } + + builder.setQuadOrientation(Direction.getFacingFromVector(norm[0].x, norm[0].y,norm[0].z)); + + Direction cull = null; + if (detectCullableFaces) + { + if (MathHelper.epsilonEquals(pos[0].getX(), 0) && // vertex.position.x + MathHelper.epsilonEquals(pos[1].getX(), 0) && + MathHelper.epsilonEquals(pos[2].getX(), 0) && + MathHelper.epsilonEquals(pos[3].getX(), 0) && + norm[0].getX() < 0) // vertex.normal.x + { + cull = Direction.WEST; + } + else if (MathHelper.epsilonEquals(pos[0].getX(), 1) && // vertex.position.x + MathHelper.epsilonEquals(pos[1].getX(), 1) && + MathHelper.epsilonEquals(pos[2].getX(), 1) && + MathHelper.epsilonEquals(pos[3].getX(), 1) && + norm[0].getX() > 0) // vertex.normal.x + { + cull = Direction.EAST; + } + else if (MathHelper.epsilonEquals(pos[0].getZ(), 0) && // vertex.position.z + MathHelper.epsilonEquals(pos[1].getZ(), 0) && + MathHelper.epsilonEquals(pos[2].getZ(), 0) && + MathHelper.epsilonEquals(pos[3].getZ(), 0) && + norm[0].getZ() < 0) // vertex.normal.z + { + cull = Direction.NORTH; // can never remember + } + else if (MathHelper.epsilonEquals(pos[0].getZ(), 1) && // vertex.position.z + MathHelper.epsilonEquals(pos[1].getZ(), 1) && + MathHelper.epsilonEquals(pos[2].getZ(), 1) && + MathHelper.epsilonEquals(pos[3].getZ(), 1) && + norm[0].getZ() > 0) // vertex.normal.z + { + cull = Direction.SOUTH; + } + else if (MathHelper.epsilonEquals(pos[0].getY(), 0) && // vertex.position.y + MathHelper.epsilonEquals(pos[1].getY(), 0) && + MathHelper.epsilonEquals(pos[2].getY(), 0) && + MathHelper.epsilonEquals(pos[3].getY(), 0) && + norm[0].getY() < 0) // vertex.normal.z + { + cull = Direction.DOWN; // can never remember + } + else if (MathHelper.epsilonEquals(pos[0].getY(), 1) && // vertex.position.y + MathHelper.epsilonEquals(pos[1].getY(), 1) && + MathHelper.epsilonEquals(pos[2].getY(), 1) && + MathHelper.epsilonEquals(pos[3].getY(), 1) && + norm[0].getY() > 0) // vertex.normal.y + { + cull = Direction.UP; + } + } + + return Pair.of(builder.build(), cull); + } + + private void putVertexData(IVertexConsumer consumer, VertexFormat format, Vector4f position0, Vector2f texCoord0, Vector3f normal0, Vector4f color0, Vector2f uv2, TextureAtlasSprite texture) + { + int elementCount = format.getElementCount(); + for(int j=0;j meshes = Lists.newArrayList(); + + ModelObject(String name) + { + this.name = name; + } + + @Override + public String name() + { + return name; + } + + @Override + public void addQuads(IModelConfiguration owner, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ISprite sprite, VertexFormat format) + { + for(ModelMesh mesh : meshes) + { + MaterialLibrary2.Material mat = mesh.mat; + if (mat == null) + continue; + TextureAtlasSprite texture = spriteGetter.apply(ModelLoaderRegistry2.resolveTexture(mat.diffuseColorMap, owner)); + int tintIndex = mat.diffuseTintIndex; + Vector4f colorTint = mat.diffuseColor; + boolean isFullbright = ambientToFullbright && mesh.isFullbright(); + + if (format.equals(DefaultVertexFormats.ITEM) && isFullbright) + { + format = DefaultVertexFormats.BLOCK; + } + + for (int[][] face : mesh.faces) + { + Pair quad = makeQuad(face, tintIndex, colorTint, mat.ambientColor, isFullbright, texture, format, sprite.getState().apply(Optional.empty())); + if (quad.getRight() == null) + modelBuilder.addGeneralQuad(quad.getLeft()); + else + modelBuilder.addFaceQuad(quad.getRight(), quad.getLeft()); + } + } + } + + @Override + public Collection getTextureDependencies(IModelConfiguration owner, Function modelGetter, Set missingTextureErrors) + { + return meshes.stream().map(mesh -> ModelLoaderRegistry2.resolveTexture(mesh.mat.diffuseColorMap, owner)).collect(Collectors.toSet()); + } + + public boolean hasAnyFullBright() + { + return meshes.stream().anyMatch(ModelMesh::isFullbright); + } + } + + public class ModelGroup extends ModelObject + { + final Map parts = Maps.newHashMap(); + + ModelGroup(String name) + { + super(name); + } + + public Collection getParts() + { + return parts.values(); + } + + @Override + public void addQuads(IModelConfiguration owner, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ISprite sprite, VertexFormat format) + { + super.addQuads(owner, modelBuilder, bakery, spriteGetter, sprite, format); + + getParts().stream().filter(part -> owner.getPartVisibility(part)) + .forEach(part -> part.addQuads(owner, modelBuilder, bakery, spriteGetter, sprite, format)); + } + + @Override + public Collection getTextureDependencies(IModelConfiguration owner, Function modelGetter, Set missingTextureErrors) + { + Set combined = Sets.newHashSet(); + combined.addAll(super.getTextureDependencies(owner, modelGetter, missingTextureErrors)); + for (IModelGeometryPart part : getParts()) + combined.addAll(part.getTextureDependencies(owner, modelGetter, missingTextureErrors)); + return combined; + } + + @Override + public boolean hasAnyFullBright() + { + return super.hasAnyFullBright() || parts.values().stream().anyMatch(ModelObject::hasAnyFullBright); + } + } + + private class ModelMesh + { + @Nullable + public MaterialLibrary2.Material mat; + @Nullable + public String smoothingGroup; + public final List faces = Lists.newArrayList(); + + public ModelMesh(@Nullable MaterialLibrary2.Material currentMat, @Nullable String currentSmoothingGroup) + { + this.mat = currentMat; + this.smoothingGroup = currentSmoothingGroup; + } + + public boolean isFullbright() + { + return mat != null && mat.ambientColor.epsilonEquals(new Vector4f(1,1,1,1), 1/256f); + } + } +} diff --git a/src/main/java/net/minecraftforge/common/data/LanguageProvider.java b/src/main/java/net/minecraftforge/common/data/LanguageProvider.java index 18a4778e3d..cbd098c5ae 100644 --- a/src/main/java/net/minecraftforge/common/data/LanguageProvider.java +++ b/src/main/java/net/minecraftforge/common/data/LanguageProvider.java @@ -16,6 +16,7 @@ * 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.common.data; import java.io.BufferedWriter; diff --git a/src/main/java/net/minecraftforge/common/util/Lazy.java b/src/main/java/net/minecraftforge/common/util/Lazy.java new file mode 100644 index 0000000000..b6aa3da333 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/util/Lazy.java @@ -0,0 +1,108 @@ +/* + * 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.common.util; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.function.Supplier; + +/** + * Proxy object for a value that is calculated on first access + * @param The type of the value + */ +public interface Lazy extends Supplier +{ + /** + * Constructs a lazy-initialized object + * @param supplier The supplier for the value, to be called the first time the value is needed. + */ + static Lazy of(@Nonnull Supplier supplier) + { + return new Lazy.Fast<>(supplier); + } + + /** + * Constructs a thread-safe lazy-initialized object + * @param supplier The supplier for the value, to be called the first time the value is needed. + */ + static Lazy concurrentOf(@Nonnull Supplier supplier) + { + return new Lazy.Concurrent<>(supplier); + } + + /** + * Non-thread-safe implementation. + */ + final class Fast implements Lazy + { + private Supplier supplier; + private T instance; + + private Fast(Supplier supplier) + { + this.supplier = supplier; + } + + @Nullable + @Override + public final T get() + { + if (supplier != null) + { + instance = supplier.get(); + supplier = null; + } + return instance; + } + } + + /** + * Thread-safe implementation. + */ + final class Concurrent implements Lazy + { + private static final Object lock = new Object(); + private volatile Supplier supplier; + private volatile T instance; + + private Concurrent(Supplier supplier) + { + this.supplier = supplier; + } + + @Nullable + @Override + public final T get() + { + if (supplier != null) + { + synchronized (lock) + { + if (supplier != null) + { + instance = supplier.get(); + supplier = null; + } + } + } + return instance; + } + } +} diff --git a/src/main/java/net/minecraftforge/common/util/NonNullLazy.java b/src/main/java/net/minecraftforge/common/util/NonNullLazy.java new file mode 100644 index 0000000000..1a5437ee63 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/util/NonNullLazy.java @@ -0,0 +1,109 @@ +/* + * 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.common.util; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.function.Supplier; + +/** + * Proxy object for a value that is calculated on first access. + * Same as {@link Lazy}, but with a nonnull contract. + * @param The type of the value + */ +public interface NonNullLazy extends NonNullSupplier +{ + /** + * Constructs a lazy-initialized object + * @param supplier The supplier for the value, to be called the first time the value is needed. + */ + static NonNullLazy of(@Nonnull NonNullSupplier supplier) + { + return new NonNullLazy.Fast<>(supplier); + } + + /** + * Constructs a thread-safe lazy-initialized object + * @param supplier The supplier for the value, to be called the first time the value is needed. + */ + static NonNullLazy concurrentOf(@Nonnull NonNullSupplier supplier) + { + return new NonNullLazy.Concurrent<>(supplier); + } + + /** + * Non-thread-safe implementation. + */ + final class Fast implements NonNullLazy + { + private NonNullSupplier supplier; + private T instance; + + private Fast(NonNullSupplier supplier) + { + this.supplier = supplier; + } + + @Nonnull + @Override + public final T get() + { + if (supplier != null) + { + instance = supplier.get(); + supplier = null; + } + return instance; + } + } + + /** + * Thread-safe implementation. + */ + final class Concurrent implements NonNullLazy + { + private static final Object lock = new Object(); + private volatile NonNullSupplier supplier; + private volatile T instance; + + private Concurrent(NonNullSupplier supplier) + { + this.supplier = supplier; + } + + @Nonnull + @Override + public final T get() + { + if (supplier != null) + { + synchronized (lock) + { + if (supplier != null) + { + instance = supplier.get(); + supplier = null; + } + } + } + return instance; + } + } +} diff --git a/src/main/java/net/minecraftforge/fml/client/ClientModLoader.java b/src/main/java/net/minecraftforge/fml/client/ClientModLoader.java index a932b57717..f501358c56 100644 --- a/src/main/java/net/minecraftforge/fml/client/ClientModLoader.java +++ b/src/main/java/net/minecraftforge/fml/client/ClientModLoader.java @@ -54,6 +54,7 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.client.model.ModelLoaderRegistry; +import net.minecraftforge.client.model.ModelLoaderRegistry2; import net.minecraftforge.common.ForgeConfig; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.Event; @@ -99,6 +100,7 @@ public class ClientModLoader mcResourceManager.addReloadListener(ClientModLoader::onreload); mcResourceManager.addReloadListener(BrandingControl.resourceManagerReloadListener()); ModelLoaderRegistry.init(); + ModelLoaderRegistry2.init(); } private static CompletableFuture onreload(final IFutureReloadListener.IStage stage, final IResourceManager resourceManager, final IProfiler prepareProfiler, final IProfiler executeProfiler, final Executor asyncExecutor, final Executor syncExecutor) { @@ -125,6 +127,7 @@ public class ClientModLoader private static void postSidedRunnable(Consumer> perModContainerEventProcessor) { RenderingRegistry.loadEntityRenderers(mc.getRenderManager()); + ModelLoaderRegistry2.initComplete(); } private static void preSidedRunnable(Consumer> perModContainerEventProcessor) { diff --git a/src/main/java/net/minecraftforge/fml/packs/DelegatableResourcePack.java b/src/main/java/net/minecraftforge/fml/packs/DelegatableResourcePack.java index 9afa8fbbfe..61c37784ab 100644 --- a/src/main/java/net/minecraftforge/fml/packs/DelegatableResourcePack.java +++ b/src/main/java/net/minecraftforge/fml/packs/DelegatableResourcePack.java @@ -1,3 +1,22 @@ +/* + * 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.fml.packs; import java.io.File; diff --git a/src/main/java/net/minecraftforge/fml/packs/DelegatingResourcePack.java b/src/main/java/net/minecraftforge/fml/packs/DelegatingResourcePack.java index 04cfbdb4c5..232df29a63 100644 --- a/src/main/java/net/minecraftforge/fml/packs/DelegatingResourcePack.java +++ b/src/main/java/net/minecraftforge/fml/packs/DelegatingResourcePack.java @@ -1,3 +1,22 @@ +/* + * 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.fml.packs; import java.io.File; diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 176b8ede7a..f00c6bd24a 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -50,6 +50,7 @@ protected net.minecraft.client.renderer.model.ModelBakery field_177609_j # textu protected net.minecraft.client.renderer.model.ModelBakery field_177616_r # MODEL_ENTITY private-f net.minecraft.client.renderer.model.ModelBakery field_217853_J # field_217853_J - need to un-finalize so that we can delay initialization to after calling super() in ModelLoader protected net.minecraft.client.renderer.model.ModelBakery func_177594_c(Lnet/minecraft/util/ResourceLocation;)Lnet/minecraft/client/renderer/model/BlockModel; # loadModel +public net.minecraft.client.renderer.texture.TextureAtlasSprite func_195665_a(IIII)I # getColor private-f net.minecraft.client.renderer.tileentity.PistonTileEntityRenderer field_178462_c # blockRenderer - it's static so we need to un-finalize in case this class loads to early. public net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher field_147557_n # fontRenderer - needed for rendering text in TESR items before entering world public net.minecraft.command.arguments.EntityOptions func_202024_a(Ljava/lang/String;Lnet/minecraft/command/arguments/EntityOptions$IFilter;Ljava/util/function/Predicate;Lnet/minecraft/util/text/ITextComponent;)V # register diff --git a/src/main/resources/assets/forge/models/block/default.json b/src/main/resources/assets/forge/models/block/default.json new file mode 100644 index 0000000000..cfe7c7ca25 --- /dev/null +++ b/src/main/resources/assets/forge/models/block/default.json @@ -0,0 +1,3 @@ +{ + "parent": "minecraft:block/block" +} diff --git a/src/main/resources/assets/forge/models/item/bucket.json b/src/main/resources/assets/forge/models/item/bucket.json index 4a8c26d791..0d22c7a624 100644 --- a/src/main/resources/assets/forge/models/item/bucket.json +++ b/src/main/resources/assets/forge/models/item/bucket.json @@ -1,6 +1,7 @@ { - "parent": "item/generated", + "parent": "forge:item/default", "textures": { - "layer0": "forge:items/bucket_base" + "base": "item/bucket", + "fluid": "forge:item/mask/bucket_fluid" } } diff --git a/src/main/resources/assets/forge/models/item/bucket_drip.json b/src/main/resources/assets/forge/models/item/bucket_drip.json new file mode 100644 index 0000000000..0f8934beb7 --- /dev/null +++ b/src/main/resources/assets/forge/models/item/bucket_drip.json @@ -0,0 +1,7 @@ +{ + "parent": "forge:item/default", + "textures": { + "base": "item/bucket", + "fluid": "forge:item/mask/bucket_fluid_drip" + } +} diff --git a/src/main/resources/assets/forge/models/item/default-tool.json b/src/main/resources/assets/forge/models/item/default-tool.json new file mode 100644 index 0000000000..e5953bab6d --- /dev/null +++ b/src/main/resources/assets/forge/models/item/default-tool.json @@ -0,0 +1,24 @@ +{ + "display": { + "thirdperson_righthand": { + "rotation": [ 0, -90, 55 ], + "translation": [ 0, 4.0, 0.5 ], + "scale": [ 0.85, 0.85, 0.85 ] + }, + "thirdperson_lefthand": { + "rotation": [ 0, 90, -55 ], + "translation": [ 0, 4.0, 0.5 ], + "scale": [ 0.85, 0.85, 0.85 ] + }, + "firstperson_righthand": { + "rotation": [ 0, -90, 25 ], + "translation": [ 1.13, 3.2, 1.13 ], + "scale": [ 0.68, 0.68, 0.68 ] + }, + "firstperson_lefthand": { + "rotation": [ 0, 90, -25 ], + "translation": [ 1.13, 3.2, 1.13 ], + "scale": [ 0.68, 0.68, 0.68 ] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/forge/models/item/default.json b/src/main/resources/assets/forge/models/item/default.json new file mode 100644 index 0000000000..0c2e9425cd --- /dev/null +++ b/src/main/resources/assets/forge/models/item/default.json @@ -0,0 +1,28 @@ +{ + "display": { + "ground": { + "rotation": [ 0, 0, 0 ], + "translation": [ 0, 2, 0], + "scale":[ 0.5, 0.5, 0.5 ] + }, + "head": { + "rotation": [ 0, 180, 0 ], + "translation": [ 0, 13, 7], + "scale":[ 1, 1, 1] + }, + "thirdperson_righthand": { + "rotation": [ 0, 0, 0 ], + "translation": [ 0, 3, 1 ], + "scale": [ 0.55, 0.55, 0.55 ] + }, + "firstperson_righthand": { + "rotation": [ 0, -90, 25 ], + "translation": [ 1.13, 3.2, 1.13], + "scale": [ 0.68, 0.68, 0.68 ] + }, + "fixed": { + "rotation": [ 0, 180, 0 ], + "scale": [ 1, 1, 1 ] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/forge/textures/item/mask/bucket_fluid.png b/src/main/resources/assets/forge/textures/item/mask/bucket_fluid.png new file mode 100644 index 0000000000000000000000000000000000000000..58f08bc71a08dc26af84e6ab771a4b1775740909 GIT binary patch literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucL1RxB#}EtuWQku5f?kIY)+;m^ZDeu-k_Q=D xojr_s6r`ITG6@_=71;H5ae@es*ntBK4EqoAuxv|Ai3VzC@O1TaS?83{1OT9HD literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/forge/textures/item/mask/bucket_fluid_cover.png b/src/main/resources/assets/forge/textures/item/mask/bucket_fluid_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..e97bcb54928106d5cff1ce0b9e3a5a519b384d39 GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucL0eB3#}EtumdK II;Vst0MZ650ssI2 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/forge/textures/item/mask/bucket_fluid_cover_drip.png b/src/main/resources/assets/forge/textures/item/mask/bucket_fluid_cover_drip.png new file mode 100644 index 0000000000000000000000000000000000000000..153f731df1a18d2df5688e45d20846277ccf1ab2 GIT binary patch literal 181 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucK`&1i#}Etujfu>>6ebNd_PEBv^MaFf%huKQ8@cT9rmN&@cv1 LS3j3^P6 BLOCKS = new DeferredRegister<>(ForgeRegistries.BLOCKS, MODID); + public static final DeferredRegister ITEMS = new DeferredRegister<>(ForgeRegistries.ITEMS, MODID); + + public static RegistryObject obj_block = BLOCKS.register("obj_block", () -> + new Block(Block.Properties.create(Material.WOOD)) { + @Override + protected void fillStateContainer(StateContainer.Builder builder) + { + builder.add(BlockStateProperties.HORIZONTAL_FACING); + } + + @Nullable + @Override + public BlockState getStateForPlacement(BlockItemUseContext context) + { + return getDefaultState().with( + BlockStateProperties.HORIZONTAL_FACING, context.getPlacementHorizontalFacing() + ); + } + } + ); + + public static RegistryObject obj_item = ITEMS.register("obj_block", () -> + new BlockItem(obj_block.get(), new Item.Properties().group(ItemGroup.MISC)) { + @Override + public boolean canEquip(ItemStack stack, EquipmentSlotType armorType, Entity entity) + { + return armorType == EquipmentSlotType.HEAD; + } + } + ); + + public static RegistryObject custom_transforms = ITEMS.register("custom_transforms", () -> + new Item(new Item.Properties().group(ItemGroup.MISC)) + ); + + public static RegistryObject custom_vanilla_loader = ITEMS.register("custom_vanilla_loader", () -> + new Item(new Item.Properties().group(ItemGroup.MISC)) + ); + + public static RegistryObject custom_loader = ITEMS.register("custom_loader", () -> + new Item(new Item.Properties().group(ItemGroup.MISC)) + ); + + public NewModelLoaderTest() + { + IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); + + BLOCKS.register(modEventBus); + ITEMS.register(modEventBus); + + modEventBus.addListener(this::clientSetup); + } + + public void clientSetup(FMLClientSetupEvent event) + { + ModelLoaderRegistry2.registerLoader(new ResourceLocation(MODID, "custom_loader"), new TestLoader()); + } + + static class TestLoader implements IModelLoader + { + @Override + public void onResourceManagerReload(IResourceManager resourceManager) + { + } + + @Override + public TestModel read(JsonDeserializationContext deserializationContext, JsonObject modelContents) + { + return new TestModel(); + } + } + + static class TestModel implements ISimpleModelGeometry + { + + @Override + public void addQuads(IModelConfiguration owner, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ISprite sprite, VertexFormat format) + { + TextureAtlasSprite texture = spriteGetter.apply(new ResourceLocation(owner.resolveTexture("particle"))); + + UnpackedBakedQuad.Builder builder = new UnpackedBakedQuad.Builder(format); + + builder.setTexture(texture); + builder.setQuadOrientation(Direction.UP); + + putVertex(builder, format, 0,1,0.5f, texture.getInterpolatedU(0), texture.getInterpolatedV(0), 1, 1, 1); + putVertex(builder, format, 0,0,0.5f, texture.getInterpolatedU(0), texture.getInterpolatedV(16), 1, 1, 1); + putVertex(builder, format, 1,0,0.5f, texture.getInterpolatedU(16), texture.getInterpolatedV(16), 1, 1, 1); + putVertex(builder, format, 1,1,0.5f, texture.getInterpolatedU(16), texture.getInterpolatedV(0), 1, 1, 1); + + modelBuilder.addGeneralQuad(builder.build()); + } + + private void putVertex(UnpackedBakedQuad.Builder builder, VertexFormat format, int x, float y, float z, float u, float v, float red, float green, float blue) + { + for(int i=0;i getTextureDependencies(IModelConfiguration owner, Function modelGetter, Set missingTextureErrors) + { + return Collections.singleton(new ResourceLocation(owner.resolveTexture("particle"))); + } + } +} diff --git a/src/test/java/net/minecraftforge/debug/entity/player/PlayerXpEventTest.java b/src/test/java/net/minecraftforge/debug/entity/player/PlayerXpEventTest.java index 2d007e40cc..1280aa66a5 100644 --- a/src/test/java/net/minecraftforge/debug/entity/player/PlayerXpEventTest.java +++ b/src/test/java/net/minecraftforge/debug/entity/player/PlayerXpEventTest.java @@ -1,3 +1,22 @@ +/* + * 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.debug.entity.player; import org.apache.logging.log4j.LogManager; diff --git a/src/test/resources/META-INF/mods.toml b/src/test/resources/META-INF/mods.toml index 2e7e6fe52a..edc2beade1 100644 --- a/src/test/resources/META-INF/mods.toml +++ b/src/test/resources/META-INF/mods.toml @@ -58,4 +58,6 @@ loaderVersion="[28,)" [[mods]] modId="forgeblockstatesloader" [[mods]] - modId="custom_tnt_test" \ No newline at end of file + modId="custom_tnt_test" +[[mods]] + modId="new_model_loader_test" diff --git a/src/test/resources/assets/new_fluid_test/blockstates/test_fluid_block.json b/src/test/resources/assets/new_fluid_test/blockstates/test_fluid_block.json new file mode 100644 index 0000000000..ccdddf7605 --- /dev/null +++ b/src/test/resources/assets/new_fluid_test/blockstates/test_fluid_block.json @@ -0,0 +1,5 @@ +{ + "variants": { + "": { "model": "new_fluid_test:block/test_fluid" } + } +} diff --git a/src/test/resources/assets/new_fluid_test/models/block/test_fluid.json b/src/test/resources/assets/new_fluid_test/models/block/test_fluid.json new file mode 100644 index 0000000000..ac14d90873 --- /dev/null +++ b/src/test/resources/assets/new_fluid_test/models/block/test_fluid.json @@ -0,0 +1,5 @@ +{ + "textures": { + "particle": "block/water_still" + } +} diff --git a/src/test/resources/assets/new_fluid_test/models/item/test_fluid_bucket.json b/src/test/resources/assets/new_fluid_test/models/item/test_fluid_bucket.json new file mode 100644 index 0000000000..d67a9993ff --- /dev/null +++ b/src/test/resources/assets/new_fluid_test/models/item/test_fluid_bucket.json @@ -0,0 +1,31 @@ +{ + "parent": "forge:item/bucket_drip", + "loader": "forge:bucket", + "fluid": "new_fluid_test:test_fluid", + "display": { + "ground": { + "rotation": [ 0, 0, 0 ], + "translation": [ 0, 2, 0], + "scale":[ 0.5, 0.5, 0.5 ] + }, + "head": { + "rotation": [ 0, 180, 0 ], + "translation": [ 0, 13, 7], + "scale":[ 1, 1, 1] + }, + "thirdperson_righthand": { + "rotation": [ 0, 0, 0 ], + "translation": [ 0, 3, 1 ], + "scale": [ 0.55, 0.55, 0.55 ] + }, + "firstperson_righthand": { + "rotation": [ 0, -90, 25 ], + "translation": [ 1.13, 3.2, 1.13], + "scale": [ 0.68, 0.68, 0.68 ] + }, + "fixed": { + "rotation": [ 0, 180, 0 ], + "scale": [ 1, 1, 1 ] + } + } +} \ No newline at end of file diff --git a/src/test/resources/assets/new_model_loader_test/blockstates/obj_block.json b/src/test/resources/assets/new_model_loader_test/blockstates/obj_block.json new file mode 100644 index 0000000000..f09b752a5d --- /dev/null +++ b/src/test/resources/assets/new_model_loader_test/blockstates/obj_block.json @@ -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 } + } +} diff --git a/src/test/resources/assets/new_model_loader_test/models/block/obj_block.json b/src/test/resources/assets/new_model_loader_test/models/block/obj_block.json new file mode 100644 index 0000000000..ee6f89f9d3 --- /dev/null +++ b/src/test/resources/assets/new_model_loader_test/models/block/obj_block.json @@ -0,0 +1,10 @@ +{ + "parent": "block/block", + "loader": "forge:obj", + "model": "new_model_loader_test:models/item/sugar_glider.obj", + "ambientToFullbright": true, + "textures": { + "qr": "minecraft:block/oak_planks", + "particle": "block/oak_planks" + } +} diff --git a/src/test/resources/assets/new_model_loader_test/models/item/custom_loader.json b/src/test/resources/assets/new_model_loader_test/models/item/custom_loader.json new file mode 100644 index 0000000000..d4bb7dd2a5 --- /dev/null +++ b/src/test/resources/assets/new_model_loader_test/models/item/custom_loader.json @@ -0,0 +1,8 @@ +{ + "parent": "forge:item/default", + "loader": "new_model_loader_test:custom_loader", + "gui_3d": false, + "textures": { + "particle": "item/quartz" + } +} diff --git a/src/test/resources/assets/new_model_loader_test/models/item/custom_transforms.json b/src/test/resources/assets/new_model_loader_test/models/item/custom_transforms.json new file mode 100644 index 0000000000..4d8af77c4b --- /dev/null +++ b/src/test/resources/assets/new_model_loader_test/models/item/custom_transforms.json @@ -0,0 +1,13 @@ +{ + "parent": "forge:item/default", + "loader": "forge:obj", + "model": "new_model_loader_test:models/item/item_direction.obj", + "textures": { + "particle": "block/oak_planks" + }, + "transform": { + "firstperson_righthand": { + "scale": 3.0 + } + } +} diff --git a/src/test/resources/assets/new_model_loader_test/models/item/custom_vanilla_loader.json b/src/test/resources/assets/new_model_loader_test/models/item/custom_vanilla_loader.json new file mode 100644 index 0000000000..ecf8813461 --- /dev/null +++ b/src/test/resources/assets/new_model_loader_test/models/item/custom_vanilla_loader.json @@ -0,0 +1,56 @@ +{ + "parent": "block/block", + "loader": "minecraft:elements", + "display": { + "firstperson_righthand": { + "rotation": [ 0, 135, 0 ], + "translation": [ 0, 0, 0 ], + "scale": [ 0.4, 0.4, 0.4 ] + } + }, + "textures": { + "particle": "block/lectern_sides", + "bottom": "block/oak_planks", + "base": "block/lectern_base", + "front": "block/lectern_front", + "sides": "block/lectern_sides", + "top": "block/lectern_top" + }, + "elements": [ + { + "from": [ 0, 0, 0 ], + "to": [ 16, 2, 16 ], + "faces": { + "north": { "uv": [ 0, 14, 16, 16 ], "texture": "#base", "cullface": "north" }, + "east": { "uv": [ 0, 6, 16, 8 ], "texture": "#base", "cullface": "east" }, + "south": { "uv": [ 0, 6, 16, 8 ], "texture": "#base", "cullface": "south" }, + "west": { "uv": [ 0, 6, 16, 8 ], "texture": "#base", "cullface": "west" }, + "up": { "uv": [ 0, 0, 16, 16 ], "rotation": 180, "texture": "#base" }, + "down": { "uv": [ 0, 0, 16, 16 ], "texture": "#bottom", "cullface": "down" } + } + }, + { + "from": [4, 2, 4], + "to": [12, 15, 12], + "faces": { + "north": { "uv": [ 0, 0, 8, 13 ], "texture": "#front" }, + "east": { "uv": [ 2, 16, 15, 8 ], "rotation": 90, "texture": "#sides" }, + "south": { "uv": [ 8, 3, 16, 16 ], "texture": "#front" }, + "west": { "uv": [ 2, 8, 15, 16 ], "rotation": 90, "texture": "#sides" } + } + }, + { + "from": [ 0.01, 12, 3 ], + "to": [ 15.99, 16, 16 ], + "rotation": { "angle": -22.5, "axis": "x", "origin": [ 8, 8, 8 ] }, + "faces": { + "north": { "uv": [ 0, 0, 16, 4 ], "texture": "#sides" }, + "east": { "uv": [ 0, 4, 13, 8 ], "texture": "#sides" }, + "south": { "uv": [ 0, 4, 16, 8 ], "texture": "#sides" }, + "west": { "uv": [ 0, 4, 13, 8 ], "texture": "#sides" }, + "up": { "uv": [ 0, 1, 16, 14 ], "rotation": 180, "texture": "#top" }, + "down": { "uv": [ 0, 0, 16, 13 ], "texture": "#bottom" } + } + } + ] +} diff --git a/src/test/resources/assets/new_model_loader_test/models/item/item_direction.mtl b/src/test/resources/assets/new_model_loader_test/models/item/item_direction.mtl new file mode 100644 index 0000000000..db7f1af668 --- /dev/null +++ b/src/test/resources/assets/new_model_loader_test/models/item/item_direction.mtl @@ -0,0 +1,7 @@ +newmtl None +Ns 0 +Ka 1.0000 1.0000 1.0000 +Kd 0.8 0.8 0.8 +Ks 0.8 0.8 0.8 +d 1 +illum 2 diff --git a/src/test/resources/assets/new_model_loader_test/models/item/item_direction.obj b/src/test/resources/assets/new_model_loader_test/models/item/item_direction.obj new file mode 100644 index 0000000000..20157d0cbf --- /dev/null +++ b/src/test/resources/assets/new_model_loader_test/models/item/item_direction.obj @@ -0,0 +1,650 @@ +mtllib item_direction.mtl +o Cylinder.001 +v 0.584859 0.436110 0.874908 +v 0.659354 0.514439 0.772372 +v 0.705396 0.514439 0.914073 +v 0.584859 0.514440 1.001649 +v 0.464321 0.514439 0.914073 +v 0.510363 0.514439 0.772372 +v 0.705396 0.641182 0.835744 +v 0.659354 0.641182 0.977444 +v 0.510363 0.641182 0.977444 +v 0.464321 0.641182 0.835744 +v 0.584859 0.641182 0.748167 +v 0.584859 0.719512 0.874908 +v 0.655708 0.457272 0.897928 +v 0.628646 0.457272 0.814639 +v 0.699496 0.503313 0.837659 +v 0.584859 0.503313 0.754370 +v 0.541071 0.457272 0.814639 +v 0.584859 0.457273 0.949404 +v 0.655709 0.503313 0.972425 +v 0.514009 0.457272 0.897928 +v 0.514008 0.503313 0.972425 +v 0.470221 0.503313 0.837659 +v 0.628646 0.577811 0.740142 +v 0.541071 0.577811 0.740142 +v 0.726560 0.577811 0.874908 +v 0.699497 0.577811 0.791618 +v 0.628646 0.577811 1.009674 +v 0.699497 0.577811 0.958198 +v 0.470220 0.577811 0.958198 +v 0.541071 0.577811 1.009674 +v 0.470220 0.577811 0.791618 +v 0.443157 0.577811 0.874908 +v 0.655709 0.652308 0.777391 +v 0.699496 0.652308 0.912157 +v 0.584859 0.652308 0.995446 +v 0.470221 0.652308 0.912157 +v 0.514008 0.652308 0.777391 +v 0.655708 0.698349 0.851888 +v 0.584859 0.698349 0.800412 +v 0.628646 0.698349 0.935177 +v 0.541071 0.698349 0.935177 +v 0.514009 0.698349 0.851888 +v 0.649105 0.608429 0.910870 +v 0.649105 0.047528 0.910870 +v 0.645187 0.608429 0.871087 +v 0.645187 0.047528 0.871087 +v 0.633582 0.608429 0.832833 +v 0.633583 0.047528 0.832833 +v 0.614738 0.608429 0.797578 +v 0.614738 0.047528 0.797578 +v 0.589378 0.608429 0.766677 +v 0.589378 0.047528 0.766677 +v 0.558477 0.608429 0.741317 +v 0.558477 0.047528 0.741317 +v 0.523222 0.608429 0.722473 +v 0.523222 0.047528 0.722473 +v 0.484968 0.608429 0.710868 +v 0.484968 0.047528 0.710868 +v 0.445185 0.608429 0.706950 +v 0.445185 0.047528 0.706950 +v 0.405402 0.608429 0.710868 +v 0.405402 0.047528 0.710868 +v 0.367148 0.608429 0.722473 +v 0.367148 0.047528 0.722473 +v 0.331893 0.608429 0.741317 +v 0.331893 0.047528 0.741317 +v 0.300992 0.608429 0.766677 +v 0.300992 0.047528 0.766677 +v 0.275632 0.608429 0.797578 +v 0.275632 0.047528 0.797578 +v 0.256788 0.608429 0.832833 +v 0.256788 0.047528 0.832833 +v 0.245183 0.608429 0.871087 +v 0.245183 0.047528 0.871087 +v 0.241265 0.608429 0.910870 +v 0.241265 0.047528 0.910870 +v 0.245183 0.608429 0.950653 +v 0.245183 0.047528 0.950653 +v 0.256788 0.608429 0.988907 +v 0.256788 0.047528 0.988907 +v 0.275632 0.608429 1.024162 +v 0.275632 0.047528 1.024162 +v 0.300992 0.608429 1.055063 +v 0.300992 0.047528 1.055063 +v 0.331893 0.608429 1.080423 +v 0.331893 0.047528 1.080423 +v 0.367148 0.608429 1.099268 +v 0.367148 0.047528 1.099268 +v 0.405402 0.608429 1.110872 +v 0.405402 0.047528 1.110872 +v 0.445185 0.608429 1.114790 +v 0.445185 0.047528 1.114790 +v 0.484968 0.608429 1.110872 +v 0.484968 0.047528 1.110872 +v 0.523222 0.608429 1.099267 +v 0.523222 0.047528 1.099267 +v 0.558477 0.608429 1.080423 +v 0.558477 0.047528 1.080423 +v 0.589378 0.608429 1.055063 +v 0.589378 0.047528 1.055063 +v 0.614738 0.608429 1.024162 +v 0.614739 0.047528 1.024162 +v 0.633583 0.608429 0.988907 +v 0.633583 0.047528 0.988907 +v 0.645187 0.608429 0.950653 +v 0.645187 0.047528 0.950653 +v -0.406158 0.670618 0.910870 +v 0.627582 0.670618 0.910870 +v -0.406158 0.666700 0.871087 +v 0.627582 0.666700 0.871087 +v -0.406158 0.655096 0.832833 +v 0.627582 0.655096 0.832833 +v -0.406158 0.636251 0.797578 +v 0.627582 0.636251 0.797578 +v -0.406158 0.610891 0.766677 +v 0.627582 0.610891 0.766677 +v -0.406158 0.579990 0.741317 +v 0.627582 0.579990 0.741317 +v -0.406158 0.544735 0.722473 +v 0.627582 0.544735 0.722473 +v -0.406158 0.506481 0.710868 +v 0.627582 0.506481 0.710868 +v -0.406158 0.466698 0.706950 +v 0.627582 0.466698 0.706950 +v -0.406158 0.426915 0.710868 +v 0.627582 0.426915 0.710868 +v -0.406158 0.388661 0.722473 +v 0.627582 0.388661 0.722473 +v -0.406158 0.353406 0.741317 +v 0.627582 0.353406 0.741317 +v -0.406158 0.322505 0.766677 +v 0.627582 0.322505 0.766677 +v -0.406158 0.297145 0.797578 +v 0.627582 0.297145 0.797578 +v -0.406158 0.278301 0.832833 +v 0.627582 0.278301 0.832833 +v -0.406158 0.266696 0.871087 +v 0.627582 0.266696 0.871087 +v -0.406158 0.262778 0.910870 +v 0.627582 0.262778 0.910870 +v -0.406158 0.266696 0.950653 +v 0.627582 0.266696 0.950653 +v -0.406158 0.278301 0.988907 +v 0.627582 0.278301 0.988907 +v -0.406158 0.297145 1.024162 +v 0.627582 0.297145 1.024162 +v -0.406158 0.322505 1.055063 +v 0.627582 0.322505 1.055063 +v -0.406158 0.353406 1.080423 +v 0.627582 0.353406 1.080423 +v -0.406158 0.388661 1.099268 +v 0.627582 0.388661 1.099268 +v -0.406158 0.426915 1.110872 +v 0.627582 0.426915 1.110872 +v -0.406158 0.466698 1.114790 +v 0.627582 0.466698 1.114790 +v -0.406158 0.506481 1.110872 +v 0.627582 0.506481 1.110872 +v -0.406158 0.544735 1.099267 +v 0.627582 0.544735 1.099267 +v -0.406158 0.579990 1.080423 +v 0.627582 0.579990 1.080423 +v -0.406158 0.610891 1.055063 +v 0.627582 0.610891 1.055063 +v -0.406158 0.636251 1.024162 +v 0.627582 0.636251 1.024162 +v -0.406158 0.655096 0.988907 +v 0.627582 0.655096 0.988907 +v -0.406158 0.666700 0.950653 +v 0.627582 0.666700 0.950653 +vn 0.315100 -0.943500 -0.102400 +vn 0.268000 -0.661700 -0.700200 +vn 0.194700 -0.943500 0.268000 +vn -0.194700 -0.943500 0.268000 +vn -0.315100 -0.943500 -0.102400 +vn 0.268000 -0.330400 -0.905000 +vn 0.943500 -0.330400 -0.024700 +vn 0.315100 -0.330400 0.889700 +vn -0.748800 -0.330400 0.574600 +vn -0.777900 -0.330400 -0.534600 +vn 0.583100 -0.125600 -0.802600 +vn 0.943500 -0.125600 0.306600 +vn -0.000000 -0.125600 0.992100 +vn -0.943500 -0.125600 0.306600 +vn -0.583100 -0.125600 -0.802600 +vn 0.628400 0.661700 -0.408900 +vn 0.583100 0.661700 0.471300 +vn -0.268000 0.661700 0.700200 +vn -0.748800 0.661700 -0.038500 +vn -0.194700 0.661700 -0.724000 +vn -0.194700 0.943500 -0.268000 +vn -0.356800 0.794700 -0.491100 +vn -0.628400 0.661700 -0.408900 +vn -0.315100 0.943500 0.102400 +vn -0.577300 0.794700 0.187600 +vn -0.583100 0.661700 0.471300 +vn -0.000000 0.943500 0.331300 +vn -0.000000 0.794700 0.607100 +vn 0.268000 0.661700 0.700200 +vn 0.315100 0.943500 0.102400 +vn 0.577300 0.794700 0.187600 +vn 0.748800 0.661700 -0.038500 +vn 0.194700 0.943500 -0.268000 +vn 0.356800 0.794700 -0.491100 +vn 0.194700 0.661700 -0.724000 +vn -0.315100 0.330400 -0.889700 +vn -0.577300 0.187600 -0.794700 +vn -0.748800 0.330400 -0.574600 +vn -0.943500 0.330400 0.024700 +vn -0.934200 0.187600 0.303500 +vn -0.777900 0.330400 0.534600 +vn -0.268000 0.330400 0.905000 +vn 0.000000 0.187600 0.982200 +vn 0.268000 0.330400 0.905000 +vn 0.777900 0.330400 0.534600 +vn 0.934200 0.187600 0.303500 +vn 0.943500 0.330400 0.024700 +vn 0.748800 0.330400 -0.574600 +vn 0.577300 0.187600 -0.794700 +vn 0.315100 0.330400 -0.889700 +vn -0.943500 0.125600 -0.306600 +vn -0.934200 -0.187600 -0.303500 +vn -0.943500 -0.330400 -0.024700 +vn -0.583100 0.125600 0.802600 +vn -0.577300 -0.187600 0.794700 +vn -0.315100 -0.330400 0.889700 +vn 0.583100 0.125600 0.802600 +vn 0.577300 -0.187600 0.794700 +vn 0.748800 -0.330400 0.574600 +vn 0.943500 0.125600 -0.306600 +vn 0.934200 -0.187600 -0.303500 +vn 0.777900 -0.330400 -0.534600 +vn 0.000000 0.125600 -0.992100 +vn 0.000000 -0.187600 -0.982200 +vn -0.268000 -0.330400 -0.905000 +vn -0.583100 -0.661700 -0.471300 +vn -0.577300 -0.794700 -0.187600 +vn -0.748800 -0.661700 0.038500 +vn -0.628400 -0.661700 0.408900 +vn -0.356800 -0.794700 0.491100 +vn -0.194700 -0.661700 0.724000 +vn 0.194700 -0.661700 0.724000 +vn 0.356800 -0.794700 0.491100 +vn 0.628400 -0.661700 0.408900 +vn -0.268000 -0.661700 -0.700200 +vn 0.000000 -0.794700 -0.607100 +vn 0.000000 -0.943500 -0.331300 +vn 0.748800 -0.661700 0.038500 +vn 0.577300 -0.794700 -0.187600 +vn 0.583100 -0.661700 -0.471300 +vn 0.995200 0.000000 -0.098000 +vn 0.956900 0.000000 -0.290300 +vn 0.881900 0.000000 -0.471400 +vn 0.773000 0.000000 -0.634400 +vn 0.634400 0.000000 -0.773000 +vn 0.471400 0.000000 -0.881900 +vn 0.290300 0.000000 -0.956900 +vn 0.098000 0.000000 -0.995200 +vn -0.098000 0.000000 -0.995200 +vn -0.290300 0.000000 -0.956900 +vn -0.471400 -0.000000 -0.881900 +vn -0.634400 -0.000000 -0.773000 +vn -0.773000 -0.000000 -0.634400 +vn -0.881900 -0.000000 -0.471400 +vn -0.956900 -0.000000 -0.290300 +vn -0.995200 -0.000000 -0.098000 +vn -0.995200 -0.000000 0.098000 +vn -0.956900 -0.000000 0.290300 +vn -0.881900 -0.000000 0.471400 +vn -0.773000 -0.000000 0.634400 +vn -0.634400 -0.000000 0.773000 +vn -0.471400 0.000000 0.881900 +vn -0.290300 0.000000 0.956900 +vn -0.098000 -0.000000 0.995200 +vn 0.098000 0.000000 0.995200 +vn 0.290300 0.000000 0.956900 +vn 0.471400 0.000000 0.881900 +vn 0.634400 0.000000 0.773000 +vn 0.773000 0.000000 0.634400 +vn 0.881900 0.000000 0.471400 +vn 0.000000 -1.000000 -0.000000 +vn 0.995200 0.000000 0.098000 +vn 0.956900 0.000000 0.290300 +vn -0.000000 1.000000 0.000000 +vn 0.000000 0.995200 -0.098000 +vn 0.000000 0.956900 -0.290300 +vn 0.000000 0.881900 -0.471400 +vn 0.000000 0.773000 -0.634400 +vn 0.000000 0.634400 -0.773000 +vn 0.000000 0.471400 -0.881900 +vn -0.000000 0.290300 -0.956900 +vn 0.000000 0.098000 -0.995200 +vn 0.000000 -0.098000 -0.995200 +vn 0.000000 -0.290300 -0.956900 +vn 0.000000 -0.471400 -0.881900 +vn 0.000000 -0.634400 -0.773000 +vn 0.000000 -0.773000 -0.634400 +vn 0.000000 -0.881900 -0.471400 +vn 0.000000 -0.956900 -0.290300 +vn 0.000000 -0.995200 -0.098000 +vn 0.000000 -0.995200 0.098000 +vn 0.000000 -0.956900 0.290300 +vn 0.000000 -0.881900 0.471400 +vn 0.000000 -0.773000 0.634400 +vn -0.000000 -0.634400 0.773000 +vn -0.000000 -0.471400 0.881900 +vn 0.000000 -0.290300 0.956900 +vn 0.000000 -0.098000 0.995200 +vn 0.000000 0.098000 0.995200 +vn -0.000000 0.290300 0.956900 +vn -0.000000 0.471400 0.881900 +vn 0.000000 0.634400 0.773000 +vn 0.000000 0.773000 0.634400 +vn 0.000000 0.881900 0.471400 +vn 1.000000 0.000000 0.000000 +vn 0.000000 0.995200 0.098000 +vn -0.000000 0.956900 0.290300 +vn -1.000000 -0.000000 0.000000 +usemtl None +s off +f 1//1 14//1 13//1 +f 2//2 14//2 16//2 +f 1//3 13//3 18//3 +f 1//4 18//4 20//4 +f 1//5 20//5 17//5 +f 2//6 16//6 23//6 +f 3//7 15//7 25//7 +f 4//8 19//8 27//8 +f 5//9 21//9 29//9 +f 6//10 22//10 31//10 +f 2//11 23//11 26//11 +f 3//12 25//12 28//12 +f 4//13 27//13 30//13 +f 5//14 29//14 32//14 +f 6//15 31//15 24//15 +f 7//16 33//16 38//16 +f 8//17 34//17 40//17 +f 9//18 35//18 41//18 +f 10//19 36//19 42//19 +f 11//20 37//20 39//20 +f 39//21 42//21 12//21 +f 39//22 37//22 42//22 +f 37//23 10//23 42//23 +f 42//24 41//24 12//24 +f 42//25 36//25 41//25 +f 36//26 9//26 41//26 +f 41//27 40//27 12//27 +f 41//28 35//28 40//28 +f 35//29 8//29 40//29 +f 40//30 38//30 12//30 +f 40//31 34//31 38//31 +f 34//32 7//32 38//32 +f 38//33 39//33 12//33 +f 38//34 33//34 39//34 +f 33//35 11//35 39//35 +f 24//36 37//36 11//36 +f 24//37 31//37 37//37 +f 31//38 10//38 37//38 +f 32//39 36//39 10//39 +f 32//40 29//40 36//40 +f 29//41 9//41 36//41 +f 30//42 35//42 9//42 +f 30//43 27//43 35//43 +f 27//44 8//44 35//44 +f 28//45 34//45 8//45 +f 28//46 25//46 34//46 +f 25//47 7//47 34//47 +f 26//48 33//48 7//48 +f 26//49 23//49 33//49 +f 23//50 11//50 33//50 +f 31//51 32//51 10//51 +f 31//52 22//52 32//52 +f 22//53 5//53 32//53 +f 29//54 30//54 9//54 +f 29//55 21//55 30//55 +f 21//56 4//56 30//56 +f 27//57 28//57 8//57 +f 27//58 19//58 28//58 +f 19//59 3//59 28//59 +f 25//60 26//60 7//60 +f 25//61 15//61 26//61 +f 15//62 2//62 26//62 +f 23//63 24//63 11//63 +f 23//64 16//64 24//64 +f 16//65 6//65 24//65 +f 17//66 22//66 6//66 +f 17//67 20//67 22//67 +f 20//68 5//68 22//68 +f 20//69 21//69 5//69 +f 20//70 18//70 21//70 +f 18//71 4//71 21//71 +f 18//72 19//72 4//72 +f 18//73 13//73 19//73 +f 13//74 3//74 19//74 +f 16//75 17//75 6//75 +f 16//76 14//76 17//76 +f 14//77 1//77 17//77 +f 13//78 15//78 3//78 +f 13//79 14//79 15//79 +f 14//80 2//80 15//80 +f 44//81 46//81 45//81 +f 46//82 48//82 47//82 +f 48//83 50//83 49//83 +f 50//84 52//84 51//84 +f 52//85 54//85 53//85 +f 54//86 56//86 55//86 +f 56//87 58//87 57//87 +f 58//88 60//88 59//88 +f 60//89 62//89 61//89 +f 62//90 64//90 63//90 +f 64//91 66//91 65//91 +f 66//92 68//92 67//92 +f 68//93 70//93 69//93 +f 69//94 70//94 72//94 +f 72//95 74//95 73//95 +f 74//96 76//96 75//96 +f 76//97 78//97 77//97 +f 78//98 80//98 79//98 +f 80//99 82//99 81//99 +f 82//100 84//100 83//100 +f 84//101 86//101 85//101 +f 85//102 86//102 88//102 +f 88//103 90//103 89//103 +f 90//104 92//104 91//104 +f 92//105 94//105 93//105 +f 94//106 96//106 95//106 +f 96//107 98//107 97//107 +f 98//108 100//108 99//108 +f 100//109 102//109 101//109 +f 102//110 104//110 103//110 +f 80//111 64//111 48//111 +f 106//112 44//112 43//112 +f 104//113 106//113 105//113 +f 73//114 89//114 105//114 +f 108//115 110//115 109//115 +f 110//116 112//116 111//116 +f 112//117 114//117 113//117 +f 114//118 116//118 115//118 +f 116//119 118//119 117//119 +f 118//120 120//120 119//120 +f 120//121 122//121 121//121 +f 122//122 124//122 123//122 +f 124//123 126//123 125//123 +f 126//124 128//124 127//124 +f 128//125 130//125 129//125 +f 130//126 132//126 131//126 +f 132//127 134//127 133//127 +f 134//128 136//128 135//128 +f 136//129 138//129 137//129 +f 138//130 140//130 139//130 +f 140//131 142//131 141//131 +f 142//132 144//132 143//132 +f 144//133 146//133 145//133 +f 146//134 148//134 147//134 +f 148//135 150//135 149//135 +f 150//136 152//136 151//136 +f 152//137 154//137 153//137 +f 154//138 156//138 155//138 +f 156//139 158//139 157//139 +f 157//140 158//140 160//140 +f 160//141 162//141 161//141 +f 162//142 164//142 163//142 +f 164//143 166//143 165//143 +f 166//144 168//144 167//144 +f 136//145 128//145 112//145 +f 170//146 108//146 107//146 +f 168//147 170//147 169//147 +f 137//148 153//148 169//148 +f 43//81 44//81 45//81 +f 45//82 46//82 47//82 +f 47//83 48//83 49//83 +f 49//84 50//84 51//84 +f 51//85 52//85 53//85 +f 53//86 54//86 55//86 +f 55//87 56//87 57//87 +f 57//88 58//88 59//88 +f 59//89 60//89 61//89 +f 61//90 62//90 63//90 +f 63//91 64//91 65//91 +f 65//92 66//92 67//92 +f 67//93 68//93 69//93 +f 71//94 69//94 72//94 +f 71//95 72//95 73//95 +f 73//96 74//96 75//96 +f 75//97 76//97 77//97 +f 77//98 78//98 79//98 +f 79//99 80//99 81//99 +f 81//100 82//100 83//100 +f 83//101 84//101 85//101 +f 87//102 85//102 88//102 +f 87//103 88//103 89//103 +f 89//104 90//104 91//104 +f 91//105 92//105 93//105 +f 93//106 94//106 95//106 +f 95//107 96//107 97//107 +f 97//108 98//108 99//108 +f 99//109 100//109 101//109 +f 101//110 102//110 103//110 +f 48//111 46//111 104//111 +f 44//111 106//111 104//111 +f 104//111 102//111 100//111 +f 100//111 98//111 96//111 +f 96//111 94//111 92//111 +f 92//111 90//111 96//111 +f 88//111 86//111 84//111 +f 84//111 82//111 88//111 +f 80//111 78//111 76//111 +f 76//111 74//111 80//111 +f 72//111 70//111 68//111 +f 68//111 66//111 64//111 +f 64//111 62//111 56//111 +f 60//111 58//111 56//111 +f 56//111 54//111 52//111 +f 52//111 50//111 48//111 +f 46//111 44//111 104//111 +f 104//111 100//111 96//111 +f 96//111 90//111 88//111 +f 88//111 82//111 80//111 +f 80//111 74//111 72//111 +f 72//111 68//111 80//111 +f 62//111 60//111 56//111 +f 56//111 52//111 64//111 +f 48//111 104//111 96//111 +f 96//111 88//111 80//111 +f 80//111 68//111 64//111 +f 64//111 52//111 48//111 +f 48//111 96//111 80//111 +f 105//112 106//112 43//112 +f 103//113 104//113 105//113 +f 105//114 43//114 49//114 +f 45//114 47//114 49//114 +f 49//114 51//114 57//114 +f 53//114 55//114 57//114 +f 57//114 59//114 61//114 +f 61//114 63//114 65//114 +f 65//114 67//114 69//114 +f 69//114 71//114 73//114 +f 73//114 75//114 77//114 +f 77//114 79//114 73//114 +f 81//114 83//114 85//114 +f 85//114 87//114 81//114 +f 89//114 91//114 93//114 +f 93//114 95//114 89//114 +f 97//114 99//114 101//114 +f 101//114 103//114 97//114 +f 43//114 45//114 49//114 +f 51//114 53//114 57//114 +f 57//114 61//114 65//114 +f 65//114 69//114 73//114 +f 73//114 79//114 81//114 +f 81//114 87//114 89//114 +f 89//114 95//114 97//114 +f 97//114 103//114 105//114 +f 105//114 49//114 57//114 +f 57//114 65//114 73//114 +f 73//114 81//114 89//114 +f 89//114 97//114 105//114 +f 105//114 57//114 73//114 +f 107//115 108//115 109//115 +f 109//116 110//116 111//116 +f 111//117 112//117 113//117 +f 113//118 114//118 115//118 +f 115//119 116//119 117//119 +f 117//120 118//120 119//120 +f 119//121 120//121 121//121 +f 121//122 122//122 123//122 +f 123//123 124//123 125//123 +f 125//124 126//124 127//124 +f 127//125 128//125 129//125 +f 129//126 130//126 131//126 +f 131//127 132//127 133//127 +f 133//128 134//128 135//128 +f 135//129 136//129 137//129 +f 137//130 138//130 139//130 +f 139//131 140//131 141//131 +f 141//132 142//132 143//132 +f 143//133 144//133 145//133 +f 145//134 146//134 147//134 +f 147//135 148//135 149//135 +f 149//136 150//136 151//136 +f 151//137 152//137 153//137 +f 153//138 154//138 155//138 +f 155//139 156//139 157//139 +f 159//140 157//140 160//140 +f 159//141 160//141 161//141 +f 161//142 162//142 163//142 +f 163//143 164//143 165//143 +f 165//144 166//144 167//144 +f 112//145 110//145 168//145 +f 108//145 170//145 168//145 +f 168//145 166//145 164//145 +f 164//145 162//145 160//145 +f 160//145 158//145 156//145 +f 156//145 154//145 160//145 +f 152//145 150//145 144//145 +f 148//145 146//145 144//145 +f 144//145 142//145 136//145 +f 140//145 138//145 136//145 +f 136//145 134//145 132//145 +f 132//145 130//145 128//145 +f 128//145 126//145 124//145 +f 124//145 122//145 120//145 +f 120//145 118//145 116//145 +f 116//145 114//145 112//145 +f 110//145 108//145 168//145 +f 168//145 164//145 112//145 +f 160//145 154//145 152//145 +f 150//145 148//145 144//145 +f 142//145 140//145 136//145 +f 136//145 132//145 128//145 +f 128//145 124//145 120//145 +f 120//145 116//145 128//145 +f 112//145 164//145 160//145 +f 160//145 152//145 144//145 +f 144//145 136//145 112//145 +f 128//145 116//145 112//145 +f 112//145 160//145 144//145 +f 169//146 170//146 107//146 +f 167//147 168//147 169//147 +f 169//148 107//148 109//148 +f 109//148 111//148 113//148 +f 113//148 115//148 121//148 +f 117//148 119//148 121//148 +f 121//148 123//148 125//148 +f 125//148 127//148 129//148 +f 129//148 131//148 137//148 +f 133//148 135//148 137//148 +f 137//148 139//148 141//148 +f 141//148 143//148 145//148 +f 145//148 147//148 149//148 +f 149//148 151//148 153//148 +f 153//148 155//148 157//148 +f 157//148 159//148 161//148 +f 161//148 163//148 165//148 +f 165//148 167//148 169//148 +f 169//148 109//148 113//148 +f 115//148 117//148 121//148 +f 121//148 125//148 129//148 +f 131//148 133//148 137//148 +f 137//148 141//148 145//148 +f 145//148 149//148 137//148 +f 153//148 157//148 169//148 +f 161//148 165//148 169//148 +f 169//148 113//148 137//148 +f 121//148 129//148 137//148 +f 137//148 149//148 153//148 +f 157//148 161//148 169//148 +f 113//148 121//148 137//148 diff --git a/src/test/resources/assets/new_model_loader_test/models/item/obj_block.json b/src/test/resources/assets/new_model_loader_test/models/item/obj_block.json new file mode 100644 index 0000000000..f8ae311d4a --- /dev/null +++ b/src/test/resources/assets/new_model_loader_test/models/item/obj_block.json @@ -0,0 +1,59 @@ +{ + "parent": "block/block", + "loader": "forge:composite", + "parts": { + "part1": { + "loader": "forge:obj", + "model": "new_model_loader_test:models/item/sugar_glider.obj", + "ambientToFullbright": true, + "textures": { + "qr": "new_model_loader_test:item/qr" + } + }, + "part2": { + "parent": "minecraft:block/stone", + "transform": { + "scale": 0.5 + } + } + }, + "textures": { + "particle": "block/oak_planks" + }, + "display": { + "gui": { + "rotation": [ 30, 225, 0 ], + "translation": [ 0, 0, 0], + "scale":[ 0.625, 1.625, 0.625 ] + }, + "ground": { + "rotation": [ 0, 0, 0 ], + "translation": [ 0, 3, 0], + "scale":[ 0.25, 0.25, 0.25 ] + }, + "fixed": { + "rotation": [ 0, 0, 0 ], + "translation": [ 0, 0, 0], + "scale":[ 0.5, 0.5, 0.5 ] + }, + "thirdperson_righthand": { + "rotation": [ 75, 45, 0 ], + "translation": [ 0, 2.5, 0], + "scale": [ 0.375, 0.375, 0.375 ] + }, + "firstperson_righthand": { + "rotation": [ 0, 45, 0 ], + "translation": [ 0, 0, 0 ], + "scale": [ 0.40, 0.40, 0.40 ] + }, + "firstperson_lefthand": { + "rotation": [ 0, 225, 0 ], + "translation": [ 0, 0, 0 ], + "scale": [ 0.40, 0.40, 0.40 ] + } + }, + "visibility": { + "object_1": false, + "object_3": true + } +} diff --git a/src/test/resources/assets/new_model_loader_test/models/item/sugar_glider.mtl b/src/test/resources/assets/new_model_loader_test/models/item/sugar_glider.mtl new file mode 100644 index 0000000000..04ee34fde7 --- /dev/null +++ b/src/test/resources/assets/new_model_loader_test/models/item/sugar_glider.mtl @@ -0,0 +1,46 @@ +# Rhino +newmtl New material 001 (1) +Ka 0.0000 0.0000 0.0000 +Kd 0.4588 0.3333 0.1882 +Ks 1.0000 1.0000 1.0000 +Tf 0.0000 0.0000 0.0000 +d 1.0000 +Ns 0 +map_Kd #qr + +newmtl New material 001 +Ka 0.0000 0.0000 0.0000 +Kd 0.6745 0.5216 0.3412 +Ks 1.0000 1.0000 1.0000 +Tf 0.0000 0.0000 0.0000 +d 1.0000 +Ns 0 +map_Kd #qr + +newmtl Default +Ka 0.0000 0.0000 0.0000 +Kd 1.0000 1.0000 1.0000 +Ks 1.0000 1.0000 1.0000 +Tf 0.0000 0.0000 0.0000 +d 1.0000 +Ns 0 +map_Kd #qr + +newmtl New material 002 +Ka 0.0000 0.0000 0.0000 +Kd 0.4118 0.4118 0.4118 +Ks 1.0000 1.0000 1.0000 +Tf 0.0000 0.0000 0.0000 +d 1.0000 +Ns 0 +map_Kd #qr + +newmtl New material 003 +Ka 0.0000 0.0000 0.0000 +Kd 0.1490 0.1490 0.1490 +Ks 1.0000 1.0000 1.0000 +Tf 0.0000 0.0000 0.0000 +d 1.0000 +Ns 0 +map_Kd #qr + diff --git a/src/test/resources/assets/new_model_loader_test/models/item/sugar_glider.obj b/src/test/resources/assets/new_model_loader_test/models/item/sugar_glider.obj new file mode 100644 index 0000000000..3b1c5bd275 --- /dev/null +++ b/src/test/resources/assets/new_model_loader_test/models/item/sugar_glider.obj @@ -0,0 +1,579 @@ +# Rhino + +mtllib sugar_glider.mtl +o object_1 +usemtl New material 001 (1) +v 0.7132 0.6084 0.6162 +v 0.7132 0.3283 0.4863 +v 0.8296 0.5819 0.6734 +v 0.8296 0.3018 0.5435 +v 0.8605 0.7225 0.3699 +v 0.8605 0.4425 0.24 +v 0.9769 0.6963 0.4272 +v 0.9769 0.4159 0.2973 +vt 0.7132 0.6084 +vt 0.6162 0.6084 +vt 0.7132 0.3838 +vt 0.7132 0.3283 +vt 0.4863 0.3283 +vt 0.2868 0.5137 +vt 0.8296 0.5819 +vt 0.3266 0.5819 +vt 0.8296 0.3266 +vt 0.8296 0.3018 +vt 0.4565 0.3018 +vt 0.1704 0.4565 +vt 0.1395 0.7225 +vt 0.3699 0.7225 +vt 0.8605 0.6301 +vt 0.1395 0.4425 +vt 0.24 0.4425 +vt 0.1395 0.76 +vt 0.5728 0.6963 +vt 0.0231 0.6963 +vt 0.9769 0.5728 +vt 0.7027 0.4159 +vt 0.0231 0.4159 +vt 0.0231 0.7027 +vn -0.4768 -0.3698 0.7974 +vn -0.879 0.2006 -0.4325 +vn 0 0.9072 0.4207 +vn -0.4768 -0.3698 0.7974 +vn -0.879 0.2006 -0.4325 +vn 0 -0.9072 -0.4207 +vn -0.4768 -0.3698 0.7974 +vn 0.879 -0.2006 0.4325 +vn 0 0.9072 0.4207 +vn -0.4768 -0.3698 0.7974 +vn 0.879 -0.2006 0.4325 +vn 0 -0.9072 -0.4207 +vn 0.4768 0.3698 -0.7974 +vn -0.879 0.2006 -0.4325 +vn 0 0.9072 0.4207 +vn 0.4768 0.3698 -0.7974 +vn -0.879 0.2006 -0.4325 +vn 0 -0.9072 -0.4207 +vn 0.879 -0.2006 0.4325 +vn 0.4768 0.3698 -0.7974 +vn 0 0.9072 0.4207 +vn 0.879 -0.2006 0.4325 +vn 0.4768 0.3698 -0.7974 +vn 0 -0.9072 -0.4207 +f 2/4/4 4/10/10 3/7/7 1/1/1 +f 4/11/11 8/22/22 7/19/19 3/8/8 +f 8/23/23 6/16/16 5/13/13 7/20/20 +f 6/17/17 2/5/5 1/2/2 5/14/14 +f 6/18/18 8/24/24 4/12/12 2/6/6 +f 3/9/9 7/21/21 5/15/15 1/3/3 +o object_2 +usemtl New material 001 +v 0.2059 0 0.7941 +v 0.2059 0.5883 0.7941 +v 0.2059 0 0.2059 +v 0.2059 0.5883 0.2059 +v 0.7941 0 0.7941 +v 0.7941 0.5883 0.7941 +v 0.7941 0 0.2059 +v 0.7941 0.5883 0.2059 +vt 0.2059 0 +vt 0.7941 0 +vt 0.7941 0.2059 +vt 0.2059 0.5883 +vt 0.7941 0.5883 +vt 0.2059 0.2059 +vt 0.7941 0 +vt 0.2059 0 +vt 0.7941 0.7941 +vt 0.7941 0.5883 +vt 0.2059 0.5883 +vt 0.2059 0.7941 +vt 0.7941 0 +vt 0.2059 0 +vt 0.2059 0.2059 +vt 0.7941 0.5883 +vt 0.2059 0.5883 +vt 0.7941 0.2059 +vt 0.7941 0 +vt 0.2059 0 +vt 0.2059 0.7941 +vt 0.7941 0.5883 +vt 0.2059 0.5883 +vt 0.7941 0.7941 +vn 0 0 1 +vn -1 0 0 +vn 0 -1 0 +vn 0 0 1 +vn -1 0 0 +vn 0 1 0 +vn 0 0 -1 +vn -1 0 0 +vn 0 -1 0 +vn 0 0 -1 +vn -1 0 0 +vn 0 1 0 +vn 0 0 1 +vn 1 0 0 +vn 0 -1 0 +vn 0 0 1 +vn 1 0 0 +vn 0 1 0 +vn 1 0 0 +vn 0 0 -1 +vn 0 -1 0 +vn 1 0 0 +vn 0 0 -1 +vn 0 1 0 +f 9/25/25 13/37/37 14/40/40 10/28/28 +f 13/38/38 15/43/43 16/46/46 14/41/41 +f 15/44/44 11/31/31 12/34/34 16/47/47 +f 11/32/32 9/26/26 10/29/29 12/35/35 +f 11/33/33 15/45/45 13/39/39 9/27/27 +f 14/42/42 16/48/48 12/36/36 10/30/30 +o object_3 +usemtl Default +v 0.5294 0.2353 0.8235 +v 0.5294 0.4706 0.8235 +v 0.5294 0.2353 0.7941 +v 0.5294 0.4706 0.7941 +v 0.7647 0.2353 0.8235 +v 0.7647 0.4706 0.8235 +v 0.7647 0.2353 0.7941 +v 0.7647 0.4706 0.7941 +vt 0.4706 0.1765 +vt 0.8235 0.2353 +vt 0.5294 0.2353 +vt 0.5294 0.1765 +vt 0.8235 0.4706 +vt 0.5294 0.4706 +vt 0.4706 0.2059 +vt 0.7941 0.2353 +vt 0.4706 0.2353 +vt 0.5294 0.2059 +vt 0.7941 0.4706 +vt 0.4706 0.4706 +vt 0.2353 0.1765 +vt 0.1765 0.2353 +vt 0.7647 0.2353 +vt 0.1765 0.4706 +vt 0.7647 0.1765 +vt 0.7647 0.4706 +vt 0.2353 0.2059 +vt 0.2059 0.2353 +vt 0.2353 0.2353 +vt 0.2059 0.4706 +vt 0.7647 0.2059 +vt 0.2353 0.4706 +vn 0 -1 0 +vn -1 0 0 +vn 0 0 1 +vn 0 1 0 +vn -1 0 0 +vn 0 0 1 +vn 0 -1 0 +vn -1 0 0 +vn 0 0 -1 +vn 0 1 0 +vn -1 0 0 +vn 0 0 -1 +vn 0 -1 0 +vn 1 0 0 +vn 0 0 1 +vn 1 0 0 +vn 0 1 0 +vn 0 0 1 +vn 0 -1 0 +vn 1 0 0 +vn 0 0 -1 +vn 1 0 0 +vn 0 1 0 +vn 0 0 -1 +f 19/55/55 23/67/67 21/61/61 17/49/49 +f 23/68/68 24/70/70 22/64/64 21/62/62 +f 24/71/71 20/58/58 18/52/52 22/65/65 +f 20/59/59 19/56/56 17/50/50 18/53/53 +f 20/60/60 24/72/72 23/69/69 19/57/57 +f 21/63/63 22/66/66 18/54/54 17/51/51 +o object_4 +usemtl Default +v 0.2353 0.2353 0.8235 +v 0.2353 0.4706 0.8235 +v 0.2353 0.2353 0.7941 +v 0.2353 0.4706 0.7941 +v 0.4706 0.2353 0.8235 +v 0.4706 0.4706 0.8235 +v 0.4706 0.2353 0.7941 +v 0.4706 0.4706 0.7941 +vt 0.7647 0.1765 +vt 0.8235 0.2353 +vt 0.2353 0.2353 +vt 0.2353 0.1765 +vt 0.8235 0.4706 +vt 0.2353 0.4706 +vt 0.7647 0.2059 +vt 0.7941 0.2353 +vt 0.7647 0.2353 +vt 0.2353 0.2059 +vt 0.7941 0.4706 +vt 0.7647 0.4706 +vt 0.5294 0.1765 +vt 0.1765 0.2353 +vt 0.4706 0.2353 +vt 0.1765 0.4706 +vt 0.4706 0.1765 +vt 0.4706 0.4706 +vt 0.5294 0.2059 +vt 0.2059 0.2353 +vt 0.5294 0.2353 +vt 0.2059 0.4706 +vt 0.4706 0.2059 +vt 0.5294 0.4706 +vn 0 -1 0 +vn -1 0 0 +vn 0 0 1 +vn 0 1 0 +vn -1 0 0 +vn 0 0 1 +vn 0 -1 0 +vn -1 0 0 +vn 0 0 -1 +vn 0 1 0 +vn -1 0 0 +vn 0 0 -1 +vn 0 -1 0 +vn 1 0 0 +vn 0 0 1 +vn 1 0 0 +vn 0 1 0 +vn 0 0 1 +vn 0 -1 0 +vn 1 0 0 +vn 0 0 -1 +vn 1 0 0 +vn 0 1 0 +vn 0 0 -1 +f 27/79/79 31/91/91 29/85/85 25/73/73 +f 31/92/92 32/94/94 30/88/88 29/86/86 +f 32/95/95 28/82/82 26/76/76 30/89/89 +f 28/83/83 27/80/80 25/74/74 26/77/77 +f 28/84/84 32/96/96 31/93/93 27/81/81 +f 29/87/87 30/90/90 26/78/78 25/75/75 +o object_5 +usemtl New material 001 +v 0.4118 0 0.8824 +v 0.4118 0.1765 0.8824 +v 0.4118 0 0.7353 +v 0.4118 0.1765 0.7353 +v 0.5882 0 0.8824 +v 0.5882 0.1765 0.8824 +v 0.5882 0 0.7353 +v 0.5882 0.1765 0.7353 +vt 0.4118 0 +vt 0.8824 0 +vt 0.5882 0.1176 +vt 0.4118 0.1765 +vt 0.8824 0.1765 +vt 0.4118 0.1176 +vt 0.5882 0 +vt 0.7353 0 +vt 0.5882 0.2647 +vt 0.5882 0.1765 +vt 0.7353 0.1765 +vt 0.4118 0.2647 +vt 0.5882 0 +vt 0.1176 0 +vt 0.4118 0.1176 +vt 0.5882 0.1765 +vt 0.1176 0.1765 +vt 0.5882 0.1176 +vt 0.2647 0 +vt 0.4118 0 +vt 0.4118 0.2647 +vt 0.2647 0.1765 +vt 0.4118 0.1765 +vt 0.5882 0.2647 +vn 0 0 1 +vn -1 0 0 +vn 0 -1 0 +vn 0 0 1 +vn -1 0 0 +vn 0 1 0 +vn 0 0 -1 +vn -1 0 0 +vn 0 -1 0 +vn 0 0 -1 +vn -1 0 0 +vn 0 1 0 +vn 0 0 1 +vn 1 0 0 +vn 0 -1 0 +vn 0 0 1 +vn 1 0 0 +vn 0 1 0 +vn 1 0 0 +vn 0 0 -1 +vn 0 -1 0 +vn 1 0 0 +vn 0 0 -1 +vn 0 1 0 +f 33/97/97 37/109/109 38/112/112 34/100/100 +f 37/110/110 39/115/115 40/118/118 38/113/113 +f 39/116/116 35/103/103 36/106/106 40/119/119 +f 35/104/104 33/98/98 34/101/101 36/107/107 +f 35/105/105 39/117/117 37/111/111 33/99/99 +f 38/114/114 40/120/120 36/108/108 34/102/102 +o object_6 +usemtl New material 002 +v 0.4706 0.1176 0.9118 +v 0.4706 0.1765 0.9118 +v 0.4706 0.1176 0.8824 +v 0.4706 0.1765 0.8824 +v 0.5294 0.1176 0.9118 +v 0.5294 0.1765 0.9118 +v 0.5294 0.1176 0.8824 +v 0.5294 0.1765 0.8824 +vt 0.5294 0.0882 +vt 0.9118 0.1176 +vt 0.4706 0.1176 +vt 0.4706 0.0882 +vt 0.9118 0.1765 +vt 0.4706 0.1765 +vt 0.5294 0.1176 +vt 0.8824 0.1176 +vt 0.5294 0.1176 +vt 0.4706 0.1176 +vt 0.8824 0.1765 +vt 0.5294 0.1765 +vt 0.4706 0.0882 +vt 0.0882 0.1176 +vt 0.5294 0.1176 +vt 0.0882 0.1765 +vt 0.5294 0.0882 +vt 0.5294 0.1765 +vt 0.4706 0.1176 +vt 0.1176 0.1176 +vt 0.4706 0.1176 +vt 0.1176 0.1765 +vt 0.5294 0.1176 +vt 0.4706 0.1765 +vn 0 -1 0 +vn -1 0 0 +vn 0 0 1 +vn 0 1 0 +vn -1 0 0 +vn 0 0 1 +vn 0 -1 0 +vn -1 0 0 +vn 0 0 -1 +vn 0 1 0 +vn -1 0 0 +vn 0 0 -1 +vn 0 -1 0 +vn 1 0 0 +vn 0 0 1 +vn 1 0 0 +vn 0 1 0 +vn 0 0 1 +vn 0 -1 0 +vn 1 0 0 +vn 0 0 -1 +vn 1 0 0 +vn 0 1 0 +vn 0 0 -1 +f 43/127/127 47/139/139 45/133/133 41/121/121 +f 47/140/140 48/142/142 46/136/136 45/134/134 +f 48/143/143 44/130/130 42/124/124 46/137/137 +f 44/131/131 43/128/128 41/122/122 42/125/125 +f 44/132/132 48/144/144 47/141/141 43/129/129 +f 45/135/135 46/138/138 42/126/126 41/123/123 +o object_7 +usemtl New material 003 +v 0.5882 0.2736 0.8347 +v 0.5882 0.3912 0.8347 +v 0.5882 0.2736 0.8053 +v 0.5882 0.3912 0.8053 +v 0.7059 0.2736 0.8347 +v 0.7059 0.3912 0.8347 +v 0.7059 0.2736 0.8053 +v 0.7059 0.3912 0.8053 +vt 0.4118 0.1653 +vt 0.8347 0.2736 +vt 0.5882 0.2736 +vt 0.5882 0.1653 +vt 0.8347 0.3912 +vt 0.5882 0.3912 +vt 0.4118 0.1947 +vt 0.8053 0.2736 +vt 0.4118 0.2736 +vt 0.5882 0.1947 +vt 0.8053 0.3912 +vt 0.4118 0.3912 +vt 0.2941 0.1653 +vt 0.1653 0.2736 +vt 0.7059 0.2736 +vt 0.1653 0.3912 +vt 0.7059 0.1653 +vt 0.7059 0.3912 +vt 0.2941 0.1947 +vt 0.1947 0.2736 +vt 0.2941 0.2736 +vt 0.1947 0.3912 +vt 0.7059 0.1947 +vt 0.2941 0.3912 +vn 0 -1 0 +vn -1 0 0 +vn 0 0 1 +vn 0 1 0 +vn -1 0 0 +vn 0 0 1 +vn 0 -1 0 +vn -1 0 0 +vn 0 0 -1 +vn 0 1 0 +vn -1 0 0 +vn 0 0 -1 +vn 0 -1 0 +vn 1 0 0 +vn 0 0 1 +vn 1 0 0 +vn 0 1 0 +vn 0 0 1 +vn 0 -1 0 +vn 1 0 0 +vn 0 0 -1 +vn 1 0 0 +vn 0 1 0 +vn 0 0 -1 +f 51/151/151 55/163/163 53/157/157 49/145/145 +f 55/164/164 56/166/166 54/160/160 53/158/158 +f 56/167/167 52/154/154 50/148/148 54/161/161 +f 52/155/155 51/152/152 49/146/146 50/149/149 +f 52/156/156 56/168/168 55/165/165 51/153/153 +f 53/159/159 54/162/162 50/150/150 49/147/147 +o object_8 +usemtl New material 003 +v 0.2941 0.2736 0.8347 +v 0.2941 0.3912 0.8347 +v 0.2941 0.2736 0.8053 +v 0.2941 0.3912 0.8053 +v 0.4118 0.2736 0.8347 +v 0.4118 0.3912 0.8347 +v 0.4118 0.2736 0.8053 +v 0.4118 0.3912 0.8053 +vt 0.7059 0.1653 +vt 0.8347 0.2736 +vt 0.2941 0.2736 +vt 0.2941 0.1653 +vt 0.8347 0.3912 +vt 0.2941 0.3912 +vt 0.7059 0.1947 +vt 0.8053 0.2736 +vt 0.7059 0.2736 +vt 0.2941 0.1947 +vt 0.8053 0.3912 +vt 0.7059 0.3912 +vt 0.5882 0.1653 +vt 0.1653 0.2736 +vt 0.4118 0.2736 +vt 0.1653 0.3912 +vt 0.4118 0.1653 +vt 0.4118 0.3912 +vt 0.5882 0.1947 +vt 0.1947 0.2736 +vt 0.5882 0.2736 +vt 0.1947 0.3912 +vt 0.4118 0.1947 +vt 0.5882 0.3912 +vn 0 -1 0 +vn -1 0 0 +vn 0 0 1 +vn 0 1 0 +vn -1 0 0 +vn 0 0 1 +vn 0 -1 0 +vn -1 0 0 +vn 0 0 -1 +vn 0 1 0 +vn -1 0 0 +vn 0 0 -1 +vn 0 -1 0 +vn 1 0 0 +vn 0 0 1 +vn 1 0 0 +vn 0 1 0 +vn 0 0 1 +vn 0 -1 0 +vn 1 0 0 +vn 0 0 -1 +vn 1 0 0 +vn 0 1 0 +vn 0 0 -1 +f 59/175/175 63/187/187 61/181/181 57/169/169 +f 63/188/188 64/190/190 62/184/184 61/182/182 +f 64/191/191 60/178/178 58/172/172 62/185/185 +f 60/179/179 59/176/176 57/170/170 58/173/173 +f 60/180/180 64/192/192 63/189/189 59/177/177 +f 61/183/183 62/186/186 58/174/174 57/171/171 +o object_9 +usemtl New material 001 (1) +v 0.02313 0.6963 0.4272 +v 0.02313 0.4159 0.2973 +v 0.1395 0.7225 0.3699 +v 0.1395 0.4425 0.24 +v 0.1704 0.5819 0.6734 +v 0.1704 0.3018 0.5435 +v 0.2868 0.6084 0.6162 +v 0.2868 0.3283 0.4863 +vt 0.9769 0.6963 +vt 0.4272 0.6963 +vt 0.02313 0.5728 +vt 0.9769 0.4159 +vt 0.2973 0.4159 +vt 0.9769 0.7027 +vt 0.6301 0.7225 +vt 0.8605 0.7225 +vt 0.1395 0.6301 +vt 0.76 0.4425 +vt 0.8605 0.4425 +vt 0.8605 0.76 +vt 0.6734 0.5819 +vt 0.1704 0.5819 +vt 0.1704 0.3266 +vt 0.5435 0.3018 +vt 0.1704 0.3018 +vt 0.8296 0.4565 +vt 0.3838 0.6084 +vt 0.2868 0.6084 +vt 0.2868 0.3838 +vt 0.5137 0.3283 +vt 0.2868 0.3283 +vt 0.7132 0.5137 +vn -0.4768 0.3698 -0.7974 +vn -0.879 -0.2006 0.4325 +vn 0 0.9072 0.4207 +vn -0.4768 0.3698 -0.7974 +vn -0.879 -0.2006 0.4325 +vn 0 -0.9072 -0.4207 +vn 0.879 0.2006 -0.4325 +vn -0.4768 0.3698 -0.7974 +vn 0 0.9072 0.4207 +vn 0.879 0.2006 -0.4325 +vn -0.4768 0.3698 -0.7974 +vn 0 -0.9072 -0.4207 +vn -0.879 -0.2006 0.4325 +vn 0.4768 -0.3698 0.7974 +vn 0 0.9072 0.4207 +vn -0.879 -0.2006 0.4325 +vn 0.4768 -0.3698 0.7974 +vn 0 -0.9072 -0.4207 +vn 0.879 0.2006 -0.4325 +vn 0.4768 -0.3698 0.7974 +vn 0 0.9072 0.4207 +vn 0.879 0.2006 -0.4325 +vn 0.4768 -0.3698 0.7974 +vn 0 -0.9072 -0.4207 +f 72/214/214 68/202/202 67/199/199 71/211/211 +f 68/203/203 66/196/196 65/193/193 67/200/200 +f 66/197/197 70/208/208 69/205/205 65/194/194 +f 70/209/209 72/215/215 71/212/212 69/206/206 +f 66/198/198 68/204/204 72/216/216 70/210/210 +f 71/213/213 67/201/201 65/195/195 69/207/207 diff --git a/src/test/resources/assets/new_model_loader_test/textures/item/qr.png b/src/test/resources/assets/new_model_loader_test/textures/item/qr.png new file mode 100644 index 0000000000000000000000000000000000000000..05b2f3b33ba36fcfdb829ec05ff4907cd630e07f GIT binary patch literal 237 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!6r`^#}EtusgoS}8Vm%OR{#HBoSJGp>DG)B ziLwi-Gaeg0m)SpsJ58uDRlC#wM8g!B?Hk(S7DODe7A#A7%#<6y(A@f`QO%=0mZ^^mpR_DUw!y#t@U|Uc2mGkMCf(x%jtgpq={%plcXBUHx3vIVCg!0A$TshX4Qo literal 0 HcmV?d00001