Render without BlockEntityRenderer (#2)
* Add model-based rendering * Add model-based rendering * Rebase, clean up, fix rendering * Update to newer Fabric API - fixes Indigo bug w/ render layers * Fuss with lighting, ran out of time.
This commit is contained in:
parent
07abe31ea4
commit
197f57f202
@ -44,7 +44,7 @@ dependencies {
|
|||||||
minecraft "com.mojang:minecraft:1.14.2"
|
minecraft "com.mojang:minecraft:1.14.2"
|
||||||
mappings "net.fabricmc:yarn:1.14.2+build.7"
|
mappings "net.fabricmc:yarn:1.14.2+build.7"
|
||||||
modCompile "net.fabricmc:fabric-loader:0.4.8+build.154"
|
modCompile "net.fabricmc:fabric-loader:0.4.8+build.154"
|
||||||
modCompile "net.fabricmc.fabric-api:fabric-api:0.3.0+build.179"
|
modCompile "net.fabricmc.fabric-api:fabric-api:0.3.0+build.185"
|
||||||
|
|
||||||
implementation "com.google.code.findbugs:jsr305:3.0.2"
|
implementation "com.google.code.findbugs:jsr305:3.0.2"
|
||||||
|
|
||||||
|
@ -15,7 +15,8 @@ public class SlopeTest implements ModInitializer {
|
|||||||
public static final String MODID = "slopetest";
|
public static final String MODID = "slopetest";
|
||||||
|
|
||||||
public static final Block SLOPE = register("slope", new SlopeTestBlock(), ItemGroup.DECORATIONS);
|
public static final Block SLOPE = register("slope", new SlopeTestBlock(), ItemGroup.DECORATIONS);
|
||||||
public static final BlockEntityType<SlopeTestEntity> SLOPE_ENTITY = register("slope", SlopeTestEntity::new, SLOPE);
|
@SuppressWarnings("unchecked")
|
||||||
|
public static final BlockEntityType<SlopeTestEntity> SLOPE_ENTITY = register("slope", SlopeTestEntity::new, SLOPE);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInitialize() {
|
public void onInitialize() {
|
||||||
@ -29,7 +30,8 @@ public class SlopeTest implements ModInitializer {
|
|||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlockEntityType register(String name, Supplier<BlockEntity> be, Block...blocks) {
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static BlockEntityType register(String name, Supplier<BlockEntity> be, Block...blocks) {
|
||||||
return Registry.register(Registry.BLOCK_ENTITY, new Identifier(MODID, name), BlockEntityType.Builder.create(be, blocks).build(null));
|
return Registry.register(Registry.BLOCK_ENTITY, new Identifier(MODID, name), BlockEntityType.Builder.create(be, blocks).build(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package io.github.cottonmc.slopetest;
|
package io.github.cottonmc.slopetest;
|
||||||
|
|
||||||
import io.github.cottonmc.slopetest.block.entity.SlopeTestEntity;
|
import io.github.cottonmc.slopetest.model.SlopeModelVariantProvider;
|
||||||
import io.github.cottonmc.slopetest.block.entity.render.SlopeTestRenderer;
|
|
||||||
import net.fabricmc.api.ClientModInitializer;
|
import net.fabricmc.api.ClientModInitializer;
|
||||||
import net.fabricmc.fabric.api.client.render.BlockEntityRendererRegistry;
|
import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry;
|
||||||
|
|
||||||
public class SlopeTestClient implements ClientModInitializer {
|
public class SlopeTestClient implements ClientModInitializer {
|
||||||
@Override
|
@Override
|
||||||
public void onInitializeClient() {
|
public void onInitializeClient() {
|
||||||
BlockEntityRendererRegistry.INSTANCE.register(SlopeTestEntity.class, new SlopeTestRenderer());
|
//BlockEntityRendererRegistry.INSTANCE.register(SlopeTestEntity.class, new SlopeTestRenderer());
|
||||||
|
ModelLoadingRegistry.INSTANCE.registerVariantProvider(rm -> new SlopeModelVariantProvider());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,10 +84,10 @@ public class SlopeTestBlock extends Block implements BlockEntityProvider {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// @Override
|
||||||
public BlockRenderType getRenderType(BlockState state) {
|
// public BlockRenderType getRenderType(BlockState state) {
|
||||||
return BlockRenderType.INVISIBLE;
|
// return BlockRenderType.INVISIBLE;
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBlockRemoved(BlockState state, World world, BlockPos pos, BlockState newState, boolean boolean_1) {
|
public void onBlockRemoved(BlockState state, World world, BlockPos pos, BlockState newState, boolean boolean_1) {
|
||||||
|
@ -3,18 +3,18 @@ package io.github.cottonmc.slopetest.block.entity;
|
|||||||
import io.github.cottonmc.slopetest.SlopeTest;
|
import io.github.cottonmc.slopetest.SlopeTest;
|
||||||
import io.github.cottonmc.slopetest.util.BlockStateUtil;
|
import io.github.cottonmc.slopetest.util.BlockStateUtil;
|
||||||
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable;
|
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable;
|
||||||
|
import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachmentBlockEntity;
|
||||||
import net.fabricmc.fabric.api.server.PlayerStream;
|
import net.fabricmc.fabric.api.server.PlayerStream;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.block.entity.BlockEntity;
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.client.world.ClientWorld;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
import net.minecraft.util.registry.Registry;
|
|
||||||
|
|
||||||
public class SlopeTestEntity extends BlockEntity implements BlockEntityClientSerializable {
|
|
||||||
private BlockState renderedState = Blocks.AIR.getDefaultState();
|
|
||||||
|
|
||||||
|
public class SlopeTestEntity extends BlockEntity implements BlockEntityClientSerializable, RenderAttachmentBlockEntity {
|
||||||
|
private BlockState renderedState = Blocks.AIR.getDefaultState();
|
||||||
|
|
||||||
public SlopeTestEntity() {
|
public SlopeTestEntity() {
|
||||||
super(SlopeTest.SLOPE_ENTITY);
|
super(SlopeTest.SLOPE_ENTITY);
|
||||||
}
|
}
|
||||||
@ -32,6 +32,9 @@ public class SlopeTestEntity extends BlockEntity implements BlockEntityClientSer
|
|||||||
public void fromTag(CompoundTag tag) {
|
public void fromTag(CompoundTag tag) {
|
||||||
super.fromTag(tag);
|
super.fromTag(tag);
|
||||||
renderedState = BlockStateUtil.fromTag(tag);
|
renderedState = BlockStateUtil.fromTag(tag);
|
||||||
|
if (world.isClient) {
|
||||||
|
((ClientWorld)world).scheduleBlockRender(pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -61,4 +64,9 @@ public class SlopeTestEntity extends BlockEntity implements BlockEntityClientSer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getRenderAttachmentData() {
|
||||||
|
return renderedState;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,204 +0,0 @@
|
|||||||
package io.github.cottonmc.slopetest.block.entity.render;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.platform.GlStateManager;
|
|
||||||
import io.github.cottonmc.slopetest.util.SpriteSet;
|
|
||||||
import io.github.cottonmc.slopetest.block.entity.SlopeTestEntity;
|
|
||||||
import net.fabricmc.fabric.api.client.render.ColorProviderRegistry;
|
|
||||||
import net.minecraft.block.BlockState;
|
|
||||||
import net.minecraft.block.Blocks;
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
import net.minecraft.client.color.block.BlockColorProvider;
|
|
||||||
import net.minecraft.client.render.BufferBuilder;
|
|
||||||
import net.minecraft.client.render.Tessellator;
|
|
||||||
import net.minecraft.client.render.VertexFormats;
|
|
||||||
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
|
|
||||||
import net.minecraft.client.render.model.BakedModel;
|
|
||||||
import net.minecraft.client.texture.Sprite;
|
|
||||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
|
||||||
import net.minecraft.state.property.Properties;
|
|
||||||
import net.minecraft.util.math.Direction;
|
|
||||||
import org.lwjgl.opengl.GL11;
|
|
||||||
|
|
||||||
public class SlopeTestRenderer extends BlockEntityRenderer<SlopeTestEntity> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render(SlopeTestEntity be, double x, double y, double z, float partialTicks, int destroyStage) {
|
|
||||||
final Tessellator tessellator = Tessellator.getInstance();
|
|
||||||
final BufferBuilder buffer = tessellator.getBufferBuilder();
|
|
||||||
MinecraftClient minecraft = MinecraftClient.getInstance();
|
|
||||||
buffer.setOffset(x, y, z);
|
|
||||||
GlStateManager.enableBlend();
|
|
||||||
GlStateManager.disableAlphaTest();
|
|
||||||
GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
|
|
||||||
renderManager.textureManager.bindTexture(SpriteAtlasTexture.BLOCK_ATLAS_TEX);
|
|
||||||
BlockState state = getWorld().getBlockState(be.getPos());
|
|
||||||
Direction dir = state.get(Properties.HORIZONTAL_FACING);
|
|
||||||
SpriteSet sprites;
|
|
||||||
int color = 0xffffff;
|
|
||||||
if (be.getRenderedState().getBlock() != Blocks.AIR) {
|
|
||||||
BlockState renderedState = be.getRenderedState();
|
|
||||||
BakedModel model = minecraft.getBlockRenderManager().getModel(renderedState);
|
|
||||||
sprites = new SpriteSet(model);
|
|
||||||
BlockColorProvider blockColor = ColorProviderRegistry.BLOCK.get(be.getRenderedState().getBlock());
|
|
||||||
if (blockColor != null) {
|
|
||||||
color = blockColor.getColor(renderedState, be.getWorld(), be.getPos(), 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sprites = new SpriteSet(minecraft.getSpriteAtlas().getSprite("minecraft:block/scaffolding_top"), false);
|
|
||||||
}
|
|
||||||
buffer.begin(GL11.GL_QUADS, VertexFormats.POSITION_UV_COLOR);
|
|
||||||
drawSlope(dir, sprites.getSprite(Direction.UP), buffer, sprites.hasColor(Direction.UP)? color : 0xffffff);
|
|
||||||
drawLeftSide(dir, sprites.getSprite(dir.rotateYCounterclockwise()), buffer, sprites.hasColor(dir.rotateYCounterclockwise())? color : 0xffffff);
|
|
||||||
drawRightSide(dir, sprites.getSprite(dir.rotateYClockwise()), buffer, sprites.hasColor(dir.rotateYClockwise())? color: 0xffffff);
|
|
||||||
drawBack(dir, sprites.getSprite(dir), buffer, sprites.hasColor(dir)? color : 0xffffff);
|
|
||||||
drawBottom(sprites.getSprite(Direction.DOWN), buffer, sprites.hasColor(Direction.DOWN)? color : 0xffffff);
|
|
||||||
GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F);
|
|
||||||
tessellator.draw();
|
|
||||||
GlStateManager.disableBlend();
|
|
||||||
GlStateManager.enableAlphaTest();
|
|
||||||
buffer.setOffset(0.0d, 0.0d, 0.0d);
|
|
||||||
super.render(be, x, y, z, partialTicks, destroyStage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void drawSlope(Direction dir, Sprite sprite, BufferBuilder buffer, int color) {
|
|
||||||
float r = (float)(color >> 16 & 255) / 255.0F;
|
|
||||||
float g = (float)(color >> 8 & 255) / 255.0F;
|
|
||||||
float b = (float)(color & 255) / 255.0F;
|
|
||||||
switch (dir) {
|
|
||||||
case NORTH:
|
|
||||||
buffer.vertex(0f, 1f, 0f).texture(sprite.getMinU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 0f, 1f).texture(sprite.getMinU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 0f, 1f).texture(sprite.getMaxU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 1f, 0f).texture(sprite.getMaxU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
break;
|
|
||||||
case SOUTH:
|
|
||||||
buffer.vertex(0f, 0f, 0f).texture(sprite.getMaxU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 1f, 1f).texture(sprite.getMaxU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 1f, 1f).texture(sprite.getMinU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 0f, 0f).texture(sprite.getMinU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
break;
|
|
||||||
case EAST:
|
|
||||||
buffer.vertex(0f, 0f, 0f).texture(sprite.getMinU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 0f, 1f).texture(sprite.getMaxU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 1f, 1f).texture(sprite.getMaxU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 1f, 0f).texture(sprite.getMinU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
break;
|
|
||||||
case WEST:
|
|
||||||
buffer.vertex(0f, 1f, 0f).texture(sprite.getMaxU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 1f, 1f).texture(sprite.getMinU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 0f, 1f).texture(sprite.getMinU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 0f, 0f).texture(sprite.getMaxU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void drawLeftSide(Direction dir, Sprite sprite, BufferBuilder buffer, int color) {
|
|
||||||
float r = (float)(color >> 16 & 255) / 255.0F;
|
|
||||||
float g = (float)(color >> 8 & 255) / 255.0F;
|
|
||||||
float b = (float)(color & 255) / 255.0F;
|
|
||||||
switch(dir) {
|
|
||||||
case NORTH:
|
|
||||||
buffer.vertex(0f, 0f, 0f).texture(sprite.getMinU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 0f, 1f).texture(sprite.getMaxU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 0f, 1f).texture(sprite.getMaxU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 1f, 0f).texture(sprite.getMinU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
break;
|
|
||||||
case SOUTH:
|
|
||||||
buffer.vertex(1f, 0f, 0f).texture(sprite.getMaxU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 1f, 1f).texture(sprite.getMinU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 0f, 1f).texture(sprite.getMinU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 0f, 0f).texture(sprite.getMaxU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
break;
|
|
||||||
case EAST:
|
|
||||||
buffer.vertex(1f, 0f, 0f).texture(sprite.getMinU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 0f, 0f).texture(sprite.getMaxU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 0f, 0f).texture(sprite.getMaxU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 1f, 0f).texture(sprite.getMinU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
break;
|
|
||||||
case WEST:
|
|
||||||
buffer.vertex(0f, 0f, 1f).texture(sprite.getMinU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 0f, 1f).texture(sprite.getMaxU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 0f, 1f).texture(sprite.getMaxU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 1f, 1f).texture(sprite.getMinU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void drawRightSide(Direction dir, Sprite sprite, BufferBuilder buffer, int color) {
|
|
||||||
float r = (float)(color >> 16 & 255) / 255.0F;
|
|
||||||
float g = (float)(color >> 8 & 255) / 255.0F;
|
|
||||||
float b = (float)(color & 255) / 255.0F;
|
|
||||||
switch(dir) {
|
|
||||||
case NORTH:
|
|
||||||
buffer.vertex(1f, 0f, 0f).texture(sprite.getMaxU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 1f, 0f).texture(sprite.getMaxU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 0f, 1f).texture(sprite.getMinU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 0f, 1f).texture(sprite.getMinU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
break;
|
|
||||||
case SOUTH:
|
|
||||||
buffer.vertex(0f, 0f, 0f).texture(sprite.getMinU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 0f, 0f).texture(sprite.getMinU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 0f, 1f).texture(sprite.getMaxU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 1f, 1f).texture(sprite.getMaxU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
break;
|
|
||||||
case EAST:
|
|
||||||
buffer.vertex(0f, 0f, 1f).texture(sprite.getMinU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 0f, 1f).texture(sprite.getMinU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 0f, 1f).texture(sprite.getMaxU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 1f, 1f).texture(sprite.getMaxU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
break;
|
|
||||||
case WEST:
|
|
||||||
buffer.vertex(0f, 0f, 0f).texture(sprite.getMaxU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 1f, 0f).texture(sprite.getMaxU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 0f, 0f).texture(sprite.getMinU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 0f, 0f).texture(sprite.getMinU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void drawBack(Direction dir, Sprite sprite, BufferBuilder buffer, int color) {
|
|
||||||
float r = (float)(color >> 16 & 255) / 255.0F;
|
|
||||||
float g = (float)(color >> 8 & 255) / 255.0F;
|
|
||||||
float b = (float)(color & 255) / 255.0F;
|
|
||||||
switch(dir) {
|
|
||||||
case NORTH:
|
|
||||||
buffer.vertex(0f, 0f, 0f).texture(sprite.getMaxU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 1f, 0f).texture(sprite.getMaxU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 1f, 0f).texture(sprite.getMinU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 0f, 0f).texture(sprite.getMinU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
break;
|
|
||||||
case SOUTH:
|
|
||||||
buffer.vertex(0f, 0f, 1f).texture(sprite.getMinU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 0f, 1f).texture(sprite.getMaxU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 1f, 1f).texture(sprite.getMaxU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 1f, 1f).texture(sprite.getMinU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
break;
|
|
||||||
case EAST:
|
|
||||||
buffer.vertex(1f, 0f, 0f).texture(sprite.getMaxU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 1f, 0f).texture(sprite.getMaxU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 1f, 1f).texture(sprite.getMinU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 0f, 1f).texture(sprite.getMinU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
break;
|
|
||||||
case WEST:
|
|
||||||
buffer.vertex(0f, 0f, 0f).texture(sprite.getMinU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 0f, 1f).texture(sprite.getMaxU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 1f, 1f).texture(sprite.getMaxU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 1f, 0f).texture(sprite.getMinU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void drawBottom(Sprite sprite, BufferBuilder buffer, int color) {
|
|
||||||
float r = (float)(color >> 16 & 255) / 255.0F;
|
|
||||||
float g = (float)(color >> 8 & 255) / 255.0F;
|
|
||||||
float b = (float)(color & 255) / 255.0F;
|
|
||||||
buffer.vertex(0f, 0f, 0f).texture(sprite.getMinU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 0f, 0f).texture(sprite.getMaxU(), sprite.getMaxV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(1f, 0f, 1f).texture(sprite.getMaxU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
buffer.vertex(0f, 0f, 1f).texture(sprite.getMinU(), sprite.getMinV()).color(r, g, b, 1f).next();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,47 @@
|
|||||||
|
package io.github.cottonmc.slopetest.model;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
|
||||||
|
import net.minecraft.client.render.model.BakedModel;
|
||||||
|
import net.minecraft.client.render.model.json.ModelTransformation;
|
||||||
|
import net.minecraft.client.texture.Sprite;
|
||||||
|
|
||||||
|
public abstract class AbstractModel implements BakedModel, FabricBakedModel {
|
||||||
|
protected static final Renderer RENDERER = RendererAccess.INSTANCE.getRenderer();
|
||||||
|
|
||||||
|
protected final Sprite modelSprite;
|
||||||
|
protected final ModelTransformation transformation;
|
||||||
|
|
||||||
|
protected AbstractModel(
|
||||||
|
Sprite sprite,
|
||||||
|
ModelTransformation transformation) {
|
||||||
|
this.modelSprite = sprite;
|
||||||
|
this.transformation = transformation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useAmbientOcclusion() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasDepthInGui() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBuiltin() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Sprite getSprite() {
|
||||||
|
return modelSprite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ModelTransformation getTransformation() {
|
||||||
|
return transformation;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package io.github.cottonmc.slopetest.model;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext.QuadTransform;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.ExtendedBlockView;
|
||||||
|
|
||||||
|
public interface MeshTransformer extends QuadTransform {
|
||||||
|
MeshTransformer prepare(ExtendedBlockView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier);
|
||||||
|
|
||||||
|
MeshTransformer prepare(ItemStack stack, Supplier<Random> randomSupplier);
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
package io.github.cottonmc.slopetest.model;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.client.render.model.BakedModel;
|
||||||
|
import net.minecraft.client.render.model.BakedQuad;
|
||||||
|
import net.minecraft.client.render.model.json.ModelItemPropertyOverrideList;
|
||||||
|
import net.minecraft.client.render.model.json.ModelTransformation;
|
||||||
|
import net.minecraft.client.texture.Sprite;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.world.ExtendedBlockView;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple baked model supporting the Fabric Render API features.<p>
|
||||||
|
*/
|
||||||
|
public class SimpleModel extends AbstractModel {
|
||||||
|
protected final Mesh mesh;
|
||||||
|
protected final Supplier<MeshTransformer> transformerFactory;
|
||||||
|
protected WeakReference<List<BakedQuad>[]> quadLists = null;
|
||||||
|
protected final ItemProxy itemProxy = new ItemProxy();
|
||||||
|
|
||||||
|
public SimpleModel(
|
||||||
|
Mesh mesh,
|
||||||
|
Supplier<MeshTransformer> transformerFactory,
|
||||||
|
Sprite sprite,
|
||||||
|
ModelTransformation transformation) {
|
||||||
|
super(sprite, transformation);
|
||||||
|
this.mesh = mesh;
|
||||||
|
this.transformerFactory = transformerFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isVanillaAdapter() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BakedQuad> getQuads(BlockState state, Direction face, Random rand) {
|
||||||
|
List<BakedQuad>[] lists = quadLists == null ? null : quadLists.get();
|
||||||
|
if(lists == null) {
|
||||||
|
lists = ModelHelper.toQuadLists(this.mesh);
|
||||||
|
quadLists = new WeakReference<>(lists);
|
||||||
|
}
|
||||||
|
List<BakedQuad> result = lists[face == null ? 6 : face.getId()];
|
||||||
|
return result == null ? ImmutableList.of() : result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void emitBlockQuads(ExtendedBlockView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
|
||||||
|
final MeshTransformer transform = transformerFactory == null ? null : transformerFactory.get().prepare(blockView, state, pos, randomSupplier);
|
||||||
|
if(transform != null) {
|
||||||
|
context.pushTransform(transform);
|
||||||
|
}
|
||||||
|
if(mesh != null) {
|
||||||
|
context.meshConsumer().accept(mesh);
|
||||||
|
}
|
||||||
|
if(transform != null) {
|
||||||
|
context.popTransform();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ModelItemPropertyOverrideList getItemPropertyOverrides() {
|
||||||
|
return itemProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class ItemProxy extends ModelItemPropertyOverrideList {
|
||||||
|
public ItemProxy() {
|
||||||
|
super(null, null, null, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BakedModel apply(BakedModel bakedModel_1, ItemStack itemStack_1, World world_1, LivingEntity livingEntity_1) {
|
||||||
|
return SimpleModel.this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
|
||||||
|
final MeshTransformer transform = transformerFactory == null ? null : transformerFactory.get().prepare(stack, randomSupplier);
|
||||||
|
if(transform != null) {
|
||||||
|
context.pushTransform(transform);
|
||||||
|
}
|
||||||
|
if(mesh != null) {
|
||||||
|
context.meshConsumer().accept(mesh);
|
||||||
|
}
|
||||||
|
if(transform != null) {
|
||||||
|
context.popTransform();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package io.github.cottonmc.slopetest.model;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import net.minecraft.client.render.model.BakedModel;
|
||||||
|
import net.minecraft.client.render.model.ModelBakeSettings;
|
||||||
|
import net.minecraft.client.render.model.ModelLoader;
|
||||||
|
import net.minecraft.client.render.model.UnbakedModel;
|
||||||
|
import net.minecraft.client.texture.Sprite;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface SimpleUnbakedModel extends UnbakedModel {
|
||||||
|
BakedModel bake();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default Collection<Identifier> getModelDependencies() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default Collection<Identifier> getTextureDependencies(Function<Identifier, UnbakedModel> var1, Set<String> var2) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default BakedModel bake(ModelLoader loader, Function<Identifier, Sprite> spriteFunc, ModelBakeSettings settings) {
|
||||||
|
return bake();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package io.github.cottonmc.slopetest.model;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import io.github.cottonmc.slopetest.SlopeTest;
|
||||||
|
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.BlockState;
|
||||||
|
import net.minecraft.client.render.block.BlockModels;
|
||||||
|
import net.minecraft.client.render.model.UnbakedModel;
|
||||||
|
import net.minecraft.client.util.ModelIdentifier;
|
||||||
|
import net.minecraft.util.registry.Registry;
|
||||||
|
|
||||||
|
public class SlopeModelVariantProvider implements ModelVariantProvider {
|
||||||
|
|
||||||
|
private final HashMap<ModelIdentifier, UnbakedModel> variants = new HashMap<>();
|
||||||
|
|
||||||
|
public SlopeModelVariantProvider() {
|
||||||
|
// A bit ugly to hard-code this in the constructor, but however it is done,
|
||||||
|
// best to have variants for all the mod's blocks in a single provider/map
|
||||||
|
// instance so that model loader doesn't have to query a large number of providers.
|
||||||
|
|
||||||
|
for(BlockState state : SlopeTest.SLOPE.getStateFactory().getStates()) {
|
||||||
|
variants.put(BlockModels.getModelId(state), (SimpleUnbakedModel)() -> new SlopeTestModel(state));
|
||||||
|
}
|
||||||
|
|
||||||
|
variants.put(new ModelIdentifier(Registry.ITEM.getId(SlopeTest.SLOPE.asItem()), "inventory"), (SimpleUnbakedModel)() -> new SlopeTestModel(SlopeTest.SLOPE.getDefaultState()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnbakedModel loadModelVariant(ModelIdentifier modelId, ModelProviderContext context) throws ModelProviderException {
|
||||||
|
return variants.get(modelId);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,357 @@
|
|||||||
|
package io.github.cottonmc.slopetest.model;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
|
||||||
|
import io.github.cottonmc.slopetest.util.SpriteSet;
|
||||||
|
import net.fabricmc.fabric.api.client.render.ColorProviderRegistry;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.material.MaterialFinder;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
||||||
|
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.MutableQuadView;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
|
||||||
|
import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockRenderLayer;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.Blocks;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.color.block.BlockColorProvider;
|
||||||
|
import net.minecraft.client.render.model.BakedModel;
|
||||||
|
import net.minecraft.client.texture.MissingSprite;
|
||||||
|
import net.minecraft.client.texture.Sprite;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.state.property.Properties;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.world.ExtendedBlockView;
|
||||||
|
|
||||||
|
public class SlopeTestModel extends SimpleModel {
|
||||||
|
|
||||||
|
private static final ThreadLocal<Transformer> TRANSFORMERS = ThreadLocal.withInitial(Transformer::new);
|
||||||
|
|
||||||
|
public SlopeTestModel(BlockState blockState) {
|
||||||
|
super(baseMesh(blockState), TRANSFORMERS::get, MissingSprite.getMissingSprite(), ModelHelper.MODEL_TRANSFORM_BLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Mesh baseMesh(BlockState state) {
|
||||||
|
final MeshBuilder builder = RENDERER.meshBuilder();
|
||||||
|
final QuadEmitter quad = builder.getEmitter();
|
||||||
|
final Direction dir = state.get(Properties.HORIZONTAL_FACING);
|
||||||
|
drawSlope(quad.spriteColor(0, -1, -1, -1, -1), dir);
|
||||||
|
drawLeftSide(quad.spriteColor(0, -1, -1, -1, -1), dir);
|
||||||
|
drawRightSide(quad.spriteColor(0, -1, -1, -1, -1), dir);
|
||||||
|
drawBack(quad.spriteColor(0, -1, -1, -1, -1), dir);
|
||||||
|
drawBottom(quad.spriteColor(0, -1, -1, -1, -1));
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int TAG_SLOPE = 0;
|
||||||
|
private static final int TAG_LEFT = 1;
|
||||||
|
private static final int TAG_RIGHT = 2;
|
||||||
|
private static final int TAG_BACK = 3;
|
||||||
|
private 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Transformer implements MeshTransformer {
|
||||||
|
private final MinecraftClient minecraft = MinecraftClient.getInstance();
|
||||||
|
private final SpriteSet sprites = new SpriteSet();
|
||||||
|
private final MaterialFinder finder = RENDERER.materialFinder();
|
||||||
|
|
||||||
|
private int color;
|
||||||
|
private Direction dir;
|
||||||
|
private RenderMaterial material;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MeshTransformer prepare(ExtendedBlockView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier) {
|
||||||
|
dir = state.get(Properties.HORIZONTAL_FACING);
|
||||||
|
color = 0xffffff;
|
||||||
|
final BlockState template = ObjectUtils.defaultIfNull((BlockState) ((RenderAttachedBlockView)blockView).getBlockEntityRenderAttachment(pos), Blocks.AIR.getDefaultState());
|
||||||
|
final Block block = template.getBlock();
|
||||||
|
|
||||||
|
if(block == Blocks.AIR) {
|
||||||
|
sprites.clear();
|
||||||
|
material = finder.clear().blendMode(0, BlockRenderLayer.CUTOUT).find();
|
||||||
|
} else {
|
||||||
|
material = finder.clear().disableDiffuse(0, false).disableAo(0, false).blendMode(0, block.getRenderLayer()).find();
|
||||||
|
BakedModel model = minecraft.getBlockRenderManager().getModel(template);
|
||||||
|
sprites.prepare(model, randomSupplier.get());
|
||||||
|
BlockColorProvider blockColor = ColorProviderRegistry.BLOCK.get(block);
|
||||||
|
if (blockColor != null) {
|
||||||
|
color = 0xff000000 | blockColor.getColor(template, blockView, pos, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MeshTransformer prepare(ItemStack stack, Supplier<Random> randomSupplier) {
|
||||||
|
dir = Direction.NORTH;
|
||||||
|
color = 0xffffff;
|
||||||
|
sprites.clear();
|
||||||
|
material = finder.clear().find();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean transform(MutableQuadView quad) {
|
||||||
|
quad.material(material);
|
||||||
|
|
||||||
|
final SpriteSet sprites = this.sprites;
|
||||||
|
switch(quad.tag()) {
|
||||||
|
|
||||||
|
case TAG_SLOPE:
|
||||||
|
if(sprites.hasColor(Direction.UP)) {
|
||||||
|
quad.spriteColor(0, color, color, color, color);
|
||||||
|
}
|
||||||
|
paintSlope(quad, dir, sprites.getSprite(Direction.UP));
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case TAG_LEFT:
|
||||||
|
final Direction leftDir = this.dir.rotateYCounterclockwise();
|
||||||
|
if(sprites.hasColor(leftDir)) {
|
||||||
|
quad.spriteColor(0, color, color, color, color);
|
||||||
|
}
|
||||||
|
paintLeftSide(quad, dir, sprites.getSprite(leftDir));
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case TAG_RIGHT: {
|
||||||
|
final Direction rightDir = this.dir.rotateYClockwise();
|
||||||
|
if(sprites.hasColor(rightDir)) {
|
||||||
|
quad.spriteColor(0, color, color, color, color);
|
||||||
|
}
|
||||||
|
paintRightSide(quad, dir, sprites.getSprite(rightDir));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TAG_BACK: {
|
||||||
|
if(sprites.hasColor(dir)) {
|
||||||
|
quad.spriteColor(0, color, color, color, color);
|
||||||
|
}
|
||||||
|
paintBack(quad, dir, sprites.getSprite(dir));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TAG_BOTTOM: {
|
||||||
|
if(sprites.hasColor(Direction.DOWN)) {
|
||||||
|
quad.spriteColor(0, color, color, color, color);
|
||||||
|
}
|
||||||
|
paintBottom(quad, sprites.getSprite(Direction.DOWN));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void paintSlope(MutableQuadView quad, Direction dir, Sprite sprite) {
|
||||||
|
switch (dir) {
|
||||||
|
case NORTH:
|
||||||
|
quad.sprite(0, 0, sprite.getMinU(), sprite.getMinV())
|
||||||
|
.sprite(1, 0, sprite.getMinU(), sprite.getMaxV())
|
||||||
|
.sprite(2, 0, sprite.getMaxU(), sprite.getMaxV())
|
||||||
|
.sprite(3, 0, sprite.getMaxU(), sprite.getMinV());
|
||||||
|
break;
|
||||||
|
case SOUTH:
|
||||||
|
quad.sprite(0, 0, sprite.getMaxU(), sprite.getMaxV())
|
||||||
|
.sprite(1, 0, sprite.getMaxU(), sprite.getMinV())
|
||||||
|
.sprite(2, 0, sprite.getMinU(), sprite.getMinV())
|
||||||
|
.sprite(3, 0, sprite.getMinU(), sprite.getMaxV());
|
||||||
|
break;
|
||||||
|
case EAST:
|
||||||
|
quad.sprite(0, 0, sprite.getMinU(), sprite.getMaxV())
|
||||||
|
.sprite(1, 0, sprite.getMaxU(), sprite.getMaxV())
|
||||||
|
.sprite(2, 0, sprite.getMaxU(), sprite.getMinV())
|
||||||
|
.sprite(3, 0, sprite.getMinU(), sprite.getMinV());
|
||||||
|
break;
|
||||||
|
case WEST:
|
||||||
|
quad.sprite(0, 0, sprite.getMaxU(), sprite.getMinV())
|
||||||
|
.sprite(1, 0, sprite.getMinU(), sprite.getMinV())
|
||||||
|
.sprite(2, 0, sprite.getMinU(), sprite.getMaxV())
|
||||||
|
.sprite(3, 0, sprite.getMaxU(), sprite.getMaxV());
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void paintLeftSide(MutableQuadView quad, Direction dir, Sprite sprite) {
|
||||||
|
switch(dir) {
|
||||||
|
case NORTH:
|
||||||
|
quad.sprite(0, 0, sprite.getMinU(), sprite.getMaxV())
|
||||||
|
.sprite(1, 0, sprite.getMaxU(), sprite.getMaxV())
|
||||||
|
.sprite(2, 0, sprite.getMaxU(), sprite.getMinV())
|
||||||
|
.sprite(3, 0, sprite.getMinU(), sprite.getMinV());
|
||||||
|
break;
|
||||||
|
case SOUTH:
|
||||||
|
quad.sprite(0, 0, sprite.getMaxU(), sprite.getMinV())
|
||||||
|
.sprite(1, 0, sprite.getMinU(), sprite.getMinV())
|
||||||
|
.sprite(2, 0, sprite.getMinU(), sprite.getMaxV())
|
||||||
|
.sprite(3, 0, sprite.getMaxU(), sprite.getMaxV());
|
||||||
|
break;
|
||||||
|
case EAST:
|
||||||
|
quad.sprite(0, 0, sprite.getMinU(), sprite.getMaxV())
|
||||||
|
.sprite(1, 0, sprite.getMaxU(), sprite.getMaxV())
|
||||||
|
.sprite(2, 0, sprite.getMaxU(), sprite.getMinV())
|
||||||
|
.sprite(3, 0, sprite.getMinU(), sprite.getMinV());
|
||||||
|
break;
|
||||||
|
case WEST:
|
||||||
|
quad.sprite(0, 0, sprite.getMinU(), sprite.getMaxV())
|
||||||
|
.sprite(1, 0, sprite.getMaxU(), sprite.getMaxV())
|
||||||
|
.sprite(2, 0, sprite.getMaxU(), sprite.getMinV())
|
||||||
|
.sprite(3, 0, sprite.getMinU(), sprite.getMinV());
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void paintRightSide(MutableQuadView quad, Direction dir, Sprite sprite) {
|
||||||
|
switch(dir) {
|
||||||
|
case NORTH:
|
||||||
|
quad.sprite(0, 0, sprite.getMaxU(), sprite.getMaxV())
|
||||||
|
.sprite(1, 0, sprite.getMaxU(), sprite.getMinV())
|
||||||
|
.sprite(2, 0, sprite.getMinU(), sprite.getMinV())
|
||||||
|
.sprite(3, 0, sprite.getMinU(), sprite.getMaxV());
|
||||||
|
break;
|
||||||
|
case SOUTH:
|
||||||
|
quad.sprite(0, 0, sprite.getMinU(), sprite.getMinV())
|
||||||
|
.sprite(1, 0, sprite.getMinU(), sprite.getMaxV())
|
||||||
|
.sprite(2, 0, sprite.getMaxU(), sprite.getMaxV())
|
||||||
|
.sprite(3, 0, sprite.getMaxU(), sprite.getMinV());
|
||||||
|
break;
|
||||||
|
case EAST:
|
||||||
|
quad.sprite(0, 0, sprite.getMinU(), sprite.getMinV())
|
||||||
|
.sprite(1, 0, sprite.getMinU(), sprite.getMaxV())
|
||||||
|
.sprite(2, 0, sprite.getMaxU(), sprite.getMaxV())
|
||||||
|
.sprite(3, 0, sprite.getMaxU(), sprite.getMinV());
|
||||||
|
break;
|
||||||
|
case WEST:
|
||||||
|
quad.sprite(0, 0, sprite.getMaxU(), sprite.getMaxV())
|
||||||
|
.sprite(1, 0, sprite.getMaxU(), sprite.getMinV())
|
||||||
|
.sprite(2, 0, sprite.getMinU(), sprite.getMinV())
|
||||||
|
.sprite(3, 0, sprite.getMinU(), sprite.getMaxV());
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void paintBack(MutableQuadView quad, Direction dir, Sprite sprite) {
|
||||||
|
switch(dir) {
|
||||||
|
case NORTH:
|
||||||
|
quad.sprite(0, 0, sprite.getMaxU(), sprite.getMaxV())
|
||||||
|
.sprite(1, 0, sprite.getMaxU(), sprite.getMinV())
|
||||||
|
.sprite(2, 0, sprite.getMinU(), sprite.getMinV())
|
||||||
|
.sprite(3, 0, sprite.getMinU(), sprite.getMaxV());
|
||||||
|
break;
|
||||||
|
case SOUTH:
|
||||||
|
quad.sprite(0, 0, sprite.getMinU(), sprite.getMaxV())
|
||||||
|
.sprite(1, 0, sprite.getMaxU(), sprite.getMaxV())
|
||||||
|
.sprite(2, 0, sprite.getMaxU(), sprite.getMinV())
|
||||||
|
.sprite(3, 0, sprite.getMinU(), sprite.getMinV());
|
||||||
|
break;
|
||||||
|
case EAST:
|
||||||
|
quad.sprite(0, 0, sprite.getMaxU(), sprite.getMaxV())
|
||||||
|
.sprite(1, 0, sprite.getMaxU(), sprite.getMinV())
|
||||||
|
.sprite(2, 0, sprite.getMinU(), sprite.getMinV())
|
||||||
|
.sprite(3, 0, sprite.getMinU(), sprite.getMaxV());
|
||||||
|
break;
|
||||||
|
case WEST:
|
||||||
|
quad.sprite(0, 0, sprite.getMinU(), sprite.getMaxV())
|
||||||
|
.sprite(1, 0, sprite.getMaxU(), sprite.getMaxV())
|
||||||
|
.sprite(2, 0, sprite.getMaxU(), sprite.getMinV())
|
||||||
|
.sprite(3, 0, sprite.getMinU(), sprite.getMinV());
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void paintBottom(MutableQuadView quad, Sprite sprite) {
|
||||||
|
quad.sprite(0, 0, sprite.getMinU(), sprite.getMaxV())
|
||||||
|
.sprite(1, 0, sprite.getMaxU(), sprite.getMaxV())
|
||||||
|
.sprite(2, 0, sprite.getMaxU(), sprite.getMinV())
|
||||||
|
.sprite(3, 0, sprite.getMinU(), sprite.getMinV());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,12 @@
|
|||||||
package io.github.cottonmc.slopetest.util;
|
package io.github.cottonmc.slopetest.util;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.render.model.BakedModel;
|
import net.minecraft.client.render.model.BakedModel;
|
||||||
import net.minecraft.client.render.model.BakedQuad;
|
import net.minecraft.client.render.model.BakedQuad;
|
||||||
@ -7,42 +14,39 @@ import net.minecraft.client.texture.Sprite;
|
|||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
public class SpriteSet {
|
public class SpriteSet {
|
||||||
private Sprite global;
|
private Object2ObjectOpenHashMap<Direction, BakedQuad> quads = new Object2ObjectOpenHashMap<>();
|
||||||
private Map<Direction, BakedQuad> quads;
|
private boolean isDefault = true;
|
||||||
private boolean singleSprite = false;
|
|
||||||
private boolean globalHasColor = false;
|
|
||||||
public static final Sprite FALLBACK = MinecraftClient.getInstance().getSpriteAtlas().getSprite(new Identifier("minecraft:block/scaffolding_top"));
|
public static final Sprite FALLBACK = MinecraftClient.getInstance().getSpriteAtlas().getSprite(new Identifier("minecraft:block/scaffolding_top"));
|
||||||
|
|
||||||
public SpriteSet(Sprite allSprite, boolean hasColor) {
|
public SpriteSet() {
|
||||||
this.global = allSprite;
|
clear();
|
||||||
singleSprite = true;
|
|
||||||
globalHasColor = hasColor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpriteSet(BakedModel model) {
|
/** Allow re-use of instances to avoid allocation in render loop */
|
||||||
Random rand = new Random();
|
public void clear() {
|
||||||
quads = new HashMap<>();
|
isDefault = true;
|
||||||
for (Direction dir : Direction.values()) {
|
|
||||||
List<BakedQuad> quads = model.getQuads(null, dir, rand);
|
|
||||||
if (!quads.isEmpty()) this.quads.put(dir, quads.get(0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Allow re-use of instances to avoid allocation in render loop */
|
||||||
|
//TODO: pass in block state?
|
||||||
|
public void prepare(BakedModel model, Random rand) {
|
||||||
|
this.quads.clear();
|
||||||
|
isDefault = false;
|
||||||
|
// avoid Direction.values() in hot loop - for thread safety may generate new array instances
|
||||||
|
//for (Direction dir : Direction.values()) {
|
||||||
|
for(int i = 0; i < 6; i++) {
|
||||||
|
final Direction dir = ModelHelper.faceFromIndex(i);
|
||||||
|
List<BakedQuad> quads = model.getQuads(null, dir, rand);
|
||||||
|
if (!quads.isEmpty()) this.quads.put(dir, quads.get(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Sprite getSprite(Direction dir) {
|
public Sprite getSprite(Direction dir) {
|
||||||
if (singleSprite) return global;
|
return isDefault ? FALLBACK : ObjectUtils.defaultIfNull(quads.get(dir).getSprite(), FALLBACK);
|
||||||
if (quads.get(dir) == null) return FALLBACK;
|
|
||||||
else return quads.get(dir).getSprite();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasColor(Direction dir) {
|
public boolean hasColor(Direction dir) {
|
||||||
if (singleSprite) return globalHasColor;
|
return isDefault ? false : ObjectUtils.defaultIfNull(quads.get(dir).hasColor(), false);
|
||||||
if (quads.get(dir) == null) return false;
|
|
||||||
else return quads.get(dir).hasColor();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user