Lots of fixes
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.client.render;
|
||||
|
||||
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
|
||||
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.ModelOverrideList;
|
||||
import net.minecraft.client.render.model.json.ModelTransformation;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* @author DrummerMC
|
||||
* @version rv6 - 2018-01-22
|
||||
* @since rv6 2018-01-22
|
||||
*/
|
||||
public class DummyFluidBakedModel implements BakedModel, FabricBakedModel {
|
||||
|
||||
private final FluidVolume volume;
|
||||
|
||||
public DummyFluidBakedModel(FluidVolume volume) {
|
||||
this.volume = volume;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVanillaAdapter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
|
||||
// Not used as an item model
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
|
||||
volume.renderGuiRect(0, 0, 16, 16);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAmbientOcclusion() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDepth() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSideLit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sprite getSprite() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelTransformation getTransformation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelOverrideList getOverrides() {
|
||||
return ModelOverrideList.EMPTY;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.client.render;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
|
||||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.client.render.model.json.ModelOverrideList;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
|
||||
import appeng.client.render.cablebus.FacadeBuilder;
|
||||
|
||||
/**
|
||||
* This model used the provided FacadeBuilder to "slice" the item quads for the
|
||||
* facade provided.
|
||||
*
|
||||
* @author covers1624
|
||||
*/
|
||||
public class FacadeBakedItemModel extends ForwardingBakedModel implements FabricBakedModel {
|
||||
|
||||
private final ItemStack textureStack;
|
||||
private final FacadeBuilder facadeBuilder;
|
||||
private List<BakedQuad> quads = null;
|
||||
|
||||
protected FacadeBakedItemModel(BakedModel base, ItemStack textureStack, FacadeBuilder facadeBuilder) {
|
||||
this.wrapped = base;
|
||||
this.textureStack = textureStack;
|
||||
this.facadeBuilder = facadeBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
|
||||
super.emitItemQuads(stack, randomSupplier, context);
|
||||
|
||||
if (quads == null) {
|
||||
quads = new ArrayList<>();
|
||||
quads.addAll(this.facadeBuilder.buildFacadeItemQuads(this.textureStack, Direction.NORTH));
|
||||
quads = Collections.unmodifiableList(quads);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDepth() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSideLit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelOverrideList getOverrides() {
|
||||
return ModelOverrideList.EMPTY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.client.render;
|
||||
|
||||
import appeng.client.render.cablebus.FacadeBuilder;
|
||||
import appeng.items.parts.FacadeItem;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
|
||||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* This baked model class is used as a dispatcher to redirect the renderer to
|
||||
* the *real* model that should be used based on the item stack. A custom Item
|
||||
* Override List is used to accomplish this.
|
||||
*/
|
||||
public class FacadeDispatcherBakedModel extends ForwardingBakedModel {
|
||||
private final FacadeBuilder facadeBuilder;
|
||||
private final Int2ObjectMap<FacadeBakedItemModel> cache = new Int2ObjectArrayMap<>();
|
||||
|
||||
public FacadeDispatcherBakedModel(BakedModel baseModel, FacadeBuilder facadeBuilder) {
|
||||
this.wrapped = baseModel;
|
||||
this.facadeBuilder = facadeBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVanillaAdapter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
|
||||
if (!(stack.getItem() instanceof FacadeItem)) {
|
||||
return;
|
||||
}
|
||||
|
||||
FacadeItem itemFacade = (FacadeItem) stack.getItem();
|
||||
|
||||
ItemStack textureItem = itemFacade.getTextureItem(stack);
|
||||
|
||||
int itemId = Item.getRawId(textureItem.getItem());
|
||||
int hash = Objects.hash(itemId, textureItem.getTag());
|
||||
FacadeBakedItemModel model = FacadeDispatcherBakedModel.this.cache.get(hash);
|
||||
if (model == null) {
|
||||
model = new FacadeBakedItemModel(FacadeDispatcherBakedModel.this.wrapped, textureItem,
|
||||
FacadeDispatcherBakedModel.this.facadeBuilder);
|
||||
FacadeDispatcherBakedModel.this.cache.put(hash, model);
|
||||
}
|
||||
|
||||
context.fallbackConsumer().accept(model);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.client.render;
|
||||
|
||||
import appeng.client.render.cablebus.FacadeBuilder;
|
||||
import appeng.core.AppEng;
|
||||
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.texture.Sprite;
|
||||
import net.minecraft.client.util.SpriteIdentifier;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* The model class for facades. Since facades wrap existing models, they don't
|
||||
* declare any dependencies here other than the cable anchor.
|
||||
*/
|
||||
public class FacadeItemModel implements BasicUnbakedModel {
|
||||
|
||||
// We use this to get the default item transforms and make our lives easier
|
||||
private static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "item/facade_base");
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BakedModel bake(ModelLoader loader, Function<SpriteIdentifier, Sprite> textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) {
|
||||
BakedModel bakedBaseModel = loader.bake(MODEL_BASE, rotationContainer);
|
||||
FacadeBuilder facadeBuilder = new FacadeBuilder(loader);
|
||||
|
||||
return new FacadeDispatcherBakedModel(bakedBaseModel, facadeBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Identifier> getModelDependencies() {
|
||||
return Collections.singleton(MODEL_BASE);
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
package appeng.client.render.cablebus;
|
||||
|
||||
import appeng.api.parts.IDynamicPartBakedModel;
|
||||
import appeng.api.parts.IPartModel;
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.AEColor;
|
||||
@@ -25,17 +26,13 @@ import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||
import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
|
||||
import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
|
||||
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.QuadEmitter;
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
|
||||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||
import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.IndigoRenderer;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.client.render.model.json.ModelOverrideList;
|
||||
@@ -49,8 +46,14 @@ import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Random;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@@ -125,7 +128,11 @@ public class CableBusBakedModel implements BakedModel, FabricBakedModel {
|
||||
}
|
||||
|
||||
context.pushTransform(QuadRotator.get(facing, Direction.UP));
|
||||
if (bakedModel instanceof FabricBakedModel) {
|
||||
if (bakedModel instanceof IDynamicPartBakedModel) {
|
||||
((IDynamicPartBakedModel) bakedModel).emitQuads(blockView, state, pos, randomSupplier, context,
|
||||
facing, partModelData);
|
||||
}
|
||||
else if (bakedModel instanceof FabricBakedModel) {
|
||||
((FabricBakedModel) bakedModel).emitBlockQuads(blockView, state, pos, randomSupplier, context);
|
||||
} else {
|
||||
context.fallbackConsumer().accept(bakedModel);
|
||||
@@ -134,7 +141,8 @@ public class CableBusBakedModel implements BakedModel, FabricBakedModel {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME this.facadeBuilder.buildFacadeQuads(layer, renderState, randomSupplier, context, this.partModels::get);
|
||||
Mesh mesh = this.facadeBuilder.getFacadeMesh(renderState, randomSupplier, this.partModels::get);
|
||||
context.meshConsumer().accept(mesh);
|
||||
}
|
||||
|
||||
// Determines whether a cable is connected to exactly two sides that are
|
||||
|
||||
@@ -67,7 +67,7 @@ public class CableBusModel implements BasicUnbakedModel {
|
||||
Map<Identifier, BakedModel> partModels = this.loadPartModels(loader, rotationContainer);
|
||||
|
||||
CableBuilder cableBuilder = new CableBuilder(textureGetter);
|
||||
FacadeBuilder facadeBuilder = new FacadeBuilder();
|
||||
FacadeBuilder facadeBuilder = new FacadeBuilder(loader);
|
||||
|
||||
// This should normally not be used, but we *have* to provide a particle texture
|
||||
// or otherwise damage models will
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.client.render.cablebus;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.fluid.FluidState;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
import net.minecraft.world.chunk.light.LightingProvider;
|
||||
import net.minecraft.world.level.ColorResolver;
|
||||
|
||||
/**
|
||||
* This is used to retrieve the ExtendedState of a block for facade rendering.
|
||||
* It fakes the block at BlockPos provided as the BlockState provided.
|
||||
*
|
||||
* @author covers1624
|
||||
*/
|
||||
public class FacadeBlockAccess implements BlockRenderView {
|
||||
|
||||
private final BlockRenderView world;
|
||||
private final BlockPos pos;
|
||||
private final Direction side;
|
||||
private final BlockState state;
|
||||
|
||||
public FacadeBlockAccess(BlockRenderView world, BlockPos pos, Direction side, BlockState state) {
|
||||
this.world = world;
|
||||
this.pos = pos;
|
||||
this.side = side;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockEntity getBlockEntity(BlockPos pos) {
|
||||
return this.world.getBlockEntity(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos pos) {
|
||||
if (this.pos == pos) {
|
||||
return this.state;
|
||||
}
|
||||
return this.world.getBlockState(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidState getFluidState(BlockPos pos) {
|
||||
return world.getFluidState(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LightingProvider getLightingProvider() {
|
||||
return world.getLightingProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getBrightness(Direction direction, boolean shaded) {
|
||||
return world.getBrightness(direction, shaded);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor(BlockPos pos, ColorResolver colorResolver) {
|
||||
return world.getColor(pos, colorResolver);
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,42 @@
|
||||
|
||||
package appeng.client.render.cablebus;
|
||||
|
||||
import appeng.api.util.AEAxisAlignedBB;
|
||||
import appeng.core.Api;
|
||||
import appeng.parts.misc.CableAnchorPart;
|
||||
import appeng.thirdparty.codechicken.lib.model.pipeline.transformers.QuadClamper;
|
||||
import appeng.thirdparty.codechicken.lib.model.pipeline.transformers.QuadCornerKicker;
|
||||
import appeng.thirdparty.codechicken.lib.model.pipeline.transformers.QuadFaceStripper;
|
||||
import appeng.thirdparty.codechicken.lib.model.pipeline.transformers.QuadReInterpolator;
|
||||
import appeng.thirdparty.codechicken.lib.model.pipeline.transformers.QuadTinter;
|
||||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||
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.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
|
||||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.color.block.BlockColors;
|
||||
import net.minecraft.client.render.block.BlockRenderManager;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.client.render.model.ModelLoader;
|
||||
import net.minecraft.client.render.model.ModelRotation;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Direction.Axis;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
@@ -28,31 +62,6 @@ import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.RenderLayers;
|
||||
import net.minecraft.client.render.VertexFormats;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.block.BlockRenderManager;
|
||||
import net.minecraft.client.color.block.BlockColors;
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Direction.Axis;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
|
||||
import appeng.api.util.AEAxisAlignedBB;
|
||||
import appeng.core.Api;
|
||||
import appeng.parts.misc.CableAnchorPart;
|
||||
/**
|
||||
* The FacadeBuilder builds for facades..
|
||||
*
|
||||
@@ -60,43 +69,93 @@ import appeng.parts.misc.CableAnchorPart;
|
||||
*/
|
||||
public class FacadeBuilder {
|
||||
|
||||
private final Renderer renderer = RendererAccess.INSTANCE.getRenderer();
|
||||
|
||||
public static final double THICK_THICKNESS = 2D / 16D;
|
||||
public static final double THIN_THICKNESS = 1D / 16D;
|
||||
|
||||
public static final Box[] THICK_FACADE_BOXES = new Box[] {
|
||||
public static final Box[] THICK_FACADE_BOXES = new Box[]{
|
||||
new Box(0.0, 0.0, 0.0, 1.0, THICK_THICKNESS, 1.0),
|
||||
new Box(0.0, 1.0 - THICK_THICKNESS, 0.0, 1.0, 1.0, 1.0),
|
||||
new Box(0.0, 0.0, 0.0, 1.0, 1.0, THICK_THICKNESS),
|
||||
new Box(0.0, 0.0, 1.0 - THICK_THICKNESS, 1.0, 1.0, 1.0),
|
||||
new Box(0.0, 0.0, 0.0, THICK_THICKNESS, 1.0, 1.0),
|
||||
new Box(1.0 - THICK_THICKNESS, 0.0, 0.0, 1.0, 1.0, 1.0) };
|
||||
new Box(1.0 - THICK_THICKNESS, 0.0, 0.0, 1.0, 1.0, 1.0)};
|
||||
|
||||
public static final Box[] THIN_FACADE_BOXES = new Box[] {
|
||||
public static final Box[] THIN_FACADE_BOXES = new Box[]{
|
||||
new Box(0.0, 0.0, 0.0, 1.0, THIN_THICKNESS, 1.0),
|
||||
new Box(0.0, 1.0 - THIN_THICKNESS, 0.0, 1.0, 1.0, 1.0),
|
||||
new Box(0.0, 0.0, 0.0, 1.0, 1.0, THIN_THICKNESS),
|
||||
new Box(0.0, 0.0, 1.0 - THIN_THICKNESS, 1.0, 1.0, 1.0),
|
||||
new Box(0.0, 0.0, 0.0, THIN_THICKNESS, 1.0, 1.0),
|
||||
new Box(1.0 - THIN_THICKNESS, 0.0, 0.0, 1.0, 1.0, 1.0) };
|
||||
new Box(1.0 - THIN_THICKNESS, 0.0, 0.0, 1.0, 1.0, 1.0)};
|
||||
|
||||
//FIXME private final ThreadLocal<BakedPipeline> pipelines = ThreadLocal.withInitial(() -> BakedPipeline.builder()
|
||||
//FIXME // Clamper is responsible for clamping the vertex to the bounds specified.
|
||||
//FIXME .addElement("clamper", QuadClamper.FACTORY)
|
||||
//FIXME // Strips faces if they match a mask.
|
||||
//FIXME .addElement("face_stripper", QuadFaceStripper.FACTORY)
|
||||
//FIXME // Kicks the edge inner corners in, solves Z fighting
|
||||
//FIXME .addElement("corner_kicker", QuadCornerKicker.FACTORY)
|
||||
//FIXME // Re-Interpolates the UV's for the quad.
|
||||
//FIXME .addElement("interp", QuadReInterpolator.FACTORY)
|
||||
//FIXME // Tints the quad if we need it to. Disabled by default.
|
||||
//FIXME .addElement("tinter", QuadTinter.FACTORY, false)
|
||||
//FIXME // Overrides the quad's alpha if we are forcing transparent facades.
|
||||
//FIXME .addElement("transparent", QuadAlphaOverride.FACTORY, false, e -> e.setAlphaOverride(0x4C / 255F)).build()//
|
||||
//FIXME );
|
||||
//FIXME private final ThreadLocal<Quad> collectors = ThreadLocal.withInitial(Quad::new);
|
||||
private final Map<Direction, Mesh> cableAnchorStilts;
|
||||
|
||||
public void buildFacadeQuads(RenderLayer layer, CableBusRenderState renderState, Supplier<Random> rand,
|
||||
RenderContext context, Function<Identifier, BakedModel> modelLookup) {
|
||||
public FacadeBuilder(ModelLoader modelLoader) {
|
||||
cableAnchorStilts = buildCableAnchorStems(modelLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a map of pre-rotated cable anchor stilts, which are the shortened cable anchors that
|
||||
* will still be visible for facades attached to a cable.
|
||||
*/
|
||||
private Map<Direction, Mesh> buildCableAnchorStems(ModelLoader modelLoader) {
|
||||
Map<Direction, Mesh> stems = new EnumMap<>(Direction.class);
|
||||
|
||||
List<BakedModel> cableAnchorParts = new ArrayList<>();
|
||||
for (Identifier model : CableAnchorPart.FACADE_MODELS.getModels()) {
|
||||
BakedModel cableAnchor = modelLoader.bake(model, ModelRotation.X0_Y0);
|
||||
cableAnchorParts.add(cableAnchor);
|
||||
}
|
||||
|
||||
// Create pre-rotated variants of the cable anchor stems
|
||||
for (Direction side : Direction.values()) {
|
||||
RenderContext.QuadTransform rotator = QuadRotator.get(side, Direction.UP);
|
||||
|
||||
MeshBuilder meshBuilder = renderer.meshBuilder();
|
||||
QuadEmitter emitter = meshBuilder.getEmitter();
|
||||
|
||||
for (BakedModel model : cableAnchorParts) {
|
||||
for (int cullFaceIdx = 0; cullFaceIdx <= ModelHelper.NULL_FACE_ID; cullFaceIdx++) {
|
||||
Direction cullFace = ModelHelper.faceFromIndex(cullFaceIdx);
|
||||
List<BakedQuad> quads = model.getQuads(null, cullFace, new Random());
|
||||
for (BakedQuad quad : quads) {
|
||||
emitter.fromVanilla(quad.getVertexData(), 0, false);
|
||||
emitter.cullFace(cullFace);
|
||||
emitter.nominalFace(quad.getFace());
|
||||
if (!rotator.transform(emitter)) {
|
||||
continue;
|
||||
}
|
||||
emitter.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stems.put(side, meshBuilder.build());
|
||||
}
|
||||
|
||||
return stems;
|
||||
}
|
||||
|
||||
// private final ThreadLocal<BakedPipeline> pipelines = ThreadLocal.withInitial(() -> BakedPipeline.builder()
|
||||
// // Clamper is responsible for clamping the vertex to the bounds specified.
|
||||
// .addElement("clamper", QuadClamper.FACTORY)
|
||||
// // Strips faces if they match a mask.
|
||||
// .addElement("face_stripper", QuadFaceStripper.FACTORY)
|
||||
// // Kicks the edge inner corners in, solves Z fighting
|
||||
// .addElement("corner_kicker", QuadCornerKicker.FACTORY)
|
||||
// // Re-Interpolates the UV's for the quad.
|
||||
// .addElement("interp", QuadReInterpolator.FACTORY)
|
||||
// // Tints the quad if we need it to. Disabled by default.
|
||||
// .addElement("tinter", QuadTinter.FACTORY, false)
|
||||
// // Overrides the quad's alpha if we are forcing transparent facades.
|
||||
// .addElement("transparent", QuadAlphaOverride.FACTORY, false, e -> e.setAlphaOverride(0x4C / 255F)).build()//
|
||||
// );
|
||||
|
||||
public Mesh getFacadeMesh(CableBusRenderState renderState,
|
||||
Supplier<Random> rand,
|
||||
Function<Identifier, BakedModel> modelLookup) {
|
||||
//FIXME BakedPipeline pipeline = this.pipelines.get();
|
||||
//FIXME Quad collectorQuad = this.collectors.get();
|
||||
boolean transparent = Api.instance().partHelper().getCableRenderMode().transparentFacades;
|
||||
@@ -108,32 +167,29 @@ public class FacadeBuilder {
|
||||
BlockColors blockColors = MinecraftClient.getInstance().getBlockColors();
|
||||
boolean thinFacades = isUseThinFacades(partBoxes);
|
||||
|
||||
MeshBuilder meshBuilder = renderer.meshBuilder();
|
||||
QuadEmitter emitter = meshBuilder.getEmitter();
|
||||
|
||||
for (Entry<Direction, FacadeRenderState> entry : facadeStates.entrySet()) {
|
||||
Direction side = entry.getKey();
|
||||
int sideIndex = side.ordinal();
|
||||
FacadeRenderState facadeRenderState = entry.getValue();
|
||||
boolean renderStilt = !sidesWithParts.contains(side);
|
||||
if (layer == RenderLayer.getCutout() && renderStilt) {
|
||||
context.pushTransform(QuadRotator.get(side, Direction.UP));
|
||||
for (Identifier part : CableAnchorPart.FACADE_MODELS.getModels()) {
|
||||
BakedModel partModel = modelLookup.apply(part);
|
||||
context.fallbackConsumer().accept(partModel);
|
||||
}
|
||||
context.popTransform();
|
||||
}
|
||||
// If we are forcing transparency and this isn't the Translucent layer.
|
||||
if (transparent && layer != RenderLayer.getTranslucent()) {
|
||||
continue;
|
||||
if (renderStilt) {
|
||||
cableAnchorStilts.get(entry.getKey()).forEach(quad -> {
|
||||
quad.copyTo(emitter);
|
||||
emitter.emit();
|
||||
});
|
||||
}
|
||||
|
||||
BlockState blockState = facadeRenderState.getSourceBlock();
|
||||
// If we aren't forcing transparency let the block decide if it should render.
|
||||
if (!transparent && layer != null) {
|
||||
// FIXME FABRIC if (!transparent && layer != null) {
|
||||
// FIXME FABRIC only one layer per block
|
||||
// FIXME FABRIC if (!RenderLayers.canRenderInLayer(blockState, layer)) {
|
||||
// FIXME FABRIC continue;
|
||||
// FIXME FABRIC }
|
||||
}
|
||||
// FIXME FABRIC }
|
||||
|
||||
Box fullBounds = thinFacades ? THIN_FACADE_BOXES[sideIndex] : THICK_FACADE_BOXES[sideIndex];
|
||||
Box facadeBox = fullBounds;
|
||||
@@ -179,97 +235,114 @@ public class FacadeBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
// calculate the side mask.
|
||||
int facadeMask = 0;
|
||||
for (Entry<Direction, FacadeRenderState> ent : facadeStates.entrySet()) {
|
||||
Direction s = ent.getKey();
|
||||
if (s.getAxis() != side.getAxis()) {
|
||||
FacadeRenderState otherState = ent.getValue();
|
||||
if (!otherState.isTransparent()) {
|
||||
facadeMask |= 1 << s.ordinal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AEAxisAlignedBB cutOutBox = getCutOutBox(facadeBox, partBoxes);
|
||||
List<Box> holeStrips = getBoxes(facadeBox, cutOutBox, side.getAxis());
|
||||
// FIXME BlockRenderView facadeAccess = new FacadeBlockAccess(parentWorld, pos, side, blockState);
|
||||
BlockRenderView facadeAccess = new FacadeBlockAccess(parentWorld, pos, side, blockState);
|
||||
|
||||
// FIXME FABRIC BlockRenderManager dispatcher = MinecraftClient.getInstance().getBlockRenderManager();
|
||||
// FIXME FABRIC BakedModel model = dispatcher.getModel(blockState);
|
||||
// FIXME FABRIC IModelData modelData = model.getModelData(facadeAccess, pos, blockState, EmptyModelData.INSTANCE);
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC List<BakedQuad> modelQuads = new ArrayList<>();
|
||||
// FIXME FABRIC // If we are forcing transparent facades, fake the render layer, and grab all
|
||||
// FIXME FABRIC // quads.
|
||||
// FIXME FABRIC if (transparent || layer == null) {
|
||||
// FIXME FABRIC for (RenderLayer forcedLayer : RenderLayer.getBlockRenderTypes()) {
|
||||
// FIXME FABRIC // Check if the block renders on the layer we want to force.
|
||||
// FIXME FABRIC if (RenderLayers.canRenderInLayer(blockState, forcedLayer)) {
|
||||
// FIXME FABRIC // Force the layer and gather quads.
|
||||
// FIXME FABRIC ForgeHooksClient.setRenderLayer(forcedLayer);
|
||||
// FIXME FABRIC modelQuads.addAll(gatherQuads(model, blockState, rand, modelData));
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC // Reset.
|
||||
// FIXME FABRIC ForgeHooksClient.setRenderLayer(layer);
|
||||
// FIXME FABRIC } else {
|
||||
// FIXME FABRIC modelQuads.addAll(gatherQuads(model, blockState, rand, modelData));
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC // No quads.. Cool, next!
|
||||
// FIXME FABRIC if (modelQuads.isEmpty()) {
|
||||
// FIXME FABRIC continue;
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC // Grab out pipeline elements.
|
||||
// FIXME FABRIC QuadClamper clamper = pipeline.getElement("clamper", QuadClamper.class);
|
||||
// FIXME FABRIC QuadFaceStripper edgeStripper = pipeline.getElement("face_stripper", QuadFaceStripper.class);
|
||||
// FIXME FABRIC QuadTinter tinter = pipeline.getElement("tinter", QuadTinter.class);
|
||||
// FIXME FABRIC QuadCornerKicker kicker = pipeline.getElement("corner_kicker", QuadCornerKicker.class);
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC // Set global element states.
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC // calculate the side mask.
|
||||
// FIXME FABRIC int facadeMask = 0;
|
||||
// FIXME FABRIC for (Entry<Direction, FacadeRenderState> ent : facadeStates.entrySet()) {
|
||||
// FIXME FABRIC Direction s = ent.getKey();
|
||||
// FIXME FABRIC if (s.getAxis() != side.getAxis()) {
|
||||
// FIXME FABRIC FacadeRenderState otherState = ent.getValue();
|
||||
// FIXME FABRIC if (!otherState.isTransparent()) {
|
||||
// FIXME FABRIC facadeMask |= 1 << s.ordinal();
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC // Setup the edge stripper.
|
||||
// FIXME FABRIC edgeStripper.setBounds(fullBounds);
|
||||
// FIXME FABRIC edgeStripper.setMask(facadeMask);
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC // Setup the kicker.
|
||||
// FIXME FABRIC kicker.setSide(sideIndex);
|
||||
// FIXME FABRIC kicker.setFacadeMask(facadeMask);
|
||||
// FIXME FABRIC kicker.setBox(fullBounds);
|
||||
// FIXME FABRIC kicker.setThickness(thinFacades ? THIN_THICKNESS : THICK_THICKNESS);
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC for (BakedQuad quad : modelQuads) {
|
||||
// FIXME FABRIC // lookup the format in CachedFormat.
|
||||
// FIXME FABRIC CachedFormat format = CachedFormat.lookup(VertexFormats.POSITION_COLOR_TEXTURE_LIGHT_NORMAL);
|
||||
// FIXME FABRIC // If this quad has a tint index, setup the tinter.
|
||||
// FIXME FABRIC if (quad.hasTintIndex()) {
|
||||
// FIXME FABRIC tinter.setTint(blockColors.getColor(blockState, facadeAccess, pos, quad.getColorIndex()));
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC for (Box box : holeStrips) {
|
||||
// FIXME FABRIC // setup the clamper for this box
|
||||
// FIXME FABRIC clamper.setClampBounds(box);
|
||||
// FIXME FABRIC // Reset the pipeline, clears all enabled/disabled states.
|
||||
// FIXME FABRIC pipeline.reset(format);
|
||||
// FIXME FABRIC // Reset out collector.
|
||||
// FIXME FABRIC collectorQuad.reset(format);
|
||||
// FIXME FABRIC // Enable / disable the optional elements
|
||||
// FIXME FABRIC pipeline.setElementState("tinter", quad.hasTintIndex());
|
||||
// FIXME FABRIC pipeline.setElementState("transparent", transparent);
|
||||
// FIXME FABRIC // Prepare the pipeline for a quad.
|
||||
// FIXME FABRIC pipeline.prepare(collectorQuad);
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC // Pipe our quad into the pipeline.
|
||||
// FIXME FABRIC quad.pipe(pipeline);
|
||||
// FIXME FABRIC // Check if the collector got any data.
|
||||
// FIXME FABRIC if (collectorQuad.full) {
|
||||
// FIXME FABRIC // Add the result.
|
||||
// FIXME FABRIC quads.add(collectorQuad.bake());
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC }
|
||||
BlockRenderManager dispatcher = MinecraftClient.getInstance().getBlockRenderManager();
|
||||
BakedModel model = dispatcher.getModel(blockState);
|
||||
|
||||
QuadFaceStripper faceStripper = new QuadFaceStripper(fullBounds, facadeMask);
|
||||
// Setup the kicker.
|
||||
QuadCornerKicker kicker = new QuadCornerKicker();
|
||||
kicker.setSide(sideIndex);
|
||||
kicker.setFacadeMask(facadeMask);
|
||||
kicker.setBox(fullBounds);
|
||||
kicker.setThickness(thinFacades ? THIN_THICKNESS : THICK_THICKNESS);
|
||||
|
||||
QuadReInterpolator interpolator = new QuadReInterpolator();
|
||||
|
||||
for (int cullFaceIdx = 0; cullFaceIdx <= ModelHelper.NULL_FACE_ID; cullFaceIdx++) {
|
||||
Direction cullFace = ModelHelper.faceFromIndex(cullFaceIdx);
|
||||
List<BakedQuad> quads = model.getQuads(blockState, cullFace, rand.get());
|
||||
|
||||
for (BakedQuad quad : quads) {
|
||||
QuadTinter quadTinter = null;
|
||||
|
||||
// Prebake the color tint into the quad
|
||||
if (quad.getColorIndex() != -1) {
|
||||
quadTinter = new QuadTinter(blockColors.getColor(blockState, facadeAccess, pos, quad.getColorIndex()));
|
||||
}
|
||||
|
||||
for (Box box : holeStrips) {
|
||||
emitter.fromVanilla(quad.getVertexData(), 0, false);
|
||||
emitter.cullFace(cullFace);
|
||||
emitter.nominalFace(quad.getFace());
|
||||
interpolator.setInputQuad(emitter);
|
||||
|
||||
QuadClamper clamper = new QuadClamper(box);
|
||||
if (!clamper.transform(emitter)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Strips faces if they match a mask.
|
||||
if (!faceStripper.transform(emitter)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Kicks the edge inner corners in, solves Z fighting
|
||||
if (!kicker.transform(emitter)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
interpolator.transform(emitter);
|
||||
|
||||
// Tints the quad if we need it to. Disabled by default.
|
||||
if (quadTinter != null) {
|
||||
quadTinter.transform(emitter);
|
||||
}
|
||||
|
||||
// // Overrides the quad's alpha if we are forcing transparent facades.
|
||||
// .addElement("transparent", QuadAlphaOverride.FACTORY, false, e -> e.setAlphaOverride(0x4C / 255F)).build()//
|
||||
|
||||
emitter.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME FABRIC List<BakedQuad> modelQuads = new ArrayList<>();
|
||||
// FIXME FABRIC modelQuads.addAll(gatherQuads(model, blockState, rand));
|
||||
|
||||
// FIXME FABRIC // No quads.. Cool, next!
|
||||
// FIXME FABRIC if (modelQuads.isEmpty()) {
|
||||
// FIXME FABRIC continue;
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC // Grab out pipeline elements.
|
||||
// FIXME FABRIC QuadClamper clamper = pipeline.getElement("clamper", QuadClamper.class);
|
||||
// FIXME FABRIC QuadFaceStripper edgeStripper = pipeline.getElement("face_stripper", QuadFaceStripper.class);
|
||||
// FIXME FABRIC QuadTinter tinter = pipeline.getElement("tinter", QuadTinter.class);
|
||||
// FIXME FABRIC QuadCornerKicker kicker = pipeline.getElement("corner_kicker", QuadCornerKicker.class);
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC // Set global element states.
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC // Setup the kicker.
|
||||
// FIXME FABRIC kicker.setSide(sideIndex);
|
||||
// FIXME FABRIC kicker.setFacadeMask(facadeMask);
|
||||
// FIXME FABRIC kicker.setBox(fullBounds);
|
||||
// FIXME FABRIC kicker.setThickness(thinFacades ? THIN_THICKNESS : THICK_THICKNESS);
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC for (BakedQuad quad : modelQuads) {
|
||||
// FIXME FABRIC // lookup the format in CachedFormat.
|
||||
// FIXME FABRIC CachedFormat format = CachedFormat.lookup(VertexFormats.POSITION_COLOR_TEXTURE_LIGHT_NORMAL);
|
||||
|
||||
// FIXME FABRIC }
|
||||
}
|
||||
|
||||
return meshBuilder.build();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -362,7 +435,6 @@ public class FacadeBuilder {
|
||||
* @param fb The Facade's box.
|
||||
* @param hole The hole to 'cut'.
|
||||
* @param axis The axis the facade is on.
|
||||
*
|
||||
* @return The box segments.
|
||||
*/
|
||||
private static List<Box> getBoxes(Box fb, AEAxisAlignedBB hole, Axis axis) {
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
|
||||
package appeng.client.render.cablebus;
|
||||
|
||||
import appeng.api.parts.IDynamicPartBakedModel;
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.util.Platform;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||
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.render.RenderContext;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.render.model.json.ModelOverrideList;
|
||||
import net.minecraft.client.render.model.json.ModelTransformation;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class P2PTunnelFrequencyBakedModel implements IDynamicPartBakedModel {
|
||||
|
||||
private final Renderer renderer = RendererAccess.INSTANCE.getRenderer();
|
||||
|
||||
private final Sprite texture;
|
||||
|
||||
private final static Cache<Long, Mesh> modelCache = CacheBuilder.newBuilder().maximumSize(100).build();
|
||||
|
||||
private static final int[][] QUAD_OFFSETS = new int[][]{{4, 10, 2}, {10, 10, 2}, {4, 4, 2}, {10, 4, 2}};
|
||||
|
||||
public P2PTunnelFrequencyBakedModel(final Sprite texture) {
|
||||
this.texture = texture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context,
|
||||
Direction partSide, @Nullable Object modelData) {
|
||||
if (!(modelData instanceof Long)) {
|
||||
return;
|
||||
}
|
||||
long frequency = (long) modelData;
|
||||
|
||||
Mesh frequencyMesh = getFrequencyModel(frequency);
|
||||
if (frequencyMesh != null) {
|
||||
context.meshConsumer().accept(frequencyMesh);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelTransformation getTransformation() {
|
||||
return ModelTransformation.NONE;
|
||||
}
|
||||
|
||||
private Mesh createFrequencyMesh(final short frequency, final boolean active) {
|
||||
|
||||
MeshBuilder meshBuilder = renderer.meshBuilder();
|
||||
|
||||
final AEColor[] colors = Platform.p2p().toColors(frequency);
|
||||
final CubeBuilder cb = new CubeBuilder(meshBuilder.getEmitter());
|
||||
|
||||
cb.setTexture(this.texture);
|
||||
cb.useStandardUV();
|
||||
cb.setRenderFullBright(active);
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
final int[] offs = QUAD_OFFSETS[i];
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
final float[] cv = colors[j].dye.getColorComponents();
|
||||
if (active) {
|
||||
cb.setColorRGB(cv[0], cv[1], cv[2]);
|
||||
} else {
|
||||
cb.setColorRGB(cv[0] * 0.5f, cv[1] * 0.5f, cv[2] * 0.5f);
|
||||
}
|
||||
|
||||
final int startx = j % 2;
|
||||
final int starty = 1 - j / 2;
|
||||
|
||||
cb.addCube(offs[0] + startx, offs[1] + starty, offs[2], offs[0] + startx + 1, offs[1] + starty + 1,
|
||||
offs[2] + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return meshBuilder.build();
|
||||
}
|
||||
|
||||
private Mesh getFrequencyModel(long partFlags) {
|
||||
try {
|
||||
return modelCache.get(partFlags, () -> {
|
||||
short frequency = (short) (partFlags & 0xffffL);
|
||||
boolean active = (partFlags & 0x10000L) != 0;
|
||||
return this.createFrequencyMesh(frequency, active);
|
||||
});
|
||||
} catch (ExecutionException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAmbientOcclusion() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDepth() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSideLit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltin() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sprite getSprite() {
|
||||
return this.texture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelOverrideList getOverrides() {
|
||||
return ModelOverrideList.EMPTY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package appeng.client.render.cablebus;
|
||||
|
||||
import appeng.client.render.BasicUnbakedModel;
|
||||
import appeng.core.AppEng;
|
||||
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.texture.Sprite;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.client.util.SpriteIdentifier;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class P2PTunnelFrequencyModel implements BasicUnbakedModel {
|
||||
|
||||
private static final SpriteIdentifier TEXTURE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
|
||||
new Identifier(AppEng.MOD_ID, "part/p2p_tunnel_frequency"));
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BakedModel bake(ModelLoader loader, Function<SpriteIdentifier, Sprite> textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) {
|
||||
final Sprite texture = textureGetter.apply(TEXTURE);
|
||||
return new P2PTunnelFrequencyBakedModel(texture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<SpriteIdentifier> getAdditionalTextures() {
|
||||
return Stream.of(TEXTURE);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user