hot swappable rendering

kind of detects optifine
still some kinks to work out
This commit is contained in:
JozsefA 2021-02-07 14:15:52 -08:00
parent 3e6ef34993
commit c9ff31b099
35 changed files with 579 additions and 268 deletions

View file

@ -12,9 +12,10 @@ import com.simibubi.create.foundation.block.render.SpriteShifter;
import com.simibubi.create.foundation.item.CustomItemModels;
import com.simibubi.create.foundation.item.CustomRenderedItems;
import com.simibubi.create.foundation.render.KineticRenderer;
import com.simibubi.create.foundation.render.OptifineHandler;
import com.simibubi.create.foundation.render.SuperByteBufferCache;
import com.simibubi.create.foundation.render.contraption.ContraptionRenderDispatcher;
import com.simibubi.create.foundation.render.gl.shader.ShaderHelper;
import com.simibubi.create.foundation.render.gl.backend.Backend;
import com.simibubi.create.foundation.utility.outliner.Outliner;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
@ -31,8 +32,6 @@ 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.ModList;
import net.minecraftforge.fml.ModLoader;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import java.util.ArrayList;
@ -62,10 +61,13 @@ public class CreateClient {
modEventBus.addListener(CreateClient::onTextureStitch);
modEventBus.addListener(AllParticleTypes::registerFactories);
ShaderHelper.initShaders();
Backend.init();
OptifineHandler.init();
}
public static void clientInit(FMLClientSetupEvent event) {
kineticRenderer = new KineticRenderer();
schematicSender = new ClientSchematicLoader();
schematicHandler = new SchematicHandler();
schematicAndQuillHandler = new SchematicAndQuillHandler();
@ -74,8 +76,6 @@ public class CreateClient {
bufferCache.registerCompartment(KineticTileEntityRenderer.KINETIC_TILE);
bufferCache.registerCompartment(ContraptionRenderer.CONTRAPTION, 20);
kineticRenderer = new KineticRenderer();
AllKeys.register();
AllContainerTypes.registerScreenFactories();
//AllTileEntities.registerRenderers();

View file

@ -30,6 +30,8 @@ import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
import javax.annotation.Nullable;
import java.util.List;
@ -475,13 +477,13 @@ public abstract class KineticTileEntity extends SmartTileEntity
public void onLoad() {
super.onLoad();
if (world != null && world.isRemote)
CreateClient.kineticRenderer.add(this);
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> CreateClient.kineticRenderer.add(this));
}
@Override
public void onChunkUnloaded() {
if (world != null && world.isRemote)
CreateClient.kineticRenderer.remove(this);
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> CreateClient.kineticRenderer.remove(this));
}
@Override

View file

