diff --git a/README.md b/README.md index 9bff74a..8fd4645 100644 --- a/README.md +++ b/README.md @@ -16,14 +16,13 @@ Template blocks can be placed in the world, then right-clicked with a full-size ## Todo +* Fix the item model lol, broke it with the new system (might need a ModelLoadingRegistry registerVariantProvider as a last resort) * Re-generalize the model system (I removed a layer of indirection while rewriting it, so it's just slopes now) -* See what I can do about using the vanilla rotation system (`ModelBakeSettings.getRotation`) instead of manually rotating the `Mesh` - * A simplification of the mesh system would *definitely* reduce the friction of adding new meshes (see all the `paintXxx` stuff in `SlopeMeshTransformer`, it's fairly ugly) - * Upside-down slopes would be nice... -* (if i may): Packages-ish "retexturing" of json blockmodels +* Upside-down slopes would be nice... +* Pass UVs as part of the mesh and retexture them at runtime too ## Notes for addon developers To create your block, instantiate or extend `TemplateBlock`. Pass your `Block.Settings` through `TemplateBlock.configureSettings` to wire up the "click for glowstone" feature. Create an `ItemBlock` as normal, and create a `BlockEntityType` by instantiating or extending `TemplateEntity`. -Next, wire up the custom model. im going to refactor this in like 5 seconds so im not documenting it >:). \ No newline at end of file +Next, wire up the custom model todo document this, it's easy \ No newline at end of file diff --git a/src/main/java/io/github/cottonmc/templates/TemplatesClient.java b/src/main/java/io/github/cottonmc/templates/TemplatesClient.java index aafa948..6a952c0 100644 --- a/src/main/java/io/github/cottonmc/templates/TemplatesClient.java +++ b/src/main/java/io/github/cottonmc/templates/TemplatesClient.java @@ -1,6 +1,5 @@ package io.github.cottonmc.templates; -import io.github.cottonmc.templates.block.SlopeBlock; import io.github.cottonmc.templates.model.SlopeUnbakedModel; import io.github.cottonmc.templates.model.TemplateModelVariantProvider; import net.fabricmc.api.ClientModInitializer; @@ -14,7 +13,6 @@ import net.minecraft.resource.ResourceManager; import net.minecraft.resource.ResourceType; import net.minecraft.util.Identifier; import net.minecraft.util.math.ChunkSectionPos; -import net.minecraft.util.math.Direction; public class TemplatesClient implements ClientModInitializer { public static TemplateModelVariantProvider provider = new TemplateModelVariantProvider(); @@ -43,17 +41,10 @@ public class TemplatesClient implements ClientModInitializer { } }); - ModelLoadingRegistry.INSTANCE.registerVariantProvider(rm -> provider); + ModelLoadingRegistry.INSTANCE.registerResourceProvider(rm -> provider); + BlockRenderLayerMap.INSTANCE.putBlock(Templates.SLOPE, RenderLayer.getCutout()); - //ADDON DEVELOEPRS: do this! - provider.registerTemplateModels( - //block - Templates.SLOPE, - //the blockstate you'd like the item model to show - Templates.SLOPE.getDefaultState().with(SlopeBlock.FACING, Direction.EAST), - //Function that creates your model - SlopeUnbakedModel::new - ); + provider.addTemplateModel(Templates.id("slope_special"), SlopeUnbakedModel::new); } } diff --git a/src/main/java/io/github/cottonmc/templates/model/AffineQuadTransformer.java b/src/main/java/io/github/cottonmc/templates/model/AffineQuadTransformer.java index 705e72e..4cde530 100644 --- a/src/main/java/io/github/cottonmc/templates/model/AffineQuadTransformer.java +++ b/src/main/java/io/github/cottonmc/templates/model/AffineQuadTransformer.java @@ -3,8 +3,6 @@ package io.github.cottonmc.templates.model; import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView; import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; import net.minecraft.util.math.AffineTransformation; -import net.minecraft.util.math.AffineTransformations; -import net.minecraft.util.math.Direction; import org.joml.Matrix4f; import org.joml.Vector3f; import org.joml.Vector4f; @@ -16,40 +14,36 @@ public record AffineQuadTransformer(Matrix4f affineMatrix) implements RenderCont @Override public boolean transform(MutableQuadView quad) { - Matrix4f mat = affineMatrix; - //TODO: Hard Coded for DEBUGGING - mat = ( - AffineTransformations.DIRECTION_ROTATIONS.get(Direction.NORTH) - ).getMatrix(); - Vector3f pos3 = new Vector3f(); - //Vector3f norm3 = new Vector3f(); + Vector3f norm3 = new Vector3f(); //ugh Vector4f pos4 = new Vector4f(); - //Vector4f norm4 = new Vector4f(); + Vector4f norm4 = new Vector4f(); for(int i = 0; i < 4; i++) { //Copy quad data into vec3's quad.copyPos(i, pos3); - //quad.copyNormal(i, norm3); + quad.copyNormal(i, norm3); - pos3.add(-0.5f, -0.5f, -0.5f); //TODO HACK + pos3.add(-0.5f, -0.5f, -0.5f); //TODO, kinda a hack to center the affine transformation not at 0,0,0 //Initialize the x/y/z components of vec4s using that data //W component of normal vector is set to 1, normal vectors transform differently from points :) pos4.set(pos3, 0); - //norm4.set(norm3, 1); + norm4.set(norm3, 1); //Compute the matrix-vector product. This function mutates the vec4 in-place. //Note that `transformAffine` has the same purpose as `transform`; the difference is it //assumes (without checking) that the last row of the matrix is 0,0,0,1, as an optimization - mat.transformAffine(pos4); - //mat.transformAffine(norm4); + affineMatrix.transformAffine(pos4); + affineMatrix.transformAffine(norm4); //Manually copy the data back onto the vertex quad.pos(i, pos4.x + 0.5f, pos4.y + 0.5f, pos4.z + 0.5f); - //quad.normal(i, norm4.x, norm4.y + 1, norm4.z); + + //TODO: makes everything turn black for some reason (norm vec is (0, 0, 0)) + //quad.normal(i, norm4.x, norm4.y, norm4.z); } return true; diff --git a/src/main/java/io/github/cottonmc/templates/model/SlopeBakedModel.java b/src/main/java/io/github/cottonmc/templates/model/SlopeBakedModel.java index 7359bf2..36386c7 100644 --- a/src/main/java/io/github/cottonmc/templates/model/SlopeBakedModel.java +++ b/src/main/java/io/github/cottonmc/templates/model/SlopeBakedModel.java @@ -17,12 +17,12 @@ import java.util.function.Function; import java.util.function.Supplier; public final class SlopeBakedModel extends ForwardingBakedModel { - public SlopeBakedModel(BakedModel baseModel, BlockState slopeState, AffineTransformation aff, Function spriteLookup) { + public SlopeBakedModel(BakedModel baseModel, Function spriteLookup, AffineTransformation aff) { this.wrapped = baseModel; this.preparer = new SlopeMeshTransformPreparer(spriteLookup); this.affineTransformer = new AffineQuadTransformer(aff); - this.baseMesh = SlopeBaseMesh.make(slopeState.getBlock().getDefaultState()); //TODO + this.baseMesh = SlopeBaseMesh.make(); } private final TemplateQuadTransformPreparer preparer; diff --git a/src/main/java/io/github/cottonmc/templates/model/SlopeBaseMesh.java b/src/main/java/io/github/cottonmc/templates/model/SlopeBaseMesh.java index 4abe2e2..4dc6fef 100644 --- a/src/main/java/io/github/cottonmc/templates/model/SlopeBaseMesh.java +++ b/src/main/java/io/github/cottonmc/templates/model/SlopeBaseMesh.java @@ -5,106 +5,25 @@ import net.fabricmc.fabric.api.renderer.v1.RendererAccess; import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh; import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder; import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter; -import net.minecraft.block.BlockState; -import net.minecraft.state.property.Properties; -import net.minecraft.util.math.Direction; public class SlopeBaseMesh { - public static Mesh make(BlockState state) { - Renderer renderer = RendererAccess.INSTANCE.getRenderer(); - if(renderer == null) throw new IllegalStateException("RenderAccess.INSTANCE not populated - no Fabric Renderer API?"); - - final MeshBuilder builder = renderer.meshBuilder(); - final QuadEmitter quad = builder.getEmitter(); - final Direction dir = state.get(Properties.HORIZONTAL_FACING); - drawSlope(quad.color(-1, -1, -1, -1), dir); - drawLeftSide(quad.color(-1, -1, -1, -1), dir); - drawRightSide(quad.color(-1, -1, -1, -1), dir); - drawBack(quad.color(-1, -1, -1, -1), dir); - drawBottom(quad.color(-1, -1, -1, -1)); - return builder.build(); - } - public static final int TAG_SLOPE = 0; public static final int TAG_LEFT = 1; public static final int TAG_RIGHT = 2; public static final int TAG_BACK = 3; public static final int TAG_BOTTOM = 4; - private static void drawSlope(QuadEmitter quad, Direction dir) { - quad.tag(TAG_SLOPE); - switch(dir) { - case NORTH: - quad.pos(0, 0f, 1f, 0f).pos(1, 0f, 0f, 1f).pos(2, 1f, 0f, 1f).pos(3, 1f, 1f, 0f).emit(); - break; - case SOUTH: - quad.pos(0, 0f, 0f, 0f).pos(1, 0f, 1f, 1f).pos(2, 1f, 1f, 1f).pos(3, 1f, 0f, 0f).emit(); - break; - case EAST: - quad.pos(0, 0f, 0f, 0f).pos(1, 0f, 0f, 1f).pos(2, 1f, 1f, 1f).pos(3, 1f, 1f, 0f).emit(); - break; - case WEST: - quad.pos(0, 0f, 1f, 0f).pos(1, 0f, 1f, 1f).pos(2, 1f, 0f, 1f).pos(3, 1f, 0f, 0f).emit(); - default: - break; - } - } - - private static void drawLeftSide(QuadEmitter quad, Direction dir) { - switch(dir) { - case NORTH: - quad.tag(TAG_LEFT).pos(0, 0f, 0f, 0f).pos(1, 0f, 0f, 1f).pos(2, 0f, 0f, 1f).pos(3, 0f, 1f, 0f).emit(); - break; - case SOUTH: - quad.tag(TAG_LEFT).pos(0, 1f, 0f, 0f).pos(1, 1f, 1f, 1f).pos(2, 1f, 0f, 1f).pos(3, 1f, 0f, 1f).emit(); - break; - case EAST: - quad.tag(TAG_LEFT).pos(0, 1f, 0f, 0f).pos(1, 0f, 0f, 0f).pos(2, 0f, 0f, 0f).pos(3, 1f, 1f, 0f).emit(); - break; - case WEST: - quad.tag(TAG_LEFT).pos(0, 0f, 0f, 1f).pos(1, 1f, 0f, 1f).pos(2, 1f, 0f, 1f).pos(3, 0f, 1f, 1f).emit(); - default: - break; - } - } - - private static void drawRightSide(QuadEmitter quad, Direction dir) { - switch(dir) { - case NORTH: - quad.tag(TAG_RIGHT).pos(0, 1f, 0f, 0f).pos(1, 1f, 1f, 0f).pos(2, 1f, 0f, 1f).pos(3, 1f, 0f, 1f).emit(); - break; - case SOUTH: - quad.tag(TAG_RIGHT).pos(0, 0f, 0f, 0f).pos(1, 0f, 0f, 0f).pos(2, 0f, 0f, 1f).pos(3, 0f, 1f, 1f).emit(); - break; - case EAST: - quad.tag(TAG_RIGHT).pos(0, 0f, 0f, 1f).pos(1, 0f, 0f, 1f).pos(2, 1f, 0f, 1f).pos(3, 1f, 1f, 1f).emit(); - break; - case WEST: - quad.tag(TAG_RIGHT).pos(0, 0f, 0f, 0f).pos(1, 0f, 1f, 0f).pos(2, 1f, 0f, 0f).pos(3, 1f, 0f, 0f).emit(); - default: - break; - } - } - - private static void drawBack(QuadEmitter quad, Direction dir) { - switch(dir) { - case NORTH: - quad.tag(TAG_BACK).pos(0, 0f, 0f, 0f).pos(1, 0f, 1f, 0f).pos(2, 1f, 1f, 0f).pos(3, 1f, 0f, 0f).emit(); - break; - case SOUTH: - quad.tag(TAG_BACK).pos(0, 0f, 0f, 1f).pos(1, 1f, 0f, 1f).pos(2, 1f, 1f, 1f).pos(3, 0f, 1f, 1f).emit(); - break; - case EAST: - quad.tag(TAG_BACK).pos(0, 1f, 0f, 0f).pos(1, 1f, 1f, 0f).pos(2, 1f, 1f, 1f).pos(3, 1f, 0f, 1f).emit(); - break; - case WEST: - quad.tag(TAG_BACK).pos(0, 0f, 0f, 0f).pos(1, 0f, 0f, 1f).pos(2, 0f, 1f, 1f).pos(3, 0f, 1f, 0f).emit(); - default: - break; - } - } - - private static void drawBottom(QuadEmitter quad) { - quad.tag(TAG_BOTTOM).pos(0, 0f, 0f, 0f).pos(1, 1f, 0f, 0f).pos(2, 1f, 0f, 1f).pos(3, 0f, 0f, 1f).emit(); + public static Mesh make() { + Renderer renderer = RendererAccess.INSTANCE.getRenderer(); + if(renderer == null) throw new IllegalStateException("RenderAccess.INSTANCE not populated - no Fabric Renderer API?"); + + MeshBuilder builder = renderer.meshBuilder(); + QuadEmitter qu = builder.getEmitter(); + qu.color(-1, -1, -1, -1).tag(TAG_SLOPE) .pos(0, 0f, 0f, 0f).pos(1, 0f, 1f, 1f).pos(2, 1f, 1f, 1f).pos(3, 1f, 0f, 0f).emit() + .color(-1, -1, -1, -1).tag(TAG_LEFT) .pos(0, 1f, 0f, 0f).pos(1, 1f, 1f, 1f).pos(2, 1f, 0f, 1f).pos(3, 1f, 0f, 1f).emit() + .color(-1, -1, -1, -1).tag(TAG_RIGHT) .pos(0, 0f, 0f, 0f).pos(1, 0f, 0f, 0f).pos(2, 0f, 0f, 1f).pos(3, 0f, 1f, 1f).emit() + .color(-1, -1, -1, -1).tag(TAG_BACK) .pos(0, 0f, 0f, 1f).pos(1, 1f, 0f, 1f).pos(2, 1f, 1f, 1f).pos(3, 0f, 1f, 1f).emit() + .color(-1, -1, -1, -1).tag(TAG_BOTTOM).pos(0, 0f, 0f, 0f).pos(1, 1f, 0f, 0f).pos(2, 1f, 0f, 1f).pos(3, 0f, 0f, 1f).emit(); + return builder.build(); } } diff --git a/src/main/java/io/github/cottonmc/templates/model/SlopeUnbakedModel.java b/src/main/java/io/github/cottonmc/templates/model/SlopeUnbakedModel.java index bcea86c..32c25c2 100644 --- a/src/main/java/io/github/cottonmc/templates/model/SlopeUnbakedModel.java +++ b/src/main/java/io/github/cottonmc/templates/model/SlopeUnbakedModel.java @@ -1,6 +1,5 @@ package io.github.cottonmc.templates.model; -import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.client.render.block.BlockModels; import net.minecraft.client.render.model.BakedModel; @@ -15,7 +14,7 @@ import java.util.Collection; import java.util.Collections; import java.util.function.Function; -public record SlopeUnbakedModel(BlockState slopeState) implements UnbakedModel { +public class SlopeUnbakedModel implements UnbakedModel { @Override public Collection getModelDependencies() { return Collections.emptyList(); @@ -28,10 +27,9 @@ public record SlopeUnbakedModel(BlockState slopeState) implements UnbakedModel { @Override public BakedModel bake(Baker baker, Function function, ModelBakeSettings modelBakeSettings, Identifier identifier) { - //TODO: weird, should use my own model instead + //TODO: this is weird, should use my own model instead BakedModel baseModel = baker.bake(BlockModels.getModelId(Blocks.SANDSTONE_STAIRS.getDefaultState()), modelBakeSettings); - //TODO: ModelBakeSettings.getRotation is always the identity transform atm - return new SlopeBakedModel(baseModel, slopeState, modelBakeSettings.getRotation(), function); + return new SlopeBakedModel(baseModel, function, modelBakeSettings.getRotation()); } } diff --git a/src/main/java/io/github/cottonmc/templates/model/TemplateModelVariantProvider.java b/src/main/java/io/github/cottonmc/templates/model/TemplateModelVariantProvider.java index 93fc4fc..92216f3 100644 --- a/src/main/java/io/github/cottonmc/templates/model/TemplateModelVariantProvider.java +++ b/src/main/java/io/github/cottonmc/templates/model/TemplateModelVariantProvider.java @@ -2,34 +2,29 @@ package io.github.cottonmc.templates.model; import net.fabricmc.fabric.api.client.model.ModelProviderContext; import net.fabricmc.fabric.api.client.model.ModelProviderException; -import net.fabricmc.fabric.api.client.model.ModelVariantProvider; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.client.render.block.BlockModels; +import net.fabricmc.fabric.api.client.model.ModelResourceProvider; import net.minecraft.client.render.model.UnbakedModel; -import net.minecraft.client.util.ModelIdentifier; -import net.minecraft.registry.Registries; +import net.minecraft.util.Identifier; import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.Map; -import java.util.function.Function; import java.util.function.Supplier; -public class TemplateModelVariantProvider implements ModelVariantProvider { - private final Map> factories = new HashMap<>(); - private final Map cache = new HashMap<>(); +public class TemplateModelVariantProvider implements ModelResourceProvider { + private final Map> factories = new HashMap<>(); + private final Map cache = new HashMap<>(); @Override - public @Nullable UnbakedModel loadModelVariant(ModelIdentifier modelId, ModelProviderContext context) throws ModelProviderException { - UnbakedModel cacheResult = cache.get(modelId); + public @Nullable UnbakedModel loadModelResource(Identifier resourceId, ModelProviderContext context) throws ModelProviderException { + UnbakedModel cacheResult = cache.get(resourceId); if(cacheResult != null) return cacheResult; //Either we have a factory for this model (just haven't cached its output yet), - Supplier factory = factories.get(modelId); + Supplier factory = factories.get(resourceId); if(factory != null) { UnbakedModel freshModel = factory.get(); - cache.put(modelId, freshModel); + cache.put(resourceId, freshModel); return freshModel; } @@ -37,9 +32,8 @@ public class TemplateModelVariantProvider implements ModelVariantProvider { return null; } - public void registerTemplateModels(Block block, BlockState itemState, Function model) { - for(BlockState state : block.getStateManager().getStates()) factories.put(BlockModels.getModelId(state), () -> model.apply(state)); - factories.put(new ModelIdentifier(Registries.ITEM.getId(block.asItem()), "inventory"), () -> model.apply(itemState)); + public void addTemplateModel(Identifier id, Supplier modelFactory) { + factories.put(id, modelFactory); } public void dumpCache() { diff --git a/src/main/resources/assets/templates/blockstates/slope.json b/src/main/resources/assets/templates/blockstates/slope.json new file mode 100644 index 0000000..4e51b33 --- /dev/null +++ b/src/main/resources/assets/templates/blockstates/slope.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "templates:slope_special", + "y": 270 + }, + "facing=north": { + "model": "templates:slope_special", + "y": 180 + }, + "facing=south": { + "model": "templates:slope_special" + }, + "facing=west": { + "model": "templates:slope_special", + "y": 90 + } + } +} \ No newline at end of file