mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-11-11 13:04:19 +01:00
Connecting the Quads
- Added models and a block interface for connected textures - Added Framed glass as an example block
This commit is contained in:
parent
720a370f2d
commit
4e1b33c0ea
@ -61,6 +61,7 @@ import com.simibubi.create.modules.logistics.management.base.LogisticalControlle
|
||||
import com.simibubi.create.modules.logistics.management.index.LogisticalIndexBlock;
|
||||
import com.simibubi.create.modules.logistics.transport.villager.LogisticiansTableBlock;
|
||||
import com.simibubi.create.modules.logistics.transport.villager.PackageFunnelBlock;
|
||||
import com.simibubi.create.modules.palettes.CTGlassBlock;
|
||||
import com.simibubi.create.modules.palettes.GlassPaneBlock;
|
||||
import com.simibubi.create.modules.schematics.block.CreativeCrateBlock;
|
||||
import com.simibubi.create.modules.schematics.block.SchematicTableBlock;
|
||||
@ -173,6 +174,7 @@ public enum AllBlocks {
|
||||
__PALETTES__(),
|
||||
TILED_GLASS(new GlassBlock(Properties.from(Blocks.GLASS))),
|
||||
TILED_GLASS_PANE(new GlassPaneBlock(Properties.from(Blocks.GLASS))),
|
||||
FRAMED_GLASS(new CTGlassBlock(true)),
|
||||
|
||||
ANDESITE_BRICKS(new Block(Properties.from(Blocks.ANDESITE))),
|
||||
DIORITE_BRICKS(new Block(Properties.from(Blocks.DIORITE))),
|
||||
@ -264,7 +266,7 @@ public enum AllBlocks {
|
||||
blockItem = new MechanicalMixerBlockItem(standardItemProperties);
|
||||
else
|
||||
blockItem = new BlockItem(blockIn, standardItemProperties);
|
||||
|
||||
|
||||
registry.register(blockItem.setRegistryName(blockIn.getRegistryName()));
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,9 @@ package com.simibubi.create;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.simibubi.create.foundation.block.CTModel;
|
||||
import com.simibubi.create.foundation.block.IHaveConnectedTextures;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
import com.simibubi.create.modules.contraptions.CachedBufferReloader;
|
||||
import com.simibubi.create.modules.contraptions.WrenchModel;
|
||||
import com.simibubi.create.modules.contraptions.receivers.EncasedFanParticleHandler;
|
||||
@ -27,6 +30,7 @@ import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.client.event.ModelBakeEvent;
|
||||
import net.minecraftforge.client.event.ModelRegistryEvent;
|
||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
@ -41,7 +45,7 @@ public class CreateClient {
|
||||
public static SchematicAndQuillHandler schematicAndQuillHandler;
|
||||
public static EncasedFanParticleHandler fanParticles;
|
||||
public static int renderTicks;
|
||||
|
||||
|
||||
public static ModConfig config;
|
||||
|
||||
public static void addListeners(IEventBus modEventBus) {
|
||||
@ -50,6 +54,7 @@ public class CreateClient {
|
||||
modEventBus.addListener(CreateClient::createConfigs);
|
||||
modEventBus.addListener(CreateClient::onModelBake);
|
||||
modEventBus.addListener(CreateClient::onModelRegistry);
|
||||
modEventBus.addListener(CreateClient::onTextureStitch);
|
||||
});
|
||||
}
|
||||
|
||||
@ -86,16 +91,33 @@ public class CreateClient {
|
||||
schematicHologram.tick();
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void onTextureStitch(TextureStitchEvent.Pre event) {
|
||||
if (!event.getMap().getBasePath().equals("textures"))
|
||||
return;
|
||||
for (AllBlocks allBlocks : AllBlocks.values()) {
|
||||
if (!(allBlocks.get() instanceof IHaveConnectedTextures))
|
||||
continue;
|
||||
event.addSprite(new ResourceLocation(Create.ID, "block/connected/" + Lang.asId(allBlocks.name())));
|
||||
}
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void onModelBake(ModelBakeEvent event) {
|
||||
Map<ResourceLocation, IBakedModel> modelRegistry = event.getModelRegistry();
|
||||
|
||||
for (AllBlocks allBlocks : AllBlocks.values()) {
|
||||
if (!(allBlocks.get() instanceof IHaveConnectedTextures))
|
||||
continue;
|
||||
swapModels(modelRegistry, getBlockModelLocation(allBlocks, ""),
|
||||
t -> new CTModel(t, Lang.asId(allBlocks.name())));
|
||||
}
|
||||
|
||||
swapModels(modelRegistry, getItemModelLocation(AllItems.SYMMETRY_WAND),
|
||||
t -> new SymmetryWandModel(t).loadPartials(event));
|
||||
swapModels(modelRegistry, getItemModelLocation(AllItems.PLACEMENT_HANDGUN),
|
||||
t -> new BuilderGunModel(t).loadPartials(event));
|
||||
swapModels(modelRegistry, getItemModelLocation(AllItems.WRENCH),
|
||||
t -> new WrenchModel(t).loadPartials(event));
|
||||
swapModels(modelRegistry, getItemModelLocation(AllItems.WRENCH), t -> new WrenchModel(t).loadPartials(event));
|
||||
swapModels(modelRegistry, getItemModelLocation(AllItems.DEFORESTER),
|
||||
t -> new DeforesterModel(t).loadPartials(event));
|
||||
swapModels(modelRegistry,
|
||||
|
109
src/main/java/com/simibubi/create/foundation/block/CTModel.java
Normal file
109
src/main/java/com/simibubi/create/foundation/block/CTModel.java
Normal file
@ -0,0 +1,109 @@
|
||||
package com.simibubi.create.foundation.block;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import com.simibubi.create.foundation.block.CTModelTextureHandler.TextureEntry;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.renderer.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IEnviromentBlockReader;
|
||||
import net.minecraftforge.client.model.BakedModelWrapper;
|
||||
import net.minecraftforge.client.model.data.EmptyModelData;
|
||||
import net.minecraftforge.client.model.data.IModelData;
|
||||
import net.minecraftforge.client.model.data.ModelDataMap;
|
||||
import net.minecraftforge.client.model.data.ModelProperty;
|
||||
|
||||
public class CTModel extends BakedModelWrapper<IBakedModel> {
|
||||
|
||||
private static ModelProperty<CTData> CT_PROPERTY = new ModelProperty<>();
|
||||
private TextureEntry texture;
|
||||
|
||||
private class CTData {
|
||||
int[] textures;
|
||||
|
||||
public CTData() {
|
||||
textures = new int[6];
|
||||
Arrays.fill(textures, -1);
|
||||
}
|
||||
|
||||
void put(Direction face, int texture) {
|
||||
textures[face.getIndex()] = texture;
|
||||
}
|
||||
|
||||
int get(Direction face) {
|
||||
return textures[face.getIndex()];
|
||||
}
|
||||
}
|
||||
|
||||
public CTModel(IBakedModel originalModel, String blockId) {
|
||||
super(originalModel);
|
||||
texture = CTModelTextureHandler.get(blockId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IModelData getModelData(IEnviromentBlockReader world, BlockPos pos, BlockState state, IModelData tileData) {
|
||||
if (!(state.getBlock() instanceof IHaveConnectedTextures))
|
||||
return EmptyModelData.INSTANCE;
|
||||
CTData data = new CTData();
|
||||
IHaveConnectedTextures texDef = (IHaveConnectedTextures) state.getBlock();
|
||||
for (Direction face : Direction.values()) {
|
||||
if (!Block.shouldSideBeRendered(state, world, pos, face))
|
||||
continue;
|
||||
data.put(face, texDef.getTextureIndex(world, pos, state, face));
|
||||
}
|
||||
return new ModelDataMap.Builder().withInitial(CT_PROPERTY, data).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(BlockState state, Direction side, Random rand, IModelData extraData) {
|
||||
List<BakedQuad> quads = new ArrayList<>(super.getQuads(state, side, rand, extraData));
|
||||
if (!extraData.hasProperty(CT_PROPERTY))
|
||||
return quads;
|
||||
IHaveConnectedTextures texDef = (IHaveConnectedTextures) state.getBlock();
|
||||
CTData data = extraData.getData(CT_PROPERTY);
|
||||
|
||||
for (int i = 0; i < quads.size(); i++) {
|
||||
BakedQuad quad = quads.get(i);
|
||||
if (!texDef.appliesTo(quad))
|
||||
continue;
|
||||
int index = data.get(quad.getFace());
|
||||
if (index == -1)
|
||||
return quads;
|
||||
|
||||
float textureSize = 16f / 128f / 8f;
|
||||
float uShift = (index % 8) * textureSize;
|
||||
float vShift = (index / 8) * textureSize * 2;
|
||||
|
||||
uShift = texture.connectedTextures.getInterpolatedU((index % 8) * 2) - texture.originalTexture.getMinU();
|
||||
vShift = texture.connectedTextures.getInterpolatedV((index / 8) * 2) - texture.originalTexture.getMinV();
|
||||
|
||||
BakedQuad newQuad = new BakedQuad(Arrays.copyOf(quad.getVertexData(), quad.getVertexData().length),
|
||||
quad.getTintIndex(), quad.getFace(), quad.getSprite(), quad.shouldApplyDiffuseLighting(),
|
||||
quad.getFormat());
|
||||
VertexFormat format = quad.getFormat();
|
||||
int[] vertexData = newQuad.getVertexData();
|
||||
for (int vertex = 0; vertex < vertexData.length; vertex += format.getIntegerSize()) {
|
||||
int uvOffset = format.getUvOffsetById(0) / 4;
|
||||
int uIndex = vertex + uvOffset;
|
||||
int vIndex = vertex + uvOffset + 1;
|
||||
float u = Float.intBitsToFloat(vertexData[uIndex]);
|
||||
float v = Float.intBitsToFloat(vertexData[vIndex]);
|
||||
u += uShift;
|
||||
v += vShift;
|
||||
vertexData[uIndex] = Float.floatToIntBits(u);
|
||||
vertexData[vIndex] = Float.floatToIntBits(v);
|
||||
}
|
||||
quads.set(i, newQuad);
|
||||
}
|
||||
return quads;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.simibubi.create.foundation.block;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.AtlasTexture;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class CTModelTextureHandler {
|
||||
|
||||
static class TextureEntry {
|
||||
ResourceLocation originalTextureLocation;
|
||||
ResourceLocation connectedTextureLocation;
|
||||
TextureAtlasSprite originalTexture;
|
||||
TextureAtlasSprite connectedTextures;
|
||||
|
||||
void loadTextures() {
|
||||
AtlasTexture textureMap = Minecraft.getInstance().getTextureMap();
|
||||
originalTexture = textureMap.getSprite(originalTextureLocation);
|
||||
connectedTextures = textureMap.getSprite(connectedTextureLocation);
|
||||
}
|
||||
}
|
||||
|
||||
static Map<String, TextureEntry> textures = new HashMap<>();
|
||||
|
||||
public static TextureEntry get(String blockId) {
|
||||
if (textures.containsKey(blockId))
|
||||
return textures.get(blockId);
|
||||
|
||||
TextureEntry entry = new TextureEntry();
|
||||
entry.originalTextureLocation = new ResourceLocation(Create.ID, "block/" + blockId);
|
||||
entry.connectedTextureLocation = new ResourceLocation(Create.ID, "block/connected/" + blockId);
|
||||
entry.loadTextures();
|
||||
textures.put(blockId, entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
public static void reloadUVs() {
|
||||
textures.values().forEach(TextureEntry::loadTextures);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
package com.simibubi.create.foundation.block;
|
||||
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.renderer.model.BakedQuad;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.Direction.AxisDirection;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IEnviromentBlockReader;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
public interface IHaveConnectedTextures {
|
||||
|
||||
class CTContext {
|
||||
boolean up, down, left, right;
|
||||
boolean topLeft, topRight, bottomLeft, bottomRight;
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public boolean appliesTo(BakedQuad quad);
|
||||
|
||||
default boolean connectsTo(BlockState state, BlockState other, IEnviromentBlockReader reader, BlockPos pos,
|
||||
BlockPos otherPos, Direction face) {
|
||||
|
||||
BlockPos blockingPos = otherPos.offset(face);
|
||||
if ((face.getAxis().getCoordinate(pos.getX(), pos.getY(), pos.getZ()) == face.getAxis()
|
||||
.getCoordinate(otherPos.getX(), otherPos.getY(), otherPos.getZ()))
|
||||
&& connectsTo(state, reader.getBlockState(blockingPos), reader, pos, blockingPos, face))
|
||||
return false;
|
||||
|
||||
return state.getBlock() == other.getBlock();
|
||||
}
|
||||
|
||||
default int getTextureIndex(IEnviromentBlockReader reader, BlockPos pos, BlockState state, Direction face) {
|
||||
return getTextureIndexForContext(reader, pos, state, face, buildContext(reader, pos, state, face));
|
||||
}
|
||||
|
||||
default CTContext buildContext(IEnviromentBlockReader reader, BlockPos pos, BlockState state, Direction face) {
|
||||
Axis axis = face.getAxis();
|
||||
boolean positive = face.getAxisDirection() == AxisDirection.POSITIVE;
|
||||
Direction h = axis == Axis.X ? Direction.SOUTH : Direction.WEST;
|
||||
Direction v = axis.isHorizontal() ? Direction.UP : Direction.NORTH;
|
||||
h = positive ? h.getOpposite() : h;
|
||||
if (face == Direction.DOWN) {
|
||||
v = v.getOpposite();
|
||||
h = h.getOpposite();
|
||||
}
|
||||
|
||||
final Direction horizontal = h;
|
||||
final Direction vertical = v;
|
||||
|
||||
BiPredicate<Integer, Integer> connection = (x, y) -> {
|
||||
BlockPos p = pos.offset(horizontal, x).offset(vertical, y);
|
||||
return connectsTo(state, reader.getBlockState(p), reader, pos, p, face);
|
||||
};
|
||||
|
||||
CTContext context = new CTContext();
|
||||
context.up = connection.test(0, 1);
|
||||
context.down = connection.test(0, -1);
|
||||
context.left = connection.test(-1, 0);
|
||||
context.right = connection.test(1, 0);
|
||||
context.topLeft = connection.test(-1, 1);
|
||||
context.topRight = connection.test(1, 1);
|
||||
context.bottomLeft = connection.test(-1, -1);
|
||||
context.bottomRight = connection.test(1, -1);
|
||||
return context;
|
||||
}
|
||||
|
||||
default int getTextureIndexForContext(IEnviromentBlockReader reader, BlockPos pos, BlockState state, Direction face,
|
||||
CTContext c) {
|
||||
int tileX = 0, tileY = 0;
|
||||
int borders = (!c.up ? 1 : 0) + (!c.down ? 1 : 0) + (!c.left ? 1 : 0) + (!c.right ? 1 : 0);
|
||||
|
||||
if (c.up)
|
||||
tileX++;
|
||||
if (c.down)
|
||||
tileX += 2;
|
||||
if (c.left)
|
||||
tileY++;
|
||||
if (c.right)
|
||||
tileY += 2;
|
||||
|
||||
if (borders == 0) {
|
||||
if (c.topRight)
|
||||
tileX++;
|
||||
if (c.topLeft)
|
||||
tileX += 2;
|
||||
if (c.bottomRight)
|
||||
tileY += 2;
|
||||
if (c.bottomLeft)
|
||||
tileY++;
|
||||
}
|
||||
|
||||
if (borders == 1) {
|
||||
if (!c.right) {
|
||||
if (c.topLeft || c.bottomLeft) {
|
||||
tileY = 4;
|
||||
tileX = -1 + (c.bottomLeft ? 1 : 0) + (c.topLeft ? 1 : 0) * 2;
|
||||
}
|
||||
}
|
||||
if (!c.left) {
|
||||
if (c.topRight || c.bottomRight) {
|
||||
tileY = 5;
|
||||
tileX = -1 + (c.bottomRight ? 1 : 0) + (c.topRight ? 1 : 0) * 2;
|
||||
}
|
||||
}
|
||||
if (!c.down) {
|
||||
if (c.topLeft || c.topRight) {
|
||||
tileY = 6;
|
||||
tileX = -1 + (c.topLeft ? 1 : 0) + (c.topRight ? 1 : 0) * 2;
|
||||
}
|
||||
}
|
||||
if (!c.up) {
|
||||
if (c.bottomLeft || c.bottomRight) {
|
||||
tileY = 7;
|
||||
tileX = -1 + (c.bottomLeft ? 1 : 0) + (c.bottomRight ? 1 : 0) * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (borders == 2) {
|
||||
if ((c.up && c.left && c.topLeft) || (c.down && c.left && c.bottomLeft) || (c.up && c.right && c.topRight)
|
||||
|| (c.down && c.right && c.bottomRight))
|
||||
tileX += 3;
|
||||
}
|
||||
|
||||
return tileX + 8 * tileY;
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.simibubi.create.modules.contraptions;
|
||||
|
||||
import com.simibubi.create.foundation.block.CTModelTextureHandler;
|
||||
import com.simibubi.create.foundation.utility.ColoredIndicatorRenderer;
|
||||
import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer;
|
||||
import com.simibubi.create.modules.contraptions.receivers.constructs.ContraptionRenderer;
|
||||
@ -22,6 +23,7 @@ public class CachedBufferReloader extends ReloadListener<String> {
|
||||
ContraptionRenderer.invalidateCache();
|
||||
MechanicalBearingTileEntityRenderer.invalidateCache();
|
||||
ColoredIndicatorRenderer.invalidateCache();
|
||||
CTModelTextureHandler.reloadUVs();
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,37 @@
|
||||
package com.simibubi.create.modules.palettes;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.foundation.block.IHaveConnectedTextures;
|
||||
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.GlassBlock;
|
||||
import net.minecraft.client.renderer.model.BakedQuad;
|
||||
import net.minecraft.util.BlockRenderLayer;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class CTGlassBlock extends GlassBlock implements IHaveConnectedTextures {
|
||||
|
||||
private Supplier<ResourceLocation> textureToReplace;
|
||||
private boolean hasAlpha;
|
||||
|
||||
public CTGlassBlock(boolean hasAlpha) {
|
||||
super(Properties.from(Blocks.GLASS));
|
||||
textureToReplace = () -> {
|
||||
return new ResourceLocation(Create.ID, "block/" + getRegistryName().getPath());
|
||||
};
|
||||
this.hasAlpha = hasAlpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean appliesTo(BakedQuad quad) {
|
||||
return quad.getSprite().getName().equals(textureToReplace.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockRenderLayer getRenderLayer() {
|
||||
return hasAlpha ? BlockRenderLayer.TRANSLUCENT : super.getRenderLayer();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"variants": {
|
||||
"": { "model": "create:block/palettes/framed_glass" }
|
||||
}
|
||||
}
|
17
src/main/resources/assets/create/models/block/ctblock.json
Normal file
17
src/main/resources/assets/create/models/block/ctblock.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"parent": "block/block",
|
||||
"elements": [
|
||||
{
|
||||
"from": [0, 0, 0],
|
||||
"to": [16, 16, 16],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 2, 2], "texture": "#sheet", "cullface": "north"},
|
||||
"east": {"uv": [0, 0, 2, 2], "texture": "#sheet", "cullface": "east"},
|
||||
"south": {"uv": [0, 0, 2, 2], "texture": "#sheet", "cullface": "south"},
|
||||
"west": {"uv": [0, 0, 2, 2], "texture": "#sheet", "cullface": "west"},
|
||||
"up": {"uv": [0, 0, 2, 2], "texture": "#sheet", "cullface": "up"},
|
||||
"down": {"uv": [0, 0, 2, 2], "texture": "#sheet", "cullface": "down"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "block/cube_all",
|
||||
"textures": {
|
||||
"all": "create:block/framed_glass"
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"parent": "create:block/palettes/framed_glass"
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
BIN
src/main/resources/assets/create/textures/block/framed_glass.png
Normal file
BIN
src/main/resources/assets/create/textures/block/framed_glass.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 478 B |
Loading…
Reference in New Issue
Block a user