Lots of fixes

This commit is contained in:
Sebastian Hartte
2020-07-23 02:38:32 +02:00
parent 1933b4b10d
commit 9fcfbf31be
100 changed files with 1771 additions and 1866 deletions
@@ -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);
}
}