@ -6,6 +6,9 @@ import com.simibubi.create.AllBlocks;
import com.simibubi.create.CreateClient;
import com.simibubi.create.content.contraptions.KineticDebugger;
import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.config.ConfigBase;
import com.simibubi.create.foundation.render.FastRenderDispatcher;
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.ColorHelper;
@ -38,6 +41,8 @@ public class KineticTileEntityRenderer extends SafeTileEntityRenderer<KineticTil
@Override
protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
int light, int overlay) {
if (FastRenderDispatcher.available()) return;
for (RenderType type : RenderType.getBlockLayers())
if (RenderTypeLookup.canRenderInLayer(te.getBlockState(), type))
renderRotatingBuffer(te, getRotatedModel(te), ms, buffer.getBuffer(type), light);

View file

@ -6,6 +6,8 @@ import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.AllSpriteShifts;
import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterTileEntity.Phase;
import com.simibubi.create.content.contraptions.components.crafter.RecipeGridHandler.GroupedItems;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.render.FastRenderDispatcher;
import com.simibubi.create.foundation.render.SuperByteBuffer;
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
import com.simibubi.create.foundation.utility.AngleHelper;
@ -152,12 +154,13 @@ public class MechanicalCrafterRenderer extends SafeTileEntityRenderer<Mechanical
BlockState blockState = te.getBlockState();
IVertexBuilder vb = buffer.getBuffer(RenderType.getSolid());
SuperByteBuffer superBuffer = AllBlockPartials.SHAFTLESS_COGWHEEL.renderOn(blockState);
standardKineticRotationTransform(superBuffer, te, light);
superBuffer.rotateCentered(Direction.UP, (float) (blockState.get(HORIZONTAL_FACING)
.getAxis() != Direction.Axis.X ? 0 : Math.PI / 2));
superBuffer.rotateCentered(Direction.EAST, (float) (Math.PI / 2));
superBuffer.renderInto(ms, vb);
if (!FastRenderDispatcher.available()) {
SuperByteBuffer superBuffer = AllBlockPartials.SHAFTLESS_COGWHEEL.renderOn(blockState);
standardKineticRotationTransform(superBuffer, te, light);
superBuffer.rotateCentered(Direction.UP, (float) (blockState.get(HORIZONTAL_FACING).getAxis() != Direction.Axis.X ? 0 : Math.PI / 2));
superBuffer.rotateCentered(Direction.EAST, (float) (Math.PI / 2));
superBuffer.renderInto(ms, vb);
}
Direction targetDirection = MechanicalCrafterBlock.getTargetDirection(blockState);
BlockPos pos = te.getPos();

View file

@ -11,6 +11,8 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity.Mode;
import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity.State;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.render.FastRenderDispatcher;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringRenderer;
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
import com.simibubi.create.foundation.utility.AngleHelper;
@ -102,7 +104,9 @@ public class DeployerRenderer extends SafeTileEntityRenderer<DeployerTileEntity>
protected void renderComponents(DeployerTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
int light, int overlay) {
IVertexBuilder vb = buffer.getBuffer(RenderType.getSolid());
KineticTileEntityRenderer.renderRotatingKineticBlock(te, getRenderedBlockState(te), ms, vb, light);
if (!FastRenderDispatcher.available()) {
KineticTileEntityRenderer.renderRotatingKineticBlock(te, getRenderedBlockState(te), ms, vb, light);
}
BlockState blockState = te.getBlockState();
BlockPos pos = te.getPos();

View file

@ -376,4 +376,9 @@ public class DeployerTileEntity extends KineticTileEntity {
TooltipHelper.addHint(tooltip, "hint.full_deployer");
return true;
}
@Override
public boolean shouldRenderAsTE() {
return true;
}
}

View file

@ -7,6 +7,8 @@ import com.mojang.blaze3d.vertex.IVertexBuilder;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.render.FastRenderDispatcher;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.render.SuperByteBuffer;
@ -26,6 +28,8 @@ public class EncasedFanRenderer extends KineticTileEntityRenderer {
@Override
protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
int light, int overlay) {
if (FastRenderDispatcher.available()) return;
Direction direction = te.getBlockState()
.get(FACING);
IVertexBuilder vb = buffer.getBuffer(RenderType.getCutoutMipped());

View file

@ -5,6 +5,8 @@ import com.mojang.blaze3d.vertex.IVertexBuilder;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.render.FastRenderDispatcher;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.render.SuperByteBuffer;
@ -31,8 +33,10 @@ public class MechanicalMixerRenderer extends KineticTileEntityRenderer {
IVertexBuilder vb = buffer.getBuffer(RenderType.getSolid());
SuperByteBuffer superBuffer = AllBlockPartials.SHAFTLESS_COGWHEEL.renderOn(blockState);
standardKineticRotationTransform(superBuffer, te, light).renderInto(ms, vb);
if (!FastRenderDispatcher.available()) {
SuperByteBuffer superBuffer = AllBlockPartials.SHAFTLESS_COGWHEEL.renderOn(blockState);
standardKineticRotationTransform(superBuffer, te, light).renderInto(ms, vb);
}
int packedLightmapCoords = WorldRenderer.getLightmapCoordinates(te.getWorld(), blockState, pos);
float renderedHeadOffset = mixer.getRenderedHeadOffset(partialTicks);

View file

@ -8,6 +8,8 @@ import com.simibubi.create.CreateClient;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.render.FastRenderDispatcher;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringRenderer;
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
import com.simibubi.create.foundation.utility.AngleHelper;
@ -42,6 +44,9 @@ public class SawRenderer extends SafeTileEntityRenderer<SawTileEntity> {
renderBlade(te, ms, buffer, light);
renderItems(te, partialTicks, ms, buffer, light, overlay);
FilteringRenderer.renderOnTileEntity(te, partialTicks, ms, buffer, light, overlay);
if (FastRenderDispatcher.available()) return;
renderShaft(te, ms, buffer, light, overlay);
}

View file

@ -143,4 +143,8 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
protected abstract Object getRecipeCacheKey();
@Override
public boolean shouldRenderAsTE() {
return true;
}
}

View file

@ -1,11 +1,14 @@
package com.simibubi.create.content.contraptions.relays.advanced;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.CreateClient;
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.foundation.render.instancing.InstancedModel;
import com.simibubi.create.foundation.render.instancing.RotatingData;
import com.simibubi.create.foundation.render.FastRenderDispatcher;
import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer;
import com.simibubi.create.foundation.render.SuperByteBuffer;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
public class SpeedControllerRenderer extends SmartTileEntityRenderer<SpeedControllerTileEntity> {
@ -18,7 +21,17 @@ public class SpeedControllerRenderer extends SmartTileEntityRenderer<SpeedContro
protected void renderSafe(SpeedControllerTileEntity tileEntityIn, float partialTicks, MatrixStack ms,
IRenderTypeBuffer buffer, int light, int overlay) {
super.renderSafe(tileEntityIn, partialTicks, ms, buffer, light, overlay);
// addInstanceData(new InstanceContext.World<>(tileEntityIn));
if (FastRenderDispatcher.available()) return;
KineticTileEntityRenderer.renderRotatingBuffer(tileEntityIn, getRotatedModel(tileEntityIn), ms,
buffer.getBuffer(RenderType.getSolid()), light);
}
private SuperByteBuffer getRotatedModel(SpeedControllerTileEntity te) {
return CreateClient.bufferCache.renderBlockIn(KineticTileEntityRenderer.KINETIC_TILE,
KineticTileEntityRenderer.shaft(KineticTileEntityRenderer.getRotationAxisOf(te)));
}
}

View file

@ -9,11 +9,9 @@ import com.simibubi.create.CreateClient;
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack;
import com.simibubi.create.foundation.block.render.SpriteShiftEntry;
import com.simibubi.create.foundation.render.FastRenderDispatcher;
import com.simibubi.create.foundation.render.ShadowRenderHelper;
import com.simibubi.create.foundation.render.SuperByteBuffer;
import com.simibubi.create.foundation.render.instancing.BeltData;
import com.simibubi.create.foundation.render.instancing.InstancedModel;
import com.simibubi.create.foundation.render.instancing.RotatingData;
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
@ -34,10 +32,8 @@ import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.LightType;
import java.util.Random;
import java.util.function.Supplier;
public class BeltRenderer extends SafeTileEntityRenderer<BeltTileEntity> {
@ -54,96 +50,89 @@ public class BeltRenderer extends SafeTileEntityRenderer<BeltTileEntity> {
protected void renderSafe(BeltTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
int light, int overlay) {
BlockState blockState = te.getBlockState();
if (!AllBlocks.BELT.has(blockState))
return;
if (!FastRenderDispatcher.available()) {
BeltSlope beltSlope = blockState.get(BeltBlock.SLOPE);
BeltPart part = blockState.get(BeltBlock.PART);
Direction facing = blockState.get(BeltBlock.HORIZONTAL_FACING);
AxisDirection axisDirection = facing.getAxisDirection();
BlockState blockState = te.getBlockState();
if (!AllBlocks.BELT.has(blockState)) return;
boolean downward = beltSlope == BeltSlope.DOWNWARD;
boolean upward = beltSlope == BeltSlope.UPWARD;
boolean diagonal = downward || upward;
boolean start = part == BeltPart.START;
boolean end = part == BeltPart.END;
boolean sideways = beltSlope == BeltSlope.SIDEWAYS;
boolean alongX = facing.getAxis() == Axis.X;
BeltSlope beltSlope = blockState.get(BeltBlock.SLOPE);
BeltPart part = blockState.get(BeltBlock.PART);
Direction facing = blockState.get(BeltBlock.HORIZONTAL_FACING);
AxisDirection axisDirection = facing.getAxisDirection();
MatrixStacker msr = MatrixStacker.of(ms);
IVertexBuilder vb = buffer.getBuffer(RenderType.getSolid());
float renderTick = AnimationTickHolder.getRenderTick();
boolean downward = beltSlope == BeltSlope.DOWNWARD;
boolean upward = beltSlope == BeltSlope.UPWARD;
boolean diagonal = downward || upward;
boolean start = part == BeltPart.START;
boolean end = part == BeltPart.END;
boolean sideways = beltSlope == BeltSlope.SIDEWAYS;
boolean alongX = facing.getAxis() == Axis.X;
ms.push();
msr.centre();
msr.rotateY(AngleHelper.horizontalAngle(facing) + (upward ? 180 : 0) + (sideways ? 270 : 0));
msr.rotateZ(sideways ? 90 : 0);
msr.rotateX(!diagonal && beltSlope != BeltSlope.HORIZONTAL ? 90 : 0);
msr.unCentre();
MatrixStacker msr = MatrixStacker.of(ms);
IVertexBuilder vb = buffer.getBuffer(RenderType.getSolid());
float renderTick = AnimationTickHolder.getRenderTick();
if (downward || beltSlope == BeltSlope.VERTICAL && axisDirection == AxisDirection.POSITIVE) {
boolean b = start;
start = end;
end = b;
}
for (boolean bottom : Iterate.trueAndFalse) {
AllBlockPartials beltPartial = getBeltPartial(diagonal, start, end, bottom);
SuperByteBuffer beltBuffer = beltPartial.renderOn(blockState)
.light(light);
SpriteShiftEntry spriteShift = getSpriteShiftEntry(diagonal, bottom);
// UV shift
float speed = te.getSpeed();
if (speed != 0) {
float time = renderTick * axisDirection.getOffset();
if (diagonal && (downward ^ alongX) || !sideways && !diagonal && alongX
|| sideways && axisDirection == AxisDirection.NEGATIVE)
speed = -speed;
float scrollMult = diagonal ? 3f / 8f : 0.5f;
float spriteSize = spriteShift.getTarget().getMaxV() - spriteShift.getTarget().getMinV();
double scroll = speed * time / (36 * 16);
scroll = scroll - Math.floor(scroll);
scroll = scroll * spriteSize * scrollMult;
beltBuffer.shiftUVScrolling(spriteShift, (float) scroll);
}
beltBuffer.renderInto(ms, vb);
// Diagonal belt do not have a separate bottom model
if (diagonal)
break;
}
ms.pop();
if (te.hasPulley()) {
// TODO 1.15 find a way to cache this model matrix computation
MatrixStack modelTransform = new MatrixStack();
Direction dir = blockState.get(BeltBlock.HORIZONTAL_FACING)
.rotateY();
if (sideways)
dir = Direction.UP;
msr = MatrixStacker.of(modelTransform);
ms.push();
msr.centre();
if (dir.getAxis() == Axis.X)
msr.rotateY(90);
if (dir.getAxis() == Axis.Y)
msr.rotateX(90);
msr.rotateX(90);
msr.rotateY(AngleHelper.horizontalAngle(facing) + (upward ? 180 : 0) + (sideways ? 270 : 0));
msr.rotateZ(sideways ? 90 : 0);
msr.rotateX(!diagonal && beltSlope != BeltSlope.HORIZONTAL ? 90 : 0);
msr.unCentre();
SuperByteBuffer superBuffer = CreateClient.bufferCache
.renderDirectionalPartial(AllBlockPartials.BELT_PULLEY, blockState, dir, modelTransform);
KineticTileEntityRenderer.standardKineticRotationTransform(superBuffer, te, light)
.renderInto(ms, vb);
if (downward || beltSlope == BeltSlope.VERTICAL && axisDirection == AxisDirection.POSITIVE) {
boolean b = start;
start = end;
end = b;
}
for (boolean bottom : Iterate.trueAndFalse) {
AllBlockPartials beltPartial = getBeltPartial(diagonal, start, end, bottom);
SuperByteBuffer beltBuffer = beltPartial.renderOn(blockState).light(light);
SpriteShiftEntry spriteShift = getSpriteShiftEntry(diagonal, bottom);
// UV shift
float speed = te.getSpeed();
if (speed != 0) {
float time = renderTick * axisDirection.getOffset();
if (diagonal && (downward ^ alongX) || !sideways && !diagonal && alongX || sideways && axisDirection == AxisDirection.NEGATIVE)
speed = -speed;
float scrollMult = diagonal ? 3f / 8f : 0.5f;
float spriteSize = spriteShift.getTarget().getMaxV() - spriteShift.getTarget().getMinV();
double scroll = speed * time / (36 * 16);
scroll = scroll - Math.floor(scroll);
scroll = scroll * spriteSize * scrollMult;
beltBuffer.shiftUVScrolling(spriteShift, (float) scroll);
}
beltBuffer.renderInto(ms, vb);
// Diagonal belt do not have a separate bottom model
if (diagonal) break;
}
ms.pop();
if (te.hasPulley()) {
// TODO 1.15 find a way to cache this model matrix computation
MatrixStack modelTransform = new MatrixStack();
Direction dir = blockState.get(BeltBlock.HORIZONTAL_FACING).rotateY();
if (sideways) dir = Direction.UP;
msr = MatrixStacker.of(modelTransform);
msr.centre();
if (dir.getAxis() == Axis.X) msr.rotateY(90);
if (dir.getAxis() == Axis.Y) msr.rotateX(90);
msr.rotateX(90);
msr.unCentre();
SuperByteBuffer superBuffer = CreateClient.bufferCache.renderDirectionalPartial(AllBlockPartials.BELT_PULLEY, blockState, dir, modelTransform);
KineticTileEntityRenderer.standardKineticRotationTransform(superBuffer, te, light).renderInto(ms, vb);
}
}
renderItems(te, partialTicks, ms, buffer, light, overlay);

View file

@ -5,6 +5,7 @@ import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.contraptions.base.IRotate;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.foundation.render.FastRenderDispatcher;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.render.SuperByteBuffer;
@ -16,6 +17,7 @@ import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.BlockPos;
import sun.nio.cs.FastCharsetProvider;
public class SplitShaftRenderer extends KineticTileEntityRenderer {
@ -26,6 +28,8 @@ public class SplitShaftRenderer extends KineticTileEntityRenderer {
@Override
protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
int light, int overlay) {
if (FastRenderDispatcher.available()) return;
Block block = te.getBlockState().getBlock();
final Axis boxAxis = ((IRotate) block).getRotationAxis(te.getBlockState());
final BlockPos pos = te.getPos();

View file

@ -4,6 +4,7 @@ import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.foundation.render.FastRenderDispatcher;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.render.SuperByteBuffer;
@ -25,6 +26,8 @@ public class GearboxRenderer extends KineticTileEntityRenderer {
@Override
protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
int light, int overlay) {
if (FastRenderDispatcher.available()) return;
final Axis boxAxis = te.getBlockState().get(BlockStateProperties.AXIS);
final BlockPos pos = te.getPos();
float time = AnimationTickHolder.getRenderTick();

View file

@ -13,6 +13,7 @@ public class AllCommands {
.then(ToggleDebugCommand.register())
.then(OverlayConfigCommand.register())
.then(FixLightingCommand.register())
.then(ToggleExperimentalRenderingCommand.register())
//dev-util
//Comment out for release

View file

@ -3,6 +3,9 @@ package com.simibubi.create.foundation.command;
import java.util.function.Consumer;
import java.util.function.Supplier;
import com.simibubi.create.foundation.render.FastRenderDispatcher;
import com.simibubi.create.foundation.render.gl.backend.Backend;
import javafx.scene.layout.Background;
import org.apache.logging.log4j.LogManager;
import com.simibubi.create.content.contraptions.goggles.GoggleConfigScreen;
@ -61,6 +64,7 @@ public class ConfigureConfigPacket extends SimplePacketBase {
overlayScreen(() -> Actions::overlayScreen),
fixLighting(() -> Actions::experimentalLighting),
overlayReset(() -> Actions::overlayReset),
experimentalRendering(() -> Actions::experimentalRendering),
;
@ -79,6 +83,17 @@ public class ConfigureConfigPacket extends SimplePacketBase {
private static void rainbowDebug(String value) {
AllConfigs.CLIENT.rainbowDebug.set(Boolean.parseBoolean(value));
}
@OnlyIn(Dist.CLIENT)
private static void experimentalRendering(String value) {
boolean last = AllConfigs.CLIENT.experimentalRendering.get();
AllConfigs.CLIENT.experimentalRendering.set(Boolean.parseBoolean(value));
Backend.refreshAvailability();
if (last != AllConfigs.CLIENT.experimentalRendering.get()) {
FastRenderDispatcher.refresh();
}
}
@OnlyIn(Dist.CLIENT)
private static void overlayReset(String value) {

View file

@ -0,0 +1,35 @@
package com.simibubi.create.foundation.command;
import com.mojang.brigadier.arguments.BoolArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.simibubi.create.foundation.networking.AllPackets;
import net.minecraft.command.CommandSource;
import net.minecraft.command.Commands;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.util.text.StringTextComponent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.network.PacketDistributor;
public class ToggleExperimentalRenderingCommand {
static ArgumentBuilder<CommandSource, ?> register() {
return Commands.literal("experimentalRendering")
.requires(cs -> cs.hasPermissionLevel(0))
.then(Commands.argument("value", BoolArgumentType.bool())
.executes(ctx -> {
boolean value = BoolArgumentType.getBool(ctx, "value");
//DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> AllConfigs.CLIENT.rainbowDebug.set(value));
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> ConfigureConfigPacket.Actions.experimentalRendering.performAction(String.valueOf(value)));
DistExecutor.runWhenOn(Dist.DEDICATED_SERVER, () -> () ->
AllPackets.channel.send(
PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) ctx.getSource().getEntity()),
new ConfigureConfigPacket(ConfigureConfigPacket.Actions.experimentalRendering.name(), String.valueOf(value))));
ctx.getSource().sendFeedback(new StringTextComponent((value ? "enabled" : "disabled") + " experimental rendering"), true);
return 1;
}));
}
}

View file

@ -1,5 +1,7 @@
package com.simibubi.create.foundation.config;
import com.simibubi.create.foundation.render.gl.backend.Backend;
public class CClient extends ConfigBase {
public ConfigGroup client = group(0, "client",
@ -13,6 +15,9 @@ public class CClient extends ConfigBase {
public ConfigBool rainbowDebug =
b(true, "enableRainbowDebug", "Show colourful debug information while the F3-Menu is open.");
public ConfigRender experimentalRendering =
new ConfigRender("experimentalRendering", true, "Use modern OpenGL features to drastically increase performance.");
public ConfigInt overlayOffsetX = i(20, Integer.MIN_VALUE, Integer.MAX_VALUE, "overlayOffsetX", "Offset the overlay from goggle- and hover- information by this many pixels on the X axis; Use /create overlay");
public ConfigInt overlayOffsetY = i(0, Integer.MIN_VALUE, Integer.MAX_VALUE, "overlayOffsetY", "Offset the overlay from goggle- and hover- information by this many pixels on the Y axis; Use /create overlay");
@ -21,4 +26,32 @@ public class CClient extends ConfigBase {
return "client";
}
public class ConfigRender extends ConfigBool {
public ConfigRender(String name, boolean def, String... comment) {
super(name, def, comment);
}
/**
* Gets the configured value and checks if the rendering is actually supported.
* @return True if fast rendering is enabled and the current system/configuration is capable.
*/
@Override
public Boolean get() {
boolean enabled = super.get();
if (enabled) {
switch (Backend.getAvailability()) {
case FULL:
case PARTIAL:
return true;
default:
return false;
}
} else {
return false;
}
}
}
}

View file

@ -1,5 +1,6 @@
package com.simibubi.create.foundation.mixin;
import com.simibubi.create.foundation.render.FastRenderDispatcher;
import com.simibubi.create.foundation.render.instancing.IInstanceRendered;
import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher;
import net.minecraft.tileentity.TileEntity;
@ -25,8 +26,10 @@ public class CancelTileEntityRenderMixin {
*/
@Inject(at = @At("RETURN"), method = "getTileEntities", cancellable = true)
private void noRenderInstancedTiles(CallbackInfoReturnable<List<TileEntity>> cir) {
// List<TileEntity> tiles = cir.getReturnValue();
//
// tiles.removeIf(tile -> tile instanceof IInstanceRendered && !((IInstanceRendered) tile).shouldRenderAsTE());
if (FastRenderDispatcher.available()) {
List<TileEntity> tiles = cir.getReturnValue();
tiles.removeIf(tile -> tile instanceof IInstanceRendered && !((IInstanceRendered) tile).shouldRenderAsTE());
}
}
}

View file

@ -3,12 +3,12 @@ package com.simibubi.create.foundation.render;
import com.simibubi.create.Create;
import com.simibubi.create.foundation.render.contraption.ContraptionProgram;
import com.simibubi.create.foundation.render.gl.BasicProgram;
import com.simibubi.create.foundation.render.gl.backend.Backend;
import com.simibubi.create.foundation.render.gl.shader.GlProgram;
import com.simibubi.create.foundation.render.gl.shader.ProgramSpec;
import com.simibubi.create.foundation.render.gl.shader.ShaderConstants;
import net.minecraft.util.ResourceLocation;
import static com.simibubi.create.foundation.render.gl.shader.ShaderHelper.register;
public class AllProgramSpecs {
public static final ProgramSpec<BasicProgram> ROTATING = register(new ProgramSpec<>("rotating", Locations.ROTATING, Locations.INSTANCED, BasicProgram::new));
public static final ProgramSpec<BasicProgram> BELT = register(new ProgramSpec<>("belt", Locations.BELT, Locations.INSTANCED, BasicProgram::new));
@ -17,6 +17,10 @@ public class AllProgramSpecs {
public static final ProgramSpec<ContraptionProgram> CONTRAPTION_BELT = register(new ProgramSpec<>("contraption_belt", Locations.BELT, Locations.CONTRAPTION, ContraptionProgram::new, ShaderConstants.define("CONTRAPTION")));
public static final ProgramSpec<ContraptionProgram> CONTRAPTION_ACTOR = register(new ProgramSpec<>("contraption_actor", Locations.CONTRAPTION_ACTOR, Locations.CONTRAPTION, ContraptionProgram::new));
private static <P extends GlProgram, S extends ProgramSpec<P>> S register(S spec) {
return Backend.register(spec);
}
public static class Locations {
public static final ResourceLocation INSTANCED = loc("instanced.frag");
public static final ResourceLocation CONTRAPTION = loc("contraption.frag");

View file

@ -3,9 +3,8 @@ package com.simibubi.create.foundation.render;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.render.contraption.ContraptionRenderDispatcher;
import com.simibubi.create.foundation.render.gl.shader.ShaderHelper;
import com.simibubi.create.foundation.render.instancing.TileEntityInstance;
import com.simibubi.create.foundation.render.light.ILightListener;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.WorldAttached;
@ -25,6 +24,7 @@ import net.minecraft.world.ILightReader;
import net.minecraft.world.LightType;
import net.minecraft.world.chunk.Chunk;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
import javax.annotation.Nullable;
import java.util.ArrayList;
@ -56,18 +56,36 @@ public class FastRenderDispatcher {
runQueue(queuedUpdates.get(world), CreateClient.kineticRenderer::update);
}
public static boolean available() {
return AllConfigs.CLIENT.experimentalRendering.get();
}
public static void refresh() {
RenderWork.enqueue(() -> {
CreateClient.kineticRenderer.invalidate();
Minecraft.getInstance().worldRenderer.loadRenderers();
ClientWorld world = Minecraft.getInstance().world;
if (world != null) world.loadedTileEntityList.forEach(CreateClient.kineticRenderer::add);
});
}
private static <T> void runQueue(@Nullable ConcurrentHashMap.KeySetView<T, Boolean> changed, Consumer<T> action) {
if (changed == null) return;
// because of potential concurrency issues, we make a copy of what's in the set at the time we get here
ArrayList<T> tiles = new ArrayList<>(changed);
if (available()) {
// because of potential concurrency issues, we make a copy of what's in the set at the time we get here
ArrayList<T> tiles = new ArrayList<>(changed);
tiles.forEach(action);
changed.removeAll(tiles);
tiles.forEach(action);
changed.removeAll(tiles);
} else {
changed.clear();
}
}
public static void renderLayer(RenderType type, MatrixStack stack, double cameraX, double cameraY, double cameraZ) {
if (!available()) return;
Matrix4f viewProjection = Matrix4f.translate((float) -cameraX, (float) -cameraY, (float) -cameraZ);
viewProjection.multiplyBackward(stack.peek().getModel());
viewProjection.multiplyBackward(getProjectionMatrix());
@ -82,7 +100,7 @@ public class FastRenderDispatcher {
//RenderSystem.disableDepthTest();
ContraptionRenderDispatcher.renderLayer(type, viewProjection);
ShaderHelper.releaseShader();
GL20.glUseProgram(0);
type.endDrawing();
}

View file

@ -0,0 +1,57 @@
package com.simibubi.create.foundation.render;
import com.simibubi.create.foundation.render.gl.backend.Backend;
import net.minecraft.client.Minecraft;
import java.io.*;
import java.util.Optional;
public class OptifineHandler {
private static Package optifine;
private static OptifineHandler handler;
public final boolean usingShaders;
public OptifineHandler(boolean usingShaders) {
this.usingShaders = usingShaders;
}
public static Optional<OptifineHandler> get() {
return Optional.ofNullable(handler);
}
public static void init() {
optifine = Package.getPackage("net.optifine");
if (optifine == null) {
Backend.log.info("Optifine not detected.");
} else {
Backend.log.info("Optifine detected.");
refresh();
}
}
public static void refresh() {
if (optifine == null) return;
File dir = Minecraft.getInstance().gameDir;
File shaderOptions = new File(dir, "optionsshaders.txt");
boolean shadersOff = true;
try {
BufferedReader reader = new BufferedReader(new FileReader(shaderOptions));
shadersOff = reader.lines().anyMatch(it -> it.replaceAll("\\s", "").equals("shaderPack=OFF"));
} catch (FileNotFoundException e) {
Backend.log.info("No shader config found.");
}
handler = new OptifineHandler(!shadersOff);
}
public boolean isUsingShaders() {
return usingShaders;
}
}

View file

@ -6,8 +6,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Abs
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionHandler;
import com.simibubi.create.foundation.render.AllProgramSpecs;
import com.simibubi.create.foundation.render.gl.shader.ShaderCallback;
import com.simibubi.create.foundation.render.gl.shader.ShaderHelper;
import com.simibubi.create.foundation.render.gl.backend.Backend;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.Matrix4f;
@ -95,7 +94,7 @@ public class ContraptionRenderDispatcher {
GL11.glEnable(GL13.GL_TEXTURE_3D);
GL13.glActiveTexture(GL40.GL_TEXTURE4); // the shaders expect light volumes to be in texture 4
ContraptionProgram structureShader = ShaderHelper.getProgram(AllProgramSpecs.CONTRAPTION_STRUCTURE);
ContraptionProgram structureShader = Backend.getProgram(AllProgramSpecs.CONTRAPTION_STRUCTURE);
structureShader.bind(viewProjection, 0);
for (RenderedContraption renderer : renderers.values()) {
renderer.doRenderLayer(layer, structureShader);

View file

@ -1,7 +1,7 @@
package com.simibubi.create.foundation.render.gl;
import com.simibubi.create.foundation.render.gl.backend.Backend;
import com.simibubi.create.foundation.render.gl.shader.GlProgram;
import com.simibubi.create.foundation.render.gl.shader.ShaderHelper;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.util.ResourceLocation;
@ -43,9 +43,9 @@ public class BasicProgram extends GlProgram {
}
protected static void uploadMatrixUniform(int uniform, Matrix4f mat) {
ShaderHelper.MATRIX_BUFFER.position(0);
mat.write(ShaderHelper.MATRIX_BUFFER);
ShaderHelper.MATRIX_BUFFER.rewind();
GL20.glUniformMatrix4fv(uniform, false, ShaderHelper.MATRIX_BUFFER);
Backend.MATRIX_BUFFER.position(0);
mat.write(Backend.MATRIX_BUFFER);
Backend.MATRIX_BUFFER.rewind();
GL20.glUniformMatrix4fv(uniform, false, Backend.MATRIX_BUFFER);
}
}

View file

@ -1,20 +1,179 @@
package com.simibubi.create.foundation.render.gl.backend;
import com.simibubi.create.foundation.render.OptifineHandler;
import com.simibubi.create.foundation.render.gl.shader.*;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.TextureUtil;
import net.minecraft.resources.IReloadableResourceManager;
import net.minecraft.resources.IResourceManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.resource.IResourceType;
import net.minecraftforge.resource.ISelectiveResourceReloadListener;
import net.minecraftforge.resource.VanillaResourceType;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GLCapabilities;
import org.lwjgl.system.MemoryUtil;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Predicate;
public class Backend {
private static final MapBuffer MAP_BUFFER = MapBuffer.GL30_RANGE;
public static final Logger log = LogManager.getLogger(Backend.class);
public static final FloatBuffer FLOAT_BUFFER = MemoryUtil.memAllocFloat(1); // TODO: these leak 80 bytes of memory per program launch
public static final FloatBuffer VEC3_BUFFER = MemoryUtil.memAllocFloat(3);
public static final FloatBuffer MATRIX_BUFFER = MemoryUtil.memAllocFloat(16);
private Backend() {
throw new UnsupportedOperationException();
private static final Backend instance = new Backend();
public static Backend instance() {
return instance;
}
private static final Map<ResourceLocation, ProgramSpec<?>> registry = new HashMap<>();
private static final Map<ProgramSpec<?>, GlProgram> programs = new HashMap<>();
public static GLCapabilities capabilities;
private static RenderingAvailability availability;
private static MapBuffer mapBuffer;
public static void mapBuffer(int target, int offset, int length, Consumer<ByteBuffer> upload) {
MAP_BUFFER.mapBuffer(target, offset, length, upload);
mapBuffer.mapBuffer(target, offset, length, upload);
}
public static void mapBuffer(int target, int size, Consumer<ByteBuffer> upload) {
MAP_BUFFER.mapBuffer(target, 0, size, upload);
mapBuffer.mapBuffer(target, 0, size, upload);
}
/**
* Register a shader program. TODO: replace with forge registry?
*/
public static <P extends GlProgram, S extends ProgramSpec<P>> S register(S spec) {
ResourceLocation name = spec.name;
if (registry.containsKey(name)) {
throw new IllegalStateException("Program spec '" + name + "' already registered.");
}
registry.put(name, spec);
return spec;
}
@SuppressWarnings("unchecked")
public static <P extends GlProgram, S extends ProgramSpec<P>> P getProgram(S spec) {
return (P) programs.get(spec);
}
/**
* Get the most compatible version of a specific OpenGL feature by iterating over enum constants in order.
*
* @param clazz The class of the versioning enum.
* @param <V> The type of the versioning enum.
* @return The first defined enum variant to return true.
*/
public static <V extends Enum<V> & GlVersioned> V getLatest(Class<V> clazz) {
return getLatest(clazz, capabilities);
}
/**
* Get the most compatible version of a specific OpenGL feature by iterating over enum constants in order.
*
* @param clazz The class of the versioning enum.
* @param caps The current system's supported features.
* @param <V> The type of the versioning enum.
* @return The first defined enum variant to return true.
*/
public static <V extends Enum<V> & GlVersioned> V getLatest(Class<V> clazz, GLCapabilities caps) {
V[] constants = clazz.getEnumConstants();
V last = constants[constants.length - 1];
if (!last.supported(caps)) {
throw new IllegalStateException("");
}
return Arrays.stream(constants).filter(it -> it.supported(caps)).findFirst().orElse(last);
}
public static RenderingAvailability getAvailability() {
return availability;
}
public static void init() {
// Can be null when running datagenerators due to the unfortunate time we call this
Minecraft mc = Minecraft.getInstance();
if (mc != null && mc.getResourceManager() instanceof IReloadableResourceManager) {
ISelectiveResourceReloadListener listener = Backend::onResourceManagerReload;
((IReloadableResourceManager) mc.getResourceManager()).addReloadListener(listener);
}
}
public static void onResourceManagerReload(IResourceManager manager, Predicate<IResourceType> predicate) {
if (predicate.test(VanillaResourceType.SHADERS)) {
capabilities = GL.createCapabilities();
mapBuffer = getLatest(MapBuffer.class);
OptifineHandler.refresh();
refreshAvailability();
programs.values().forEach(GlProgram::delete);
programs.clear();
for (ProgramSpec<?> shader : registry.values()) {
loadProgram(manager, shader);
}
}
}
private static <P extends GlProgram, S extends ProgramSpec<P>> void loadProgram(IResourceManager manager, S programSpec) {
GlShader vert = null;
GlShader frag = null;
try {
vert = loadShader(manager, programSpec.getVert(), ShaderType.VERTEX, programSpec.defines);
frag = loadShader(manager, programSpec.getFrag(), ShaderType.FRAGMENT, programSpec.defines);
P program = GlProgram.builder(programSpec.name)
.attachShader(vert)
.attachShader(frag)
.build(programSpec.factory);
programs.put(programSpec, program);
log.info("Loaded program {}", programSpec.name);
} catch (IOException ex) {
log.error("Failed to load program {}", programSpec.name, ex);
} finally {
if (vert != null) vert.delete();
if (frag != null) frag.delete();
}
}
private static GlShader loadShader(IResourceManager manager, ResourceLocation name, ShaderType type, GlShader.PreProcessor preProcessor) throws IOException {
try (InputStream is = new BufferedInputStream(manager.getResource(name).getInputStream())) {
String source = TextureUtil.func_225687_b_(is);
if (source == null) {
throw new IOException("Could not load program " + name);
} else {
return new GlShader(type, name, source, preProcessor);
}
}
}
public static void refreshAvailability() {
if (capabilities.OpenGL33) {
availability = RenderingAvailability.FULL;
OptifineHandler.get()
.filter(OptifineHandler::isUsingShaders)
.ifPresent(it -> availability = RenderingAvailability.OPTIFINE_SHADERS);
} else {
availability = RenderingAvailability.INCAPABLE;
}
}
}

View file

@ -0,0 +1,8 @@
package com.simibubi.create.foundation.render.gl.backend;
import org.lwjgl.opengl.GLCapabilities;
public interface GlVersioned {
boolean supported(GLCapabilities caps);
}

View file

@ -1,15 +1,19 @@
package com.simibubi.create.foundation.render.gl.backend;
import org.lwjgl.opengl.ARBMapBufferRange;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.*;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.function.Consumer;
public enum MapBuffer {
public enum MapBuffer implements GlVersioned {
GL30_RANGE {
@Override
public boolean supported(GLCapabilities caps) {
return caps.OpenGL30;
}
@Override
public void mapBuffer(int target, int offset, int length, Consumer<ByteBuffer> upload) {
ByteBuffer buffer = GL30.glMapBufferRange(target, offset, length, GL30.GL_MAP_WRITE_BIT | GL30.GL_MAP_INVALIDATE_RANGE_BIT);
@ -21,6 +25,11 @@ public enum MapBuffer {
}
},
ARB_RANGE {
@Override
public boolean supported(GLCapabilities caps) {
return caps.GL_ARB_map_buffer_range;
}
@Override
public void mapBuffer(int target, int offset, int length, Consumer<ByteBuffer> upload) {
ByteBuffer buffer = ARBMapBufferRange.glMapBufferRange(target, offset, length, GL30.GL_MAP_WRITE_BIT | GL30.GL_MAP_INVALIDATE_RANGE_BIT);
@ -32,6 +41,11 @@ public enum MapBuffer {
}
},
GL15_MAP {
@Override
public boolean supported(GLCapabilities caps) {
return caps.OpenGL15;
}
@Override
public void mapBuffer(int target, int offset, int length, Consumer<ByteBuffer> upload) {
ByteBuffer buffer = GL15.glMapBuffer(target, GL15.GL_WRITE_ONLY);
@ -43,6 +57,11 @@ public enum MapBuffer {
}
},
UNSUPPORTED {
@Override
public boolean supported(GLCapabilities caps) {
return true;
}
@Override
public void mapBuffer(int target, int offset, int length, Consumer<ByteBuffer> upload) {
throw new UnsupportedOperationException("glMapBuffer not supported");

View file

@ -0,0 +1,27 @@
package com.simibubi.create.foundation.render.gl.backend;
public enum RenderingAvailability {
/**
* The current system does not support enough
* OpenGL features to enable fast rendering.
*/
INCAPABLE,
/**
* The current system supports OpenGL 3.3.
*/
FULL,
/**
* The current system supports OpenGL 2.0,
* or some ARBs that make it equivalent.
*/
PARTIAL,
/**
* It doesn't matter what the current system
* supports because Optifine is installed and
* a shaderpack is enabled.
*/
OPTIFINE_SHADERS,
}

View file

@ -1,6 +1,7 @@
package com.simibubi.create.foundation.render.gl.shader;
import com.simibubi.create.foundation.render.gl.GlObject;
import com.simibubi.create.foundation.render.gl.backend.Backend;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.opengl.GL20;
@ -29,13 +30,12 @@ public abstract class GlProgram extends GlObject {
* Retrieves the index of the uniform with the given name.
* @param uniform The name of the uniform to find the index of
* @return The uniform's index
* @throws NullPointerException If no uniform exists with the given name
*/
public int getUniformLocation(String uniform) {
int index = GL20.glGetUniformLocation(this.handle(), uniform);
if (index < 0) {
ShaderHelper.log.error("No uniform exists in program '" + this.name + "' with name: " + uniform);
Backend.log.warn("No active uniform '{}' exists in program '{}'. Could be unused.", uniform, this.name);
}
return index;
@ -93,7 +93,7 @@ public abstract class GlProgram extends GlObject {
String log = GL20.glGetProgramInfoLog(this.program);
if (!log.isEmpty()) {
ShaderHelper.log.warn("Program link log for " + this.name + ": " + log);
Backend.log.warn("Program link log for " + this.name + ": " + log);
}
int result = GL20.glGetProgrami(this.program, GL20.GL_LINK_STATUS);

View file

@ -1,8 +1,7 @@
package com.simibubi.create.foundation.render.gl.shader;
import com.simibubi.create.foundation.render.gl.GlObject;
import com.simibubi.create.foundation.render.gl.shader.ShaderHelper;
import com.simibubi.create.foundation.render.gl.shader.ShaderType;
import com.simibubi.create.foundation.render.gl.backend.Backend;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.opengl.GL20;
@ -18,7 +17,7 @@ public class GlShader extends GlObject {
if (preProcessor != null) {
source = preProcessor.process(source);
ShaderHelper.log.info("Preprocessor run on " + name + ":\n" + source);
Backend.log.info("Preprocessor run on " + name);// + ":\n" + source);
}
GL20.glShaderSource(handle, source);
@ -27,7 +26,7 @@ public class GlShader extends GlObject {
String log = GL20.glGetShaderInfoLog(handle);
if (!log.isEmpty()) {
ShaderHelper.log.warn("Shader compilation log for " + name + ": " + log);
Backend.log.warn("Shader compilation log for " + name + ": " + log);
}
if (GL20.glGetShaderi(handle, GL20.GL_COMPILE_STATUS) != GL20.GL_TRUE) {

View file

@ -1,109 +0,0 @@
package com.simibubi.create.foundation.render.gl.shader;
import com.mojang.blaze3d.platform.GlStateManager;
import com.simibubi.create.content.contraptions.KineticDebugger;
import com.simibubi.create.foundation.render.gl.BasicProgram;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.texture.TextureUtil;
import net.minecraft.client.shader.ShaderLinkHelper;
import net.minecraft.resources.IReloadableResourceManager;
import net.minecraft.resources.IResourceManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.resource.ISelectiveResourceReloadListener;
import net.minecraftforge.resource.VanillaResourceType;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.opengl.GL20;
import org.lwjgl.system.MemoryUtil;
import javax.annotation.Nullable;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.FloatBuffer;
import java.util.HashMap;
import java.util.Map;
public class ShaderHelper {
public static final Logger log = LogManager.getLogger(ShaderHelper.class);
public static final FloatBuffer FLOAT_BUFFER = MemoryUtil.memAllocFloat(1); // TODO: these leak 80 bytes of memory per program launch
public static final FloatBuffer VEC3_BUFFER = MemoryUtil.memAllocFloat(3);
public static final FloatBuffer MATRIX_BUFFER = MemoryUtil.memAllocFloat(16);
private static final Map<ResourceLocation, ProgramSpec<?>> REGISTRY = new HashMap<>();
private static final Map<ProgramSpec<?>, GlProgram> PROGRAMS = new HashMap<>();
public static <P extends GlProgram, S extends ProgramSpec<P>> S register(S spec) {
ResourceLocation name = spec.name;
if (REGISTRY.containsKey(name)) {
throw new IllegalStateException("Program spec '" + name + "' already registered.");
}
REGISTRY.put(name, spec);
return spec;
}
public static void initShaders() {
// Can be null when running datagenerators due to the unfortunate time we call this
Minecraft mc = Minecraft.getInstance();
if (mc != null && mc.getResourceManager() instanceof IReloadableResourceManager) {
ISelectiveResourceReloadListener listener = (manager, predicate) -> {
if (predicate.test(VanillaResourceType.SHADERS)) {
PROGRAMS.values().forEach(GlProgram::delete);
PROGRAMS.clear();
for (ProgramSpec<?> shader : REGISTRY.values()) {
loadProgram(manager, shader);
}
}
};
((IReloadableResourceManager) mc.getResourceManager()).addReloadListener(listener);
}
}
@SuppressWarnings("unchecked")
public static <P extends GlProgram, S extends ProgramSpec<P>> P getProgram(S spec) {
return (P) PROGRAMS.get(spec);
}
public static void releaseShader() {
GL20.glUseProgram(0);
}
private static <P extends GlProgram, S extends ProgramSpec<P>> void loadProgram(IResourceManager manager, S programSpec) {
GlShader vert = null;
GlShader frag = null;
try {
vert = loadShader(manager, programSpec.getVert(), ShaderType.VERTEX, programSpec.defines);
frag = loadShader(manager, programSpec.getFrag(), ShaderType.FRAGMENT, programSpec.defines);
P program = GlProgram.builder(programSpec.name)
.attachShader(vert)
.attachShader(frag)
.build(programSpec.factory);
PROGRAMS.put(programSpec, program);
log.info("Loaded program {}", programSpec.name);
} catch (IOException ex) {
log.error("Failed to load program {}", programSpec.name, ex);
} finally {
if (vert != null) vert.delete();
if (frag != null) frag.delete();
}
}
private static GlShader loadShader(IResourceManager manager, ResourceLocation name, ShaderType type, GlShader.PreProcessor preProcessor) throws IOException {
try (InputStream is = new BufferedInputStream(manager.getResource(name).getInputStream())) {
String source = TextureUtil.func_225687_b_(is);
if (source == null) {
throw new IOException("Could not load program " + name);
} else {
return new GlShader(type, name, source, preProcessor);
}
}
}
}

View file

@ -18,7 +18,7 @@ public class InstancedTileRenderRegistry {
@SuppressWarnings("unchecked")
@Nullable
public <T extends TileEntity> TileEntityInstance<? super T> create(InstancedTileRenderer manager, T tile) {
public <T extends TileEntity> TileEntityInstance<? super T> create(InstancedTileRenderer<?> manager, T tile) {
TileEntityType<?> type = tile.getType();
IRendererFactory<? super T> factory = (IRendererFactory<? super T>) this.renderers.get(type);

View file

@ -3,11 +3,11 @@ package com.simibubi.create.foundation.render.instancing;
import com.simibubi.create.foundation.render.FastRenderDispatcher;
import com.simibubi.create.foundation.render.gl.BasicProgram;
import com.simibubi.create.foundation.render.gl.shader.ShaderCallback;
import com.simibubi.create.foundation.render.gl.shader.ShaderHelper;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.tileentity.TileEntity;
import org.lwjgl.opengl.GL20;
import javax.annotation.Nullable;
import java.util.HashMap;
@ -42,15 +42,14 @@ public abstract class InstancedTileRenderer<P extends BasicProgram> {
if (instance != null) {
return (TileEntityInstance<? super T>) instance;
} else if (create) {
return null;
// TileEntityInstance<? super T> renderer = InstancedTileRenderRegistry.instance.create(this, tile);
//
// if (renderer != null) {
// FastRenderDispatcher.addedLastTick.get(tile.getWorld()).add(tile);
// instances.put(tile, renderer);
// }
//
// return renderer;
TileEntityInstance<? super T> renderer = InstancedTileRenderRegistry.instance.create(this, tile);
if (renderer != null) {
FastRenderDispatcher.addedLastTick.get(tile.getWorld()).add(tile);
instances.put(tile, renderer);
}
return renderer;
} else {
return null;
}
@ -116,6 +115,6 @@ public abstract class InstancedTileRenderer<P extends BasicProgram> {
material.render(layer, viewProjection, callback);
}
ShaderHelper.releaseShader();
GL20.glUseProgram(0);
}
}

View file

@ -8,9 +8,9 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.foundation.render.Compartment;
import com.simibubi.create.foundation.render.SuperByteBufferCache;
import com.simibubi.create.foundation.render.gl.BasicProgram;
import com.simibubi.create.foundation.render.gl.backend.Backend;
import com.simibubi.create.foundation.render.gl.shader.ProgramSpec;
import com.simibubi.create.foundation.render.gl.shader.ShaderCallback;
import com.simibubi.create.foundation.render.gl.shader.ShaderHelper;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BlockRendererDispatcher;
@ -63,7 +63,7 @@ public class RenderMaterial<P extends BasicProgram, MODEL extends InstancedModel
}
public void render(RenderType layer, Matrix4f viewProjection, ShaderCallback<P> setup) {
P program = ShaderHelper.getProgram(programSpec);
P program = Backend.getProgram(programSpec);
program.bind(viewProjection, 0);
if (setup != null) setup.call(program);

View file

@ -2,7 +2,6 @@ package com.simibubi.create.foundation.render.light;
import com.simibubi.create.foundation.render.RenderWork;
import com.simibubi.create.foundation.render.gl.GlTexture;
import com.simibubi.create.foundation.render.gl.shader.ShaderHelper;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.SectionPos;
import net.minecraft.world.ILightReader;