🦈 GET ROTATED Idiot 🦈
This commit is contained in:
parent
e1408c5a7a
commit
338e45d016
@ -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
|
||||
* 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 >:).
|
||||
Next, wire up the custom model todo document this, it's easy
|
@ -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<BlockState, UnbakedModel> that creates your model
|
||||
SlopeUnbakedModel::new
|
||||
);
|
||||
provider.addTemplateModel(Templates.id("slope_special"), SlopeUnbakedModel::new);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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<SpriteIdentifier, Sprite> spriteLookup) {
|
||||
public SlopeBakedModel(BakedModel baseModel, Function<SpriteIdentifier, Sprite> 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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
public static Mesh make() {
|
||||
Renderer renderer = RendererAccess.INSTANCE.getRenderer();
|
||||
if(renderer == null) throw new IllegalStateException("RenderAccess.INSTANCE not populated - no Fabric Renderer API?");
|
||||
|
||||
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();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -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<Identifier> getModelDependencies() {
|
||||
return Collections.emptyList();
|
||||
@ -28,10 +27,9 @@ public record SlopeUnbakedModel(BlockState slopeState) implements UnbakedModel {
|
||||
|
||||
@Override
|
||||
public BakedModel bake(Baker baker, Function<SpriteIdentifier, Sprite> 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());
|
||||
}
|
||||
}
|
||||
|
@ -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<ModelIdentifier, Supplier<UnbakedModel>> factories = new HashMap<>();
|
||||
private final Map<ModelIdentifier, UnbakedModel> cache = new HashMap<>();
|
||||
public class TemplateModelVariantProvider implements ModelResourceProvider {
|
||||
private final Map<Identifier, Supplier<UnbakedModel>> factories = new HashMap<>();
|
||||
private final Map<Identifier, UnbakedModel> 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<UnbakedModel> factory = factories.get(modelId);
|
||||
Supplier<UnbakedModel> 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<BlockState, UnbakedModel> 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<UnbakedModel> modelFactory) {
|
||||
factories.put(id, modelFactory);
|
||||
}
|
||||
|
||||
public void dumpCache() {
|
||||
|
19
src/main/resources/assets/templates/blockstates/slope.json
Normal file
19
src/main/resources/assets/templates/blockstates/slope.json
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user