diff --git a/build.gradle b/build.gradle index b8cf8d5e0..db6c95ee1 100644 --- a/build.gradle +++ b/build.gradle @@ -3,9 +3,11 @@ buildscript { maven { url = 'https://files.minecraftforge.net/maven' } jcenter() mavenCentral() + maven { url='https://dist.creeper.host/Sponge/maven' } } dependencies { classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true + classpath group: 'org.spongepowered', name: 'mixingradle', version: '0.7-SNAPSHOT' } } plugins { @@ -35,6 +37,9 @@ minecraft { runs { client { workingDirectory project.file('run') + // property 'mixin.env.disableRefMap', 'true' + arg '-mixin.config=create.mixins.json' +// jvmArgs '-XX:+UnlockCommercialFeatures' property 'forge.logging.console.level', 'info' property 'fml.earlyprogresswindow', 'false' mods { @@ -46,6 +51,8 @@ minecraft { server { workingDirectory project.file('run/server') + // property 'mixin.env.disableRefMap', 'true' + arg '-mixin.config=create.mixins.json' property 'forge.logging.console.level', 'info' mods { create { @@ -119,6 +126,8 @@ dependencies { // i'll leave this here commented for easier testing //runtimeOnly fg.deobf("vazkii.arl:AutoRegLib:1.4-35.69") //runtimeOnly fg.deobf("vazkii.quark:Quark:r2.0-212.984") + + annotationProcessor 'org.spongepowered:mixin:0.8:processor' } jar { @@ -131,7 +140,8 @@ jar { "Implementation-Title": project.name, "Implementation-Version": "${version}", "Implementation-Vendor" :"simibubi", - "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") + "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), + "MixinConfigs": "create.mixins.json" ]) } } @@ -200,3 +210,9 @@ curseforge { } } } + +apply plugin: 'org.spongepowered.mixin' + +mixin { + add sourceSets.main, "create.refmap.json" +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 025cae5ea..d70b89e89 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ org.gradle.daemon=false # mod version info mod_version=0.3.1 minecraft_version=1.15.2 -forge_version=31.2.31 +forge_version=31.2.47 # dependency versions registrate_version=1.0.0-rc.17 diff --git a/src/main/java/com/simibubi/create/AllBlockPartials.java b/src/main/java/com/simibubi/create/AllBlockPartials.java index f0b558da7..fb029ea0d 100644 --- a/src/main/java/com/simibubi/create/AllBlockPartials.java +++ b/src/main/java/com/simibubi/create/AllBlockPartials.java @@ -1,22 +1,18 @@ package com.simibubi.create; -import static net.minecraft.state.properties.BlockStateProperties.FACING; -import static net.minecraft.state.properties.BlockStateProperties.HORIZONTAL_FACING; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.content.contraptions.base.KineticRenderMaterials; +import com.simibubi.create.content.contraptions.base.RotatingData; import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour.AttachmentTypes; import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; +import com.simibubi.create.content.contraptions.relays.belt.BeltData; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.backend.instancing.*; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.MatrixStacker; -import com.simibubi.create.foundation.utility.SuperByteBuffer; - import net.minecraft.block.BlockState; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.util.Direction; @@ -25,6 +21,15 @@ import net.minecraftforge.client.event.ModelBakeEvent; import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.client.model.ModelLoader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +import static net.minecraft.state.properties.BlockStateProperties.FACING; +import static net.minecraft.state.properties.BlockStateProperties.HORIZONTAL_FACING; + public class AllBlockPartials { private static final List all = new ArrayList<>(); @@ -223,4 +228,30 @@ public class AllBlockPartials { return CreateClient.bufferCache.renderDirectionalPartial(this, referenceState, facing, ms); } + public InstancedModel renderOnRotating(InstancedTileRenderer ctx, BlockState referenceState) { + return ctx.getMaterial(KineticRenderMaterials.ROTATING).getModel(this, referenceState); + } + + public InstancedModel renderOnBelt(InstancedTileRenderer ctx, BlockState referenceState) { + return ctx.getMaterial(KineticRenderMaterials.BELTS).getModel(this, referenceState); + } + + public InstancedModel renderOnDirectionalSouthRotating(InstancedTileRenderer dispatcher, BlockState referenceState) { + Direction facing = referenceState.get(FACING); + return renderOnDirectionalSouthRotating(dispatcher, referenceState, facing); + } + + public InstancedModel renderOnDirectionalSouthRotating(InstancedTileRenderer dispatcher, BlockState referenceState, Direction facing) { + Supplier ms = () -> { + MatrixStack stack = new MatrixStack(); + MatrixStacker.of(stack) + .centre() + .rotateY(AngleHelper.horizontalAngle(facing)) + .rotateX(AngleHelper.verticalAngle(facing)) + .unCentre(); + return stack; + }; + return dispatcher.getMaterial(KineticRenderMaterials.ROTATING).getModel(this, referenceState, facing, ms); + } + } diff --git a/src/main/java/com/simibubi/create/AllEntityTypes.java b/src/main/java/com/simibubi/create/AllEntityTypes.java index 061e0507d..ba2097ff8 100644 --- a/src/main/java/com/simibubi/create/AllEntityTypes.java +++ b/src/main/java/com/simibubi/create/AllEntityTypes.java @@ -1,13 +1,8 @@ package com.simibubi.create; import com.simibubi.create.content.contraptions.components.actors.SeatEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntityRenderer; -import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntityRenderer; +import com.simibubi.create.content.contraptions.components.structureMovement.*; import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryContraptionEntityRenderer; import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueRenderer; import com.simibubi.create.foundation.utility.Lang; @@ -62,11 +57,11 @@ public class AllEntityTypes { @OnlyIn(value = Dist.CLIENT) public static void registerRenderers() { RenderingRegistry.registerEntityRenderingHandler(CONTROLLED_CONTRAPTION.get(), - ControlledContraptionEntityRenderer::new); + ContraptionEntityRenderer::new); RenderingRegistry.registerEntityRenderingHandler(ORIENTED_CONTRAPTION.get(), OrientedContraptionEntityRenderer::new); RenderingRegistry.registerEntityRenderingHandler(GANTRY_CONTRAPTION.get(), - GantryContraptionEntityRenderer::new); + ContraptionEntityRenderer::new); RenderingRegistry.registerEntityRenderingHandler(SUPER_GLUE.get(), SuperGlueRenderer::new); RenderingRegistry.registerEntityRenderingHandler(SEAT.get(), SeatEntity.Render::new); } diff --git a/src/main/java/com/simibubi/create/AllSpriteShifts.java b/src/main/java/com/simibubi/create/AllSpriteShifts.java index e358b069c..9aafdc586 100644 --- a/src/main/java/com/simibubi/create/AllSpriteShifts.java +++ b/src/main/java/com/simibubi/create/AllSpriteShifts.java @@ -51,9 +51,9 @@ public class AllSpriteShifts { FLUID_TANK = getCT(CTType.CROSS, "fluid_tank"), CREATIVE_FLUID_TANK = getCT(CTType.CROSS, "creative_fluid_tank"); - public static final SpriteShiftEntry BELT = SpriteShifter.get("block/belt", "block/belt_animated"), - BELT_OFFSET = SpriteShifter.get("block/belt_offset", "block/belt_animated"), - BELT_DIAGONAL = SpriteShifter.get("block/belt_diagonal", "block/belt_diagonal_animated"), + public static final SpriteShiftEntry BELT = SpriteShifter.get("block/belt", "block/belt_scroll"), + BELT_OFFSET = SpriteShifter.get("block/belt_offset", "block/belt_scroll"), + BELT_DIAGONAL = SpriteShifter.get("block/belt_diagonal", "block/belt_diagonal_scroll"), ANDESIDE_BELT_CASING = SpriteShifter.get("block/brass_casing_belt", "block/andesite_casing_belt"), CRAFTER_THINGIES = SpriteShifter.get("block/crafter_thingies", "block/crafter_thingies"); @@ -92,9 +92,9 @@ public class AllSpriteShifts { for (DyeColor color : DyeColor.values()) { String id = color.getName(); - DYED_BELTS.put(color, SpriteShifter.get("block/belt", "block/belt/" + id)); - DYED_OFFSET_BELTS.put(color, SpriteShifter.get("block/belt_offset", "block/belt/" + id)); - DYED_DIAGONAL_BELTS.put(color, SpriteShifter.get("block/belt_diagonal", "block/belt/" + id + "_diagonal")); + DYED_BELTS.put(color, SpriteShifter.get("block/belt", "block/belt/" + id + "_scroll")); + DYED_OFFSET_BELTS.put(color, SpriteShifter.get("block/belt_offset", "block/belt/" + id + "_scroll")); + DYED_DIAGONAL_BELTS.put(color, SpriteShifter.get("block/belt_diagonal", "block/belt/" + id + "_diagonal_scroll")); } } diff --git a/src/main/java/com/simibubi/create/AllTileEntities.java b/src/main/java/com/simibubi/create/AllTileEntities.java index 9cf3b8fb2..231836c8e 100644 --- a/src/main/java/com/simibubi/create/AllTileEntities.java +++ b/src/main/java/com/simibubi/create/AllTileEntities.java @@ -1,15 +1,10 @@ package com.simibubi.create; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.content.contraptions.components.actors.DrillRenderer; -import com.simibubi.create.content.contraptions.components.actors.DrillTileEntity; -import com.simibubi.create.content.contraptions.components.actors.HarvesterRenderer; -import com.simibubi.create.content.contraptions.components.actors.HarvesterTileEntity; -import com.simibubi.create.content.contraptions.components.actors.PortableFluidInterfaceTileEntity; -import com.simibubi.create.content.contraptions.components.actors.PortableItemInterfaceTileEntity; -import com.simibubi.create.content.contraptions.components.actors.PortableStorageInterfaceRenderer; +import com.simibubi.create.content.contraptions.base.*; +import com.simibubi.create.content.contraptions.components.actors.*; import com.simibubi.create.content.contraptions.components.clock.CuckooClockRenderer; import com.simibubi.create.content.contraptions.components.clock.CuckooClockTileEntity; +import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterInstance; import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterRenderer; import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterTileEntity; import com.simibubi.create.content.contraptions.components.crank.HandCrankRenderer; @@ -20,11 +15,14 @@ import com.simibubi.create.content.contraptions.components.deployer.DeployerRend import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity; import com.simibubi.create.content.contraptions.components.fan.EncasedFanRenderer; import com.simibubi.create.content.contraptions.components.fan.EncasedFanTileEntity; +import com.simibubi.create.content.contraptions.components.fan.FanInstance; import com.simibubi.create.content.contraptions.components.fan.NozzleTileEntity; +import com.simibubi.create.content.contraptions.components.flywheel.FlyWheelInstance; import com.simibubi.create.content.contraptions.components.flywheel.FlywheelRenderer; import com.simibubi.create.content.contraptions.components.flywheel.FlywheelTileEntity; import com.simibubi.create.content.contraptions.components.flywheel.engine.EngineRenderer; import com.simibubi.create.content.contraptions.components.flywheel.engine.FurnaceEngineTileEntity; +import com.simibubi.create.content.contraptions.components.millstone.MillStoneCogInstance; import com.simibubi.create.content.contraptions.components.millstone.MillstoneRenderer; import com.simibubi.create.content.contraptions.components.millstone.MillstoneTileEntity; import com.simibubi.create.content.contraptions.components.mixer.MechanicalMixerRenderer; @@ -33,6 +31,7 @@ import com.simibubi.create.content.contraptions.components.motor.CreativeMotorRe import com.simibubi.create.content.contraptions.components.motor.CreativeMotorTileEntity; import com.simibubi.create.content.contraptions.components.press.MechanicalPressRenderer; import com.simibubi.create.content.contraptions.components.press.MechanicalPressTileEntity; +import com.simibubi.create.content.contraptions.components.saw.SawInstance; import com.simibubi.create.content.contraptions.components.saw.SawRenderer; import com.simibubi.create.content.contraptions.components.saw.SawTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.bearing.BearingRenderer; @@ -49,20 +48,11 @@ import com.simibubi.create.content.contraptions.components.structureMovement.pul import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyTileEntity; import com.simibubi.create.content.contraptions.components.turntable.TurntableTileEntity; import com.simibubi.create.content.contraptions.components.waterwheel.WaterWheelTileEntity; +import com.simibubi.create.content.contraptions.fluids.PumpCogInstance; import com.simibubi.create.content.contraptions.fluids.PumpRenderer; import com.simibubi.create.content.contraptions.fluids.PumpTileEntity; -import com.simibubi.create.content.contraptions.fluids.actors.HosePulleyRenderer; -import com.simibubi.create.content.contraptions.fluids.actors.HosePulleyTileEntity; -import com.simibubi.create.content.contraptions.fluids.actors.ItemDrainRenderer; -import com.simibubi.create.content.contraptions.fluids.actors.ItemDrainTileEntity; -import com.simibubi.create.content.contraptions.fluids.actors.SpoutRenderer; -import com.simibubi.create.content.contraptions.fluids.actors.SpoutTileEntity; -import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeTileEntity; -import com.simibubi.create.content.contraptions.fluids.pipes.FluidValveRenderer; -import com.simibubi.create.content.contraptions.fluids.pipes.FluidValveTileEntity; -import com.simibubi.create.content.contraptions.fluids.pipes.SmartFluidPipeTileEntity; -import com.simibubi.create.content.contraptions.fluids.pipes.StraightPipeTileEntity; -import com.simibubi.create.content.contraptions.fluids.pipes.TransparentStraightPipeRenderer; +import com.simibubi.create.content.contraptions.fluids.actors.*; +import com.simibubi.create.content.contraptions.fluids.pipes.*; import com.simibubi.create.content.contraptions.fluids.tank.CreativeFluidTankTileEntity; import com.simibubi.create.content.contraptions.fluids.tank.FluidTankRenderer; import com.simibubi.create.content.contraptions.fluids.tank.FluidTankTileEntity; @@ -74,17 +64,15 @@ import com.simibubi.create.content.contraptions.relays.advanced.GantryShaftTileE import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerRenderer; import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerTileEntity; import com.simibubi.create.content.contraptions.relays.advanced.sequencer.SequencedGearshiftTileEntity; +import com.simibubi.create.content.contraptions.relays.belt.BeltInstance; import com.simibubi.create.content.contraptions.relays.belt.BeltRenderer; import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; import com.simibubi.create.content.contraptions.relays.elementary.SimpleKineticTileEntity; -import com.simibubi.create.content.contraptions.relays.encased.AdjustablePulleyTileEntity; -import com.simibubi.create.content.contraptions.relays.encased.ClutchTileEntity; -import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftRenderer; -import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftTileEntity; -import com.simibubi.create.content.contraptions.relays.encased.SplitShaftRenderer; +import com.simibubi.create.content.contraptions.relays.encased.*; import com.simibubi.create.content.contraptions.relays.gauge.GaugeRenderer; import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeTileEntity; import com.simibubi.create.content.contraptions.relays.gauge.StressGaugeTileEntity; +import com.simibubi.create.content.contraptions.relays.gearbox.GearboxInstance; import com.simibubi.create.content.contraptions.relays.gearbox.GearboxRenderer; import com.simibubi.create.content.contraptions.relays.gearbox.GearboxTileEntity; import com.simibubi.create.content.contraptions.relays.gearbox.GearshiftTileEntity; @@ -104,15 +92,10 @@ import com.simibubi.create.content.logistics.block.funnel.FunnelRenderer; import com.simibubi.create.content.logistics.block.funnel.FunnelTileEntity; import com.simibubi.create.content.logistics.block.inventories.AdjustableCrateTileEntity; import com.simibubi.create.content.logistics.block.inventories.CreativeCrateTileEntity; +import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInstance; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmRenderer; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmTileEntity; -import com.simibubi.create.content.logistics.block.redstone.AnalogLeverRenderer; -import com.simibubi.create.content.logistics.block.redstone.AnalogLeverTileEntity; -import com.simibubi.create.content.logistics.block.redstone.ContentObserverTileEntity; -import com.simibubi.create.content.logistics.block.redstone.NixieTubeRenderer; -import com.simibubi.create.content.logistics.block.redstone.NixieTubeTileEntity; -import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkTileEntity; -import com.simibubi.create.content.logistics.block.redstone.StockpileSwitchTileEntity; +import com.simibubi.create.content.logistics.block.redstone.*; import com.simibubi.create.content.schematics.block.SchematicTableTileEntity; import com.simibubi.create.content.schematics.block.SchematicannonRenderer; import com.simibubi.create.content.schematics.block.SchematicannonTileEntity; @@ -138,36 +121,42 @@ public class AllTileEntities { .tileEntity("simple_kinetic", SimpleKineticTileEntity::new) .validBlocks(AllBlocks.SHAFT, AllBlocks.COGWHEEL, AllBlocks.LARGE_COGWHEEL) .renderer(() -> KineticTileEntityRenderer::new) + .onRegister(SingleRotatingInstance::register) .register(); public static final TileEntityEntry MOTOR = Create.registrate() .tileEntity("motor", CreativeMotorTileEntity::new) .validBlocks(AllBlocks.CREATIVE_MOTOR) .renderer(() -> CreativeMotorRenderer::new) + .onRegister(HalfShaftInstance::register) .register(); public static final TileEntityEntry GEARBOX = Create.registrate() .tileEntity("gearbox", GearboxTileEntity::new) .validBlocks(AllBlocks.GEARBOX) .renderer(() -> GearboxRenderer::new) + .onRegister(GearboxInstance::register) .register(); public static final TileEntityEntry ENCASED_SHAFT = Create.registrate() .tileEntity("encased_shaft", EncasedShaftTileEntity::new) .validBlocks(AllBlocks.ANDESITE_ENCASED_SHAFT, AllBlocks.BRASS_ENCASED_SHAFT, AllBlocks.ENCASED_CHAIN_DRIVE) .renderer(() -> EncasedShaftRenderer::new) + .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry ADJUSTABLE_PULLEY = Create.registrate() .tileEntity("adjustable_pulley", AdjustablePulleyTileEntity::new) .validBlocks(AllBlocks.ADJUSTABLE_CHAIN_GEARSHIFT) .renderer(() -> EncasedShaftRenderer::new) + .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry ENCASED_FAN = Create.registrate() .tileEntity("encased_fan", EncasedFanTileEntity::new) .validBlocks(AllBlocks.ENCASED_FAN) .renderer(() -> EncasedFanRenderer::new) + .onRegister(FanInstance::register) .register(); public static final TileEntityEntry NOZZLE = Create.registrate() @@ -180,18 +169,21 @@ public class AllTileEntities { .tileEntity("clutch", ClutchTileEntity::new) .validBlocks(AllBlocks.CLUTCH) .renderer(() -> SplitShaftRenderer::new) + .onRegister(SplitShaftInstance::register) .register(); public static final TileEntityEntry GEARSHIFT = Create.registrate() .tileEntity("gearshift", GearshiftTileEntity::new) .validBlocks(AllBlocks.GEARSHIFT) .renderer(() -> SplitShaftRenderer::new) + .onRegister(SplitShaftInstance::register) .register(); public static final TileEntityEntry TURNTABLE = Create.registrate() .tileEntity("turntable", TurntableTileEntity::new) .validBlocks(AllBlocks.TURNTABLE) .renderer(() -> KineticTileEntityRenderer::new) + .onRegister(SingleRotatingInstance::register) .register(); public static final TileEntityEntry HAND_CRANK = Create.registrate() @@ -199,30 +191,35 @@ public class AllTileEntities { .validBlocks(AllBlocks.HAND_CRANK, AllBlocks.COPPER_VALVE_HANDLE) .validBlocks(AllBlocks.DYED_VALVE_HANDLES) .renderer(() -> HandCrankRenderer::new) + .onRegister(SingleRotatingInstance::register) .register(); public static final TileEntityEntry CUCKOO_CLOCK = Create.registrate() .tileEntity("cuckoo_clock", CuckooClockTileEntity::new) .validBlocks(AllBlocks.CUCKOO_CLOCK, AllBlocks.MYSTERIOUS_CUCKOO_CLOCK) .renderer(() -> CuckooClockRenderer::new) + .onRegister(HorizontalHalfShaftInstance::register) .register(); public static final TileEntityEntry GANTRY_SHAFT = Create.registrate() .tileEntity("gantry_shaft", GantryShaftTileEntity::new) .validBlocks(AllBlocks.GANTRY_SHAFT) .renderer(() -> KineticTileEntityRenderer::new) + .onRegister(SingleRotatingInstance::register) .register(); public static final TileEntityEntry GANTRY_PINION = Create.registrate() .tileEntity("gantry_pinion", GantryPinionTileEntity::new) .validBlocks(AllBlocks.GANTRY_PINION) .renderer(() -> GantryPinionRenderer::new) + .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry MECHANICAL_PUMP = Create.registrate() .tileEntity("mechanical_pump", PumpTileEntity::new) .validBlocks(AllBlocks.MECHANICAL_PUMP) .renderer(() -> PumpRenderer::new) + .onRegister(PumpCogInstance::register) .register(); public static final TileEntityEntry SMART_FLUID_PIPE = Create.registrate() @@ -251,6 +248,7 @@ public class AllTileEntities { .tileEntity("fluid_valve", FluidValveTileEntity::new) .validBlocks(AllBlocks.FLUID_VALVE) .renderer(() -> FluidValveRenderer::new) + .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry FLUID_TANK = Create.registrate() @@ -269,6 +267,7 @@ public class AllTileEntities { .tileEntity("hose_pulley", HosePulleyTileEntity::new) .validBlocks(AllBlocks.HOSE_PULLEY) .renderer(() -> HosePulleyRenderer::new) + .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry SPOUT = Create.registrate() @@ -287,6 +286,7 @@ public class AllTileEntities { .tileEntity("belt", BeltTileEntity::new) .validBlocks(AllBlocks.BELT) .renderer(() -> BeltRenderer::new) + .onRegister(BeltInstance::register) .register(); public static final TileEntityEntry CHUTE = Create.registrate() @@ -317,36 +317,42 @@ public class AllTileEntities { .tileEntity("mechanical_arm", ArmTileEntity::new) .validBlocks(AllBlocks.MECHANICAL_ARM) .renderer(() -> ArmRenderer::new) + .onRegister(ArmInstance::register) .register(); public static final TileEntityEntry MECHANICAL_PISTON = Create.registrate() .tileEntity("mechanical_piston", MechanicalPistonTileEntity::new) .validBlocks(AllBlocks.MECHANICAL_PISTON, AllBlocks.STICKY_MECHANICAL_PISTON) .renderer(() -> MechanicalPistonRenderer::new) + .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry WINDMILL_BEARING = Create.registrate() .tileEntity("windmill_bearing", WindmillBearingTileEntity::new) .validBlocks(AllBlocks.WINDMILL_BEARING) .renderer(() -> BearingRenderer::new) + .onRegister(BackHalfShaftInstance::register) .register(); public static final TileEntityEntry MECHANICAL_BEARING = Create.registrate() .tileEntity("mechanical_bearing", MechanicalBearingTileEntity::new) .validBlocks(AllBlocks.MECHANICAL_BEARING) .renderer(() -> BearingRenderer::new) + .onRegister(BackHalfShaftInstance::register) .register(); public static final TileEntityEntry CLOCKWORK_BEARING = Create.registrate() .tileEntity("clockwork_bearing", ClockworkBearingTileEntity::new) .validBlocks(AllBlocks.CLOCKWORK_BEARING) .renderer(() -> BearingRenderer::new) + .onRegister(BackHalfShaftInstance::register) .register(); public static final TileEntityEntry ROPE_PULLEY = Create.registrate() .tileEntity("rope_pulley", PulleyTileEntity::new) .validBlocks(AllBlocks.ROPE_PULLEY) .renderer(() -> PulleyRenderer::new) + .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry CHASSIS = Create.registrate() @@ -359,12 +365,14 @@ public class AllTileEntities { .tileEntity("drill", DrillTileEntity::new) .validBlocks(AllBlocks.MECHANICAL_DRILL) .renderer(() -> DrillRenderer::new) + .onRegister(DrillInstance::register) .register(); public static final TileEntityEntry SAW = Create.registrate() .tileEntity("saw", SawTileEntity::new) .validBlocks(AllBlocks.MECHANICAL_SAW) .renderer(() -> SawRenderer::new) + .onRegister(SawInstance::register) .register(); public static final TileEntityEntry HARVESTER = Create.registrate() @@ -390,6 +398,7 @@ public class AllTileEntities { .tileEntity("flywheel", FlywheelTileEntity::new) .validBlocks(AllBlocks.FLYWHEEL) .renderer(() -> FlywheelRenderer::new) + .onRegister(FlyWheelInstance::register) .register(); public static final TileEntityEntry FURNACE_ENGINE = Create.registrate() @@ -402,12 +411,14 @@ public class AllTileEntities { .tileEntity("millstone", MillstoneTileEntity::new) .validBlocks(AllBlocks.MILLSTONE) .renderer(() -> MillstoneRenderer::new) + .onRegister(MillStoneCogInstance::register) .register(); public static final TileEntityEntry CRUSHING_WHEEL = Create.registrate() .tileEntity("crushing_wheel", CrushingWheelTileEntity::new) .validBlocks(AllBlocks.CRUSHING_WHEEL) .renderer(() -> KineticTileEntityRenderer::new) + .onRegister(SingleRotatingInstance::register) .register(); public static final TileEntityEntry CRUSHING_WHEEL_CONTROLLER = @@ -421,24 +432,28 @@ public class AllTileEntities { .tileEntity("water_wheel", WaterWheelTileEntity::new) .validBlocks(AllBlocks.WATER_WHEEL) .renderer(() -> KineticTileEntityRenderer::new) + .onRegister(SingleRotatingInstance::register) .register(); public static final TileEntityEntry MECHANICAL_PRESS = Create.registrate() .tileEntity("mechanical_press", MechanicalPressTileEntity::new) .validBlocks(AllBlocks.MECHANICAL_PRESS) .renderer(() -> MechanicalPressRenderer::new) + .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry MECHANICAL_MIXER = Create.registrate() .tileEntity("mechanical_mixer", MechanicalMixerTileEntity::new) .validBlocks(AllBlocks.MECHANICAL_MIXER) .renderer(() -> MechanicalMixerRenderer::new) + .onRegister(ShaftlessCogInstance::register) .register(); public static final TileEntityEntry DEPLOYER = Create.registrate() .tileEntity("deployer", DeployerTileEntity::new) .validBlocks(AllBlocks.DEPLOYER) .renderer(() -> DeployerRenderer::new) + .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry BASIN = Create.registrate() @@ -457,30 +472,35 @@ public class AllTileEntities { .tileEntity("mechanical_crafter", MechanicalCrafterTileEntity::new) .validBlocks(AllBlocks.MECHANICAL_CRAFTER) .renderer(() -> MechanicalCrafterRenderer::new) + .onRegister(MechanicalCrafterInstance::register) .register(); public static final TileEntityEntry SEQUENCED_GEARSHIFT = Create.registrate() .tileEntity("sequenced_gearshift", SequencedGearshiftTileEntity::new) .validBlocks(AllBlocks.SEQUENCED_GEARSHIFT) .renderer(() -> SplitShaftRenderer::new) + .onRegister(SplitShaftInstance::register) .register(); public static final TileEntityEntry ROTATION_SPEED_CONTROLLER = Create.registrate() .tileEntity("rotation_speed_controller", SpeedControllerTileEntity::new) .validBlocks(AllBlocks.ROTATION_SPEED_CONTROLLER) .renderer(() -> SpeedControllerRenderer::new) + .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry SPEEDOMETER = Create.registrate() .tileEntity("speedometer", SpeedGaugeTileEntity::new) .validBlocks(AllBlocks.SPEEDOMETER) .renderer(() -> GaugeRenderer::speed) + .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry STRESSOMETER = Create.registrate() .tileEntity("stressometer", StressGaugeTileEntity::new) .validBlocks(AllBlocks.STRESSOMETER) .renderer(() -> GaugeRenderer::stress) + .onRegister(ShaftInstance::register) .register(); public static final TileEntityEntry ANALOG_LEVER = Create.registrate() diff --git a/src/main/java/com/simibubi/create/CreateClient.java b/src/main/java/com/simibubi/create/CreateClient.java index 77351c2a0..5ddaa41fd 100644 --- a/src/main/java/com/simibubi/create/CreateClient.java +++ b/src/main/java/com/simibubi/create/CreateClient.java @@ -1,7 +1,11 @@ package com.simibubi.create; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionRenderer; import com.simibubi.create.content.contraptions.relays.encased.CasingConnectivity; import com.simibubi.create.content.schematics.ClientSchematicLoader; import com.simibubi.create.content.schematics.client.SchematicAndQuillHandler; @@ -11,9 +15,14 @@ import com.simibubi.create.foundation.block.render.CustomBlockModels; 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.utility.SuperByteBufferCache; +import com.simibubi.create.foundation.render.KineticRenderer; +import com.simibubi.create.foundation.render.backend.OptifineHandler; +import com.simibubi.create.foundation.render.SuperByteBufferCache; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; +import com.simibubi.create.foundation.render.backend.Backend; import com.simibubi.create.foundation.utility.ghost.GhostBlocks; import com.simibubi.create.foundation.utility.outliner.Outliner; + import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BlockModelShapes; @@ -31,17 +40,13 @@ import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - public class CreateClient { public static ClientSchematicLoader schematicSender; public static SchematicHandler schematicHandler; public static SchematicAndQuillHandler schematicAndQuillHandler; public static SuperByteBufferCache bufferCache; + public static KineticRenderer kineticRenderer; public static final Outliner outliner = new Outliner(); public static GhostBlocks ghostBlocks; @@ -57,16 +62,21 @@ public class CreateClient { modEventBus.addListener(CreateClient::onModelRegistry); modEventBus.addListener(CreateClient::onTextureStitch); modEventBus.addListener(AllParticleTypes::registerFactories); + + Backend.init(); + OptifineHandler.init(); } public static void clientInit(FMLClientSetupEvent event) { + kineticRenderer = new KineticRenderer(); + schematicSender = new ClientSchematicLoader(); schematicHandler = new SchematicHandler(); schematicAndQuillHandler = new SchematicAndQuillHandler(); bufferCache = new SuperByteBufferCache(); bufferCache.registerCompartment(KineticTileEntityRenderer.KINETIC_TILE); - bufferCache.registerCompartment(ContraptionRenderer.CONTRAPTION, 20); + bufferCache.registerCompartment(ContraptionRenderDispatcher.CONTRAPTION, 20); ghostBlocks = new GhostBlocks(); @@ -174,4 +184,9 @@ public class CreateClient { return casingConnectivity; } + public static void invalidateRenderers() { + CreateClient.bufferCache.invalidate(); + CreateClient.kineticRenderer.invalidate(); + ContraptionRenderDispatcher.invalidateAll(); + } } diff --git a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedKinetics.java b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedKinetics.java index 33fe15a29..003cf9333 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedKinetics.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedKinetics.java @@ -3,17 +3,15 @@ package com.simibubi.create.compat.jei.category.animations; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; import com.simibubi.create.foundation.utility.AnimationTickHolder; - import mezz.jei.api.gui.drawable.IDrawable; import net.minecraft.block.BlockState; -import net.minecraft.client.Minecraft; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.util.Direction.Axis; public abstract class AnimatedKinetics implements IDrawable { public static float getCurrentAngle() { - return ((AnimationTickHolder.ticks + Minecraft.getInstance().getRenderPartialTicks()) * 4f) % 360; + return ((AnimationTickHolder.getRenderTick()) * 4f) % 360; } protected BlockState shaft(Axis axis) { diff --git a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedPress.java b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedPress.java index 4bafd18ed..7b2d99c6e 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedPress.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedPress.java @@ -1,13 +1,10 @@ package com.simibubi.create.compat.jei.category.animations; -import static com.simibubi.create.foundation.utility.AnimationTickHolder.ticks; - import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; import com.simibubi.create.foundation.gui.GuiGameElement; - -import net.minecraft.client.Minecraft; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import net.minecraft.util.Direction.Axis; public class AnimatedPress extends AnimatedKinetics { @@ -50,8 +47,7 @@ public class AnimatedPress extends AnimatedKinetics { } private float getAnimatedHeadOffset() { - float cycle = (ticks + Minecraft.getInstance() - .getRenderPartialTicks()) % 30; + float cycle = (AnimationTickHolder.getRenderTick()) % 30; if (cycle < 10) { float progress = cycle / 10; return -(progress * progress * progress); diff --git a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedSpout.java b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedSpout.java index 32869ff0a..52eed284e 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedSpout.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedSpout.java @@ -1,23 +1,20 @@ package com.simibubi.create.compat.jei.category.animations; -import static com.simibubi.create.foundation.utility.AnimationTickHolder.ticks; - -import java.util.List; - import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; import com.simibubi.create.foundation.fluid.FluidRenderer; import com.simibubi.create.foundation.gui.GuiGameElement; - -import net.minecraft.client.Minecraft; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer.Impl; import net.minecraft.client.renderer.Tessellator; import net.minecraft.util.math.MathHelper; import net.minecraftforge.fluids.FluidStack; +import java.util.List; + public class AnimatedSpout extends AnimatedKinetics { private List fluids; @@ -39,8 +36,7 @@ public class AnimatedSpout extends AnimatedKinetics { .scale(scale) .render(); - float cycle = (ticks + Minecraft.getInstance() - .getRenderPartialTicks()) % 30; + float cycle = AnimationTickHolder.getRenderTick() % 30; float squeeze = cycle < 20 ? MathHelper.sin((float) (cycle / 20f * Math.PI)) : 0; squeeze *= 20; diff --git a/src/main/java/com/simibubi/create/content/contraptions/KineticNetwork.java b/src/main/java/com/simibubi/create/content/contraptions/KineticNetwork.java index bbbe8e585..60ca8abb3 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/KineticNetwork.java +++ b/src/main/java/com/simibubi/create/content/contraptions/KineticNetwork.java @@ -1,13 +1,13 @@ package com.simibubi.create.content.contraptions; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.components.flywheel.FlywheelTileEntity; import com.simibubi.create.foundation.advancement.AllTriggers; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + public class KineticNetwork { public Long id; diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/BackHalfShaftInstance.java b/src/main/java/com/simibubi/create/content/contraptions/base/BackHalfShaftInstance.java new file mode 100644 index 000000000..4a1875d28 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/base/BackHalfShaftInstance.java @@ -0,0 +1,25 @@ +package com.simibubi.create.content.contraptions.base; + +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +public class BackHalfShaftInstance extends HalfShaftInstance { + public static void register(TileEntityType type) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> + InstancedTileRenderRegistry.instance.register(type, BackHalfShaftInstance::new)); + } + + public BackHalfShaftInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected Direction getShaftDirection() { + return tile.getBlockState().get(BlockStateProperties.FACING).getOpposite(); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/HalfShaftInstance.java b/src/main/java/com/simibubi/create/content/contraptions/base/HalfShaftInstance.java new file mode 100644 index 000000000..0547b25fc --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/base/HalfShaftInstance.java @@ -0,0 +1,32 @@ +package com.simibubi.create.content.contraptions.base; + +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +public class HalfShaftInstance extends SingleRotatingInstance { + public static void register(TileEntityType type) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> + InstancedTileRenderRegistry.instance.register(type, HalfShaftInstance::new)); + } + + public HalfShaftInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected InstancedModel getModel() { + Direction dir = getShaftDirection(); + return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(modelManager, lastState, dir); + } + + protected Direction getShaftDirection() { + return lastState.get(BlockStateProperties.FACING); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/HorizontalHalfShaftInstance.java b/src/main/java/com/simibubi/create/content/contraptions/base/HorizontalHalfShaftInstance.java new file mode 100644 index 000000000..a42524118 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/base/HorizontalHalfShaftInstance.java @@ -0,0 +1,25 @@ +package com.simibubi.create.content.contraptions.base; + +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +public class HorizontalHalfShaftInstance extends HalfShaftInstance { + public static void register(TileEntityType type) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> + InstancedTileRenderRegistry.instance.register(type, HorizontalHalfShaftInstance::new)); + } + + public HorizontalHalfShaftInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected Direction getShaftDirection() { + return lastState.get(BlockStateProperties.HORIZONTAL_FACING).getOpposite(); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticData.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticData.java new file mode 100644 index 000000000..a5f2889ba --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/base/KineticData.java @@ -0,0 +1,115 @@ +package com.simibubi.create.content.contraptions.base; + +import com.simibubi.create.foundation.render.backend.instancing.InstanceData; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.utility.ColorHelper; +import net.minecraft.client.renderer.Vector3f; +import net.minecraft.util.math.BlockPos; + +import java.nio.ByteBuffer; + +public class KineticData> extends InstanceData { + private float x; + private float y; + private float z; + private byte blockLight; + private byte skyLight; + private byte r; + private byte g; + private byte b; + private float rotationalSpeed; + private float rotationOffset; + + protected KineticData(InstancedModel owner) { + super(owner); + } + + public D setTileEntity(KineticTileEntity te) { + setPosition(te.getPos()); + if (te.hasSource()) { + setColor(te.network); + }else { + setColor(0xFF, 0xFF, 0x00); + } + return (D) this; + } + + public D setPosition(BlockPos pos) { + return setPosition(pos.getX(), pos.getY(), pos.getZ()); + } + + public D setPosition(Vector3f pos) { + return setPosition(pos.getX(), pos.getY(), pos.getZ()); + } + + public D setPosition(int x, int y, int z) { + BlockPos origin = owner.renderer.getOriginCoordinate(); + + return setPosition((float) (x - origin.getX()), + (float) (y - origin.getY()), + (float) (z - origin.getZ())); + } + + public D setPosition(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + return (D) this; + } + + public D setBlockLight(int blockLight) { + this.blockLight = (byte) ((blockLight & 0xF) << 4); + return (D) this; + } + + public D setSkyLight(int skyLight) { + this.skyLight = (byte) ((skyLight & 0xF) << 4); + return (D) this; + } + + public D setColor(Long l) { + if (l != null) + return setColor(l.longValue()); + else + return setColor(0xFF, 0xFF, 0xFF); + } + + private D setColor(long l) { + int color = ColorHelper.colorFromLong(l); + byte r = (byte) ((color >> 16) & 0xFF); + byte g = (byte) ((color >> 8) & 0xFF); + byte b = (byte) (color & 0xFF); + return setColor(r, g, b); + } + + public D setColor(int r, int g, int b) { + return setColor((byte) r, (byte) g, (byte) b); + } + + public D setColor(byte r, byte g, byte b) { + this.r = r; + this.g = g; + this.b = b; + return (D) this; + } + + public D setRotationalSpeed(float rotationalSpeed) { + this.rotationalSpeed = rotationalSpeed; + return (D) this; + } + + public D setRotationOffset(float rotationOffset) { + this.rotationOffset = rotationOffset; + return (D) this; + } + + + @Override + public void write(ByteBuffer buf) { + putVec3(buf, x, y, z); + putVec2(buf, blockLight, skyLight); + putVec3(buf, r, g, b); + put(buf, rotationalSpeed); + put(buf, rotationOffset); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticRenderMaterials.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticRenderMaterials.java new file mode 100644 index 000000000..77a14eabb --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/base/KineticRenderMaterials.java @@ -0,0 +1,13 @@ +package com.simibubi.create.content.contraptions.base; + +import com.simibubi.create.content.contraptions.relays.belt.BeltData; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.MaterialType; +import com.simibubi.create.content.contraptions.components.actors.ContraptionActorData; + +public class KineticRenderMaterials { + public static final MaterialType> ROTATING = new MaterialType<>(); + public static final MaterialType> BELTS = new MaterialType<>(); + + public static final MaterialType> ACTORS = new MaterialType<>(); +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java index a7d96c5be..afc9304f8 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java @@ -8,6 +8,7 @@ import java.util.List; import javax.annotation.Nullable; import com.simibubi.create.Create; +import com.simibubi.create.CreateClient; import com.simibubi.create.content.contraptions.KineticNetwork; import com.simibubi.create.content.contraptions.RotationPropagator; import com.simibubi.create.content.contraptions.base.IRotate.SpeedLevel; @@ -17,6 +18,8 @@ import com.simibubi.create.content.contraptions.goggles.IHaveHoveringInformation import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.item.TooltipHelper; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; +import com.simibubi.create.foundation.render.backend.instancing.IInstanceRendered; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.utility.Lang; @@ -32,12 +35,22 @@ import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.AxisDirection; +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.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; + +import javax.annotation.Nullable; +import java.util.List; + +import static net.minecraft.util.text.TextFormatting.GOLD; +import static net.minecraft.util.text.TextFormatting.GRAY; public abstract class KineticTileEntity extends SmartTileEntity - implements ITickableTileEntity, IHaveGoggleInformation, IHaveHoveringInformation { + implements ITickableTileEntity, IHaveGoggleInformation, IHaveHoveringInformation, IInstanceRendered { public @Nullable Long network; public @Nullable BlockPos source; @@ -245,6 +258,9 @@ public abstract class KineticTileEntity extends SmartTileEntity if (clientPacket && overStressedBefore != overStressed && speed != 0) effects.triggerOverStressedEffect(); + + if (clientPacket) + FastRenderDispatcher.enqueueUpdate(this); } public float getGeneratedSpeed() { @@ -465,7 +481,7 @@ public abstract class KineticTileEntity extends SmartTileEntity /** * Specify ratio of transferred rotation from this kinetic component to a * specific other. - * + * * @param target other Kinetic TE to transfer to * @param stateFrom this TE's blockstate * @param stateTo other TE's blockstate @@ -486,7 +502,7 @@ public abstract class KineticTileEntity extends SmartTileEntity * Specify additional locations the rotation propagator should look for * potentially connected components. Neighbour list contains offset positions in * all 6 directions by default. - * + * * @param block * @param state * @param neighbours @@ -513,7 +529,7 @@ public abstract class KineticTileEntity extends SmartTileEntity * circumstance. Shaft and cogwheel connections are already handled by internal * logic. Does not have to be specified on both ends, it is assumed that this * relation is symmetrical. - * + * * @param other * @param state * @param otherState @@ -528,4 +544,42 @@ public abstract class KineticTileEntity extends SmartTileEntity return block.hasIntegratedCogwheel(world, pos, state); } + @Override + public void onLoad() { + super.onLoad(); + if (world != null && world.isRemote) + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> CreateClient.kineticRenderer.add(this)); + } + + @Override + public void onChunkUnloaded() { + if (world != null && world.isRemote) + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> CreateClient.kineticRenderer.remove(this)); + } + + @Override + public void requestModelDataUpdate() { + super.requestModelDataUpdate(); + if (!this.removed) { + FastRenderDispatcher.enqueueUpdate(this); + } + } + + @Override + public void onChunkLightUpdate() { + CreateClient.kineticRenderer.onLightUpdate(this); + } + + protected AxisAlignedBB cachedBoundingBox; + @OnlyIn(Dist.CLIENT) + public AxisAlignedBB getRenderBoundingBox() { + if (cachedBoundingBox == null) { + cachedBoundingBox = makeRenderBoundingBox(); + } + return cachedBoundingBox; + } + + protected AxisAlignedBB makeRenderBoundingBox() { + return super.getRenderBoundingBox(); + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntityRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntityRenderer.java index 5eb1aea7a..836d63c66 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntityRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntityRenderer.java @@ -6,11 +6,12 @@ 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.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.ColorHelper; -import com.simibubi.create.foundation.utility.SuperByteBuffer; -import com.simibubi.create.foundation.utility.SuperByteBufferCache.Compartment; +import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.Compartment; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -38,6 +39,8 @@ public class KineticTileEntityRenderer extends SafeTileEntityRenderer extends TileEntityInstance { + + public KineticTileInstance(InstancedTileRenderer modelManager, T tile) { + super(modelManager, tile); + } + + protected final void updateRotation(InstanceKey key, Direction.Axis axis) { + key.modifyInstance(data -> { + data.setColor(tile.network) + .setRotationalSpeed(tile.getSpeed()) + .setRotationOffset(getRotationOffset(axis)) + .setRotationAxis(axis); + }); + } + + protected final Consumer setupFunc(float speed, Direction.Axis axis) { + return data -> { + data.setBlockLight(world.getLightLevel(LightType.BLOCK, pos)) + .setSkyLight(world.getLightLevel(LightType.SKY, pos)) + .setTileEntity(tile) + .setRotationalSpeed(speed) + .setRotationOffset(getRotationOffset(axis)) + .setRotationAxis(axis); + }; + } + + protected final void relight(KineticData data) { + data.setBlockLight(world.getLightLevel(LightType.BLOCK, pos)) + .setSkyLight(world.getLightLevel(LightType.SKY, pos)); + } + + protected float getRotationOffset(final Direction.Axis axis) { + float offset = CogWheelBlock.isLargeCog(lastState) ? 11.25f : 0; + double d = (((axis == Direction.Axis.X) ? 0 : pos.getX()) + ((axis == Direction.Axis.Y) ? 0 : pos.getY()) + + ((axis == Direction.Axis.Z) ? 0 : pos.getZ())) % 2; + if (d == 0) { + offset = 22.5f; + } + return offset; + } + + public static BlockState shaft(Direction.Axis axis) { + return AllBlocks.SHAFT.getDefaultState() + .with(ShaftBlock.AXIS, axis); + } + + public Direction.Axis getRotationAxis() { + return ((IRotate) lastState.getBlock()).getRotationAxis(lastState); + } + + protected final RenderMaterial> rotatingMaterial() { + return modelManager.getMaterial(KineticRenderMaterials.ROTATING); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticVertexAttributes.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticVertexAttributes.java new file mode 100644 index 000000000..46f8740f4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/base/KineticVertexAttributes.java @@ -0,0 +1,42 @@ +package com.simibubi.create.content.contraptions.base; + +import com.simibubi.create.foundation.render.backend.gl.attrib.CommonAttributes; +import com.simibubi.create.foundation.render.backend.gl.attrib.IVertexAttrib; +import com.simibubi.create.foundation.render.backend.gl.attrib.VertexAttribSpec; + +public enum KineticVertexAttributes implements IVertexAttrib { + INSTANCE_POSITION("aInstancePos", CommonAttributes.VEC3), + LIGHT("aLight", CommonAttributes.LIGHT), + NETWORK_COLOR("aNetworkTint", CommonAttributes.RGB), + SPEED("aSpeed", CommonAttributes.FLOAT), + OFFSET("aOffset", CommonAttributes.FLOAT), + ; + + private final String name; + private final VertexAttribSpec spec; + + KineticVertexAttributes(String name, VertexAttribSpec spec) { + this.name = name; + this.spec = spec; + } + + @Override + public String attribName() { + return name; + } + + @Override + public VertexAttribSpec attribSpec() { + return spec; + } + + @Override + public int getDivisor() { + return 1; + } + + @Override + public int getBufferIndex() { + return 1; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/RotatedPillarKineticBlock.java b/src/main/java/com/simibubi/create/content/contraptions/base/RotatedPillarKineticBlock.java index 2e86a897a..f76ff0319 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/RotatedPillarKineticBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/RotatedPillarKineticBlock.java @@ -1,7 +1,6 @@ package com.simibubi.create.content.contraptions.base; import com.simibubi.create.foundation.utility.Iterate; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.item.BlockItemUseContext; @@ -27,7 +26,7 @@ public abstract class RotatedPillarKineticBlock extends KineticBlock { switch (rot) { case COUNTERCLOCKWISE_90: case CLOCKWISE_90: - switch ((Direction.Axis) state.get(AXIS)) { + switch (state.get(AXIS)) { case X: return state.with(AXIS, Direction.Axis.Z); case Z: diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/RotatingData.java b/src/main/java/com/simibubi/create/content/contraptions/base/RotatingData.java new file mode 100644 index 000000000..75fca6a53 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/base/RotatingData.java @@ -0,0 +1,48 @@ +package com.simibubi.create.content.contraptions.base; + +import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import net.minecraft.client.renderer.Vector3f; +import net.minecraft.util.Direction; + +import java.nio.ByteBuffer; + +public class RotatingData extends KineticData { + public static VertexFormat FORMAT = VertexFormat.builder() + .addAttributes(KineticVertexAttributes.class) + .addAttributes(RotatingVertexAttributes.class) + .build(); + + private byte rotationAxisX; + private byte rotationAxisY; + private byte rotationAxisZ; + + protected RotatingData(InstancedModel owner) { + super(owner); + } + + public RotatingData setRotationAxis(Direction.Axis axis) { + Direction orientation = Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis); + setRotationAxis(orientation.getUnitVector()); + return this; + } + + public RotatingData setRotationAxis(Vector3f axis) { + setRotationAxis(axis.getX(), axis.getY(), axis.getZ()); + return this; + } + + public RotatingData setRotationAxis(float rotationAxisX, float rotationAxisY, float rotationAxisZ) { + this.rotationAxisX = (byte) (rotationAxisX * 127); + this.rotationAxisY = (byte) (rotationAxisY * 127); + this.rotationAxisZ = (byte) (rotationAxisZ * 127); + return this; + } + + @Override + public void write(ByteBuffer buf) { + super.write(buf); + + putVec3(buf, rotationAxisX, rotationAxisY, rotationAxisZ); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/RotatingInstancedModel.java b/src/main/java/com/simibubi/create/content/contraptions/base/RotatingInstancedModel.java new file mode 100644 index 000000000..0b9a2e998 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/base/RotatingInstancedModel.java @@ -0,0 +1,23 @@ +package com.simibubi.create.content.contraptions.base; + +import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import net.minecraft.client.renderer.BufferBuilder; + +public class RotatingInstancedModel extends InstancedModel { + public RotatingInstancedModel(InstancedTileRenderer renderer, BufferBuilder buf) { + super(renderer, buf); + } + + @Override + protected RotatingData newInstance() { + return new RotatingData(this); + } + + @Override + protected VertexFormat getInstanceFormat() { + return RotatingData.FORMAT; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/RotatingVertexAttributes.java b/src/main/java/com/simibubi/create/content/contraptions/base/RotatingVertexAttributes.java new file mode 100644 index 000000000..677b18190 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/base/RotatingVertexAttributes.java @@ -0,0 +1,38 @@ +package com.simibubi.create.content.contraptions.base; + +import com.simibubi.create.foundation.render.backend.gl.attrib.CommonAttributes; +import com.simibubi.create.foundation.render.backend.gl.attrib.IVertexAttrib; +import com.simibubi.create.foundation.render.backend.gl.attrib.VertexAttribSpec; + +public enum RotatingVertexAttributes implements IVertexAttrib { + AXIS("aAxis", CommonAttributes.NORMAL), + ; + + private final String name; + private final VertexAttribSpec spec; + + RotatingVertexAttributes(String name, VertexAttribSpec spec) { + this.name = name; + this.spec = spec; + } + + @Override + public String attribName() { + return name; + } + + @Override + public VertexAttribSpec attribSpec() { + return spec; + } + + @Override + public int getDivisor() { + return 1; + } + + @Override + public int getBufferIndex() { + return 1; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/ShaftlessCogInstance.java b/src/main/java/com/simibubi/create/content/contraptions/base/ShaftlessCogInstance.java new file mode 100644 index 000000000..a64b049bd --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/base/ShaftlessCogInstance.java @@ -0,0 +1,25 @@ +package com.simibubi.create.content.contraptions.base; + +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; +import net.minecraft.tileentity.TileEntityType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +public class ShaftlessCogInstance extends SingleRotatingInstance { + public static void register(TileEntityType type) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> + InstancedTileRenderRegistry.instance.register(type, ShaftlessCogInstance::new)); + } + + public ShaftlessCogInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected InstancedModel getModel() { + return AllBlockPartials.SHAFTLESS_COGWHEEL.renderOnRotating(modelManager, tile.getBlockState()); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/SingleRotatingInstance.java b/src/main/java/com/simibubi/create/content/contraptions/base/SingleRotatingInstance.java new file mode 100644 index 000000000..3a717e5a7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/base/SingleRotatingInstance.java @@ -0,0 +1,56 @@ +package com.simibubi.create.content.contraptions.base; + +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; +import net.minecraft.block.BlockState; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +import static com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer.KINETIC_TILE; + +public class SingleRotatingInstance extends KineticTileInstance { + public static void register(TileEntityType type) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> + InstancedTileRenderRegistry.instance.register(type, SingleRotatingInstance::new)); + } + + protected InstanceKey rotatingModelKey; + + public SingleRotatingInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected void init() { + Direction.Axis axis = ((IRotate) lastState.getBlock()).getRotationAxis(lastState); + rotatingModelKey = getModel().setupInstance(setupFunc(tile.getSpeed(), axis)); + } + + @Override + public void onUpdate() { + Direction.Axis axis = ((IRotate) lastState.getBlock()).getRotationAxis(lastState); + updateRotation(rotatingModelKey, axis); + } + + @Override + public void updateLight() { + rotatingModelKey.modifyInstance(this::relight); + } + + @Override + public void remove() { + rotatingModelKey.delete(); + } + + protected BlockState getRenderedBlockState() { + return lastState; + } + + protected InstancedModel getModel() { + return rotatingMaterial().getModel(KINETIC_TILE, getRenderedBlockState()); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/ActorVertexAttributes.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/ActorVertexAttributes.java new file mode 100644 index 000000000..fdeae0d94 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/ActorVertexAttributes.java @@ -0,0 +1,43 @@ +package com.simibubi.create.content.contraptions.components.actors; + +import com.simibubi.create.foundation.render.backend.gl.attrib.CommonAttributes; +import com.simibubi.create.foundation.render.backend.gl.attrib.IVertexAttrib; +import com.simibubi.create.foundation.render.backend.gl.attrib.VertexAttribSpec; + +public enum ActorVertexAttributes implements IVertexAttrib { + INSTANCE_POSITION("aInstancePos", CommonAttributes.VEC3), + LIGHT("aModelLight", CommonAttributes.LIGHT), + OFFSET("aOffset", CommonAttributes.FLOAT), + AXIS("aAxis", CommonAttributes.NORMAL), + INSTANCE_ROTATION("aInstanceRot", CommonAttributes.VEC3), + ROTATION_CENTER("aRotationCenter", CommonAttributes.NORMAL), + ; + + private final String name; + private final VertexAttribSpec spec; + + ActorVertexAttributes(String name, VertexAttribSpec spec) { + this.name = name; + this.spec = spec; + } + + @Override + public String attribName() { + return name; + } + + @Override + public VertexAttribSpec attribSpec() { + return spec; + } + + @Override + public int getDivisor() { + return 1; + } + + @Override + public int getBufferIndex() { + return 1; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/BellMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/BellMovementBehaviour.java index cc14b1ffc..3bcaa5286 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/BellMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/BellMovementBehaviour.java @@ -10,8 +10,8 @@ import net.minecraft.util.math.Vec3d; public class BellMovementBehaviour extends MovementBehaviour { @Override - public boolean hasSpecialMovementRenderer() { - return false; + public boolean renderAsNormalTileEntity() { + return true; } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/CampfireMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/CampfireMovementBehaviour.java index a1f1c148f..e27cffee5 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/CampfireMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/CampfireMovementBehaviour.java @@ -10,8 +10,8 @@ import net.minecraft.particles.ParticleTypes; public class CampfireMovementBehaviour extends MovementBehaviour { @Override - public boolean hasSpecialMovementRenderer() { - return false; + public boolean renderAsNormalTileEntity() { + return true; } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/ContraptionActorData.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/ContraptionActorData.java new file mode 100644 index 000000000..d7eb78b24 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/ContraptionActorData.java @@ -0,0 +1,105 @@ +package com.simibubi.create.content.contraptions.components.actors; + +import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; +import com.simibubi.create.foundation.render.backend.instancing.InstanceData; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import net.minecraft.client.renderer.Vector3f; +import net.minecraft.util.math.BlockPos; + +import java.nio.ByteBuffer; + +public class ContraptionActorData extends InstanceData { + public static VertexFormat FORMAT = VertexFormat.builder() + .addAttributes(ActorVertexAttributes.class) + .build(); + + private float x; + private float y; + private float z; + private byte blockLight; + private byte skyLight; + private float rotationOffset; + private byte rotationAxisX; + private byte rotationAxisY; + private byte rotationAxisZ; + private float localRotationX; + private float localRotationY; + private float localRotationZ; + private byte rotationCenterX = 64; + private byte rotationCenterY = 64; + private byte rotationCenterZ = 64; + + protected ContraptionActorData(InstancedModel owner) { + super(owner); + } + + + public ContraptionActorData setPosition(BlockPos pos) { + this.x = pos.getX(); + this.y = pos.getY(); + this.z = pos.getZ(); + return this; + } + + public ContraptionActorData setBlockLight(int blockLight) { + this.blockLight = (byte) ((blockLight & 0xF) << 4); + return this; + } + + public ContraptionActorData setSkyLight(int skyLight) { + this.skyLight = (byte) ((skyLight & 0xF) << 4); + return this; + } + + public ContraptionActorData setRotationOffset(float rotationOffset) { + this.rotationOffset = rotationOffset; + return this; + } + + public ContraptionActorData setRotationAxis(Vector3f axis) { + setRotationAxis(axis.getX(), axis.getY(), axis.getZ()); + return this; + } + + public ContraptionActorData setRotationAxis(float rotationAxisX, float rotationAxisY, float rotationAxisZ) { + this.rotationAxisX = (byte) (rotationAxisX * 127); + this.rotationAxisY = (byte) (rotationAxisY * 127); + this.rotationAxisZ = (byte) (rotationAxisZ * 127); + return this; + } + + public ContraptionActorData setRotationCenter(Vector3f axis) { + setRotationCenter(axis.getX(), axis.getY(), axis.getZ()); + return this; + } + + public ContraptionActorData setRotationCenter(float rotationCenterX, float rotationCenterY, float rotationCenterZ) { + this.rotationCenterX = (byte) (rotationCenterX * 127); + this.rotationCenterY = (byte) (rotationCenterY * 127); + this.rotationCenterZ = (byte) (rotationCenterZ * 127); + return this; + } + + public ContraptionActorData setLocalRotation(Vector3f axis) { + setLocalRotation(axis.getX(), axis.getY(), axis.getZ()); + return this; + } + + public ContraptionActorData setLocalRotation(float localRotationX, float localRotationY, float localRotationZ) { + this.localRotationX = localRotationX; + this.localRotationY = localRotationY; + this.localRotationZ = localRotationZ; + return this; + } + + @Override + public void write(ByteBuffer buf) { + putVec3(buf, x, y, z); + putVec2(buf, blockLight, skyLight); + put(buf, rotationOffset); + putVec3(buf, rotationAxisX, rotationAxisY, rotationAxisZ); + putVec3(buf, localRotationX, localRotationY, localRotationZ); + putVec3(buf, rotationCenterX, rotationCenterY, rotationCenterZ); + + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillInstance.java new file mode 100644 index 000000000..16fd9b7d4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillInstance.java @@ -0,0 +1,49 @@ +package com.simibubi.create.content.contraptions.components.actors; + +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.content.contraptions.base.RotatingData; +import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; +import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import com.simibubi.create.content.contraptions.components.structureMovement.render.RenderedContraption; +import com.simibubi.create.foundation.render.backend.instancing.*; +import com.simibubi.create.foundation.utility.AngleHelper; +import net.minecraft.block.BlockState; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraft.world.LightType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +public class DrillInstance extends SingleRotatingInstance { + public static void register(TileEntityType type) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> + InstancedTileRenderRegistry.instance.register(type, DrillInstance::new)); } + + public DrillInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + super(modelManager, tile); + } + + public static void addInstanceForContraption(RenderedContraption contraption, MovementContext context) { + RenderMaterial> renderMaterial = contraption.getActorMaterial(); + + BlockState state = context.state; + InstancedModel model = renderMaterial.getModel(AllBlockPartials.DRILL_HEAD, state); + + model.setupInstance(data -> { + Direction facing = state.get(DrillBlock.FACING); + float eulerX = AngleHelper.verticalAngle(facing) + ((facing.getAxis() == Direction.Axis.Y) ? 180 : 0); + float eulerY = facing.getHorizontalAngle(); + data.setPosition(context.localPos) + .setBlockLight(contraption.renderWorld.getLightLevel(LightType.BLOCK, context.localPos)) + .setRotationOffset(0) + .setRotationAxis(0, 0, 1) + .setLocalRotation(eulerX, eulerY, 0); + }); + } + + @Override + protected InstancedModel getModel() { + return AllBlockPartials.DRILL_HEAD.renderOnDirectionalSouthRotating(modelManager, tile.getBlockState()); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillMovementBehaviour.java index 62f8c319d..a600cf9da 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillMovementBehaviour.java @@ -2,6 +2,8 @@ package com.simibubi.create.content.contraptions.components.actors; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; +import com.simibubi.create.content.contraptions.components.structureMovement.render.RenderedContraption; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.block.BlockState; @@ -31,7 +33,18 @@ public class DrillMovementBehaviour extends BlockBreakingMovementBehaviour { @OnlyIn(value = Dist.CLIENT) public void renderInContraption(MovementContext context, MatrixStack ms, MatrixStack msLocal, IRenderTypeBuffer buffer) { - DrillRenderer.renderInContraption(context, ms, msLocal, buffer); + if (!FastRenderDispatcher.available()) + DrillRenderer.renderInContraption(context, ms, msLocal, buffer); + } + + @Override + public boolean hasSpecialInstancedRendering() { + return true; + } + + @Override + public void addInstance(RenderedContraption contraption, MovementContext context) { + DrillInstance.addInstanceForContraption(contraption, context); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillRenderer.java index 40945edf1..57e858cde 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillRenderer.java @@ -10,7 +10,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Mov import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.MatrixStacker; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.block.BlockState; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterMovementBehaviour.java index 38d5f55f8..c2d2b7880 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterMovementBehaviour.java @@ -2,6 +2,8 @@ package com.simibubi.create.content.contraptions.components.actors; import static net.minecraft.block.HorizontalBlock.HORIZONTAL_FACING; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; +import com.simibubi.create.content.contraptions.components.structureMovement.render.RenderedContraption; import org.apache.commons.lang3.mutable.MutableBoolean; import com.mojang.blaze3d.matrix.MatrixStack; @@ -35,10 +37,21 @@ public class HarvesterMovementBehaviour extends MovementBehaviour { .getOpposite()); } + @Override + public boolean hasSpecialInstancedRendering() { + return true; + } + + @Override + public void addInstance(RenderedContraption contraption, MovementContext context) { + HarvesterRenderer.addInstanceForContraption(contraption, context); + } + @Override public void renderInContraption(MovementContext context, MatrixStack ms, MatrixStack msLocal, IRenderTypeBuffer buffers) { - HarvesterRenderer.renderInContraption(context, ms, msLocal, buffers); + if (!FastRenderDispatcher.available()) + HarvesterRenderer.renderInContraption(context, ms, msLocal, buffers); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterRenderer.java index 71ecfdbc6..7456140d0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterRenderer.java @@ -5,19 +5,25 @@ import static net.minecraft.state.properties.BlockStateProperties.HORIZONTAL_FAC import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; +import com.simibubi.create.content.contraptions.components.structureMovement.render.RenderedContraption; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.RenderMaterial; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AnimationTickHolder; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.Vector3f; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; +import net.minecraft.world.LightType; public class HarvesterRenderer extends SafeTileEntityRenderer { @@ -34,6 +40,25 @@ public class HarvesterRenderer extends SafeTileEntityRenderer> renderMaterial = contraption.getActorMaterial(); + + BlockState state = context.state; + InstancedModel model = renderMaterial.getModel(AllBlockPartials.HARVESTER_BLADE, state); + + model.setupInstance(data -> { + Direction facing = state.get(HORIZONTAL_FACING); + float originOffset = 1 / 16f; + Vector3f rotOffset = new Vector3f(0.5f, -2 * originOffset + 0.5f, originOffset + 0.5f); + data.setPosition(context.localPos) + .setBlockLight(contraption.renderWorld.getLightLevel(LightType.BLOCK, context.localPos)) + .setRotationOffset(0) + .setRotationCenter(rotOffset) + .setRotationAxis(-1, 0, 0) + .setLocalRotation(0, facing.getHorizontalAngle(), 0); + }); + } + public static void renderInContraption(MovementContext context, MatrixStack ms, MatrixStack msLocal, IRenderTypeBuffer buffers) { BlockState blockState = context.state; @@ -55,7 +80,7 @@ public class HarvesterRenderer extends SafeTileEntityRenderer { public PortableStorageInterfaceRenderer(TileEntityRendererDispatcher dispatcher) { @@ -43,8 +43,7 @@ public class PortableStorageInterfaceRenderer extends SafeTileEntityRenderer sbb.light(msLocal.peek() - .getModel()) + .getModel(), ContraptionRenderDispatcher.getLightOnContraption(context)) .renderInto(ms, vb), ms, msLocal); } - protected static PortableStorageInterfaceTileEntity getTargetPSI(MovementContext context) { - String _workingPos_ = PortableStorageInterfaceMovement._workingPos_; - if (!context.contraption.stalled || !context.data.contains(_workingPos_)) - return null; - - BlockPos pos = NBTUtil.readBlockPos(context.data.getCompound(_workingPos_)); - TileEntity tileEntity = context.world.getTileEntity(pos); - if (!(tileEntity instanceof PortableStorageInterfaceTileEntity)) - return null; - - PortableStorageInterfaceTileEntity psi = (PortableStorageInterfaceTileEntity) tileEntity; - if (!psi.isTransferring()) - return null; - return psi; - } - private static void render(BlockState blockState, float progress, boolean lit, Consumer drawCallback, MatrixStack... matrixStacks) { for (MatrixStack ms : matrixStacks) @@ -109,6 +92,22 @@ public class PortableStorageInterfaceRenderer extends SafeTileEntityRenderer { + public RotatingActorModel(InstancedTileRenderer renderer, BufferBuilder buf) { + super(renderer, buf); + } + + @Override + protected VertexFormat getInstanceFormat() { + return ContraptionActorData.FORMAT; + } + + @Override + protected ContraptionActorData newInstance() { + return new ContraptionActorData(this); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockRenderer.java index 6e8250e35..6f7c8c427 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockRenderer.java @@ -7,7 +7,7 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.content.contraptions.components.clock.CuckooClockTileEntity.Animation; import com.simibubi.create.foundation.utility.AngleHelper; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockTileEntity.java index dad7b19ce..bc2d77826 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockTileEntity.java @@ -1,9 +1,5 @@ package com.simibubi.create.content.contraptions.components.clock; -import static com.simibubi.create.foundation.utility.AngleHelper.deg; -import static com.simibubi.create.foundation.utility.AngleHelper.getShortestAngleDiff; -import static com.simibubi.create.foundation.utility.AngleHelper.rad; - import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue; @@ -11,7 +7,6 @@ import com.simibubi.create.foundation.gui.widgets.InterpolatedValue; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.nbt.CompoundNBT; import net.minecraft.particles.ParticleTypes; import net.minecraft.tileentity.TileEntityType; @@ -22,6 +17,8 @@ import net.minecraft.util.SoundEvents; import net.minecraft.util.math.Vec3d; import net.minecraft.world.Explosion; +import static com.simibubi.create.foundation.utility.AngleHelper.*; + public class CuckooClockTileEntity extends KineticTileEntity { public static DamageSource CUCKOO_SURPRISE = new DamageSource("create.cuckoo_clock_explosion").setExplosion(); @@ -95,9 +92,9 @@ public class CuckooClockTileEntity extends KineticTileEntity { moveHands(hours, minutes); if (animationType == Animation.NONE) { - if (AnimationTickHolder.ticks % 32 == 0) + if (AnimationTickHolder.getTicks() % 32 == 0) playSound(SoundEvents.BLOCK_NOTE_BLOCK_HAT, 1 / 16f, 2f); - else if (AnimationTickHolder.ticks % 16 == 0) + else if (AnimationTickHolder.getTicks() % 16 == 0) playSound(SoundEvents.BLOCK_NOTE_BLOCK_HAT, 1 / 16f, 1.5f); } else { @@ -172,4 +169,8 @@ public class CuckooClockTileEntity extends KineticTileEntity { world.playSound(vec.x, vec.y, vec.z, sound, SoundCategory.BLOCKS, volume, pitch, false); } + @Override + public boolean shouldRenderAsTE() { + return true; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterInstance.java new file mode 100644 index 000000000..74c889e01 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterInstance.java @@ -0,0 +1,48 @@ +package com.simibubi.create.content.contraptions.components.crafter; + +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.SingleRotatingInstance; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; +import com.simibubi.create.content.contraptions.base.RotatingData; +import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.MatrixStacker; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +import java.util.function.Supplier; + +public class MechanicalCrafterInstance extends SingleRotatingInstance { + public static void register(TileEntityType type) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> + InstancedTileRenderRegistry.instance.register(type, MechanicalCrafterInstance::new)); + } + + public MechanicalCrafterInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected InstancedModel getModel() { + Direction facing = lastState.get(MechanicalCrafterBlock.HORIZONTAL_FACING); + + Supplier ms = () -> { + MatrixStack stack = new MatrixStack(); + MatrixStacker stacker = MatrixStacker.of(stack).centre(); + + if (facing.getAxis() == Direction.Axis.X) + stacker.rotateZ(90); + else if (facing.getAxis() == Direction.Axis.Z) + stacker.rotateX(90); + + stacker.unCentre(); + return stack; + }; + return rotatingMaterial().getModel(AllBlockPartials.SHAFTLESS_COGWHEEL, lastState, facing, ms); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterRenderer.java index 9de9abd72..d94e5c35c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterRenderer.java @@ -1,20 +1,17 @@ package com.simibubi.create.content.contraptions.components.crafter; -import static com.simibubi.create.content.contraptions.base.HorizontalKineticBlock.HORIZONTAL_FACING; -import static com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer.standardKineticRotationTransform; - import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.vertex.IVertexBuilder; 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.render.backend.FastRenderDispatcher; +import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.MatrixStacker; -import com.simibubi.create.foundation.utility.SuperByteBuffer; - import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -25,11 +22,13 @@ import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.item.ItemStack; import net.minecraft.util.Direction; -import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; +import static com.simibubi.create.content.contraptions.base.HorizontalKineticBlock.HORIZONTAL_FACING; +import static com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer.standardKineticRotationTransform; + public class MechanicalCrafterRenderer extends SafeTileEntityRenderer { public MechanicalCrafterRenderer(TileEntityRendererDispatcher dispatcher) { @@ -154,12 +153,13 @@ public class MechanicalCrafterRenderer extends SafeTileEntityRenderer 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(te.getWorld())) { + KineticTileEntityRenderer.renderRotatingKineticBlock(te, getRenderedBlockState(te), ms, vb, light); + } BlockState blockState = te.getBlockState(); BlockPos pos = te.getPos(); @@ -178,8 +182,7 @@ public class DeployerRenderer extends SafeTileEntityRenderer double distance = context.position.distanceTo(center); double nextDistance = context.position.add(context.motion) .distanceTo(center); - factor = .5f - MathHelper.clamp(MathHelper.lerp(Minecraft.getInstance() - .getRenderPartialTicks(), distance, nextDistance), 0, 1); + factor = .5f - MathHelper.clamp(MathHelper.lerp(AnimationTickHolder.getPartialTicks(), distance, nextDistance), 0, 1); } Vec3d offset = new Vec3d(blockState.get(FACING) @@ -189,9 +192,9 @@ public class DeployerRenderer extends SafeTileEntityRenderer .getModel(); for (MatrixStack m : matrixStacks) m.translate(offset.x, offset.y, offset.z); - pole.light(lighting) + pole.light(lighting, ContraptionRenderDispatcher.getLightOnContraption(context)) .renderInto(ms, builder); - hand.light(lighting) + hand.light(lighting, ContraptionRenderDispatcher.getLightOnContraption(context)) .renderInto(ms, builder); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java index 1aa3a0330..b31a3a607 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java @@ -1,10 +1,5 @@ package com.simibubi.create.content.contraptions.components.deployer; -import static com.simibubi.create.content.contraptions.base.DirectionalKineticBlock.FACING; - -import java.util.ArrayList; -import java.util.List; - import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.base.KineticTileEntity; @@ -15,7 +10,6 @@ import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; @@ -24,20 +18,20 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.Hand; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.RayTraceContext; +import net.minecraft.util.math.*; import net.minecraft.util.math.RayTraceContext.BlockMode; import net.minecraft.util.math.RayTraceContext.FluidMode; -import net.minecraft.util.math.Vec3d; import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.items.IItemHandlerModifiable; +import java.util.ArrayList; +import java.util.List; + +import static com.simibubi.create.content.contraptions.base.DirectionalKineticBlock.FACING; + public class DeployerTileEntity extends KineticTileEntity { protected State state; @@ -346,8 +340,8 @@ public class DeployerTileEntity extends KineticTileEntity { } @Override - public AxisAlignedBB getRenderBoundingBox() { - return super.getRenderBoundingBox().grow(3); + public AxisAlignedBB makeRenderBoundingBox() { + return super.makeRenderBoundingBox().grow(3); } @Override @@ -382,4 +376,8 @@ public class DeployerTileEntity extends KineticTileEntity { return true; } + @Override + public boolean shouldRenderAsTE() { + return true; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanRenderer.java index 957ec69e7..870aebca3 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanRenderer.java @@ -7,8 +7,9 @@ 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.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.utility.AnimationTickHolder; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; @@ -26,6 +27,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(te.getWorld())) return; + Direction direction = te.getBlockState() .get(FACING); IVertexBuilder vb = buffer.getBuffer(RenderType.getCutoutMipped()); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/FanInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/fan/FanInstance.java new file mode 100644 index 000000000..88a702f56 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/fan/FanInstance.java @@ -0,0 +1,117 @@ +package com.simibubi.create.content.contraptions.components.fan; + +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.IRotate; +import com.simibubi.create.content.contraptions.base.KineticTileInstance; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; +import com.simibubi.create.content.contraptions.base.RotatingData; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.LightType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +import static net.minecraft.state.properties.BlockStateProperties.FACING; + +public class FanInstance extends KineticTileInstance { + public static void register(TileEntityType type) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> + InstancedTileRenderRegistry.instance.register(type, FanInstance::new)); + } + + protected InstanceKey shaft; + protected InstanceKey fan; + + public FanInstance(InstancedTileRenderer modelManager, EncasedFanTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected void init() { + final Direction direction = lastState.get(FACING); + final Direction.Axis axis = ((IRotate) lastState.getBlock()).getRotationAxis(lastState); + + InstancedModel shaftHalf = + AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(modelManager, lastState, direction.getOpposite()); + InstancedModel fanInner = + AllBlockPartials.ENCASED_FAN_INNER.renderOnDirectionalSouthRotating(modelManager, lastState, direction.getOpposite()); + + shaft = shaftHalf.setupInstance(data -> { + BlockPos behind = pos.offset(direction.getOpposite()); + int blockLight = world.getLightLevel(LightType.BLOCK, behind); + int skyLight = world.getLightLevel(LightType.SKY, behind); + + data.setRotationalSpeed(tile.getSpeed()) + .setRotationOffset(getRotationOffset(axis)) + .setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector()) + .setTileEntity(tile) + .setBlockLight(blockLight) + .setSkyLight(skyLight); + }); + fan = fanInner.setupInstance(data -> { + BlockPos inFront = pos.offset(direction); + int blockLight = world.getLightLevel(LightType.BLOCK, inFront); + int skyLight = world.getLightLevel(LightType.SKY, inFront); + + data.setRotationalSpeed(getFanSpeed()) + .setRotationOffset(getRotationOffset(axis)) + .setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector()) + .setTileEntity(tile) + .setBlockLight(blockLight) + .setSkyLight(skyLight); + }); + } + + private float getFanSpeed() { + float speed = tile.getSpeed() * 5; + if (speed > 0) + speed = MathHelper.clamp(speed, 80, 64 * 20); + if (speed < 0) + speed = MathHelper.clamp(speed, -64 * 20, -80); + return speed; + } + + @Override + protected void onUpdate() { + Direction.Axis axis = lastState.get(FACING).getAxis(); + updateRotation(shaft, axis); + + fan.modifyInstance(data -> { + data.setColor(tile.network) + .setRotationalSpeed(getFanSpeed()) + .setRotationOffset(getRotationOffset(axis)) + .setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector()); + }); + } + + @Override + public void updateLight() { + final Direction direction = lastState.get(FACING); + + shaft.modifyInstance(data -> { + BlockPos behind = pos.offset(direction.getOpposite()); + int blockLight = world.getLightLevel(LightType.BLOCK, behind); + int skyLight = world.getLightLevel(LightType.SKY, behind); + data.setBlockLight(blockLight) + .setSkyLight(skyLight); + }); + fan.modifyInstance(data -> { + BlockPos inFront = pos.offset(direction); + int blockLight = world.getLightLevel(LightType.BLOCK, inFront); + int skyLight = world.getLightLevel(LightType.SKY, inFront); + data.setBlockLight(blockLight) + .setSkyLight(skyLight); + }); + } + + @Override + public void remove() { + shaft.delete(); + fan.delete(); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlyWheelInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlyWheelInstance.java new file mode 100644 index 000000000..f1f9cda0d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlyWheelInstance.java @@ -0,0 +1,72 @@ +package com.simibubi.create.content.contraptions.components.flywheel; + +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.IRotate; +import com.simibubi.create.content.contraptions.base.KineticTileInstance; +import com.simibubi.create.content.contraptions.base.RotatingData; +import com.simibubi.create.foundation.render.backend.instancing.*; +import net.minecraft.block.BlockState; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraft.util.Rotation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +import java.util.function.Consumer; + +public class FlyWheelInstance extends KineticTileInstance { + public static void register(TileEntityType type) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> + InstancedTileRenderRegistry.instance.register(type, FlyWheelInstance::new)); + } + + protected Direction facing; + + protected InstanceKey shaft; +// protected InstanceKey wheel; + + public FlyWheelInstance(InstancedTileRenderer modelManager, FlywheelTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected void init() { + facing = lastState.get(BlockStateProperties.HORIZONTAL_FACING); + + Direction.Axis axis = ((IRotate) lastState.getBlock()).getRotationAxis(lastState); + Consumer setup = setupFunc(tile.getSpeed(), axis); + shaft = shaftModel().setupInstance(setup); +// wheel = wheelModel().setupInstance(setup); + } + + @Override + protected void onUpdate() { + Direction.Axis axis = ((IRotate) lastState.getBlock()).getRotationAxis(lastState); + updateRotation(shaft, axis); +// updateRotation(wheel, axis); + } + + @Override + public void updateLight() { + shaft.modifyInstance(this::relight); +// wheel.modifyInstance(this::relight); + } + + @Override + public void remove() { + shaft.delete(); + shaft = null; +// wheel.delete(); +// wheel = null; + } + + protected InstancedModel shaftModel() { + return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(modelManager, lastState, facing.getOpposite()); + } + + protected InstancedModel wheelModel() { + BlockState rotate = lastState.rotate(Rotation.CLOCKWISE_90); + return AllBlockPartials.FLYWHEEL.renderOnDirectionalSouthRotating(modelManager, rotate, rotate.get(BlockStateProperties.HORIZONTAL_FACING)); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelRenderer.java index 9632779d4..76453c14e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelRenderer.java @@ -9,7 +9,7 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.content.contraptions.components.flywheel.FlywheelBlock.ConnectionState; import com.simibubi.create.foundation.utility.AngleHelper; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelTileEntity.java index 05283aebd..830081dfb 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelTileEntity.java @@ -2,7 +2,6 @@ package com.simibubi.create.content.contraptions.components.flywheel; import com.simibubi.create.content.contraptions.base.GeneratingKineticTileEntity; import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue; - import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.math.AxisAlignedBB; @@ -48,8 +47,8 @@ public class FlywheelTileEntity extends GeneratingKineticTileEntity { } @Override - public AxisAlignedBB getRenderBoundingBox() { - return super.getRenderBoundingBox().grow(2); + public AxisAlignedBB makeRenderBoundingBox() { + return super.makeRenderBoundingBox().grow(2); } @Override @@ -101,4 +100,8 @@ public class FlywheelTileEntity extends GeneratingKineticTileEntity { } } + @Override + public boolean shouldRenderAsTE() { + return true; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/engine/EngineTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/engine/EngineTileEntity.java index a0869af09..6a3988caa 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/engine/EngineTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/engine/EngineTileEntity.java @@ -14,6 +14,8 @@ import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; public class EngineTileEntity extends SmartTileEntity { @@ -34,9 +36,14 @@ public class EngineTileEntity extends SmartTileEntity { return true; } + protected AxisAlignedBB cachedBoundingBox; @Override + @OnlyIn(Dist.CLIENT) public AxisAlignedBB getRenderBoundingBox() { - return super.getRenderBoundingBox().grow(1.5f); + if (cachedBoundingBox == null) { + cachedBoundingBox = super.getRenderBoundingBox().grow(1.5f); + } + return cachedBoundingBox; } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillStoneCogInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillStoneCogInstance.java new file mode 100644 index 000000000..bcaddb716 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillStoneCogInstance.java @@ -0,0 +1,27 @@ +package com.simibubi.create.content.contraptions.components.millstone; + +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; +import com.simibubi.create.content.contraptions.base.RotatingData; +import net.minecraft.tileentity.TileEntityType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +public class MillStoneCogInstance extends SingleRotatingInstance { + public static void register(TileEntityType type) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> + InstancedTileRenderRegistry.instance.register(type, MillStoneCogInstance::new)); } + + public MillStoneCogInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected InstancedModel getModel() { + return AllBlockPartials.MILLSTONE_COG.renderOnRotating(modelManager, tile.getBlockState()); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneRenderer.java index 2890f16d3..f9fa65b7b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneRenderer.java @@ -4,7 +4,7 @@ import com.simibubi.create.AllBlockPartials; 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.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerRenderer.java index da84d012f..4d4477d9f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerRenderer.java @@ -5,8 +5,9 @@ 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.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.utility.AnimationTickHolder; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -22,6 +23,11 @@ public class MechanicalMixerRenderer extends KineticTileEntityRenderer { super(dispatcher); } + @Override + public boolean isGlobalRenderer(KineticTileEntity te) { + return true; + } + @Override protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { @@ -31,8 +37,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(te.getWorld())) { + 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); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerTileEntity.java index b6037c0c7..6073f366e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerTileEntity.java @@ -80,7 +80,7 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity { } @Override - public AxisAlignedBB getRenderBoundingBox() { + public AxisAlignedBB makeRenderBoundingBox() { return new AxisAlignedBB(pos).expand(0, -1.5, 0); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorRenderer.java index 0993097d0..215cf1b57 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorRenderer.java @@ -3,7 +3,7 @@ package com.simibubi.create.content.contraptions.components.motor; 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.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressRenderer.java index 1a721bac8..18f2353a7 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressRenderer.java @@ -4,7 +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.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -19,6 +19,11 @@ public class MechanicalPressRenderer extends KineticTileEntityRenderer { super(dispatcher); } + @Override + public boolean isGlobalRenderer(KineticTileEntity te) { + return true; + } + @Override protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java index ca52ae3a6..ddc48fb8b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java @@ -102,7 +102,7 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { } @Override - public AxisAlignedBB getRenderBoundingBox() { + public AxisAlignedBB makeRenderBoundingBox() { return new AxisAlignedBB(pos).expand(0, -1.5, 0) .expand(0, 1, 0); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawInstance.java new file mode 100644 index 000000000..0a04d43bb --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawInstance.java @@ -0,0 +1,35 @@ +package com.simibubi.create.content.contraptions.components.saw; + +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.content.contraptions.base.SingleRotatingInstance; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; +import com.simibubi.create.content.contraptions.base.RotatingData; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Rotation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +import static net.minecraft.state.properties.BlockStateProperties.FACING; + +public class SawInstance extends SingleRotatingInstance { + public static void register(TileEntityType type) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> + InstancedTileRenderRegistry.instance.register(type, SawInstance::new)); + } + + public SawInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected InstancedModel getModel() { + if (lastState.get(FACING).getAxis().isHorizontal()) + return AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(modelManager, lastState.rotate(tile.getWorld(), tile.getPos(), Rotation.CLOCKWISE_180)); + else + return rotatingMaterial().getModel(KineticTileEntityRenderer.KINETIC_TILE, shaft(getRotationAxis())); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawRenderer.java index 6ab63b12f..fb9d56fc3 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawRenderer.java @@ -8,11 +8,13 @@ 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.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; +import com.simibubi.create.foundation.render.backend.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; import com.simibubi.create.foundation.utility.MatrixStacker; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.block.BlockState; @@ -42,6 +44,9 @@ public class SawRenderer extends SafeTileEntityRenderer { renderBlade(te, ms, buffer, light); renderItems(te, partialTicks, ms, buffer, light, overlay); FilteringRenderer.renderOnTileEntity(te, partialTicks, ms, buffer, light, overlay); + + if (FastRenderDispatcher.available(te.getWorld())) return; + renderShaft(te, ms, buffer, light, overlay); } @@ -179,7 +184,7 @@ public class SawRenderer extends SafeTileEntityRenderer { superBuffer .light(msLocal.peek() - .getModel()) + .getModel(), ContraptionRenderDispatcher.getLightOnContraption(context)) .renderInto(ms, buffer.getBuffer(RenderType.getCutoutMipped())); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java index 64a448598..2cf10642d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java @@ -1,11 +1,5 @@ package com.simibubi.create.content.contraptions.components.saw; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Random; -import java.util.stream.Collectors; - import com.google.common.base.Predicate; import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.content.contraptions.components.actors.BlockBreakingKineticTileEntity; @@ -21,16 +15,7 @@ import com.simibubi.create.foundation.utility.TreeCutter.Tree; import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.recipe.RecipeConditions; import com.simibubi.create.foundation.utility.recipe.RecipeFinder; - -import net.minecraft.block.BambooBlock; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.CactusBlock; -import net.minecraft.block.ChorusPlantBlock; -import net.minecraft.block.KelpBlock; -import net.minecraft.block.KelpTopBlock; -import net.minecraft.block.StemGrownBlock; -import net.minecraft.block.SugarCaneBlock; +import net.minecraft.block.*; import net.minecraft.entity.item.ItemEntity; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; @@ -53,6 +38,12 @@ import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; + public class SawTileEntity extends BlockBreakingKineticTileEntity { private static final Object cuttingRecipesKey = new Object(); @@ -393,4 +384,9 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity { return false; } + @Override + public boolean shouldRenderAsTE() { + return true; + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java index c863f4372..f3c3d8a99 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java @@ -7,6 +7,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.UUID; +import com.mojang.blaze3d.matrix.MatrixStack; import org.apache.commons.lang3.mutable.MutableInt; import org.apache.commons.lang3.tuple.MutablePair; @@ -597,6 +598,9 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit return false; } + @OnlyIn(Dist.CLIENT) + public abstract void doLocalTransforms(float partialTicks, MatrixStack[] matrixStacks); + public static class ContraptionRotationState { public static final ContraptionRotationState NONE = new ContraptionRotationState(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java index 45638b9a3..1de138917 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java @@ -28,6 +28,7 @@ import com.simibubi.create.content.logistics.block.inventories.AdjustableCrateBl import com.simibubi.create.content.logistics.block.redstone.RedstoneContactBlock; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.fluid.CombinedTankWrapper; +import com.simibubi.create.foundation.render.backend.light.EmptyLighter; import com.simibubi.create.foundation.utility.*; import com.simibubi.create.foundation.utility.worldWrappers.WrappedWorld; import net.minecraft.block.*; @@ -56,6 +57,8 @@ import net.minecraft.util.palette.PaletteHashMap; import net.minecraft.world.IWorld; import net.minecraft.world.World; import net.minecraft.world.gen.feature.template.Template.BlockInfo; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.util.Constants.BlockFlags; import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.fluids.FluidStack; @@ -101,7 +104,8 @@ public abstract class Contraption { // Client public Map presentTileEntities; - public List renderedTileEntities; + public List maybeInstancedTileEntities; + public List specialRenderedTileEntities; public Contraption() { blocks = new HashMap<>(); @@ -114,7 +118,8 @@ public abstract class Contraption { glueToRemove = new ArrayList<>(); initialPassengers = new HashMap<>(); presentTileEntities = new HashMap<>(); - renderedTileEntities = new ArrayList<>(); + maybeInstancedTileEntities = new ArrayList<>(); + specialRenderedTileEntities = new ArrayList<>(); pendingSubContraptions = new ArrayList<>(); stabilizedSubContraptions = new HashMap<>(); } @@ -592,7 +597,7 @@ public abstract class Contraption { public void readNBT(World world, CompoundNBT nbt, boolean spawnData) { blocks.clear(); presentTileEntities.clear(); - renderedTileEntities.clear(); + specialRenderedTileEntities.clear(); INBT blocks = nbt.get("Blocks"); //used to differentiate between the 'old' and the paletted serialization @@ -794,7 +799,7 @@ public abstract class Contraption { Block block = info.state.getBlock(); CompoundNBT tag = info.nbt; MovementBehaviour movementBehaviour = AllMovementBehaviours.of(block); - if (tag == null || (movementBehaviour != null && movementBehaviour.hasSpecialMovementRenderer())) + if (tag == null) return; tag.putInt("x", info.pos.getX()); @@ -817,8 +822,15 @@ public abstract class Contraption { if (te instanceof KineticTileEntity) ((KineticTileEntity) te).setSpeed(0); te.getBlockState(); + + if (movementBehaviour == null || !movementBehaviour.hasSpecialInstancedRendering()) + maybeInstancedTileEntities.add(te); + + if (movementBehaviour != null && !movementBehaviour.renderAsNormalTileEntity()) + return; + presentTileEntities.put(info.pos, te); - renderedTileEntities.add(te); + specialRenderedTileEntities.add(te); } }); @@ -1100,4 +1112,9 @@ public abstract class Contraption { mountedFluidStorage.updateFluid(containedFluid); } + @OnlyIn(Dist.CLIENT) + public ContraptionLighter makeLighter() { + return new EmptyLighter(this); + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntityRenderer.java similarity index 58% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntityRenderer.java rename to src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntityRenderer.java index f6b9ad44d..850d92446 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntityRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntityRenderer.java @@ -1,8 +1,8 @@ package com.simibubi.create.content.contraptions.components.structureMovement; import com.mojang.blaze3d.matrix.MatrixStack; - -import net.minecraft.client.Minecraft; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.culling.ClippingHelperImpl; import net.minecraft.client.renderer.entity.EntityRenderer; @@ -10,29 +10,26 @@ import net.minecraft.client.renderer.entity.EntityRendererManager; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.MathHelper; -public abstract class AbstractContraptionEntityRenderer extends EntityRenderer { +public class ContraptionEntityRenderer extends EntityRenderer { - protected AbstractContraptionEntityRenderer(EntityRendererManager p_i46179_1_) { + public ContraptionEntityRenderer(EntityRendererManager p_i46179_1_) { super(p_i46179_1_); } @Override - public ResourceLocation getEntityTexture(C p_110775_1_) { + public ResourceLocation getEntityTexture(C entity) { return null; } - protected abstract void transform(C contraptionEntity, float partialTicks, MatrixStack[] matrixStacks); - @Override - public boolean shouldRender(C entity, ClippingHelperImpl p_225626_2_, double p_225626_3_, double p_225626_5_, + public boolean shouldRender(C entity, ClippingHelperImpl clippingHelper, double p_225626_3_, double p_225626_5_, double p_225626_7_) { - if (!super.shouldRender(entity, p_225626_2_, p_225626_3_, p_225626_5_, p_225626_7_)) + if (entity.getContraption() == null) return false; if (!entity.isAlive()) return false; - if (entity.getContraption() == null) - return false; - return true; + + return super.shouldRender(entity, clippingHelper, p_225626_3_, p_225626_5_, p_225626_7_); } @Override @@ -41,21 +38,20 @@ public abstract class AbstractContraptionEntityRenderer { + protected final C contraption; + public final LightVolume lightVolume; + + protected GridAlignedBB bounds; + + protected boolean scheduleRebuild; + + protected ContraptionLighter(C contraption) { + this.contraption = contraption; + + bounds = getContraptionBounds(); + + lightVolume = new LightVolume(contraptionBoundsToVolume(bounds.copy())); + + lightVolume.initialize(contraption.entity.world); + scheduleRebuild = true; + } + + protected GridAlignedBB contraptionBoundsToVolume(GridAlignedBB bounds) { + bounds.grow(1); // so we have at least enough data on the edges to avoid artifacts and have smooth lighting + bounds.minY = Math.max(bounds.minY, 0); + bounds.maxY = Math.min(bounds.maxY, 255); + + return bounds; + } + + public void tick(RenderedContraption owner) { + if (scheduleRebuild) { + lightVolume.initialize(owner.contraption.entity.world); + scheduleRebuild = false; + } + } + + public abstract GridAlignedBB getContraptionBounds(); +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionRenderer.java deleted file mode 100644 index 7892307d8..000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionRenderer.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -import java.util.List; -import java.util.Random; - -import org.apache.commons.lang3.tuple.Pair; -import org.lwjgl.opengl.GL11; - -import com.mojang.blaze3d.matrix.MatrixStack; -import com.simibubi.create.AllMovementBehaviours; -import com.simibubi.create.CreateClient; -import com.simibubi.create.foundation.utility.MatrixStacker; -import com.simibubi.create.foundation.utility.SuperByteBuffer; -import com.simibubi.create.foundation.utility.SuperByteBufferCache; -import com.simibubi.create.foundation.utility.SuperByteBufferCache.Compartment; -import com.simibubi.create.foundation.utility.TileEntityRenderHelper; -import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld; - -import net.minecraft.block.BlockRenderType; -import net.minecraft.block.BlockState; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.BlockModelRenderer; -import net.minecraft.client.renderer.BlockRendererDispatcher; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.Matrix4f; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.RenderTypeLookup; -import net.minecraft.client.renderer.model.IBakedModel; -import net.minecraft.client.renderer.texture.OverlayTexture; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.LightType; -import net.minecraft.world.World; -import net.minecraft.world.gen.feature.template.Template.BlockInfo; -import net.minecraftforge.client.ForgeHooksClient; -import net.minecraftforge.client.model.data.EmptyModelData; - -public class ContraptionRenderer { - - public static final Compartment> CONTRAPTION = new Compartment<>(); - protected static PlacementSimulationWorld renderWorld; - - public static void render(World world, Contraption c, MatrixStack ms, MatrixStack msLocal, - IRenderTypeBuffer buffer) { - renderTileEntities(world, c, ms, msLocal, buffer); - if (buffer instanceof IRenderTypeBuffer.Impl) - ((IRenderTypeBuffer.Impl) buffer).draw(); - renderStructure(world, c, ms, msLocal, buffer); - renderActors(world, c, ms, msLocal, buffer); - } - - protected static void renderStructure(World world, Contraption c, MatrixStack ms, MatrixStack msLocal, - IRenderTypeBuffer buffer) { - SuperByteBufferCache bufferCache = CreateClient.bufferCache; - List blockLayers = RenderType.getBlockLayers(); - - buffer.getBuffer(RenderType.getSolid()); - for (int i = 0; i < blockLayers.size(); i++) { - RenderType layer = blockLayers.get(i); - Pair key = Pair.of(c, i); - SuperByteBuffer contraptionBuffer = bufferCache.get(CONTRAPTION, key, () -> buildStructureBuffer(c, layer)); - if (contraptionBuffer.isEmpty()) - continue; - Matrix4f model = msLocal.peek() - .getModel(); - contraptionBuffer.light(model) - .renderInto(ms, buffer.getBuffer(layer)); - } - } - - private static void renderTileEntities(World world, Contraption c, MatrixStack ms, MatrixStack msLocal, - IRenderTypeBuffer buffer) { - TileEntityRenderHelper.renderTileEntities(world, c.renderedTileEntities, ms, msLocal, buffer); - } - - private static SuperByteBuffer buildStructureBuffer(Contraption c, RenderType layer) { - if (renderWorld == null || renderWorld.getWorld() != Minecraft.getInstance().world) - renderWorld = new PlacementSimulationWorld(Minecraft.getInstance().world); - - ForgeHooksClient.setRenderLayer(layer); - MatrixStack ms = new MatrixStack(); - BlockRendererDispatcher dispatcher = Minecraft.getInstance() - .getBlockRendererDispatcher(); - BlockModelRenderer blockRenderer = dispatcher.getBlockModelRenderer(); - Random random = new Random(); - BufferBuilder builder = new BufferBuilder(DefaultVertexFormats.BLOCK.getIntegerSize()); - builder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK); - renderWorld.setTileEntities(c.presentTileEntities.values()); - - for (BlockInfo info : c.getBlocks() - .values()) - renderWorld.setBlockState(info.pos, info.state); - for (BlockInfo info : c.getBlocks() - .values()) { - BlockState state = info.state; - - if (state.getRenderType() == BlockRenderType.ENTITYBLOCK_ANIMATED) - continue; - if (!RenderTypeLookup.canRenderInLayer(state, layer)) - continue; - - IBakedModel originalModel = dispatcher.getModelForState(state); - ms.push(); - ms.translate(info.pos.getX(), info.pos.getY(), info.pos.getZ()); - blockRenderer.renderModel(renderWorld, originalModel, state, info.pos, ms, builder, true, random, 42, - OverlayTexture.DEFAULT_UV, EmptyModelData.INSTANCE); - ms.pop(); - } - - builder.finishDrawing(); - renderWorld.clear(); - return new SuperByteBuffer(builder); - } - - private static void renderActors(World world, Contraption c, MatrixStack ms, MatrixStack msLocal, - IRenderTypeBuffer buffer) { - MatrixStack[] matrixStacks = new MatrixStack[] { ms, msLocal }; - for (Pair actor : c.getActors()) { - MovementContext context = actor.getRight(); - if (context == null) - continue; - if (context.world == null) - context.world = world; - BlockInfo blockInfo = actor.getLeft(); - for (MatrixStack m : matrixStacks) { - m.push(); - MatrixStacker.of(m) - .translate(blockInfo.pos); - } - - MovementBehaviour movementBehaviour = AllMovementBehaviours.of(blockInfo.state); - if (movementBehaviour != null) - movementBehaviour.renderInContraption(context, ms, msLocal, buffer); - - for (MatrixStack m : matrixStacks) - m.pop(); - } - } - - public static int getLight(World world, float lx, float ly, float lz) { - BlockPos.Mutable pos = new BlockPos.Mutable(); - float sky = 0, block = 0; - float offset = 1 / 8f; - - for (float zOffset = offset; zOffset >= -offset; zOffset -= 2 * offset) - for (float yOffset = offset; yOffset >= -offset; yOffset -= 2 * offset) - for (float xOffset = offset; xOffset >= -offset; xOffset -= 2 * offset) { - pos.setPos(lx + xOffset, ly + yOffset, lz + zOffset); - sky += world.getLightLevel(LightType.SKY, pos) / 8f; - block += world.getLightLevel(LightType.BLOCK, pos) / 8f; - } - - return ((int) sky) << 20 | ((int) block) << 4; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ControlledContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ControlledContraptionEntity.java index 5ef894acb..9c78cf924 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ControlledContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ControlledContraptionEntity.java @@ -2,8 +2,10 @@ package com.simibubi.create.content.contraptions.components.structureMovement; import static com.simibubi.create.foundation.utility.AngleHelper.angleLerp; +import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllEntityTypes; import com.simibubi.create.content.contraptions.components.structureMovement.bearing.BearingContraption; +import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.VecHelper; @@ -219,4 +221,18 @@ public class ControlledContraptionEntity extends AbstractContraptionEntity { setPos(x, y, z); this.angle = angle; } + + @Override + @OnlyIn(Dist.CLIENT) + public void doLocalTransforms(float partialTicks, MatrixStack[] matrixStacks) { + float angle = getAngle(partialTicks); + Axis axis = getRotationAxis(); + + for (MatrixStack stack : matrixStacks) + MatrixStacker.of(stack) + .nudge(getEntityId()) + .centre() + .rotate(angle, axis) + .unCentre(); + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ControlledContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ControlledContraptionEntityRenderer.java deleted file mode 100644 index 6567b0419..000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ControlledContraptionEntityRenderer.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -import com.mojang.blaze3d.matrix.MatrixStack; -import com.simibubi.create.foundation.utility.MatrixStacker; - -import net.minecraft.client.renderer.entity.EntityRendererManager; -import net.minecraft.util.Direction.Axis; - -public class ControlledContraptionEntityRenderer extends AbstractContraptionEntityRenderer { - - public ControlledContraptionEntityRenderer(EntityRendererManager p_i46179_1_) { - super(p_i46179_1_); - } - - @Override - protected void transform(ControlledContraptionEntity entity, float partialTicks, - MatrixStack[] matrixStacks) { - float angle = entity.getAngle(partialTicks); - Axis axis = entity.getRotationAxis(); - - for (MatrixStack stack : matrixStacks) - MatrixStacker.of(stack) - .nudge(entity.getEntityId()) - .centre() - .rotate(angle, axis) - .unCentre(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementBehaviour.java index bf25055fe..72ede2acb 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementBehaviour.java @@ -2,6 +2,7 @@ package com.simibubi.create.content.contraptions.components.structureMovement; import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.content.contraptions.components.structureMovement.render.RenderedContraption; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.entity.item.ItemEntity; import net.minecraft.item.ItemStack; @@ -47,14 +48,21 @@ public abstract class MovementBehaviour { } - public boolean hasSpecialMovementRenderer() { - return true; + public boolean renderAsNormalTileEntity() { + return false; + } + + public boolean hasSpecialInstancedRendering() { + return false; } @OnlyIn(Dist.CLIENT) public void renderInContraption(MovementContext context, MatrixStack ms, MatrixStack msLocal, IRenderTypeBuffer buffer) {} + @OnlyIn(Dist.CLIENT) + public void addInstance(RenderedContraption contraption, MovementContext context) {} + public void onSpeedChanged(MovementContext context, Vec3d oldMotion, Vec3d motion) { } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/NonStationaryLighter.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/NonStationaryLighter.java new file mode 100644 index 000000000..f93fd9beb --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/NonStationaryLighter.java @@ -0,0 +1,39 @@ +package com.simibubi.create.content.contraptions.components.structureMovement; + +import com.simibubi.create.content.contraptions.components.structureMovement.render.RenderedContraption; +import com.simibubi.create.foundation.render.backend.light.GridAlignedBB; + +public class NonStationaryLighter extends ContraptionLighter { + public NonStationaryLighter(C contraption) { + super(contraption); + } + + @Override + protected GridAlignedBB contraptionBoundsToVolume(GridAlignedBB bounds) { + bounds.grow(2); // so we have at least enough data on the edges to avoid artifacts and have smooth lighting + bounds.minY = Math.max(bounds.minY, 0); + bounds.maxY = Math.min(bounds.maxY, 255); + + return bounds; + } + + @Override + public void tick(RenderedContraption owner) { + super.tick(owner); + GridAlignedBB contraptionBounds = getContraptionBounds(); + + if (!contraptionBounds.sameAs(bounds)) { + lightVolume.move(contraption.entity.world, contraptionBoundsToVolume(contraptionBounds)); + bounds = contraptionBounds; + } + } + + @Override + public GridAlignedBB getContraptionBounds() { + GridAlignedBB bb = GridAlignedBB.fromAABB(contraption.bounds); + + bb.translate(contraption.entity.getPosition()); + + return bb; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java index cf77d0a14..8b6df8b9b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java @@ -7,6 +7,7 @@ import java.util.UUID; import javax.annotation.Nullable; +import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllEntityTypes; import com.simibubi.create.content.contraptions.components.structureMovement.bearing.StabilizedContraption; import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity.CartMovementMode; @@ -14,10 +15,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.mou import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController; import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController; import com.simibubi.create.foundation.item.ItemHelper; -import com.simibubi.create.foundation.utility.AngleHelper; -import com.simibubi.create.foundation.utility.Couple; -import com.simibubi.create.foundation.utility.NBTHelper; -import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.foundation.utility.*; import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; @@ -40,6 +38,8 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.util.LazyOptional; /** @@ -494,4 +494,89 @@ public class OrientedContraptionEntity extends AbstractContraptionEntity { yaw = angle; } + @Override + @OnlyIn(Dist.CLIENT) + public void doLocalTransforms(float partialTicks, MatrixStack[] matrixStacks) { + float angleInitialYaw = getInitialYaw(); + float angleYaw = getYaw(partialTicks); + float anglePitch = getPitch(partialTicks); + + for (MatrixStack stack : matrixStacks) + stack.translate(-.5f, 0, -.5f); + + Entity ridingEntity = getRidingEntity(); + if (ridingEntity instanceof AbstractMinecartEntity) + repositionOnCart(partialTicks, matrixStacks, ridingEntity); + else if (ridingEntity instanceof AbstractContraptionEntity) { + if (ridingEntity.getRidingEntity() instanceof AbstractMinecartEntity) + repositionOnCart(partialTicks, matrixStacks, ridingEntity.getRidingEntity()); + else + repositionOnContraption(partialTicks, matrixStacks, ridingEntity); + } + + for (MatrixStack stack : matrixStacks) + MatrixStacker.of(stack) + .nudge(getEntityId()) + .centre() + .rotateY(angleYaw) + .rotateZ(anglePitch) + .rotateY(angleInitialYaw) + .unCentre(); + } + + @OnlyIn(Dist.CLIENT) + private void repositionOnContraption(float partialTicks, MatrixStack[] matrixStacks, Entity ridingEntity) { + Vec3d pos = getContraptionOffset(partialTicks, ridingEntity); + for (MatrixStack stack : matrixStacks) + stack.translate(pos.x, pos.y, pos.z); + } + + // Minecarts do not always render at their exact location, so the contraption + // has to adjust aswell + @OnlyIn(Dist.CLIENT) + private void repositionOnCart(float partialTicks, MatrixStack[] matrixStacks, Entity ridingEntity) { + Vec3d cartPos = getCartOffset(partialTicks, ridingEntity); + + if (cartPos == Vec3d.ZERO) return; + + for (MatrixStack stack : matrixStacks) + stack.translate(cartPos.x, cartPos.y, cartPos.z); + } + + @OnlyIn(Dist.CLIENT) + private Vec3d getContraptionOffset(float partialTicks, Entity ridingEntity) { + AbstractContraptionEntity parent = (AbstractContraptionEntity) ridingEntity; + Vec3d passengerPosition = parent.getPassengerPosition(this, partialTicks); + double x = passengerPosition.x - MathHelper.lerp(partialTicks, this.lastTickPosX, this.getX()); + double y = passengerPosition.y - MathHelper.lerp(partialTicks, this.lastTickPosY, this.getY()); + double z = passengerPosition.z - MathHelper.lerp(partialTicks, this.lastTickPosZ, this.getZ()); + + return new Vec3d(x, y, z); + } + + @OnlyIn(Dist.CLIENT) + private Vec3d getCartOffset(float partialTicks, Entity ridingEntity) { + AbstractMinecartEntity cart = (AbstractMinecartEntity) ridingEntity; + double cartX = MathHelper.lerp(partialTicks, cart.lastTickPosX, cart.getX()); + double cartY = MathHelper.lerp(partialTicks, cart.lastTickPosY, cart.getY()); + double cartZ = MathHelper.lerp(partialTicks, cart.lastTickPosZ, cart.getZ()); + Vec3d cartPos = cart.getPos(cartX, cartY, cartZ); + + if (cartPos != null) { + Vec3d cartPosFront = cart.getPosOffset(cartX, cartY, cartZ, (double) 0.3F); + Vec3d cartPosBack = cart.getPosOffset(cartX, cartY, cartZ, (double) -0.3F); + if (cartPosFront == null) + cartPosFront = cartPos; + if (cartPosBack == null) + cartPosBack = cartPos; + + cartX = cartPos.x - cartX; + cartY = (cartPosFront.y + cartPosBack.y) / 2.0D - cartY; + cartZ = cartPos.z - cartZ; + + return new Vec3d(cartX, cartY, cartZ); + } + + return Vec3d.ZERO; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntityRenderer.java index bbef43c57..f3f6fd7b2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntityRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntityRenderer.java @@ -1,16 +1,9 @@ package com.simibubi.create.content.contraptions.components.structureMovement; -import com.mojang.blaze3d.matrix.MatrixStack; -import com.simibubi.create.foundation.utility.MatrixStacker; - import net.minecraft.client.renderer.culling.ClippingHelperImpl; import net.minecraft.client.renderer.entity.EntityRendererManager; -import net.minecraft.entity.Entity; -import net.minecraft.entity.item.minecart.AbstractMinecartEntity; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; -public class OrientedContraptionEntityRenderer extends AbstractContraptionEntityRenderer { +public class OrientedContraptionEntityRenderer extends ContraptionEntityRenderer { public OrientedContraptionEntityRenderer(EntityRendererManager p_i46179_1_) { super(p_i46179_1_); @@ -18,79 +11,12 @@ public class OrientedContraptionEntityRenderer extends AbstractContraptionEntity @Override public boolean shouldRender(OrientedContraptionEntity entity, ClippingHelperImpl p_225626_2_, double p_225626_3_, - double p_225626_5_, double p_225626_7_) { + double p_225626_5_, double p_225626_7_) { if (!super.shouldRender(entity, p_225626_2_, p_225626_3_, p_225626_5_, p_225626_7_)) return false; if (entity.getContraption() - .getType() == ContraptionType.MOUNTED && entity.getRidingEntity() == null) + .getType() == ContraptionType.MOUNTED && entity.getRidingEntity() == null) return false; return true; } - - @Override - protected void transform(OrientedContraptionEntity entity, float partialTicks, MatrixStack[] matrixStacks) { - float angleInitialYaw = entity.getInitialYaw(); - float angleYaw = entity.getYaw(partialTicks); - float anglePitch = entity.getPitch(partialTicks); - - for (MatrixStack stack : matrixStacks) - stack.translate(-.5f, 0, -.5f); - - Entity ridingEntity = entity.getRidingEntity(); - if (ridingEntity instanceof AbstractMinecartEntity) - repositionOnCart(partialTicks, matrixStacks, ridingEntity); - if (ridingEntity instanceof AbstractContraptionEntity) { - if (ridingEntity.getRidingEntity() instanceof AbstractMinecartEntity) - repositionOnCart(partialTicks, matrixStacks, ridingEntity.getRidingEntity()); - else - repositionOnContraption(entity, partialTicks, matrixStacks, ridingEntity); - } - - for (MatrixStack stack : matrixStacks) - MatrixStacker.of(stack) - .nudge(entity.getEntityId()) - .centre() - .rotateY(angleYaw) - .rotateZ(anglePitch) - .rotateY(angleInitialYaw) - .unCentre(); - } - - private void repositionOnContraption(OrientedContraptionEntity entity, float partialTicks, - MatrixStack[] matrixStacks, Entity ridingEntity) { - AbstractContraptionEntity parent = (AbstractContraptionEntity) ridingEntity; - Vec3d passengerPosition = parent.getPassengerPosition(entity, partialTicks); - double x = passengerPosition.x - MathHelper.lerp(partialTicks, entity.lastTickPosX, entity.getX()); - double y = passengerPosition.y - MathHelper.lerp(partialTicks, entity.lastTickPosY, entity.getY()); - double z = passengerPosition.z - MathHelper.lerp(partialTicks, entity.lastTickPosZ, entity.getZ()); - for (MatrixStack stack : matrixStacks) - stack.translate(x, y, z); - } - - // Minecarts do not always render at their exact location, so the contraption - // has to adjust aswell - private void repositionOnCart(float partialTicks, MatrixStack[] matrixStacks, Entity ridingEntity) { - AbstractMinecartEntity cart = (AbstractMinecartEntity) ridingEntity; - double cartX = MathHelper.lerp(partialTicks, cart.lastTickPosX, cart.getX()); - double cartY = MathHelper.lerp(partialTicks, cart.lastTickPosY, cart.getY()); - double cartZ = MathHelper.lerp(partialTicks, cart.lastTickPosZ, cart.getZ()); - Vec3d cartPos = cart.getPos(cartX, cartY, cartZ); - - if (cartPos != null) { - Vec3d cartPosFront = cart.getPosOffset(cartX, cartY, cartZ, (double) 0.3F); - Vec3d cartPosBack = cart.getPosOffset(cartX, cartY, cartZ, (double) -0.3F); - if (cartPosFront == null) - cartPosFront = cartPos; - if (cartPosBack == null) - cartPosBack = cartPos; - - cartX = cartPos.x - cartX; - cartY = (cartPosFront.y + cartPosBack.y) / 2.0D - cartY; - cartZ = cartPos.z - cartZ; - - for (MatrixStack stack : matrixStacks) - stack.translate(cartX, cartY, cartZ); - } - } - } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java index 49656f15e..82fef4ed0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java @@ -1,5 +1,8 @@ package com.simibubi.create.content.contraptions.components.structureMovement.bearing; +import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import org.apache.commons.lang3.tuple.Pair; import com.simibubi.create.AllTags.AllBlockTags; @@ -90,4 +93,9 @@ public class BearingContraption extends Contraption { return facing.getAxis() == this.facing.getAxis(); } + @OnlyIn(Dist.CLIENT) + @Override + public ContraptionLighter makeLighter() { + return new BearingLighter(this); + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingLighter.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingLighter.java new file mode 100644 index 000000000..6584cb2d2 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingLighter.java @@ -0,0 +1,54 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.bearing; + +import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; +import com.simibubi.create.foundation.render.backend.light.GridAlignedBB; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; + +import java.util.Set; + +public class BearingLighter extends ContraptionLighter { + + public BearingLighter(BearingContraption contraption) { + super(contraption); + } + + @Override + public GridAlignedBB getContraptionBounds() { + Set blocks = contraption.getBlocks().keySet(); + + Direction orientation = contraption.facing; + + float maxDistanceSq = -1; + for (BlockPos pos : blocks) { + float x = pos.getX(); + float y = pos.getY(); + float z = pos.getZ(); + + float distSq = x * x + y * y + z * z; + + if (distSq > maxDistanceSq) maxDistanceSq = distSq; + } + + int radius = (int) (Math.ceil(Math.sqrt(maxDistanceSq))); + + GridAlignedBB betterBounds = GridAlignedBB.ofRadius(radius); + GridAlignedBB contraptionBounds = GridAlignedBB.fromAABB(contraption.bounds); + + Direction.Axis axis = orientation.getAxis(); + + if (axis == Direction.Axis.X) { + betterBounds.maxX = contraptionBounds.maxX; + betterBounds.minX = contraptionBounds.minX; + } else if (axis == Direction.Axis.Y) { + betterBounds.maxY = contraptionBounds.maxY; + betterBounds.minY = contraptionBounds.minY; + } else if (axis == Direction.Axis.Z) { + betterBounds.maxZ = contraptionBounds.maxZ; + betterBounds.minZ = contraptionBounds.minZ; + } + + betterBounds.translate(contraption.anchor); + return betterBounds; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingRenderer.java index e1f7978f5..b1c071ea3 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingRenderer.java @@ -5,7 +5,7 @@ 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.utility.AngleHelper; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java index 69b40f6fd..aa4693786 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java @@ -408,4 +408,8 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe return pos; } + @Override + public boolean shouldRenderAsTE() { + return true; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java index 65573cb35..b313cf931 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java @@ -298,4 +298,9 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp TooltipHelper.addHint(tooltip, "hint.empty_bearing"); return true; } + + @Override + public boolean shouldRenderAsTE() { + return true; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingMovementBehaviour.java index 3bec0cedf..6a8243f90 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingMovementBehaviour.java @@ -2,15 +2,11 @@ package com.simibubi.create.content.contraptions.components.structureMovement.be import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.*; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; +import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.utility.AngleHelper; -import com.simibubi.create.foundation.utility.SuperByteBuffer; - -import net.minecraft.client.Minecraft; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; import net.minecraft.state.properties.BlockStateProperties; @@ -28,8 +24,7 @@ public class StabilizedBearingMovementBehaviour extends MovementBehaviour { Direction facing = context.state.get(BlockStateProperties.FACING); AllBlockPartials top = AllBlockPartials.BEARING_TOP; SuperByteBuffer superBuffer = top.renderOn(context.state); - float renderPartialTicks = Minecraft.getInstance() - .getRenderPartialTicks(); + float renderPartialTicks = AnimationTickHolder.getPartialTicks(); // rotate to match blockstate Axis axis = facing.getAxis(); @@ -63,7 +58,7 @@ public class StabilizedBearingMovementBehaviour extends MovementBehaviour { // render superBuffer.light(msLocal.peek() - .getModel()); + .getModel(), ContraptionRenderDispatcher.getLightOnContraption(context)); superBuffer.renderInto(ms, buffer.getBuffer(RenderType.getSolid())); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedContraption.java index a8b726cd2..7ad42fd21 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedContraption.java @@ -3,7 +3,8 @@ package com.simibubi.create.content.contraptions.components.structureMovement.be import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; - +import com.simibubi.create.content.contraptions.components.structureMovement.NonStationaryLighter; +import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; @@ -26,12 +27,11 @@ public class StabilizedContraption extends Contraption { if (!searchMovedStructure(world, offset, null)) return false; startMoving(world); - expandBoundsAroundAxis(Axis.Y); if (blocks.isEmpty()) return false; return true; } - + @Override protected boolean isAnchoringBlockAt(BlockPos pos) { return false; @@ -64,4 +64,8 @@ public class StabilizedContraption extends Contraption { return facing; } + @Override + public ContraptionLighter makeLighter() { + return new NonStationaryLighter<>(this); + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraption.java index 8bc426b3e..0db060fb7 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraption.java @@ -1,9 +1,7 @@ package com.simibubi.create.content.contraptions.components.structureMovement.gantry; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; -import com.simibubi.create.content.contraptions.components.structureMovement.TranslatingContraption; +import com.simibubi.create.content.contraptions.components.structureMovement.*; import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; @@ -60,4 +58,8 @@ public class GantryContraption extends TranslatingContraption { return super.shouldUpdateAfterMovement(info) && !AllBlocks.GANTRY_PINION.has(info.state); } + @Override + public ContraptionLighter makeLighter() { + return new NonStationaryLighter<>(this); + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionEntity.java index ac2aacbc7..c16b3d03d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionEntity.java @@ -1,5 +1,6 @@ package com.simibubi.create.content.contraptions.components.structureMovement.gantry; +import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllEntityTypes; import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; @@ -172,6 +173,9 @@ public class GantryContraptionEntity extends AbstractContraptionEntity { return ContraptionRotationState.NONE; } + @Override + public void doLocalTransforms(float partialTicks, MatrixStack[] matrixStacks) { } + public void updateClientMotion() { float modifier = movementAxis.getAxisDirection() .getOffset(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionEntityRenderer.java deleted file mode 100644 index b7eafa361..000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionEntityRenderer.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.gantry; - -import com.mojang.blaze3d.matrix.MatrixStack; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntityRenderer; - -import net.minecraft.client.renderer.entity.EntityRendererManager; - -public class GantryContraptionEntityRenderer extends AbstractContraptionEntityRenderer { - - public GantryContraptionEntityRenderer(EntityRendererManager p_i46179_1_) { - super(p_i46179_1_); - } - - @Override - protected void transform(GantryContraptionEntity contraptionEntity, float partialTicks, - MatrixStack[] matrixStacks) {} - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionRenderer.java index 86a498d12..7772d70de 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionRenderer.java @@ -5,6 +5,7 @@ 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.utility.AngleHelper; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.MatrixStacker; @@ -59,7 +60,7 @@ public class GantryPinionRenderer extends KineticTileEntityRenderer { .rotateY(alongFirst ^ facing.getAxis() == Axis.Z ? 90 : 0); ms.translate(0, -9 / 16f, 0); - ms.multiply(Vector3f.POSITIVE_X.getRadialQuaternion(-angleForTe / 2f)); + ms.multiply(Vector3f.POSITIVE_X.getRadialQuaternion(-angleForTe)); ms.translate(0, 9 / 16f, 0); msr.unCentre(); @@ -70,6 +71,12 @@ public class GantryPinionRenderer extends KineticTileEntityRenderer { ms.pop(); } + public static float getAngleForTe(KineticTileEntity te, final BlockPos pos, Axis axis) { + float time = AnimationTickHolder.getRenderTick(); + float offset = getRotationOffsetForPosition(te, pos, axis); + return ((time * te.getSpeed() * 3f / 20 + offset) % 360) / 180 * (float) Math.PI; + } + @Override protected BlockState getRenderedBlockState(KineticTileEntity te) { return shaft(getRotationAxisOf(te)); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionTileEntity.java index 000a944ba..15c4d6a86 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionTileEntity.java @@ -164,4 +164,8 @@ public class GantryPinionTileEntity extends KineticTileEntity implements IDispla return te instanceof GantryShaftTileEntity && ((GantryShaftTileEntity) te).canAssembleOn(); } + @Override + public boolean shouldRenderAsTE() { + return true; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java index eba72ea54..46db36d90 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java @@ -1,9 +1,5 @@ package com.simibubi.create.content.contraptions.components.structureMovement.glue; -import javax.annotation.Nullable; - -import org.apache.commons.lang3.Validate; - import com.simibubi.create.AllEntityTypes; import com.simibubi.create.AllItems; import com.simibubi.create.AllSoundEvents; @@ -12,17 +8,13 @@ import com.simibubi.create.content.schematics.ISpecialEntityItemRequirement; import com.simibubi.create.content.schematics.ItemRequirement; import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType; import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.BlockFace; - import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.world.ClientWorld; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntitySize; -import net.minecraft.entity.EntityType; -import net.minecraft.entity.MoverType; -import net.minecraft.entity.Pose; +import net.minecraft.entity.*; import net.minecraft.entity.effect.LightningBoltEntity; import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.player.PlayerEntity; @@ -30,20 +22,9 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.network.IPacket; import net.minecraft.network.PacketBuffer; -import net.minecraft.util.ActionResultType; -import net.minecraft.util.DamageSource; -import net.minecraft.util.Direction; +import net.minecraft.util.*; import net.minecraft.util.Direction.Axis; -import net.minecraft.util.Hand; -import net.minecraft.util.Mirror; -import net.minecraft.util.Rotation; -import net.minecraft.util.SoundEvents; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.*; import net.minecraft.util.math.RayTraceResult.Type; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; @@ -52,6 +33,9 @@ import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import net.minecraftforge.fml.network.NetworkHooks; import net.minecraftforge.fml.network.PacketDistributor; +import org.apache.commons.lang3.Validate; + +import javax.annotation.Nullable; public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnData, ISpecialEntityItemRequirement { @@ -266,7 +250,7 @@ public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnDat ClientPlayerEntity cPlayer = (ClientPlayerEntity) player; Minecraft mc = Minecraft.getInstance(); RayTraceResult ray = - cPlayer.pick(mc.playerController.getBlockReachDistance(), mc.getRenderPartialTicks(), false); + cPlayer.pick(mc.playerController.getBlockReachDistance(), AnimationTickHolder.getPartialTicks(), false); if (!(ray instanceof BlockRayTraceResult)) return; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java index 07868c475..f929c847a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java @@ -10,7 +10,9 @@ import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.contraptions.components.structureMovement.NonStationaryLighter; import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity.CartMovementMode; +import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.VecHelper; @@ -33,6 +35,11 @@ import net.minecraft.world.gen.feature.template.Template.BlockInfo; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.wrapper.CombinedInvWrapper; import net.minecraftforge.items.wrapper.InvWrapper; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.List; + +import static com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerBlock.RAIL_SHAPE; public class MountedContraption extends Contraption { @@ -160,4 +167,9 @@ public class MountedContraption extends Contraption { IItemHandlerModifiable handlerFromInv = new InvWrapper((IInventory) cart); inventory = new CombinedInvWrapper(handlerFromInv, inventory); } + + @Override + public ContraptionLighter makeLighter() { + return new NonStationaryLighter<>(this); + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java index e0b12b263..2af438fd7 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java @@ -6,6 +6,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Con import com.simibubi.create.content.contraptions.components.structureMovement.TranslatingContraption; import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.*; import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.block.BlockState; import net.minecraft.block.CarpetBlock; @@ -20,6 +21,8 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.IWorld; import net.minecraft.world.World; import net.minecraft.world.gen.feature.template.Template.BlockInfo; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import org.apache.commons.lang3.tuple.Pair; import java.util.ArrayList; @@ -236,4 +239,9 @@ public class PistonContraption extends TranslatingContraption { return tag; } + @OnlyIn(Dist.CLIENT) + @Override + public ContraptionLighter makeLighter() { + return new PistonLighter(this); + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonLighter.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonLighter.java new file mode 100644 index 000000000..94d4e25d1 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonLighter.java @@ -0,0 +1,34 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.piston; + +import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; +import com.simibubi.create.foundation.render.backend.light.GridAlignedBB; +import net.minecraft.util.math.Vec3i; + +public class PistonLighter extends ContraptionLighter { + public PistonLighter(PistonContraption contraption) { + super(contraption); + } + + @Override + public GridAlignedBB getContraptionBounds() { + GridAlignedBB bounds = GridAlignedBB.fromAABB(contraption.bounds); + bounds.translate(contraption.anchor); + + int length = contraption.extensionLength; + Vec3i direction = contraption.orientation.getDirectionVec(); + + int shift = length / 2; + int shiftX = direction.getX() * shift; + int shiftY = direction.getY() * shift; + int shiftZ = direction.getZ() * shift; + bounds.translate(shiftX, shiftY, shiftZ); + + int grow = (length + 1) / 2; + int extendX = Math.abs(direction.getX() * grow); + int extendY = Math.abs(direction.getY() * grow); + int extendZ = Math.abs(direction.getZ() * grow); + bounds.grow(extendX, extendY, extendZ); + + return bounds; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/AbstractPulleyRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/AbstractPulleyRenderer.java index e93ecf899..3e1b87452 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/AbstractPulleyRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/AbstractPulleyRenderer.java @@ -7,7 +7,7 @@ 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.utility.AngleHelper; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyContraption.java index 5c444e4da..5f8487c6e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyContraption.java @@ -4,6 +4,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Ass import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; import com.simibubi.create.content.contraptions.components.structureMovement.TranslatingContraption; +import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -54,4 +55,8 @@ public class PulleyContraption extends TranslatingContraption { super.readNBT(world, nbt, spawnData); } + @Override + public ContraptionLighter makeLighter() { + return new PulleyLighter(this); + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyLighter.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyLighter.java new file mode 100644 index 000000000..1541eb941 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyLighter.java @@ -0,0 +1,31 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.pulley; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; +import com.simibubi.create.foundation.render.backend.light.GridAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class PulleyLighter extends ContraptionLighter { + public PulleyLighter(PulleyContraption contraption) { + super(contraption); + } + + @Override + public GridAlignedBB getContraptionBounds() { + + GridAlignedBB bounds = GridAlignedBB.fromAABB(contraption.bounds); + + World world = contraption.entity.world; + + BlockPos.Mutable pos = new BlockPos.Mutable(contraption.anchor); + while (!AllBlocks.ROPE_PULLEY.has(world.getBlockState(pos)) && pos.getY() < 256) { + pos.move(0, 1, 0); + } + + bounds.translate(pos); + bounds.minY = 1; // the super constructor will take care of making this 0 + + return bounds; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyRenderer.java index 0922e6ba1..182e063bb 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyRenderer.java @@ -5,7 +5,7 @@ import com.simibubi.create.AllBlocks; import com.simibubi.create.CreateClient; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.util.Direction.Axis; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java index b20ff7fdc..1f0eef324 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java @@ -32,8 +32,8 @@ public class PulleyTileEntity extends LinearActuatorTileEntity { } @Override - public AxisAlignedBB getRenderBoundingBox() { - return super.getRenderBoundingBox().expand(0, -offset, 0); + public AxisAlignedBB makeRenderBoundingBox() { + return super.makeRenderBoundingBox().expand(0, -offset, 0); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionKineticRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionKineticRenderer.java new file mode 100644 index 000000000..d670c354f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionKineticRenderer.java @@ -0,0 +1,26 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.render; + +import com.simibubi.create.foundation.render.AllProgramSpecs; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.content.contraptions.relays.belt.BeltInstancedModel; +import com.simibubi.create.content.contraptions.base.KineticRenderMaterials; +import com.simibubi.create.foundation.render.backend.instancing.RenderMaterial; +import com.simibubi.create.content.contraptions.base.RotatingInstancedModel; +import com.simibubi.create.content.contraptions.components.actors.RotatingActorModel; +import net.minecraft.util.math.BlockPos; + +public class ContraptionKineticRenderer extends InstancedTileRenderer { + + @Override + public void registerMaterials() { + materials.put(KineticRenderMaterials.BELTS, new RenderMaterial<>(this, AllProgramSpecs.CONTRAPTION_BELT, BeltInstancedModel::new)); + materials.put(KineticRenderMaterials.ROTATING, new RenderMaterial<>(this, AllProgramSpecs.CONTRAPTION_ROTATING, RotatingInstancedModel::new)); + materials.put(KineticRenderMaterials.ACTORS, new RenderMaterial<>(this, AllProgramSpecs.CONTRAPTION_ACTOR, RotatingActorModel::new)); + } + + @Override + public BlockPos getOriginCoordinate() { + return BlockPos.ZERO; + } +} + diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionModel.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionModel.java new file mode 100644 index 000000000..a332474a4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionModel.java @@ -0,0 +1,50 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.render; + +import com.simibubi.create.foundation.render.backend.BufferedModel; +import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.LightTexture; + +import java.nio.ByteBuffer; + +public class ContraptionModel extends BufferedModel { + public static final VertexFormat FORMAT = VertexFormat.builder() + .addAttributes(ContraptionVertexAttributes.class) + .build(); + + public ContraptionModel(BufferBuilder buf) { + super(buf); + } + + @Override + protected void copyVertex(ByteBuffer to, int vertex) { + to.putFloat(getX(template, vertex)); + to.putFloat(getY(template, vertex)); + to.putFloat(getZ(template, vertex)); + + to.put(getNX(template, vertex)); + to.put(getNY(template, vertex)); + to.put(getNZ(template, vertex)); + + to.putFloat(getU(template, vertex)); + to.putFloat(getV(template, vertex)); + + to.put(getR(template, vertex)); + to.put(getG(template, vertex)); + to.put(getB(template, vertex)); + to.put(getA(template, vertex)); + + int light = getLight(template, vertex); + + byte sky = (byte) (LightTexture.getSkyLightCoordinates(light) << 4); + byte block = (byte) (LightTexture.getBlockLightCoordinates(light) << 4); + + to.put(block); + to.put(sky); + } + + @Override + protected VertexFormat getModelFormat() { + return FORMAT; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionProgram.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionProgram.java new file mode 100644 index 000000000..ce2aede88 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionProgram.java @@ -0,0 +1,38 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.render; + +import com.simibubi.create.foundation.render.backend.gl.BasicProgram; +import com.simibubi.create.foundation.render.backend.light.GridAlignedBB; +import net.minecraft.client.renderer.Matrix4f; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.AxisAlignedBB; +import org.lwjgl.opengl.GL20; + +public class ContraptionProgram extends BasicProgram { + protected final int uLightBoxSize; + protected final int uLightBoxMin; + protected final int uModel; + + protected int uLightVolume; + + public ContraptionProgram(ResourceLocation name, int handle) { + super(name, handle); + uLightBoxSize = getUniformLocation("uLightBoxSize"); + uLightBoxMin = getUniformLocation("uLightBoxMin"); + uModel = getUniformLocation("uModel"); + } + + @Override + protected void registerSamplers() { + super.registerSamplers(); + uLightVolume = setSamplerBinding("uLightVolume", 4); + } + + public void bind(Matrix4f model, AxisAlignedBB lightVolume) { + double sizeX = lightVolume.maxX - lightVolume.minX; + double sizeY = lightVolume.maxY - lightVolume.minY; + double sizeZ = lightVolume.maxZ - lightVolume.minZ; + GL20.glUniform3f(uLightBoxSize, (float) sizeX, (float) sizeY, (float) sizeZ); + GL20.glUniform3f(uLightBoxMin, (float) lightVolume.minX, (float) lightVolume.minY, (float) lightVolume.minZ); + uploadMatrixUniform(uModel, model); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderDispatcher.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderDispatcher.java new file mode 100644 index 000000000..5c3d4f8af --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderDispatcher.java @@ -0,0 +1,298 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.render; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllMovementBehaviours; +import com.simibubi.create.CreateClient; +import com.simibubi.create.content.contraptions.components.structureMovement.*; +import com.simibubi.create.foundation.render.*; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; +import com.simibubi.create.foundation.render.backend.Backend; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.MatrixStacker; +import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.minecraft.block.BlockRenderType; +import net.minecraft.block.BlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererManager; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.SectionPos; +import net.minecraft.world.ILightReader; +import net.minecraft.world.LightType; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.template.Template; +import net.minecraftforge.client.ForgeHooksClient; +import net.minecraftforge.client.model.data.EmptyModelData; +import net.minecraftforge.event.TickEvent; +import org.apache.commons.lang3.tuple.Pair; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL40; + +import java.lang.ref.WeakReference; +import java.util.*; + +public class ContraptionRenderDispatcher { + public static final Int2ObjectMap renderers = new Int2ObjectOpenHashMap<>(); + public static final Compartment> CONTRAPTION = new Compartment<>(); + protected static PlacementSimulationWorld renderWorld; + + private static boolean firstLayer = true; + + public static void notifyLightUpdate(ILightReader world, LightType type, SectionPos pos) { + for (RenderedContraption renderer : renderers.values()) { + renderer.getLighter().lightVolume.notifyLightUpdate(world, type, pos); + } + } + + public static void renderTick() { + firstLayer = true; + } + + public static void renderTileEntities(World world, Contraption c, MatrixStack ms, MatrixStack msLocal, + IRenderTypeBuffer buffer) { + PlacementSimulationWorld renderWorld = null; + if (Backend.canUseVBOs()) { + RenderedContraption renderer = getRenderer(world, c); + + renderWorld = renderer.renderWorld; + } + TileEntityRenderHelper.renderTileEntities(world, renderWorld, c.specialRenderedTileEntities, ms, msLocal, buffer); + + } + + public static void tick() { + for (RenderedContraption contraption : renderers.values()) { + contraption.getLighter().tick(contraption); + } + } + + private static RenderedContraption getRenderer(World world, Contraption c) { + int entityId = c.entity.getEntityId(); + RenderedContraption contraption = renderers.get(entityId); + + if (contraption == null) { + contraption = new RenderedContraption(world, c); + renderers.put(entityId, contraption); + } + + return contraption; + } + + public static void renderLayer(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ) { + removeDeadContraptions(); + + if (renderers.isEmpty()) return; + + if (firstLayer) { + + for (RenderedContraption renderer : renderers.values()) { + renderer.beginFrame(camX, camY, camZ); + } + + firstLayer = false; + } + + layer.startDrawing(); + GL11.glEnable(GL13.GL_TEXTURE_3D); + GL13.glActiveTexture(GL40.GL_TEXTURE4); // the shaders expect light volumes to be in texture 4 + + if (Backend.canUseVBOs()) { + ContraptionProgram structureShader = Backend.getProgram(AllProgramSpecs.CONTRAPTION_STRUCTURE); + structureShader.bind(viewProjection, camX, camY, camZ, FastRenderDispatcher.getDebugMode()); + for (RenderedContraption renderer : renderers.values()) { + renderer.doRenderLayer(layer, structureShader); + } + } + + if (Backend.canUseInstancing()) { + for (RenderedContraption renderer : renderers.values()) { + renderer.kinetics.render(layer, viewProjection, camX, camY, camZ, renderer::setup); + renderer.teardown(); + } + } + + layer.endDrawing(); + GL11.glDisable(GL13.GL_TEXTURE_3D); + GL13.glActiveTexture(GL40.GL_TEXTURE0); + } + + public static void removeDeadContraptions() { + renderers.values().removeIf(renderer -> { + if (renderer.isDead()) { + renderer.invalidate(); + return true; + } + return false; + }); + } + + public static void invalidateAll() { + for (RenderedContraption renderer : renderers.values()) { + renderer.invalidate(); + } + + renderers.clear(); + } + + public static void render(AbstractContraptionEntity entity, MatrixStack ms, IRenderTypeBuffer buffers, + MatrixStack msLocal, Contraption contraption) { + if (Backend.canUseVBOs()) { + ContraptionRenderDispatcher.renderDynamic(entity.world, contraption, ms, msLocal, buffers); + } else { + ContraptionRenderDispatcher.renderDynamic(entity.world, contraption, ms, msLocal, buffers); + ContraptionRenderDispatcher.renderStructure(entity.world, contraption, ms, msLocal, buffers); + } + } + + public static void renderDynamic(World world, Contraption c, MatrixStack ms, MatrixStack msLocal, + IRenderTypeBuffer buffer) { + renderTileEntities(world, c, ms, msLocal, buffer); + if (buffer instanceof IRenderTypeBuffer.Impl) + ((IRenderTypeBuffer.Impl) buffer).draw(); + renderActors(world, c, ms, msLocal, buffer); + } + + public static void renderStructure(World world, Contraption c, MatrixStack ms, MatrixStack msLocal, + IRenderTypeBuffer buffer) { + SuperByteBufferCache bufferCache = CreateClient.bufferCache; + List blockLayers = RenderType.getBlockLayers(); + + buffer.getBuffer(RenderType.getSolid()); + for (int i = 0; i < blockLayers.size(); i++) { + RenderType layer = blockLayers.get(i); + Pair key = Pair.of(c, i); + SuperByteBuffer contraptionBuffer = bufferCache.get(CONTRAPTION, key, () -> buildStructureBuffer(c, layer)); + if (contraptionBuffer.isEmpty()) + continue; + Matrix4f model = msLocal.peek() + .getModel(); + contraptionBuffer.light(model) + .renderInto(ms, buffer.getBuffer(layer)); + } + } + + private static SuperByteBuffer buildStructureBuffer(Contraption c, RenderType layer) { + BufferBuilder builder = buildStructure(c, layer); + return new SuperByteBuffer(builder); + } + + public static BufferBuilder buildStructure(Contraption c, RenderType layer) { + if (renderWorld == null || renderWorld.getWorld() != Minecraft.getInstance().world) + renderWorld = new PlacementSimulationWorld(Minecraft.getInstance().world); + + ForgeHooksClient.setRenderLayer(layer); + MatrixStack ms = new MatrixStack(); + BlockRendererDispatcher dispatcher = Minecraft.getInstance() + .getBlockRendererDispatcher(); + BlockModelRenderer blockRenderer = dispatcher.getBlockModelRenderer(); + Random random = new Random(); + BufferBuilder builder = new BufferBuilder(DefaultVertexFormats.BLOCK.getIntegerSize()); + builder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK); + renderWorld.setTileEntities(c.presentTileEntities.values()); + + for (Template.BlockInfo info : c.getBlocks() + .values()) + renderWorld.setBlockState(info.pos, info.state); + + for (Template.BlockInfo info : c.getBlocks() + .values()) { + BlockState state = info.state; + + if (state.getRenderType() == BlockRenderType.ENTITYBLOCK_ANIMATED) + continue; + if (!RenderTypeLookup.canRenderInLayer(state, layer)) + continue; + + IBakedModel originalModel = dispatcher.getModelForState(state); + ms.push(); + ms.translate(info.pos.getX(), info.pos.getY(), info.pos.getZ()); + blockRenderer.renderModel(renderWorld, originalModel, state, info.pos, ms, builder, true, random, 42, + OverlayTexture.DEFAULT_UV, EmptyModelData.INSTANCE); + ms.pop(); + } + + builder.finishDrawing(); + renderWorld.clear(); + renderWorld = null; + return builder; + } + + protected static void renderActors(World world, Contraption c, MatrixStack ms, MatrixStack msLocal, + IRenderTypeBuffer buffer) { + MatrixStack[] matrixStacks = new MatrixStack[] { ms, msLocal }; + for (Pair actor : c.getActors()) { + MovementContext context = actor.getRight(); + if (context == null) + continue; + if (context.world == null) + context.world = world; + Template.BlockInfo blockInfo = actor.getLeft(); + for (MatrixStack m : matrixStacks) { + m.push(); + MatrixStacker.of(m) + .translate(blockInfo.pos); + } + + MovementBehaviour movementBehaviour = AllMovementBehaviours.of(blockInfo.state); + if (movementBehaviour != null) + movementBehaviour.renderInContraption(context, ms, msLocal, buffer); + + for (MatrixStack m : matrixStacks) + m.pop(); + } + } + + public static int getLight(World world, float lx, float ly, float lz) { + BlockPos.Mutable pos = new BlockPos.Mutable(); + float sky = 0, block = 0; + float offset = 1 / 8f; + + for (float zOffset = offset; zOffset >= -offset; zOffset -= 2 * offset) + for (float yOffset = offset; yOffset >= -offset; yOffset -= 2 * offset) + for (float xOffset = offset; xOffset >= -offset; xOffset -= 2 * offset) { + pos.setPos(lx + xOffset, ly + yOffset, lz + zOffset); + sky += world.getLightLevel(LightType.SKY, pos) / 8f; + block += world.getLightLevel(LightType.BLOCK, pos) / 8f; + } + + return ((int) sky) << 20 | ((int) block) << 4; + } + + public static int getLightOnContraption(World world, PlacementSimulationWorld renderWorld, BlockPos pos, BlockPos lightPos) { + int worldLight = WorldRenderer.getLightmapCoordinates(world, lightPos); + + if (renderWorld != null) + return getMaxBlockLight(worldLight, renderWorld.getLightLevel(LightType.BLOCK, pos)); + + return worldLight; + } + + public static int getMaxBlockLight(int packedLight, int blockLightValue) { + int unpackedBlockLight = LightTexture.getBlockLightCoordinates(packedLight); + + if (blockLightValue > unpackedBlockLight) { + packedLight = (packedLight & 0xFFFF0000) | (blockLightValue << 4); + } + + return packedLight; + } + + public static int getLightOnContraption(MovementContext context) { + int entityId = context.contraption.entity.getEntityId(); + + RenderedContraption renderedContraption = renderers.get(entityId); + if (renderedContraption != null) { + return renderedContraption.renderWorld.getLightLevel(LightType.BLOCK, context.localPos); + } else { + return -1; + } + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderer.java new file mode 100644 index 000000000..70b823e70 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderer.java @@ -0,0 +1,46 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.render; + +import java.util.List; +import java.util.Random; + +import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; +import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; +import com.simibubi.create.foundation.render.*; +import com.simibubi.create.foundation.render.backend.Backend; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; +import org.apache.commons.lang3.tuple.Pair; +import org.lwjgl.opengl.GL11; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllMovementBehaviours; +import com.simibubi.create.CreateClient; +import com.simibubi.create.foundation.utility.MatrixStacker; +import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld; + +import net.minecraft.block.BlockRenderType; +import net.minecraft.block.BlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BlockModelRenderer; +import net.minecraft.client.renderer.BlockRendererDispatcher; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.Matrix4f; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.RenderTypeLookup; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.LightType; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.template.Template.BlockInfo; +import net.minecraftforge.client.ForgeHooksClient; +import net.minecraftforge.client.model.data.EmptyModelData; + +public class ContraptionRenderer { + + + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionVertexAttributes.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionVertexAttributes.java new file mode 100644 index 000000000..6bfbf8af7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionVertexAttributes.java @@ -0,0 +1,42 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.render; + +import com.simibubi.create.foundation.render.backend.gl.attrib.CommonAttributes; +import com.simibubi.create.foundation.render.backend.gl.attrib.IVertexAttrib; +import com.simibubi.create.foundation.render.backend.gl.attrib.VertexAttribSpec; + +public enum ContraptionVertexAttributes implements IVertexAttrib { + VERTEX_POSITION("aPos", CommonAttributes.VEC3), + NORMAL("aNormal", CommonAttributes.NORMAL), + TEXTURE("aTexCoords", CommonAttributes.UV), + COLOR("aColor", CommonAttributes.RGBA), + MODEL_LIGHT("aModelLight", CommonAttributes.LIGHT), + ; + + private final String name; + private final VertexAttribSpec spec; + + ContraptionVertexAttributes(String name, VertexAttribSpec spec) { + this.name = name; + this.spec = spec; + } + + @Override + public String attribName() { + return name; + } + + @Override + public VertexAttribSpec attribSpec() { + return spec; + } + + @Override + public int getDivisor() { + return 0; + } + + @Override + public int getBufferIndex() { + return 0; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/RenderedContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/RenderedContraption.java new file mode 100644 index 000000000..32fed725d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/RenderedContraption.java @@ -0,0 +1,230 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.render; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllMovementBehaviours; +import com.simibubi.create.content.contraptions.base.KineticRenderMaterials; +import com.simibubi.create.content.contraptions.components.structureMovement.*; +import com.simibubi.create.foundation.render.backend.Backend; +import com.simibubi.create.foundation.render.backend.instancing.*; +import com.simibubi.create.content.contraptions.components.actors.ContraptionActorData; +import com.simibubi.create.foundation.render.backend.light.GridAlignedBB; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld; +import net.minecraft.block.BlockRenderType; +import net.minecraft.block.BlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererManager; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.template.Template; +import net.minecraft.world.lighting.WorldLightManager; +import net.minecraftforge.client.ForgeHooksClient; +import net.minecraftforge.client.model.data.EmptyModelData; +import org.apache.commons.lang3.tuple.MutablePair; +import org.lwjgl.opengl.GL11; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Random; + +public class RenderedContraption { + private final HashMap renderLayers = new HashMap<>(); + + public final PlacementSimulationWorld renderWorld; + + private final ContraptionLighter lighter; + + public final ContraptionKineticRenderer kinetics; + + public Contraption contraption; + + private Matrix4f model; + private AxisAlignedBB lightBox; + + public RenderedContraption(World world, Contraption contraption) { + this.contraption = contraption; + this.lighter = contraption.makeLighter(); + this.kinetics = new ContraptionKineticRenderer(); + this.renderWorld = setupRenderWorld(world, contraption); + + buildLayers(); + if (Backend.canUseInstancing()) { + buildInstancedTiles(); + buildActors(); + } + } + + public int getEntityId() { + return contraption.entity.getEntityId(); + } + + public boolean isDead() { + return !contraption.entity.isAlive(); + } + + public ContraptionLighter getLighter() { + return lighter; + } + + public RenderMaterial> getActorMaterial() { + return kinetics.getMaterial(KineticRenderMaterials.ACTORS); + } + + public void doRenderLayer(RenderType layer, ContraptionProgram shader) { + ContraptionModel structure = renderLayers.get(layer); + if (structure != null) { + setup(shader); + structure.render(); + teardown(); + } + } + + public void beginFrame(double camX, double camY, double camZ) { + AbstractContraptionEntity entity = contraption.entity; + float pt = AnimationTickHolder.getPartialTicks(); + + MatrixStack stack = new MatrixStack(); + + double x = MathHelper.lerp(pt, entity.lastTickPosX, entity.getX()) - camX; + double y = MathHelper.lerp(pt, entity.lastTickPosY, entity.getY()) - camY; + double z = MathHelper.lerp(pt, entity.lastTickPosZ, entity.getZ()) - camZ; + stack.translate(x, y, z); + + entity.doLocalTransforms(pt, new MatrixStack[]{ stack }); + + model = stack.peek().getModel(); + + AxisAlignedBB lightBox = GridAlignedBB.toAABB(lighter.lightVolume.getTextureVolume()); + + this.lightBox = lightBox.offset(-camX, -camY, -camZ); + } + + void setup(ContraptionProgram shader) { + if (model == null || lightBox == null) return; + shader.bind(model, lightBox); + lighter.lightVolume.bind(); + } + + void teardown() { + lighter.lightVolume.unbind(); + } + + void invalidate() { + for (ContraptionModel buffer : renderLayers.values()) { + buffer.delete(); + } + renderLayers.clear(); + + lighter.lightVolume.delete(); + + kinetics.invalidate(); + } + + private void buildLayers() { + for (ContraptionModel buffer : renderLayers.values()) { + buffer.delete(); + } + + renderLayers.clear(); + + List blockLayers = RenderType.getBlockLayers(); + + for (RenderType layer : blockLayers) { + renderLayers.put(layer, buildStructureModel(renderWorld, contraption, layer)); + } + } + + private void buildInstancedTiles() { + Collection tileEntities = contraption.maybeInstancedTileEntities; + if (!tileEntities.isEmpty()) { + for (TileEntity te : tileEntities) { + if (te instanceof IInstanceRendered) { + World world = te.getWorld(); + BlockPos pos = te.getPos(); + te.setLocation(renderWorld, pos); + kinetics.add(te); + te.setLocation(world, pos); + } + } + } + } + + private void buildActors() { + List> actors = contraption.getActors(); + + for (MutablePair actor : actors) { + Template.BlockInfo blockInfo = actor.left; + MovementContext context = actor.right; + + MovementBehaviour movementBehaviour = AllMovementBehaviours.of(blockInfo.state); + + if (movementBehaviour != null) { + movementBehaviour.addInstance(this, context); + } + } + } + + private static ContraptionModel buildStructureModel(PlacementSimulationWorld renderWorld, Contraption c, RenderType layer) { + BufferBuilder builder = buildStructure(renderWorld, c, layer); + return new ContraptionModel(builder); + } + + private static PlacementSimulationWorld setupRenderWorld(World world, Contraption c) { + PlacementSimulationWorld renderWorld = new PlacementSimulationWorld(world); + + renderWorld.setTileEntities(c.presentTileEntities.values()); + + for (Template.BlockInfo info : c.getBlocks() + .values()) + renderWorld.setBlockState(info.pos, info.state); + + WorldLightManager lighter = renderWorld.lighter; + + renderWorld.chunkProvider.getLightSources().forEach((pos) -> lighter.func_215573_a(pos, renderWorld.getLightValue(pos))); + + lighter.tick(Integer.MAX_VALUE, true, false); + + return renderWorld; + } + + private static BufferBuilder buildStructure(PlacementSimulationWorld renderWorld, Contraption c, RenderType layer) { + + ForgeHooksClient.setRenderLayer(layer); + MatrixStack ms = new MatrixStack(); + BlockRendererDispatcher dispatcher = Minecraft.getInstance() + .getBlockRendererDispatcher(); + BlockModelRenderer blockRenderer = dispatcher.getBlockModelRenderer(); + Random random = new Random(); + BufferBuilder builder = new BufferBuilder(DefaultVertexFormats.BLOCK.getIntegerSize()); + builder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK); + + for (Template.BlockInfo info : c.getBlocks() + .values()) { + BlockState state = info.state; + + if (state.getRenderType() == BlockRenderType.ENTITYBLOCK_ANIMATED) + continue; + if (!RenderTypeLookup.canRenderInLayer(state, layer)) + continue; + + IBakedModel originalModel = dispatcher.getModelForState(state); + ms.push(); + ms.translate(info.pos.getX(), info.pos.getY(), info.pos.getZ()); + blockRenderer.renderModel(renderWorld, originalModel, state, info.pos, ms, builder, true, random, 42, + OverlayTexture.DEFAULT_UV, EmptyModelData.INSTANCE); + ms.pop(); + } + + builder.finishDrawing(); + return builder; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingRenderer.java index 35041160d..34a52daa3 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingRenderer.java @@ -1,19 +1,13 @@ package com.simibubi.create.content.contraptions.components.structureMovement.train; -import static net.minecraft.util.math.MathHelper.lerp; - import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.vertex.IVertexBuilder; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.CreateClient; import com.simibubi.create.content.contraptions.KineticDebugger; import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController; -import com.simibubi.create.foundation.utility.ColorHelper; -import com.simibubi.create.foundation.utility.Couple; -import com.simibubi.create.foundation.utility.MatrixStacker; -import com.simibubi.create.foundation.utility.SuperByteBuffer; -import com.simibubi.create.foundation.utility.VecHelper; - +import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.utility.*; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.client.Minecraft; @@ -28,6 +22,8 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; +import static net.minecraft.util.math.MathHelper.lerp; + public class CouplingRenderer { public static void renderAll(MatrixStack ms, IRenderTypeBuffer buffer) { @@ -115,8 +111,7 @@ public class CouplingRenderer { float y = (((float) (i >> 20 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F + 0.375F; float z = (((float) (i >> 24 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F; - float pt = Minecraft.getInstance() - .getRenderPartialTicks(); + float pt = AnimationTickHolder.getPartialTicks(); double xIn = lerp(pt, cart.lastTickPosX, cart.getX()); double yIn = lerp(pt, cart.lastTickPosY, cart.getY()); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/turntable/TurntableHandler.java b/src/main/java/com/simibubi/create/content/contraptions/components/turntable/TurntableHandler.java index a3ba8aaf9..d335edaf3 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/turntable/TurntableHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/turntable/TurntableHandler.java @@ -1,8 +1,8 @@ package com.simibubi.create.content.contraptions.components.turntable; import com.simibubi.create.AllBlocks; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.client.Minecraft; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; @@ -38,7 +38,7 @@ public class TurntableHandler { if (offset.length() > 1/4f) speed *= MathHelper.clamp((1/2f - offset.length()) * 2, 0, 1); - mc.player.rotationYaw = mc.player.prevRotationYaw - speed * mc.getRenderPartialTicks(); + mc.player.rotationYaw = mc.player.prevRotationYaw - speed * AnimationTickHolder.getPartialTicks(); mc.player.renderYawOffset = mc.player.rotationYaw; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelTileEntity.java index 882f2a15e..6b0fc0df9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelTileEntity.java @@ -36,7 +36,7 @@ public class WaterWheelTileEntity extends GeneratingKineticTileEntity { } @Override - public AxisAlignedBB getRenderBoundingBox() { + public AxisAlignedBB makeRenderBoundingBox() { return new AxisAlignedBB(pos).grow(1); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpCogInstance.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpCogInstance.java new file mode 100644 index 000000000..a8e7f6c61 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpCogInstance.java @@ -0,0 +1,28 @@ +package com.simibubi.create.content.contraptions.fluids; + +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; +import com.simibubi.create.content.contraptions.base.RotatingData; +import net.minecraft.tileentity.TileEntityType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +public class PumpCogInstance extends SingleRotatingInstance { + public static void register(TileEntityType type) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> + InstancedTileRenderRegistry.instance.register(type, PumpCogInstance::new)); + } + + public PumpCogInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected InstancedModel getModel() { + return AllBlockPartials.MECHANICAL_PUMP_COG.renderOnDirectionalSouthRotating(modelManager, tile.getBlockState()); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpRenderer.java index ff887c908..b14b30539 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpRenderer.java @@ -6,7 +6,7 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.MatrixStacker; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpTileEntity.java index 901059d71..ff0bad252 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpTileEntity.java @@ -1,28 +1,10 @@ package com.simibubi.create.content.contraptions.fluids; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Nullable; - -import org.apache.commons.lang3.mutable.MutableBoolean; - import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.utility.BlockFace; -import com.simibubi.create.foundation.utility.Couple; -import com.simibubi.create.foundation.utility.Iterate; -import com.simibubi.create.foundation.utility.LerpedFloat; +import com.simibubi.create.foundation.utility.*; import com.simibubi.create.foundation.utility.LerpedFloat.Chaser; -import com.simibubi.create.foundation.utility.Pair; - import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; @@ -34,6 +16,11 @@ import net.minecraft.world.IWorld; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler; +import org.apache.commons.lang3.mutable.MutableBoolean; + +import javax.annotation.Nullable; +import java.util.*; +import java.util.Map.Entry; public class PumpTileEntity extends KineticTileEntity { @@ -374,4 +361,8 @@ public class PumpTileEntity extends KineticTileEntity { } + @Override + public boolean shouldRenderAsTE() { + return true; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyRenderer.java index af76354d6..c0d4091c6 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyRenderer.java @@ -3,7 +3,7 @@ package com.simibubi.create.content.contraptions.fluids.actors; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.pulley.AbstractPulleyRenderer; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.util.Direction.Axis; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyTileEntity.java index 436b111f9..698f36e3f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyTileEntity.java @@ -1,14 +1,11 @@ package com.simibubi.create.content.contraptions.fluids.actors; -import java.util.List; - import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.foundation.fluid.SmartFluidTank; import com.simibubi.create.foundation.item.TooltipHelper; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.utility.LerpedFloat; import com.simibubi.create.foundation.utility.ServerSpeedProvider; - import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; @@ -20,6 +17,8 @@ import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.IFluidHandler; +import java.util.List; + public class HosePulleyTileEntity extends KineticTileEntity { LerpedFloat offset; @@ -191,4 +190,8 @@ public class HosePulleyTileEntity extends KineticTileEntity { return super.getCapability(cap, side); } + @Override + public boolean shouldRenderAsTE() { + return true; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutTileEntity.java index f7f4e3d73..33c31cc95 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutTileEntity.java @@ -27,6 +27,8 @@ import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.Vec3d; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.fluids.FluidStack; @@ -47,9 +49,14 @@ public class SpoutTileEntity extends SmartTileEntity { processingTicks = -1; } + protected AxisAlignedBB cachedBoundingBox; @Override + @OnlyIn(Dist.CLIENT) public AxisAlignedBB getRenderBoundingBox() { - return super.getRenderBoundingBox().expand(0, -2, 0); + if (cachedBoundingBox == null) { + cachedBoundingBox = super.getRenderBoundingBox().expand(0, -2, 0); + } + return cachedBoundingBox; } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveRenderer.java index c50f78bb4..bf16148fd 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveRenderer.java @@ -6,7 +6,7 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.MatrixStacker; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankTileEntity.java index aa487a29b..bfa94720a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankTileEntity.java @@ -104,7 +104,10 @@ public class FluidTankTileEntity extends SmartTileEntity { } public boolean isController() { - return controller == null || controller.equals(pos); + return controller == null || + pos.getX() == controller.getX() && + pos.getY() == controller.getY() && + pos.getZ() == controller.getZ(); } @Override @@ -281,12 +284,17 @@ public class FluidTankTileEntity extends SmartTileEntity { return isController() ? pos : controller; } + private AxisAlignedBB cachedBoundingBox; @Override @OnlyIn(Dist.CLIENT) public AxisAlignedBB getRenderBoundingBox() { - if (isController()) - return super.getRenderBoundingBox().expand(width - 1, height - 1, width - 1); - return super.getRenderBoundingBox(); + if (cachedBoundingBox == null) { + if (isController()) + cachedBoundingBox = super.getRenderBoundingBox().expand(width - 1, height - 1, width - 1); + else + cachedBoundingBox = super.getRenderBoundingBox(); + } + return cachedBoundingBox; } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/particle/RotationIndicatorParticle.java b/src/main/java/com/simibubi/create/content/contraptions/particle/RotationIndicatorParticle.java index 5ca7b26e6..f161e74bc 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/particle/RotationIndicatorParticle.java +++ b/src/main/java/com/simibubi/create/content/contraptions/particle/RotationIndicatorParticle.java @@ -5,7 +5,6 @@ import com.simibubi.create.content.contraptions.goggles.GogglesItem; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.ColorHelper; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.particle.IAnimatedSprite; @@ -67,7 +66,7 @@ public class RotationIndicatorParticle extends SimpleAnimatedParticle { } public void move(double x, double y, double z) { - float time = AnimationTickHolder.ticks; + float time = AnimationTickHolder.getTicks(); float angle = (float) ((time * speed) % 360) - (speed / 2 * age * (((float) age) / maxAge)); Vec3d position = VecHelper.rotate(this.offset.scale(radius), angle, axis).add(origin); posX = position.x; diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinMovementBehaviour.java index a3de35c6c..1f77c0caa 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinMovementBehaviour.java @@ -23,8 +23,8 @@ public class BasinMovementBehaviour extends MovementBehaviour { } @Override - public boolean hasSpecialMovementRenderer() { - return false; + public boolean renderAsNormalTileEntity() { + return true; } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinOperatingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinOperatingTileEntity.java index 20383e4f4..7c711358f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinOperatingTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinOperatingTileEntity.java @@ -1,21 +1,20 @@ package com.simibubi.create.content.contraptions.processing; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.advancement.ITriggerable; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.simple.DeferralBehaviour; import com.simibubi.create.foundation.utility.recipe.RecipeFinder; - import net.minecraft.inventory.IInventory; import net.minecraft.item.crafting.IRecipe; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + public abstract class BasinOperatingTileEntity extends KineticTileEntity { public DeferralBehaviour basinChecker; @@ -144,4 +143,8 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity { protected abstract Object getRecipeCacheKey(); + @Override + public boolean shouldRenderAsTE() { + return true; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java index c41a4f751..1eb9dd801 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java @@ -1,14 +1,5 @@ package com.simibubi.create.content.contraptions.processing; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; -import java.util.Random; - -import javax.annotation.Nonnull; - import com.simibubi.create.AllParticleTypes; import com.simibubi.create.AllTags; import com.simibubi.create.content.contraptions.components.mixer.MechanicalMixerTileEntity; @@ -25,15 +16,8 @@ import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputB import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment; -import com.simibubi.create.foundation.utility.AnimationTickHolder; -import com.simibubi.create.foundation.utility.Couple; -import com.simibubi.create.foundation.utility.IntAttached; -import com.simibubi.create.foundation.utility.Iterate; -import com.simibubi.create.foundation.utility.LerpedFloat; +import com.simibubi.create.foundation.utility.*; import com.simibubi.create.foundation.utility.LerpedFloat.Chaser; -import com.simibubi.create.foundation.utility.NBTHelper; -import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.item.ItemStack; @@ -63,6 +47,9 @@ import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.wrapper.CombinedInvWrapper; +import javax.annotation.Nonnull; +import java.util.*; + public class BasinTileEntity extends SmartTileEntity { private boolean areFluidsMoving; @@ -571,7 +558,7 @@ public class BasinTileEntity extends SmartTileEntity { Vec3d pointer = new Vec3d(1, 0, 0).scale(1 / 16f); float interval = 360f / segments; Vec3d centerOf = VecHelper.getCenterOf(pos); - float intervalOffset = (AnimationTickHolder.ticks * 18) % 360; + float intervalOffset = (AnimationTickHolder.getTicks() * 18) % 360; int currentSegment = 0; for (SmartFluidTankBehaviour behaviour : getTanks()) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerRenderer.java index e9e68a582..e4110a16b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerRenderer.java @@ -6,7 +6,7 @@ import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlo import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AnimationTickHolder; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerRenderer.java index bf43e7db4..dd20003ff 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerRenderer.java @@ -5,8 +5,9 @@ import com.mojang.blaze3d.vertex.IVertexBuilder; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.CreateClient; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -30,7 +31,9 @@ public class SpeedControllerRenderer extends SmartTileEntityRenderer { + public static VertexFormat FORMAT = VertexFormat.builder() + .addAttributes(KineticVertexAttributes.class) + .addAttributes(BeltVertexAttributes.class) + .build(); + + private float rotX; + private float rotY; + private float rotZ; + private float sourceU; + private float sourceV; + private float minU; + private float minV; + private float maxU; + private float maxV; + private byte scrollMult; + + protected BeltData(InstancedModel owner) { + super(owner); + } + + public BeltData setRotation(float rotX, float rotY, float rotZ) { + this.rotX = rotX; + this.rotY = rotY; + this.rotZ = rotZ; + return this; + } + + public BeltData setScrollTexture(SpriteShiftEntry spriteShift) { + TextureAtlasSprite source = spriteShift.getOriginal(); + TextureAtlasSprite target = spriteShift.getTarget(); + + this.sourceU = source.getMinU(); + this.sourceV = source.getMinV(); + this.minU = target.getMinU(); + this.minV = target.getMinV(); + this.maxU = target.getMaxU(); + this.maxV = target.getMaxV(); + + return this; + } + + public BeltData setScrollMult(float scrollMult) { + this.scrollMult = (byte) (scrollMult * 127); + return this; + } + + @Override + public void write(ByteBuffer buf) { + super.write(buf); + + putVec3(buf, rotX, rotY, rotZ); + + putVec2(buf, sourceU, sourceV); + putVec4(buf, minU, minV, maxU, maxV); + + put(buf, scrollMult); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltHelper.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltHelper.java index 63360a12a..0268ea996 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltHelper.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltHelper.java @@ -40,6 +40,10 @@ public class BeltHelper { return getSegmentTE(world, controllerPos); } + public static BeltTileEntity getBeltForOffset(BeltTileEntity controller, float offset) { + return getBeltAtSegment(controller, (int) Math.floor(offset)); + } + public static BeltTileEntity getBeltAtSegment(BeltTileEntity controller, int segment) { BlockPos pos = getPositionForOffset(controller, segment); TileEntity te = controller.getWorld() diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltInstance.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltInstance.java new file mode 100644 index 000000000..13c7d9f32 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltInstance.java @@ -0,0 +1,183 @@ +package com.simibubi.create.content.contraptions.relays.belt; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.base.KineticTileInstance; +import com.simibubi.create.content.contraptions.base.RotatingData; +import com.simibubi.create.foundation.block.render.SpriteShiftEntry; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.*; +import com.simibubi.create.foundation.utility.Iterate; +import com.simibubi.create.foundation.utility.MatrixStacker; +import net.minecraft.item.DyeColor; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.LightType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +import java.util.ArrayList; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class BeltInstance extends KineticTileInstance { + public static void register(TileEntityType type) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> + InstancedTileRenderRegistry.instance.register(type, BeltInstance::new)); + } + + private boolean upward; + private boolean diagonal; + private boolean sideways; + private boolean vertical; + private boolean alongX; + private boolean alongZ; + private BeltSlope beltSlope; + private Direction facing; + protected ArrayList> keys; + protected InstanceKey pulleyKey; + + public BeltInstance(InstancedTileRenderer modelManager, BeltTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected void init() { + if (!AllBlocks.BELT.has(lastState)) + return; + + keys = new ArrayList<>(2); + + beltSlope = lastState.get(BeltBlock.SLOPE); + facing = lastState.get(BeltBlock.HORIZONTAL_FACING); + upward = beltSlope == BeltSlope.UPWARD; + diagonal = beltSlope.isDiagonal(); + sideways = beltSlope == BeltSlope.SIDEWAYS; + vertical = beltSlope == BeltSlope.VERTICAL; + alongX = facing.getAxis() == Direction.Axis.X; + alongZ = facing.getAxis() == Direction.Axis.Z; + + BeltPart part = lastState.get(BeltBlock.PART); + boolean start = part == BeltPart.START; + boolean end = part == BeltPart.END; + DyeColor color = tile.color.orElse(null); + + for (boolean bottom : Iterate.trueAndFalse) { + AllBlockPartials beltPartial = BeltRenderer.getBeltPartial(diagonal, start, end, bottom); + SpriteShiftEntry spriteShift = BeltRenderer.getSpriteShiftEntry(color, diagonal, bottom); + + InstancedModel beltModel = beltPartial.renderOnBelt(modelManager, lastState); + Consumer setupFunc = setupFunc(bottom, spriteShift); + + keys.add(beltModel.setupInstance(setupFunc)); + + if (diagonal) break; + } + + if (tile.hasPulley()) { + InstancedModel pulleyModel = getPulleyModel(); + + pulleyKey = pulleyModel.setupInstance(setupFunc(tile.getSpeed(), getRotationAxis())); + } + } + + @Override + public void onUpdate() { + DyeColor color = tile.color.orElse(null); + + boolean bottom = true; + for (InstanceKey key : keys) { + + SpriteShiftEntry spriteShiftEntry = BeltRenderer.getSpriteShiftEntry(color, diagonal, bottom); + key.modifyInstance(data -> data.setScrollTexture(spriteShiftEntry) + .setColor(tile.network) + .setRotationalSpeed(getScrollSpeed())); + bottom = false; + } + + if (pulleyKey != null) { + updateRotation(pulleyKey, getRotationAxis()); + } + } + + @Override + public void updateLight() { + for (InstanceKey key : keys) { + key.modifyInstance(this::relight); + } + + if (pulleyKey != null) pulleyKey.modifyInstance(this::relight); + } + + @Override + public void remove() { + keys.forEach(InstanceKey::delete); + keys.clear(); + if (pulleyKey != null) pulleyKey.delete(); + pulleyKey = null; + } + + private float getScrollSpeed() { + float speed = tile.getSpeed(); + if (((facing.getAxisDirection() == Direction.AxisDirection.NEGATIVE) ^ upward) ^ + ((alongX && !diagonal) || (alongZ && diagonal)) ^ (vertical && facing.getAxisDirection() == Direction.AxisDirection.NEGATIVE)) { + speed = -speed; + } + if (sideways && (facing == Direction.SOUTH || facing == Direction.WEST)) + speed = -speed; + + return speed; + } + + private InstancedModel getPulleyModel() { + Direction dir = getOrientation(); + + Direction.Axis axis = dir.getAxis(); + + Supplier ms = () -> { + MatrixStack modelTransform = new MatrixStack(); + MatrixStacker msr = MatrixStacker.of(modelTransform); + msr.centre(); + if (axis == Direction.Axis.X) + msr.rotateY(90); + if (axis == Direction.Axis.Y) + msr.rotateX(90); + msr.rotateX(90); + msr.unCentre(); + + return modelTransform; + }; + + return rotatingMaterial().getModel(AllBlockPartials.BELT_PULLEY, lastState, dir, ms); + } + + private Direction getOrientation() { + Direction dir = lastState.get(BeltBlock.HORIZONTAL_FACING) + .rotateY(); + if (beltSlope == BeltSlope.SIDEWAYS) + dir = Direction.UP; + + return dir; + } + + private Consumer setupFunc(boolean bottom, SpriteShiftEntry spriteShift) { + return data -> { + float rotX = (!diagonal && beltSlope != BeltSlope.HORIZONTAL ? 90 : 0) + (beltSlope == BeltSlope.DOWNWARD ? 180 : 0); + float rotY = facing.getHorizontalAngle() + (upward ? 180 : 0) + (sideways ? 90 : 0); + float rotZ = sideways ? 90 : ((vertical && facing.getAxisDirection() == Direction.AxisDirection.NEGATIVE) ? 180 : 0); + + BlockPos pos = tile.getPos(); + data.setTileEntity(tile) + .setBlockLight(world.getLightLevel(LightType.BLOCK, pos)) + .setSkyLight(world.getLightLevel(LightType.SKY, pos)) + .setRotation(rotX, rotY, rotZ) + .setRotationalSpeed(getScrollSpeed()) + .setRotationOffset(bottom ? 0.5f : 0f) + .setScrollTexture(spriteShift) + .setScrollMult(diagonal ? 3f / 8f : 0.5f); + }; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltInstancedModel.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltInstancedModel.java new file mode 100644 index 000000000..cb8c64082 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltInstancedModel.java @@ -0,0 +1,23 @@ +package com.simibubi.create.content.contraptions.relays.belt; + +import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import net.minecraft.client.renderer.BufferBuilder; + +public class BeltInstancedModel extends InstancedModel { + public BeltInstancedModel(InstancedTileRenderer renderer, BufferBuilder buf) { + super(renderer, buf); + } + + @Override + protected BeltData newInstance() { + return new BeltData(this); + } + + @Override + protected VertexFormat getInstanceFormat() { + return BeltData.FORMAT; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltModel.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltModel.java index c4d6a592d..976a39d7d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltModel.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltModel.java @@ -10,7 +10,7 @@ import java.util.Random; import com.simibubi.create.AllSpriteShifts; import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity.CasingType; import com.simibubi.create.foundation.block.render.SpriteShiftEntry; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.model.BakedQuad; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java index e5de1192e..6717aa316 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java @@ -1,5 +1,6 @@ package com.simibubi.create.content.contraptions.relays.belt; +import java.util.Optional; import java.util.Random; import com.mojang.blaze3d.matrix.MatrixStack; @@ -11,14 +12,14 @@ 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.ShadowRenderHelper; +import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.MatrixStacker; -import com.simibubi.create.foundation.utility.ShadowRenderHelper; -import com.simibubi.create.foundation.utility.SuperByteBuffer; - import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -51,113 +52,122 @@ public class BeltRenderer extends SafeTileEntityRenderer { 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(te.getWorld())) { - 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 = diagonal - ? start ? AllBlockPartials.BELT_DIAGONAL_START - : end ? AllBlockPartials.BELT_DIAGONAL_END : AllBlockPartials.BELT_DIAGONAL_MIDDLE - : bottom - ? start ? AllBlockPartials.BELT_START_BOTTOM - : end ? AllBlockPartials.BELT_END_BOTTOM : AllBlockPartials.BELT_MIDDLE_BOTTOM - : start ? AllBlockPartials.BELT_START - : end ? AllBlockPartials.BELT_END : AllBlockPartials.BELT_MIDDLE; - - SuperByteBuffer beltBuffer = beltPartial.renderOn(blockState) - .light(light); - - SpriteShiftEntry spriteShift = null; - if (te.color.isPresent()) { - DyeColor color = te.color.get(); - spriteShift = (diagonal ? AllSpriteShifts.DYED_DIAGONAL_BELTS - : bottom ? AllSpriteShifts.DYED_OFFSET_BELTS : AllSpriteShifts.DYED_BELTS).get(color); - } else - spriteShift = diagonal ? AllSpriteShifts.BELT_DIAGONAL - : bottom ? AllSpriteShifts.BELT_OFFSET : AllSpriteShifts.BELT; - - int cycleLength = diagonal ? 12 : 16; - int cycleOffset = bottom ? 8 : 0; - - // UV shift - float speed = te.getSpeed(); - if (speed != 0 || te.color.isPresent()) { - float time = renderTick * axisDirection.getOffset(); - if (diagonal && (downward ^ alongX) || !sideways && !diagonal && alongX - || sideways && axisDirection == AxisDirection.NEGATIVE) - speed = -speed; - int textureIndex = (int) (((speed * time / 36) + cycleOffset) % cycleLength); - if (textureIndex < 0) - textureIndex += cycleLength; - - beltBuffer.shiftUVtoSheet(spriteShift, (textureIndex % 4) / 4f, (textureIndex / 4) / 4f, 4); - } - - 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; + } + + DyeColor color = te.color.orElse(null); + + for (boolean bottom : Iterate.trueAndFalse) { + + AllBlockPartials beltPartial = getBeltPartial(diagonal, start, end, bottom); + + SuperByteBuffer beltBuffer = beltPartial.renderOn(blockState) + .light(light); + + SpriteShiftEntry spriteShift = getSpriteShiftEntry(color, diagonal, bottom); + + // UV shift + float speed = te.getSpeed(); + if (speed != 0 || te.color.isPresent()) { + 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) + (bottom ? 0.5 : 0.0); + 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); } + public static SpriteShiftEntry getSpriteShiftEntry(DyeColor color, boolean diagonal, boolean bottom) { + if (color != null) { + return (diagonal ? AllSpriteShifts.DYED_DIAGONAL_BELTS + : bottom ? AllSpriteShifts.DYED_OFFSET_BELTS : AllSpriteShifts.DYED_BELTS).get(color); + } else + return diagonal ? AllSpriteShifts.BELT_DIAGONAL + : bottom ? AllSpriteShifts.BELT_OFFSET : AllSpriteShifts.BELT; + } + + public static AllBlockPartials getBeltPartial(boolean diagonal, boolean start, boolean end, boolean bottom) { + if (diagonal) { + if (start) return AllBlockPartials.BELT_DIAGONAL_START; + if (end) return AllBlockPartials.BELT_DIAGONAL_END; + return AllBlockPartials.BELT_DIAGONAL_MIDDLE; + } else if (bottom) { + if (start) return AllBlockPartials.BELT_START_BOTTOM; + if (end) return AllBlockPartials.BELT_END_BOTTOM; + return AllBlockPartials.BELT_MIDDLE_BOTTOM; + } else { + if (start) return AllBlockPartials.BELT_START; + if (end) return AllBlockPartials.BELT_END; + return AllBlockPartials.BELT_MIDDLE; + } + } + protected void renderItems(BeltTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { if (!te.isController()) @@ -167,16 +177,17 @@ public class BeltRenderer extends SafeTileEntityRenderer { ms.push(); - Vec3i directionVec = te.getBeltFacing() - .getDirectionVec(); + Direction beltFacing = te.getBeltFacing(); + Vec3i directionVec = beltFacing + .getDirectionVec(); Vec3d beltStartOffset = new Vec3d(directionVec).scale(-.5) .add(.5, 13 / 16f + .125f, .5); ms.translate(beltStartOffset.x, beltStartOffset.y, beltStartOffset.z); BeltSlope slope = te.getBlockState() .get(BeltBlock.SLOPE); int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0; - boolean slopeAlongX = te.getBeltFacing() - .getAxis() == Axis.X; + boolean slopeAlongX = beltFacing + .getAxis() == Axis.X; for (TransportedItemStack transported : te.getInventory() .getTransportedItems()) { @@ -192,6 +203,8 @@ public class BeltRenderer extends SafeTileEntityRenderer { sideOffset = transported.sideOffset; } + int stackLight = getPackedLight(te, offset); + if (offset < .5) verticalMovement = 0; verticalMovement = verticalMovement * (Math.min(offset, te.beltLength - .5f) - .5f); @@ -199,16 +212,16 @@ public class BeltRenderer extends SafeTileEntityRenderer { .add(0, verticalMovement, 0); boolean onSlope = slope != BeltSlope.HORIZONTAL && MathHelper.clamp(offset, .5f, te.beltLength - .5f) == offset; - boolean tiltForward = (slope == BeltSlope.DOWNWARD ^ te.getBeltFacing() - .getAxisDirection() == AxisDirection.POSITIVE) == (te.getBeltFacing() - .getAxis() == Axis.Z); + boolean tiltForward = (slope == BeltSlope.DOWNWARD ^ beltFacing + .getAxisDirection() == AxisDirection.POSITIVE) == (beltFacing + .getAxis() == Axis.Z); float slopeAngle = onSlope ? tiltForward ? -45 : 45 : 0; ms.translate(offsetVec.x, offsetVec.y, offsetVec.z); - boolean alongX = te.getBeltFacing() - .rotateY() - .getAxis() == Axis.X; + boolean alongX = beltFacing + .rotateY() + .getAxis() == Axis.X; if (!alongX) sideOffset *= -1; ms.translate(alongX ? sideOffset : 0, 0, alongX ? 0 : sideOffset); @@ -259,7 +272,7 @@ public class BeltRenderer extends SafeTileEntityRenderer { } ms.scale(.5f, .5f, .5f); - itemRenderer.renderItem(transported.stack, TransformType.FIXED, light, overlay, ms, buffer); + itemRenderer.renderItem(transported.stack, TransformType.FIXED, stackLight, overlay, ms, buffer); ms.pop(); if (!renderUpright) { @@ -276,4 +289,11 @@ public class BeltRenderer extends SafeTileEntityRenderer { ms.pop(); } + protected int getPackedLight(BeltTileEntity controller, float beltPos) { + BeltTileEntity belt = BeltHelper.getBeltForOffset(controller, beltPos); + + if (belt == null) return 0; + + return (belt.skyLight << 20) | (belt.blockLight << 4); + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltSlope.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltSlope.java index 8f934e10f..ab6cf32a8 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltSlope.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltSlope.java @@ -1,7 +1,6 @@ package com.simibubi.create.content.contraptions.relays.belt; import com.simibubi.create.foundation.utility.Lang; - import net.minecraft.util.IStringSerializable; public enum BeltSlope implements IStringSerializable { @@ -11,4 +10,8 @@ public enum BeltSlope implements IStringSerializable { public String getName() { return Lang.asId(name()); } + + public boolean isDiagonal() { + return this == UPWARD || this == DOWNWARD; + } } \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java index e777e5a0e..8bce6836d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java @@ -15,13 +15,13 @@ import java.util.function.Function; import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.base.IRotate; import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.relays.belt.transport.BeltInventory; -import com.simibubi.create.content.contraptions.relays.belt.transport.BeltMovementHandler; +import com.simibubi.create.content.contraptions.relays.belt.transport.*; import com.simibubi.create.content.contraptions.relays.belt.transport.BeltMovementHandler.TransportedEntityInfo; import com.simibubi.create.content.contraptions.relays.belt.transport.BeltTunnelInteractionHandler; import com.simibubi.create.content.contraptions.relays.belt.transport.ItemHandlerBeltSegment; import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; import com.simibubi.create.content.logistics.block.belts.tunnel.BrassTunnelTileEntity; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; @@ -44,11 +44,14 @@ import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3i; +import net.minecraft.world.LightType; +import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.model.data.IModelData; import net.minecraftforge.client.model.data.ModelDataMap; import net.minecraftforge.client.model.data.ModelProperty; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; @@ -67,6 +70,10 @@ public class BeltTileEntity extends KineticTileEntity { public CompoundNBT trackerUpdateTag; + // client + public byte blockLight = -1; + public byte skyLight = -1; + public static enum CasingType { NONE, ANDESITE, BRASS; } @@ -100,6 +107,9 @@ public class BeltTileEntity extends KineticTileEntity { initializeItemHandler(); + if (blockLight == -1) + updateLight(); + // Move Items if (!isController()) return; @@ -136,10 +146,11 @@ public class BeltTileEntity extends KineticTileEntity { } @Override - public AxisAlignedBB getRenderBoundingBox() { + public AxisAlignedBB makeRenderBoundingBox() { if (!isController()) - return super.getRenderBoundingBox(); - return super.getRenderBoundingBox().grow(beltLength + 1); + return super.makeRenderBoundingBox(); + else + return super.makeRenderBoundingBox().grow(beltLength + 1); } protected void initializeItemHandler() { @@ -221,6 +232,7 @@ public class BeltTileEntity extends KineticTileEntity { if (!clientPacket) return; + if (casingBefore == casing) return; requestModelDataUpdate(); @@ -251,6 +263,7 @@ public class BeltTileEntity extends KineticTileEntity { belt.color = Optional.ofNullable(colorIn); belt.markDirty(); belt.sendData(); + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> FastRenderDispatcher.enqueueUpdate(belt)); } } @@ -267,6 +280,7 @@ public class BeltTileEntity extends KineticTileEntity { public void setController(BlockPos controller) { this.controller = controller; + cachedBoundingBox = null; } public BlockPos getController() { @@ -274,7 +288,10 @@ public class BeltTileEntity extends KineticTileEntity { } public boolean isController() { - return pos.equals(controller); + return controller != null && + pos.getX() == controller.getX() && + pos.getY() == controller.getY() && + pos.getZ() == controller.getZ(); } public float getBeltMovementSpeed() { @@ -495,4 +512,24 @@ public class BeltTileEntity extends KineticTileEntity { return 0; } + @Override + public void onChunkLightUpdate() { + super.onChunkLightUpdate(); + updateLight(); + } + + @Override + public boolean shouldRenderAsTE() { + return isController(); + } + + private void updateLight() { + if (world != null) { + skyLight = (byte) world.getLightLevel(LightType.SKY, pos); + blockLight = (byte) world.getLightLevel(LightType.BLOCK, pos); + } else { + skyLight = -1; + blockLight = -1; + } + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltVertexAttributes.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltVertexAttributes.java new file mode 100644 index 000000000..ca2125848 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltVertexAttributes.java @@ -0,0 +1,41 @@ +package com.simibubi.create.content.contraptions.relays.belt; + +import com.simibubi.create.foundation.render.backend.gl.attrib.CommonAttributes; +import com.simibubi.create.foundation.render.backend.gl.attrib.IVertexAttrib; +import com.simibubi.create.foundation.render.backend.gl.attrib.VertexAttribSpec; + +public enum BeltVertexAttributes implements IVertexAttrib { + INSTANCE_ROTATION("aInstanceRot", CommonAttributes.VEC3), + SOURCE_TEX("aSourceTexture", CommonAttributes.UV), + SCROLL_TEX("aScrollTexture", CommonAttributes.VEC4), + SCROLL_MULT("aScrollMult", CommonAttributes.NORMALIZED_BYTE), + ; + + private final String name; + private final VertexAttribSpec spec; + + BeltVertexAttributes(String name, VertexAttribSpec spec) { + this.name = name; + this.spec = spec; + } + + @Override + public String attribName() { + return name; + } + + @Override + public VertexAttribSpec attribSpec() { + return spec; + } + + @Override + public int getDivisor() { + return 1; + } + + @Override + public int getBufferIndex() { + return 1; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/SimpleKineticTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/SimpleKineticTileEntity.java index 410d15108..df6b20f6f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/SimpleKineticTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/SimpleKineticTileEntity.java @@ -28,7 +28,7 @@ public class SimpleKineticTileEntity extends KineticTileEntity { } @Override - public AxisAlignedBB getRenderBoundingBox() { + public AxisAlignedBB makeRenderBoundingBox() { return new AxisAlignedBB(pos).grow(1); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ShaftInstance.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ShaftInstance.java new file mode 100644 index 000000000..bebfb5763 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ShaftInstance.java @@ -0,0 +1,28 @@ +package com.simibubi.create.content.contraptions.relays.encased; + +import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; +import net.minecraft.block.BlockState; +import net.minecraft.tileentity.TileEntityType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +public class ShaftInstance extends SingleRotatingInstance { + + public static void register(TileEntityType type) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> + InstancedTileRenderRegistry.instance.register(type, ShaftInstance::new)); + } + + public ShaftInstance(InstancedTileRenderer dispatcher, KineticTileEntity tile) { + super(dispatcher, tile); + } + + @Override + protected BlockState getRenderedBlockState() { + return shaft(getRotationAxis()); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftInstance.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftInstance.java new file mode 100644 index 000000000..860d267ba --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftInstance.java @@ -0,0 +1,86 @@ +package com.simibubi.create.content.contraptions.relays.encased; + +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.IRotate; +import com.simibubi.create.content.contraptions.base.KineticTileInstance; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; +import com.simibubi.create.content.contraptions.base.RotatingData; +import com.simibubi.create.foundation.utility.Iterate; +import net.minecraft.block.Block; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +import java.util.ArrayList; + +public class SplitShaftInstance extends KineticTileInstance { + public static void register(TileEntityType type) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> + InstancedTileRenderRegistry.instance.register(type, SplitShaftInstance::new)); + } + + protected ArrayList> keys; + + public SplitShaftInstance(InstancedTileRenderer modelManager, SplitShaftTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected void init() { + keys = new ArrayList<>(2); + + Block block = lastState.getBlock(); + final Direction.Axis boxAxis = ((IRotate) block).getRotationAxis(lastState); + + float speed = tile.getSpeed(); + + for (Direction dir : Iterate.directionsInAxis(boxAxis)) { + + InstancedModel half = AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(modelManager, lastState, dir); + + float splitSpeed = speed * tile.getRotationSpeedModifier(dir); + + keys.add(half.setupInstance(setupFunc(splitSpeed, boxAxis))); + } + } + + @Override + public void onUpdate() { + Block block = lastState.getBlock(); + final Direction.Axis boxAxis = ((IRotate) block).getRotationAxis(lastState); + + Direction[] directions = Iterate.directionsInAxis(boxAxis); + + for (int i : Iterate.zeroAndOne) { + updateRotation(keys.get(i), directions[i]); + } + } + + @Override + public void updateLight() { + for (InstanceKey key : keys) { + key.modifyInstance(this::relight); + } + } + + @Override + public void remove() { + keys.forEach(InstanceKey::delete); + keys.clear(); + } + + protected void updateRotation(InstanceKey key, Direction dir) { + key.modifyInstance(data -> { + Direction.Axis axis = dir.getAxis(); + + data.setColor(tile.network) + .setRotationalSpeed(tile.getSpeed() * tile.getRotationSpeedModifier(dir)) + .setRotationOffset(getRotationOffset(axis)) + .setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector()); + }); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftRenderer.java index 96186728f..2620aa018 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftRenderer.java @@ -5,9 +5,10 @@ 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.backend.FastRenderDispatcher; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.Iterate; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.block.Block; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -26,6 +27,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(te.getWorld())) return; + Block block = te.getBlockState().getBlock(); final Axis boxAxis = ((IRotate) block).getRotationAxis(te.getBlockState()); final BlockPos pos = te.getPos(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeRenderer.java index 8c24f63b4..c8d81bfe9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeRenderer.java @@ -7,7 +7,7 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.content.contraptions.relays.gauge.GaugeBlock.Type; import com.simibubi.create.foundation.utility.Iterate; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeTileEntity.java index 3969af754..ac4e4664a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeTileEntity.java @@ -1,14 +1,13 @@ package com.simibubi.create.content.contraptions.relays.gauge; -import java.util.List; - import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; import com.simibubi.create.foundation.utility.Lang; - import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntityType; +import java.util.List; + public class GaugeTileEntity extends KineticTileEntity implements IHaveGoggleInformation { public float dialTarget; @@ -50,4 +49,8 @@ public class GaugeTileEntity extends KineticTileEntity implements IHaveGoggleInf return true; } + @Override + public boolean shouldRenderAsTE() { + return true; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxInstance.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxInstance.java new file mode 100644 index 000000000..36e2a7b79 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxInstance.java @@ -0,0 +1,116 @@ +package com.simibubi.create.content.contraptions.relays.gearbox; + +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.KineticTileInstance; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.render.backend.instancing.InstanceKey; +import com.simibubi.create.foundation.render.backend.instancing.InstancedModel; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderRegistry; +import com.simibubi.create.content.contraptions.base.RotatingData; +import com.simibubi.create.foundation.utility.Iterate; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.LightType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +import java.util.EnumMap; +import java.util.Map; + +public class GearboxInstance extends KineticTileInstance { + public static void register(TileEntityType type) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> + InstancedTileRenderRegistry.instance.register(type, GearboxInstance::new)); + } + + protected EnumMap> keys; + protected Direction sourceFacing; + + public GearboxInstance(InstancedTileRenderer modelManager, GearboxTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected void init() { + keys = new EnumMap<>(Direction.class); + + final Direction.Axis boxAxis = lastState.get(BlockStateProperties.AXIS); + + int blockLight = world.getLightLevel(LightType.BLOCK, pos); + int skyLight = world.getLightLevel(LightType.SKY, pos); + updateSourceFacing(); + + for (Direction direction : Iterate.directions) { + final Direction.Axis axis = direction.getAxis(); + if (boxAxis == axis) + continue; + + InstancedModel shaft = AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(modelManager, lastState, direction); + + InstanceKey key = shaft.setupInstance(data -> { + data.setBlockLight(blockLight) + .setSkyLight(skyLight) + .setRotationalSpeed(getSpeed(direction)) + .setRotationOffset(getRotationOffset(axis)) + .setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector()) + .setTileEntity(tile); + }); + keys.put(direction, key); + } + } + + private float getSpeed(Direction direction) { + float speed = tile.getSpeed(); + + if (speed != 0 && sourceFacing != null) { + if (sourceFacing.getAxis() == direction.getAxis()) + speed *= sourceFacing == direction ? 1 : -1; + else if (sourceFacing.getAxisDirection() == direction.getAxisDirection()) + speed *= -1; + } + return speed; + } + + protected void updateSourceFacing() { + if (tile.hasSource()) { + BlockPos source = tile.source.subtract(pos); + sourceFacing = Direction.getFacingFromVector(source.getX(), source.getY(), source.getZ()); + } else { + sourceFacing = null; + } + } + + @Override + public void onUpdate() { + updateSourceFacing(); + for (Map.Entry> key : keys.entrySet()) { + key.getValue().modifyInstance(data -> { + Direction direction = key.getKey(); + Direction.Axis axis = direction.getAxis(); + + data.setColor(tile.network) + .setRotationalSpeed(getSpeed(direction)) + .setRotationOffset(getRotationOffset(axis)) + .setRotationAxis(Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getUnitVector()); + }); + } + } + + @Override + public void updateLight() { + int blockLight = tile.getWorld().getLightLevel(LightType.BLOCK, pos); + int skyLight = tile.getWorld().getLightLevel(LightType.SKY, pos); + + for (InstanceKey key : keys.values()) { + key.modifyInstance(data -> data.setBlockLight(blockLight).setSkyLight(skyLight)); + } + } + + @Override + public void remove() { + keys.values().forEach(InstanceKey::delete); + keys.clear(); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxRenderer.java index 7462e355c..c0f3599c9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxRenderer.java @@ -4,9 +4,10 @@ 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.backend.FastRenderDispatcher; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.Iterate; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; @@ -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(te.getWorld())) return; + final Axis boxAxis = te.getBlockState().get(BlockStateProperties.AXIS); final BlockPos pos = te.getPos(); float time = AnimationTickHolder.getRenderTick(); diff --git a/src/main/java/com/simibubi/create/content/curiosities/ChromaticCompoundColor.java b/src/main/java/com/simibubi/create/content/curiosities/ChromaticCompoundColor.java index 34b5b503d..60ba0545c 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/ChromaticCompoundColor.java +++ b/src/main/java/com/simibubi/create/content/curiosities/ChromaticCompoundColor.java @@ -2,7 +2,6 @@ package com.simibubi.create.content.curiosities; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.ColorHelper; - import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.color.IItemColor; import net.minecraft.item.ItemStack; @@ -13,7 +12,7 @@ public class ChromaticCompoundColor implements IItemColor { @Override public int getColor(ItemStack stack, int layer) { Minecraft mc = Minecraft.getInstance(); - float pt = mc.getRenderPartialTicks(); + float pt = AnimationTickHolder.getPartialTicks(); float progress = (float) ((mc.player.getYaw(pt)) / 180 * Math.PI) + (AnimationTickHolder.getRenderTick() / 10f); if (layer == 0) return ColorHelper.mixColors(0x6e5773, 0x6B3074, ((float) MathHelper.sin(progress) + 1) / 2); diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripItem.java b/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripItem.java index a74a092a0..dd9f57c99 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripItem.java +++ b/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripItem.java @@ -1,13 +1,11 @@ package com.simibubi.create.content.curiosities.tools; -import java.util.UUID; - import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.simibubi.create.AllItems; import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.networking.AllPackets; - +import com.simibubi.create.foundation.utility.AnimationTickHolder; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.entity.Entity; @@ -35,6 +33,8 @@ import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import java.util.UUID; + @EventBusSubscriber public class ExtendoGripItem extends Item { @@ -125,7 +125,7 @@ public class ExtendoGripItem extends Item { .getValue(); if (!player.isCreative()) d0 -= 0.5f; - Vec3d vec3d = player.getEyePosition(mc.getRenderPartialTicks()); + Vec3d vec3d = player.getEyePosition(AnimationTickHolder.getPartialTicks()); Vec3d vec3d1 = player.getLook(1.0F); Vec3d vec3d2 = vec3d.add(vec3d1.x * d0, vec3d1.y * d0, vec3d1.z * d0); AxisAlignedBB axisalignedbb = player.getBoundingBox() diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripItemRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripItemRenderer.java index 3788d6000..d37daa176 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripItemRenderer.java +++ b/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripItemRenderer.java @@ -6,8 +6,6 @@ import com.simibubi.create.foundation.block.render.CustomRenderedItemModelRender import com.simibubi.create.foundation.item.PartialItemModelRenderer; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.MatrixStacker; - -import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; import net.minecraft.item.ItemStack; @@ -28,9 +26,9 @@ public class ExtendoGripItemRenderer extends CustomRenderedItemModelRenderer mainHandAnimation && swingProgress > 0) mainHandAnimation = 0.95f; - float animation = MathHelper.lerp(Minecraft.getInstance() - .getRenderPartialTicks(), ExtendoGripRenderHandler.lastMainHandAnimation, - ExtendoGripRenderHandler.mainHandAnimation); + float animation = MathHelper.lerp(AnimationTickHolder.getPartialTicks(), + ExtendoGripRenderHandler.lastMainHandAnimation, + ExtendoGripRenderHandler.mainHandAnimation); animation = animation * animation * animation; ms.translate(flip * (0.64000005F - .1f), -0.4F + equipProgress * -0.6F, -0.71999997F + .3f); diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/SandPaperItemRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/tools/SandPaperItemRenderer.java index 78b741a2b..5be2fb467 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/SandPaperItemRenderer.java +++ b/src/main/java/com/simibubi/create/content/curiosities/tools/SandPaperItemRenderer.java @@ -4,7 +4,6 @@ import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.foundation.block.render.CustomRenderedItemModel; import com.simibubi.create.foundation.utility.AnimationTickHolder; - import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -25,7 +24,7 @@ public class SandPaperItemRenderer extends ItemStackTileEntityRenderer { ClientPlayerEntity player = Minecraft.getInstance().player; SandPaperModel mainModel = (SandPaperModel) itemRenderer.getItemModelWithOverrides(stack, Minecraft.getInstance().world, null); TransformType perspective = mainModel.getCurrentPerspective(); - float partialTicks = Minecraft.getInstance().getRenderPartialTicks(); + float partialTicks = AnimationTickHolder.getPartialTicks(); boolean leftHand = perspective == TransformType.FIRST_PERSON_LEFT_HAND; boolean firstPerson = leftHand || perspective == TransformType.FIRST_PERSON_RIGHT_HAND; @@ -49,7 +48,7 @@ public class SandPaperItemRenderer extends ItemStackTileEntityRenderer { // Reverse bobbing float time = (float) (!jeiMode ? player.getItemInUseCount() - : (-AnimationTickHolder.ticks) % stack.getUseDuration()) - partialTicks + 1.0F; + : (-AnimationTickHolder.getTicks()) % stack.getUseDuration()) - partialTicks + 1.0F; if (time / (float) stack.getUseDuration() < 0.8F) { float bobbing = -MathHelper.abs(MathHelper.cos(time / 4.0F * (float) Math.PI) * 0.1F); diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperRenderHandler.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperRenderHandler.java index fe428b05d..2c8d579ce 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperRenderHandler.java +++ b/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperRenderHandler.java @@ -1,14 +1,9 @@ package com.simibubi.create.content.curiosities.zapper; -import java.util.LinkedList; -import java.util.List; -import java.util.Random; -import java.util.function.Supplier; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllSoundEvents; import com.simibubi.create.CreateClient; - +import com.simibubi.create.foundation.utility.AnimationTickHolder; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.AbstractClientPlayerEntity; import net.minecraft.client.entity.player.ClientPlayerEntity; @@ -30,6 +25,11 @@ import net.minecraftforge.client.event.RenderHandEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import java.util.LinkedList; +import java.util.List; +import java.util.Random; +import java.util.function.Supplier; + @EventBusSubscriber(value = Dist.CLIENT) public class ZapperRenderHandler { @@ -63,8 +63,7 @@ public class ZapperRenderHandler { } public static Vec3d getExactBarrelPos(boolean mainHand) { - float partialTicks = Minecraft.getInstance() - .getRenderPartialTicks(); + float partialTicks = AnimationTickHolder.getPartialTicks(); ClientPlayerEntity player = Minecraft.getInstance().player; float yaw = (float) ((player.getYaw(partialTicks)) / -180 * Math.PI); float pitch = (float) ((player.getPitch(partialTicks)) / -180 * Math.PI); diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/blockzapper/BlockzapperItemRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/blockzapper/BlockzapperItemRenderer.java index 3f05fca7f..6d8eaf1e7 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/blockzapper/BlockzapperItemRenderer.java +++ b/src/main/java/com/simibubi/create/content/curiosities/zapper/blockzapper/BlockzapperItemRenderer.java @@ -1,20 +1,11 @@ package com.simibubi.create.content.curiosities.zapper.blockzapper; -import static com.simibubi.create.content.curiosities.zapper.blockzapper.BlockzapperItem.Components.Accelerator; -import static com.simibubi.create.content.curiosities.zapper.blockzapper.BlockzapperItem.Components.Amplifier; -import static com.simibubi.create.content.curiosities.zapper.blockzapper.BlockzapperItem.Components.Body; -import static com.simibubi.create.content.curiosities.zapper.blockzapper.BlockzapperItem.Components.Retriever; -import static com.simibubi.create.content.curiosities.zapper.blockzapper.BlockzapperItem.Components.Scope; -import static java.lang.Math.max; -import static net.minecraft.util.math.MathHelper.clamp; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.content.curiosities.zapper.ZapperItemRenderer; import com.simibubi.create.content.curiosities.zapper.blockzapper.BlockzapperItem.ComponentTier; import com.simibubi.create.content.curiosities.zapper.blockzapper.BlockzapperItem.Components; import com.simibubi.create.foundation.item.PartialItemModelRenderer; import com.simibubi.create.foundation.utility.AnimationTickHolder; - import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -25,6 +16,10 @@ import net.minecraft.item.ItemStack; import net.minecraft.util.HandSide; import net.minecraft.util.math.MathHelper; +import static com.simibubi.create.content.curiosities.zapper.blockzapper.BlockzapperItem.Components.*; +import static java.lang.Math.max; +import static net.minecraft.util.math.MathHelper.clamp; + public class BlockzapperItemRenderer extends ZapperItemRenderer { @Override @@ -32,8 +27,7 @@ public class BlockzapperItemRenderer extends ZapperItemRenderer { @Override @@ -24,8 +23,7 @@ public class WorldshaperItemRenderer extends ZapperItemRenderer type) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> + InstancedTileRenderRegistry.instance.register(type, ArmInstance::new)); + } + + public ArmInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + super(modelManager, tile); + } + + @Override + protected InstancedModel getModel() { + return AllBlockPartials.ARM_COG.renderOnRotating(modelManager, tile.getBlockState()); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java index f770012ed..6d005cebc 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java @@ -6,12 +6,11 @@ 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.content.logistics.block.mechanicalArm.ArmTileEntity.Phase; +import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.ColorHelper; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.MatrixStacker; -import com.simibubi.create.foundation.utility.SuperByteBuffer; - import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -29,6 +28,11 @@ public class ArmRenderer extends KineticTileEntityRenderer { super(dispatcher); } + @Override + public boolean isGlobalRenderer(KineticTileEntity te) { + return true; + } + @Override protected void renderSafe(KineticTileEntity te, float pt, MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { @@ -44,14 +48,14 @@ public class ArmRenderer extends KineticTileEntityRenderer { float upperArmAngle = arm.upperArmAngle.get(pt) - 90; float headAngle = arm.headAngle.get(pt); - boolean rave = te instanceof ArmTileEntity && ((ArmTileEntity) te).phase == Phase.DANCING; + boolean rave = arm.phase == Phase.DANCING; float renderTick = AnimationTickHolder.getRenderTick() + (te.hashCode() % 64); if (rave) { baseAngle = (renderTick * 10) % 360; lowerArmAngle = MathHelper.lerp((MathHelper.sin(renderTick / 4) + 1) / 2, -45, 15); upperArmAngle = MathHelper.lerp((MathHelper.sin(renderTick / 8) + 1) / 4, -45, 95); headAngle = -lowerArmAngle; - color = ColorHelper.rainbowColor(AnimationTickHolder.ticks * 100); + color = ColorHelper.rainbowColor(AnimationTickHolder.getTicks() * 100); } ms.push(); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java index 6a65e0e26..ad46d9652 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java @@ -1,10 +1,5 @@ package com.simibubi.create.content.logistics.block.mechanicalArm; -import java.util.ArrayList; -import java.util.List; - -import javax.annotation.Nullable; - import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Jukebox; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Mode; @@ -21,7 +16,6 @@ import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.VecHelper; - import net.minecraft.block.BlockState; import net.minecraft.block.JukeboxBlock; import net.minecraft.item.ItemStack; @@ -37,6 +31,10 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.util.Constants.NBT; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; + public class ArmTileEntity extends KineticTileEntity { // Server @@ -145,8 +143,8 @@ public class ArmTileEntity extends KineticTileEntity { @Override @OnlyIn(Dist.CLIENT) - public AxisAlignedBB getRenderBoundingBox() { - return super.getRenderBoundingBox().grow(3); + public AxisAlignedBB makeRenderBoundingBox() { + return super.makeRenderBoundingBox().grow(3); } private boolean checkForMusicAmong(List list) { @@ -474,6 +472,11 @@ public class ArmTileEntity extends KineticTileEntity { return true; } + @Override + public boolean shouldRenderAsTE() { + return true; + } + private class SelectionModeValueBox extends CenteredSideValueBoxTransform { public SelectionModeValueBox() { diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverRenderer.java index dcc0521c8..72a11a15a 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverRenderer.java @@ -6,7 +6,7 @@ import com.simibubi.create.AllBlockPartials; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.ColorHelper; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonRenderer.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonRenderer.java index 706d9d931..0fe84ba4a 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonRenderer.java +++ b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonRenderer.java @@ -8,7 +8,7 @@ import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.schematics.block.LaunchedItem.ForBlockState; import com.simibubi.create.content.schematics.block.LaunchedItem.ForEntity; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; diff --git a/src/main/java/com/simibubi/create/content/schematics/client/SchematicAndQuillHandler.java b/src/main/java/com/simibubi/create/content/schematics/client/SchematicAndQuillHandler.java index cfdf35b51..6965c9b97 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/SchematicAndQuillHandler.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/SchematicAndQuillHandler.java @@ -1,30 +1,13 @@ package com.simibubi.create.content.schematics.client; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; - -import org.apache.commons.io.IOUtils; - -import com.simibubi.create.AllItems; -import com.simibubi.create.AllKeys; -import com.simibubi.create.AllSpecialTextures; -import com.simibubi.create.Create; -import com.simibubi.create.CreateClient; +import com.simibubi.create.*; import com.simibubi.create.content.schematics.ClientSchematicLoader; import com.simibubi.create.content.schematics.packet.InstantSchematicPacket; import com.simibubi.create.foundation.gui.ScreenOpener; import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.utility.FilesHelper; -import com.simibubi.create.foundation.utility.Lang; -import com.simibubi.create.foundation.utility.RaycastHelper; +import com.simibubi.create.foundation.utility.*; import com.simibubi.create.foundation.utility.RaycastHelper.PredicateTraceResult; -import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.outliner.Outliner; - import net.minecraft.block.Blocks; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; @@ -35,15 +18,17 @@ import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.util.Direction; import net.minecraft.util.Direction.AxisDirection; import net.minecraft.util.Hand; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.MutableBoundingBox; +import net.minecraft.util.math.*; import net.minecraft.util.math.RayTraceResult.Type; -import net.minecraft.util.math.Vec3d; -import net.minecraft.util.math.Vec3i; import net.minecraft.world.gen.feature.template.Template; +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; public class SchematicAndQuillHandler { @@ -139,8 +124,7 @@ public class SchematicAndQuillHandler { ClientPlayerEntity player = Minecraft.getInstance().player; if (AllKeys.ACTIVATE_TOOL.isPressed()) { - float pt = Minecraft.getInstance() - .getRenderPartialTicks(); + float pt = AnimationTickHolder.getPartialTicks(); Vec3d targetVec = player.getEyePosition(pt) .add(player.getLookVec() .scale(range)); diff --git a/src/main/java/com/simibubi/create/content/schematics/client/SchematicHandler.java b/src/main/java/com/simibubi/create/content/schematics/client/SchematicHandler.java index 8eebde8f5..26505e742 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/SchematicHandler.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/SchematicHandler.java @@ -1,8 +1,5 @@ package com.simibubi.create.content.schematics.client; -import java.util.List; -import java.util.Vector; - import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlocks; @@ -17,8 +14,8 @@ import com.simibubi.create.content.schematics.packet.SchematicSyncPacket; import com.simibubi.create.foundation.gui.ToolSelectionScreen; import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.outliner.AABBOutline; - import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -35,6 +32,9 @@ import net.minecraft.world.World; import net.minecraft.world.gen.feature.template.PlacementSettings; import net.minecraft.world.gen.feature.template.Template; +import java.util.List; +import java.util.Vector; + public class SchematicHandler { private String displayedSchematic; @@ -160,8 +160,7 @@ public class SchematicHandler { transformation.applyGLTransformations(ms); if (!renderers.isEmpty()) { - float pt = Minecraft.getInstance() - .getRenderPartialTicks(); + float pt = AnimationTickHolder.getPartialTicks(); boolean lr = transformation.getScaleLR() .get(pt) < 0; boolean fb = transformation.getScaleFB() @@ -193,8 +192,7 @@ public class SchematicHandler { currentTool.getTool() .renderOverlay(ms, buffer); - selectionScreen.renderPassive(Minecraft.getInstance() - .getRenderPartialTicks()); + selectionScreen.renderPassive(AnimationTickHolder.getPartialTicks()); } public void onMouseInput(int button, boolean pressed) { diff --git a/src/main/java/com/simibubi/create/content/schematics/client/SchematicRenderer.java b/src/main/java/com/simibubi/create/content/schematics/client/SchematicRenderer.java index 21971355a..2f9159897 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/SchematicRenderer.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/SchematicRenderer.java @@ -13,8 +13,8 @@ import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.content.schematics.SchematicWorld; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; import com.simibubi.create.foundation.utility.MatrixStacker; -import com.simibubi.create.foundation.utility.SuperByteBuffer; -import com.simibubi.create.foundation.utility.TileEntityRenderHelper; +import com.simibubi.create.foundation.render.SuperByteBuffer; +import com.simibubi.create.foundation.render.TileEntityRenderHelper; import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; @@ -34,7 +34,7 @@ public class SchematicRenderer { private final Set startedBufferBuilders = new HashSet<>(getLayerCount()); private boolean active; private boolean changed; - private SchematicWorld schematic; + protected SchematicWorld schematic; private BlockPos anchor; public SchematicRenderer() { @@ -81,7 +81,7 @@ public class SchematicRenderer { buffer); } - private void redraw(Minecraft minecraft) { + protected void redraw(Minecraft minecraft) { usedBlockRenderLayers.clear(); startedBufferBuilders.clear(); diff --git a/src/main/java/com/simibubi/create/content/schematics/client/SchematicTransformation.java b/src/main/java/com/simibubi/create/content/schematics/client/SchematicTransformation.java index 6a78ca4a3..9fad2795a 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/SchematicTransformation.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/SchematicTransformation.java @@ -1,14 +1,11 @@ package com.simibubi.create.content.schematics.client; -import static java.lang.Math.abs; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingAngle; import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.VecHelper; - -import net.minecraft.client.Minecraft; import net.minecraft.util.Direction.Axis; import net.minecraft.util.Mirror; import net.minecraft.util.Rotation; @@ -17,6 +14,8 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.gen.feature.template.PlacementSettings; +import static java.lang.Math.abs; + public class SchematicTransformation { private InterpolatedChasingValue x, y, z, scaleFrontBack, scaleLeftRight; @@ -52,8 +51,7 @@ public class SchematicTransformation { } public void applyGLTransformations(MatrixStack ms) { - float pt = Minecraft.getInstance() - .getRenderPartialTicks(); + float pt = AnimationTickHolder.getPartialTicks(); // Translation ms.translate(x.get(pt), y.get(pt), z.get(pt)); @@ -93,8 +91,7 @@ public class SchematicTransformation { } public Vec3d toLocalSpace(Vec3d vec) { - float pt = Minecraft.getInstance() - .getRenderPartialTicks(); + float pt = AnimationTickHolder.getPartialTicks(); Vec3d rotationOffset = getRotationOffset(true); vec = vec.subtract(x.get(pt), y.get(pt), z.get(pt)); @@ -181,8 +178,7 @@ public class SchematicTransformation { } public float getCurrentRotation() { - float pt = Minecraft.getInstance() - .getRenderPartialTicks(); + float pt = AnimationTickHolder.getPartialTicks(); return rotation.get(pt); } diff --git a/src/main/java/com/simibubi/create/content/schematics/client/tools/DeployTool.java b/src/main/java/com/simibubi/create/content/schematics/client/tools/DeployTool.java index e58e5cd85..97624af02 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/tools/DeployTool.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/tools/DeployTool.java @@ -4,10 +4,9 @@ import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllKeys; import com.simibubi.create.content.schematics.client.SchematicTransformation; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.outliner.AABBOutline; - -import net.minecraft.client.Minecraft; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTUtil; import net.minecraft.util.math.AxisAlignedBB; @@ -43,8 +42,7 @@ public class DeployTool extends PlacementToolBase { return; ms.push(); - float pt = Minecraft.getInstance() - .getRenderPartialTicks(); + float pt = AnimationTickHolder.getPartialTicks(); double x = MathHelper.lerp(pt, lastChasingSelectedPos.x, chasingSelectedPos.x); double y = MathHelper.lerp(pt, lastChasingSelectedPos.y, chasingSelectedPos.y); double z = MathHelper.lerp(pt, lastChasingSelectedPos.z, chasingSelectedPos.z); diff --git a/src/main/java/com/simibubi/create/content/schematics/client/tools/SchematicToolBase.java b/src/main/java/com/simibubi/create/content/schematics/client/tools/SchematicToolBase.java index c20606a52..9c795cc9c 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/tools/SchematicToolBase.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/tools/SchematicToolBase.java @@ -1,8 +1,5 @@ package com.simibubi.create.content.schematics.client.tools; -import java.util.Arrays; -import java.util.List; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllKeys; import com.simibubi.create.AllSpecialTextures; @@ -10,11 +7,11 @@ import com.simibubi.create.CreateClient; import com.simibubi.create.content.schematics.client.SchematicHandler; import com.simibubi.create.content.schematics.client.SchematicTransformation; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.RaycastHelper; import com.simibubi.create.foundation.utility.RaycastHelper.PredicateTraceResult; import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.outliner.AABBOutline; - import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -25,6 +22,9 @@ import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.RayTraceResult.Type; import net.minecraft.util.math.Vec3d; +import java.util.Arrays; +import java.util.List; + public abstract class SchematicToolBase implements ISchematicTool { protected SchematicHandler schematicHandler; @@ -91,8 +91,7 @@ public abstract class SchematicToolBase implements ISchematicTool { // Select location at distance if (selectIgnoreBlocks) { - float pt = Minecraft.getInstance() - .getRenderPartialTicks(); + float pt = AnimationTickHolder.getPartialTicks(); selectedPos = new BlockPos(player.getEyePosition(pt) .add(player.getLookVec() .scale(selectionRange))); diff --git a/src/main/java/com/simibubi/create/events/ClientEvents.java b/src/main/java/com/simibubi/create/events/ClientEvents.java index 333166ffd..fdc1fbd34 100644 --- a/src/main/java/com/simibubi/create/events/ClientEvents.java +++ b/src/main/java/com/simibubi/create/events/ClientEvents.java @@ -25,6 +25,9 @@ import com.simibubi.create.foundation.gui.ScreenOpener; import com.simibubi.create.foundation.item.TooltipHelper; import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.networking.LeftClickPacket; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; +import com.simibubi.create.foundation.render.backend.RenderWork; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; import com.simibubi.create.foundation.tileEntity.behaviour.edgeInteraction.EdgeInteractionRenderer; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringRenderer; @@ -37,11 +40,13 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.ActiveRenderInfo; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.world.ClientWorld; import net.minecraft.fluid.Fluid; import net.minecraft.fluid.IFluidState; import net.minecraft.item.ItemStack; import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.ITextComponent; +import net.minecraft.world.IWorld; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.EntityViewRenderEvent; @@ -72,11 +77,12 @@ public class ClientEvents { if (event.phase == Phase.START) return; - AnimationTickHolder.tick(); - if (!isGameActive()) return; + AnimationTickHolder.tick(); + FastRenderDispatcher.tick(); + CreateClient.schematicSender.tick(); CreateClient.schematicAndQuillHandler.tick(); CreateClient.schematicHandler.tick(); @@ -105,20 +111,34 @@ public class ClientEvents { PlacementHelpers.tick(); CreateClient.outliner.tickOutlines(); CreateClient.ghostBlocks.tickGhosts(); + ContraptionRenderDispatcher.tick(); } @SubscribeEvent public static void onLoadWorld(WorldEvent.Load event) { - CreateClient.bufferCache.invalidate(); + IWorld world = event.getWorld(); + if (world.isRemote() && world instanceof ClientWorld) { + CreateClient.invalidateRenderers(); + AnimationTickHolder.reset(); + ((ClientWorld) world).loadedTileEntityList.forEach(CreateClient.kineticRenderer::add); + } + } + + @SubscribeEvent + public static void onUnloadWorld(WorldEvent.Unload event) { + if (event.getWorld().isRemote()) { + CreateClient.invalidateRenderers(); + AnimationTickHolder.reset(); + } } @SubscribeEvent public static void onRenderWorld(RenderWorldLastEvent event) { + Vec3d cameraPos = Minecraft.getInstance().gameRenderer.getActiveRenderInfo().getProjectedView(); + MatrixStack ms = event.getMatrixStack(); - ActiveRenderInfo info = Minecraft.getInstance().gameRenderer.getActiveRenderInfo(); - Vec3d view = info.getProjectedView(); ms.push(); - ms.translate(-view.getX(), -view.getY(), -view.getZ()); + ms.translate(-cameraPos.getX(), -cameraPos.getY(), -cameraPos.getZ()); SuperRenderTypeBuffer buffer = SuperRenderTypeBuffer.getInstance(); CouplingRenderer.renderAll(ms, buffer); @@ -126,11 +146,15 @@ public class ClientEvents { CreateClient.ghostBlocks.renderAll(ms, buffer); CreateClient.outliner.renderOutlines(ms, buffer); +// LightVolumeDebugger.render(ms, buffer); // CollisionDebugger.render(ms, buffer); buffer.draw(); RenderSystem.enableCull(); ms.pop(); + + RenderWork.runAll(); + FastRenderDispatcher.endFrame(); } @SubscribeEvent @@ -176,6 +200,7 @@ public class ClientEvents { if (!isGameActive()) return; TurntableHandler.gameRenderTick(); + ContraptionRenderDispatcher.renderTick(); } protected static boolean isGameActive() { diff --git a/src/main/java/com/simibubi/create/foundation/ResourceReloadHandler.java b/src/main/java/com/simibubi/create/foundation/ResourceReloadHandler.java index 9206a88c4..6342594b9 100644 --- a/src/main/java/com/simibubi/create/foundation/ResourceReloadHandler.java +++ b/src/main/java/com/simibubi/create/foundation/ResourceReloadHandler.java @@ -17,7 +17,7 @@ public class ResourceReloadHandler extends ReloadListener { @Override protected void apply(Object $, IResourceManager resourceManagerIn, IProfiler profilerIn) { SpriteShifter.reloadUVs(); - CreateClient.bufferCache.invalidate(); + CreateClient.invalidateRenderers(); } } diff --git a/src/main/java/com/simibubi/create/foundation/block/connected/CTSpriteShiftEntry.java b/src/main/java/com/simibubi/create/foundation/block/connected/CTSpriteShiftEntry.java index 41741eb5b..fa99114c3 100644 --- a/src/main/java/com/simibubi/create/foundation/block/connected/CTSpriteShiftEntry.java +++ b/src/main/java/com/simibubi/create/foundation/block/connected/CTSpriteShiftEntry.java @@ -3,7 +3,7 @@ package com.simibubi.create.foundation.block.connected; import com.simibubi.create.foundation.block.connected.CTSpriteShifter.CTType; import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour.CTContext; import com.simibubi.create.foundation.block.render.SpriteShiftEntry; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; public abstract class CTSpriteShiftEntry extends SpriteShiftEntry { diff --git a/src/main/java/com/simibubi/create/foundation/command/AllCommands.java b/src/main/java/com/simibubi/create/foundation/command/AllCommands.java index cf36c3c7a..d61be2834 100644 --- a/src/main/java/com/simibubi/create/foundation/command/AllCommands.java +++ b/src/main/java/com/simibubi/create/foundation/command/AllCommands.java @@ -23,6 +23,7 @@ public class AllCommands { .then(FixLightingCommand.register()) .then(ReplaceInCommandBlocksCommand.register()) .then(HighlightCommand.register()) + .then(ToggleExperimentalRenderingCommand.register()) //dev-util //Comment out for release diff --git a/src/main/java/com/simibubi/create/foundation/command/ClearBufferCacheCommand.java b/src/main/java/com/simibubi/create/foundation/command/ClearBufferCacheCommand.java index 2398d9406..7d9a6cb74 100644 --- a/src/main/java/com/simibubi/create/foundation/command/ClearBufferCacheCommand.java +++ b/src/main/java/com/simibubi/create/foundation/command/ClearBufferCacheCommand.java @@ -22,6 +22,6 @@ public class ClearBufferCacheCommand { @OnlyIn(Dist.CLIENT) private static void execute() { - CreateClient.bufferCache.invalidate(); + CreateClient.invalidateRenderers(); } } diff --git a/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigPacket.java b/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigPacket.java index b6790ab4b..b6fa8ca1a 100644 --- a/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigPacket.java +++ b/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigPacket.java @@ -3,6 +3,7 @@ package com.simibubi.create.foundation.command; import java.util.function.Consumer; import java.util.function.Supplier; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import org.apache.logging.log4j.LogManager; import com.simibubi.create.content.contraptions.goggles.GoggleConfigScreen; @@ -61,6 +62,7 @@ public class ConfigureConfigPacket extends SimplePacketBase { overlayScreen(() -> Actions::overlayScreen), fixLighting(() -> Actions::experimentalLighting), overlayReset(() -> Actions::overlayReset), + experimentalRendering(() -> Actions::experimentalRendering), ; @@ -79,6 +81,14 @@ 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) { + if (!"".equals(value)) { + AllConfigs.CLIENT.experimentalRendering.set(Boolean.parseBoolean(value)); + } + FastRenderDispatcher.refresh(); + } @OnlyIn(Dist.CLIENT) private static void overlayReset(String value) { diff --git a/src/main/java/com/simibubi/create/foundation/command/ToggleExperimentalRenderingCommand.java b/src/main/java/com/simibubi/create/foundation/command/ToggleExperimentalRenderingCommand.java new file mode 100644 index 000000000..82f5442df --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/command/ToggleExperimentalRenderingCommand.java @@ -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 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; + })); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/config/CClient.java b/src/main/java/com/simibubi/create/foundation/config/CClient.java index 7954b2545..b243f0e9f 100644 --- a/src/main/java/com/simibubi/create/foundation/config/CClient.java +++ b/src/main/java/com/simibubi/create/foundation/config/CClient.java @@ -1,5 +1,7 @@ package com.simibubi.create.foundation.config; +import com.simibubi.create.foundation.render.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 ConfigBool experimentalRendering = + b(true, "experimentalRendering", "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"); public ConfigBool smoothPlacementIndicator = b(false, "smoothPlacementIndicator", "Use an alternative indicator when showing where the assisted placement ends up relative to your crosshair"); @@ -21,5 +26,4 @@ public class CClient extends ConfigBase { public String getName() { return "client"; } - } diff --git a/src/main/java/com/simibubi/create/foundation/mixin/CancelTileEntityRenderMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/CancelTileEntityRenderMixin.java new file mode 100644 index 000000000..ba76ddb6d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/mixin/CancelTileEntityRenderMixin.java @@ -0,0 +1,34 @@ +package com.simibubi.create.foundation.mixin; + +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; +import com.simibubi.create.foundation.render.backend.instancing.IInstanceRendered; +import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.List; + +@OnlyIn(Dist.CLIENT) +@Mixin(ChunkRenderDispatcher.CompiledChunk.class) +public class CancelTileEntityRenderMixin { + + /** + * JUSTIFICATION: when instanced rendering is enabled, many tile entities no longer need + * to be processed by the normal game renderer. This method is only called to retrieve the + * list of tile entities to render. By filtering the output here, we prevent the game from + * doing unnecessary light lookups and frustum checks. + */ + @Inject(at = @At("RETURN"), method = "getTileEntities", cancellable = true) + private void noRenderInstancedTiles(CallbackInfoReturnable> cir) { + if (FastRenderDispatcher.available()) { + List tiles = cir.getReturnValue(); + + tiles.removeIf(tile -> tile instanceof IInstanceRendered && !((IInstanceRendered) tile).shouldRenderAsTE()); + } + } +} diff --git a/src/main/java/com/simibubi/create/foundation/mixin/FogColorTrackerMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/FogColorTrackerMixin.java new file mode 100644 index 000000000..599cd50c7 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/mixin/FogColorTrackerMixin.java @@ -0,0 +1,20 @@ +package com.simibubi.create.foundation.mixin; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.foundation.render.backend.gl.GlFog; +import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(GlStateManager.class) +public class FogColorTrackerMixin { + + @Inject(at = @At("TAIL"), method = "fog") + private static void copyFogColor(int pname, float[] params, CallbackInfo ci) { + if (pname == GL11.GL_FOG_COLOR) { + GlFog.FOG_COLOR = params; + } + } +} diff --git a/src/main/java/com/simibubi/create/foundation/mixin/LightUpdateMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/LightUpdateMixin.java new file mode 100644 index 000000000..efc086daa --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/mixin/LightUpdateMixin.java @@ -0,0 +1,51 @@ +package com.simibubi.create.foundation.mixin; + +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; +import com.simibubi.create.foundation.render.backend.light.ILightListener; +import net.minecraft.client.multiplayer.ClientChunkProvider; +import net.minecraft.util.math.SectionPos; +import net.minecraft.world.ILightReader; +import net.minecraft.world.LightType; +import net.minecraft.world.chunk.AbstractChunkProvider; +import net.minecraft.world.chunk.Chunk; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Map; + +@OnlyIn(Dist.CLIENT) +@Mixin(ClientChunkProvider.class) +public abstract class LightUpdateMixin extends AbstractChunkProvider { + + /** + * JUSTIFICATION: This method is called after a lighting tick once per subchunk where a + * lighting change occurred that tick. On the client, Minecraft uses this method to inform + * the rendering system that it needs to redraw a chunk. It does all that work asynchronously, + * and we should too. + */ + @Inject(at = @At("HEAD"), method = "markLightChanged") + private void onLightUpdate(LightType type, SectionPos pos, CallbackInfo ci) { + ClientChunkProvider thi = ((ClientChunkProvider) (Object) this); + + Chunk chunk = thi.getChunk(pos.getSectionX(), pos.getSectionZ(), false); + + int sectionY = pos.getSectionY(); + + if (chunk != null) { + chunk.getTileEntityMap() + .entrySet() + .stream() + .filter(entry -> SectionPos.toChunk(entry.getKey().getY()) == sectionY) + .map(Map.Entry::getValue) + .filter(tile -> tile instanceof ILightListener) + .map(tile -> (ILightListener) tile) + .forEach(ILightListener::onChunkLightUpdate); + } + + ContraptionRenderDispatcher.notifyLightUpdate((ILightReader) thi.getWorld(), type, pos); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/mixin/OnRemoveTileMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/OnRemoveTileMixin.java new file mode 100644 index 000000000..1e9e13139 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/mixin/OnRemoveTileMixin.java @@ -0,0 +1,32 @@ +package com.simibubi.create.foundation.mixin; + +import com.simibubi.create.CreateClient; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +@OnlyIn(Dist.CLIENT) +@Mixin(World.class) +public class OnRemoveTileMixin { + + @Shadow @Final public boolean isRemote; + + /** + * JUSTIFICATION: This method is called whenever a tile entity is removed due + * to a change in block state, even on the client. By hooking into this method, + * we gain easy access to the information while having no impact on performance. + */ + @Inject(at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/world/World;getTileEntity(Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/tileentity/TileEntity;"), method = "removeTileEntity", locals = LocalCapture.CAPTURE_FAILHARD) + private void onRemoveTile(BlockPos pos, CallbackInfo ci, TileEntity te) { + if (isRemote) CreateClient.kineticRenderer.remove(te); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java new file mode 100644 index 000000000..c3fecc726 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java @@ -0,0 +1,61 @@ +package com.simibubi.create.foundation.mixin; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.CreateClient; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; +import com.simibubi.create.foundation.render.backend.Backend; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; +import com.simibubi.create.foundation.render.backend.OptifineHandler; +import net.minecraft.client.renderer.Matrix4f; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import org.lwjgl.opengl.GL20; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Set; + +@OnlyIn(Dist.CLIENT) +@Mixin(WorldRenderer.class) +public class RenderHooksMixin { + + @Shadow private ClientWorld world; + + /** + * JUSTIFICATION: This method is called once per layer per frame. It allows us to perform + * layer-correct custom rendering. RenderWorldLast is not refined enough for rendering world objects. + * This should probably be a forge event. + */ + @Inject(at = @At(value = "TAIL"), method = "renderLayer") + private void renderLayer(RenderType type, MatrixStack stack, double camX, double camY, double camZ, CallbackInfo ci) { + if (!Backend.available()) return; + + Matrix4f viewProjection = stack.peek().getModel().copy(); + viewProjection.multiplyBackward(FastRenderDispatcher.getProjectionMatrix()); + + FastRenderDispatcher.renderLayer(type, viewProjection, camX, camY, camZ); + + ContraptionRenderDispatcher.renderLayer(type, viewProjection, camX, camY, camZ); + + GL20.glUseProgram(0); + } + + @Inject(at = @At(value = "TAIL"), method = "loadRenderers") + private void refresh(CallbackInfo ci) { + CreateClient.kineticRenderer.invalidate(); + ContraptionRenderDispatcher.invalidateAll(); + OptifineHandler.refresh(); + Backend.refresh(); + + if (Backend.canUseInstancing() && world != null) world.loadedTileEntityList.forEach(CreateClient.kineticRenderer::add); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/mixin/ShaderCloseMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/ShaderCloseMixin.java new file mode 100644 index 000000000..c82406e20 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/mixin/ShaderCloseMixin.java @@ -0,0 +1,29 @@ +package com.simibubi.create.foundation.mixin; + +import com.simibubi.create.foundation.render.backend.OptifineHandler; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.VideoSettingsScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import javax.annotation.Nullable; + +@Mixin(Minecraft.class) +public class ShaderCloseMixin { + + @Shadow @Nullable public Screen currentScreen; + + @Inject(at = @At("HEAD"), method = "displayGuiScreen") + private void whenScreenChanges(Screen screen, CallbackInfo info) { + if (OptifineHandler.optifineInstalled() && screen instanceof VideoSettingsScreen) { + Screen old = this.currentScreen; + if (old != null && old.getClass().getName().startsWith(OptifineHandler.SHADER_PACKAGE)) { + OptifineHandler.refresh(); + } + } + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/AllProgramSpecs.java b/src/main/java/com/simibubi/create/foundation/render/AllProgramSpecs.java new file mode 100644 index 000000000..f447a156f --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/AllProgramSpecs.java @@ -0,0 +1,80 @@ +package com.simibubi.create.foundation.render; + +import com.simibubi.create.Create; +import com.simibubi.create.content.contraptions.base.KineticVertexAttributes; +import com.simibubi.create.content.contraptions.base.RotatingVertexAttributes; +import com.simibubi.create.content.contraptions.components.actors.ActorVertexAttributes; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionVertexAttributes; +import com.simibubi.create.content.contraptions.relays.belt.BeltVertexAttributes; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionProgram; +import com.simibubi.create.foundation.render.backend.gl.BasicProgram; +import com.simibubi.create.foundation.render.backend.gl.attrib.ModelVertexAttributes; +import com.simibubi.create.foundation.render.backend.gl.shader.ProgramSpec; +import com.simibubi.create.foundation.render.backend.gl.shader.ShaderConstants; +import net.minecraft.util.ResourceLocation; + +import static com.simibubi.create.foundation.render.backend.Backend.register; + +public class AllProgramSpecs { + public static final ProgramSpec ROTATING = register(ProgramSpec.builder("rotating", BasicProgram::new) + .addAttributes(ModelVertexAttributes.class) + .addAttributes(KineticVertexAttributes.class) + .addAttributes(RotatingVertexAttributes.class) + .setVert(Locations.ROTATING) + .setFrag(Locations.INSTANCED) + .createProgramSpec()); + + public static final ProgramSpec BELT = register(ProgramSpec.builder("belt", BasicProgram::new) + .addAttributes(ModelVertexAttributes.class) + .addAttributes(KineticVertexAttributes.class) + .addAttributes(BeltVertexAttributes.class) + .setVert(Locations.BELT) + .setFrag(Locations.INSTANCED) + .createProgramSpec()); + + public static final ProgramSpec CONTRAPTION_STRUCTURE = register(ProgramSpec.builder("contraption_structure", ContraptionProgram::new) + .addAttributes(ContraptionVertexAttributes.class) + .setVert(Locations.CONTRAPTION_STRUCTURE) + .setFrag(Locations.CONTRAPTION) + .createProgramSpec()); + + public static final ProgramSpec CONTRAPTION_ROTATING = register(ProgramSpec.builder("contraption_rotating", ContraptionProgram::new) + .addAttributes(ModelVertexAttributes.class) + .addAttributes(KineticVertexAttributes.class) + .addAttributes(RotatingVertexAttributes.class) + .setVert(Locations.ROTATING) + .setFrag(Locations.CONTRAPTION) + .setDefines(ShaderConstants.define("CONTRAPTION")) + .createProgramSpec()); + + public static final ProgramSpec CONTRAPTION_BELT = register(ProgramSpec.builder("contraption_belt", ContraptionProgram::new) + .addAttributes(ModelVertexAttributes.class) + .addAttributes(KineticVertexAttributes.class) + .addAttributes(BeltVertexAttributes.class) + .setVert(Locations.BELT) + .setFrag(Locations.CONTRAPTION) + .setDefines(ShaderConstants.define("CONTRAPTION")) + .createProgramSpec()); + + public static final ProgramSpec CONTRAPTION_ACTOR = register(ProgramSpec.builder("contraption_actor", ContraptionProgram::new) + .addAttributes(ModelVertexAttributes.class) + .addAttributes(ActorVertexAttributes.class) + .setVert(Locations.CONTRAPTION_ACTOR) + .setFrag(Locations.CONTRAPTION) + .createProgramSpec()); + + public static class Locations { + public static final ResourceLocation INSTANCED = loc("instanced.frag"); + public static final ResourceLocation CONTRAPTION = loc("contraption.frag"); + + public static final ResourceLocation ROTATING = loc("rotating.vert"); + public static final ResourceLocation BELT = loc("belt.vert"); + public static final ResourceLocation CONTRAPTION_STRUCTURE = loc("contraption_structure.vert"); + public static final ResourceLocation CONTRAPTION_ACTOR = loc("contraption_actor.vert"); + + + private static ResourceLocation loc(String name) { + return new ResourceLocation(Create.ID, "shader/" + name); + } + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/Compartment.java b/src/main/java/com/simibubi/create/foundation/render/Compartment.java new file mode 100644 index 000000000..646eb7191 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/Compartment.java @@ -0,0 +1,12 @@ +package com.simibubi.create.foundation.render; + +import com.simibubi.create.AllBlockPartials; +import net.minecraft.block.BlockState; +import net.minecraft.util.Direction; +import org.apache.commons.lang3.tuple.Pair; + +public class Compartment { + public static final Compartment GENERIC_TILE = new Compartment<>(); + public static final Compartment PARTIAL = new Compartment<>(); + public static final Compartment> DIRECTIONAL_PARTIAL = new Compartment<>(); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/KineticRenderer.java b/src/main/java/com/simibubi/create/foundation/render/KineticRenderer.java new file mode 100644 index 000000000..40e9de47a --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/KineticRenderer.java @@ -0,0 +1,76 @@ +package com.simibubi.create.foundation.render; + +import com.simibubi.create.content.contraptions.base.KineticRenderMaterials; +import com.simibubi.create.content.contraptions.base.RotatingInstancedModel; +import com.simibubi.create.content.contraptions.relays.belt.BeltInstancedModel; +import com.simibubi.create.foundation.render.backend.gl.BasicProgram; +import com.simibubi.create.foundation.render.backend.gl.shader.ShaderCallback; +import com.simibubi.create.foundation.render.backend.instancing.*; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.Matrix4f; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.Entity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; + +import java.util.ArrayList; + +public class KineticRenderer extends InstancedTileRenderer { + public static int MAX_ORIGIN_DISTANCE = 1000; + + public BlockPos originCoordinate = BlockPos.ZERO; + + @Override + public void registerMaterials() { + materials.put(KineticRenderMaterials.BELTS, new RenderMaterial<>(this, AllProgramSpecs.BELT, BeltInstancedModel::new)); + materials.put(KineticRenderMaterials.ROTATING, new RenderMaterial<>(this, AllProgramSpecs.ROTATING, RotatingInstancedModel::new)); + } + + @Override + public BlockPos getOriginCoordinate() { + return originCoordinate; + } + + @Override + public void tick() { + super.tick(); + + Minecraft mc = Minecraft.getInstance(); + Entity renderViewEntity = mc.renderViewEntity; + + if (renderViewEntity == null) return; + + BlockPos renderViewPosition = renderViewEntity.getPosition(); + + int dX = Math.abs(renderViewPosition.getX() - originCoordinate.getX()); + int dY = Math.abs(renderViewPosition.getY() - originCoordinate.getY()); + int dZ = Math.abs(renderViewPosition.getZ() - originCoordinate.getZ()); + + if (dX > MAX_ORIGIN_DISTANCE || + dY > MAX_ORIGIN_DISTANCE || + dZ > MAX_ORIGIN_DISTANCE) { + + originCoordinate = renderViewPosition; + + ArrayList instancedTiles = new ArrayList<>(instances.keySet()); + invalidate(); + instancedTiles.forEach(this::add); + } + } + + @Override + public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ, ShaderCallback callback) { + BlockPos originCoordinate = getOriginCoordinate(); + + camX -= originCoordinate.getX(); + camY -= originCoordinate.getY(); + camZ -= originCoordinate.getZ(); + + Matrix4f translate = Matrix4f.translate((float) -camX, (float) -camY, (float) -camZ); + + translate.multiplyBackward(viewProjection); + + super.render(layer, translate, camX, camY, camZ, callback); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/RenderMath.java b/src/main/java/com/simibubi/create/foundation/render/RenderMath.java new file mode 100644 index 000000000..3839ff718 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/RenderMath.java @@ -0,0 +1,13 @@ +package com.simibubi.create.foundation.render; + +public class RenderMath { + public static int nextPowerOf2(int a) { + int h = Integer.highestOneBit(a); + return (h == a) ? h : (h << 1); + } + + public static boolean isPowerOf2(int n) { + int b = n & (n - 1); + return b == 0 && n != 0; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/ShadowRenderHelper.java b/src/main/java/com/simibubi/create/foundation/render/ShadowRenderHelper.java similarity index 98% rename from src/main/java/com/simibubi/create/foundation/utility/ShadowRenderHelper.java rename to src/main/java/com/simibubi/create/foundation/render/ShadowRenderHelper.java index 0a8f5349a..c42a78ae0 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/ShadowRenderHelper.java +++ b/src/main/java/com/simibubi/create/foundation/render/ShadowRenderHelper.java @@ -1,4 +1,4 @@ -package com.simibubi.create.foundation.utility; +package com.simibubi.create.foundation.render; import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.vertex.IVertexBuilder; diff --git a/src/main/java/com/simibubi/create/foundation/utility/SuperByteBuffer.java b/src/main/java/com/simibubi/create/foundation/render/SuperByteBuffer.java similarity index 58% rename from src/main/java/com/simibubi/create/foundation/utility/SuperByteBuffer.java rename to src/main/java/com/simibubi/create/foundation/render/SuperByteBuffer.java index d7c8b0569..90d7b54db 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/SuperByteBuffer.java +++ b/src/main/java/com/simibubi/create/foundation/render/SuperByteBuffer.java @@ -1,48 +1,39 @@ -package com.simibubi.create.foundation.utility; - -import java.nio.Buffer; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; +package com.simibubi.create.foundation.render; import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.vertex.IVertexBuilder; -import com.mojang.datafixers.util.Pair; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.foundation.block.render.SpriteShiftEntry; - import it.unimi.dsi.fastutil.longs.Long2DoubleMap; import it.unimi.dsi.fastutil.longs.Long2DoubleOpenHashMap; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.BufferBuilder.DrawState; -import net.minecraft.client.renderer.GLAllocation; -import net.minecraft.client.renderer.Matrix4f; -import net.minecraft.client.renderer.Vector4f; +import net.minecraft.client.renderer.*; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.LightType; import net.minecraft.world.World; +import net.minecraftforge.client.model.pipeline.LightUtil; -public class SuperByteBuffer { +import java.nio.Buffer; +import java.nio.ByteBuffer; + +public class SuperByteBuffer extends TemplateBuffer { public interface IVertexLighter { public int getPackedLight(float x, float y, float z); } - protected ByteBuffer template; - protected int formatSize; - // Vertex Position private MatrixStack transforms; // Vertex Texture Coords - private boolean shouldShiftUV; - private SpriteShiftEntry spriteShift; - private float uTarget, vTarget; + private SpriteShiftFunc spriteShiftFunc; // Vertex Lighting private boolean shouldLight; private int packedLightCoords; + private int otherBlockLight; private Matrix4f lightTransform; // Vertex Coloring @@ -51,21 +42,7 @@ public class SuperByteBuffer { private float sheetSize; public SuperByteBuffer(BufferBuilder buf) { - Pair state = buf.popData(); - ByteBuffer rendered = state.getSecond(); - rendered.order(ByteOrder.nativeOrder()); // Vanilla bug, endianness does not carry over into sliced buffers - - formatSize = buf.getVertexFormat() - .getSize(); - int size = state.getFirst() - .getCount() * formatSize; - - template = GLAllocation.createDirectByteBuffer(size); - template.order(rendered.order()); - ((Buffer) template).limit(((Buffer) rendered).limit()); - template.put(rendered); - ((Buffer) template).rewind(); - + super(buf); transforms = new MatrixStack(); } @@ -82,6 +59,7 @@ public class SuperByteBuffer { private static final Long2DoubleMap skyLightCache = new Long2DoubleOpenHashMap(); private static final Long2DoubleMap blockLightCache = new Long2DoubleOpenHashMap(); Vector4f pos = new Vector4f(); + Vector3f normal = new Vector3f(); Vector4f lightPos = new Vector4f(); public void renderInto(MatrixStack input, IVertexBuilder builder) { @@ -90,12 +68,18 @@ public class SuperByteBuffer { return; ((Buffer) buffer).rewind(); - Matrix4f t = input.peek() - .getModel() - .copy(); + Matrix3f normalMat = transforms.peek() + .getNormal() + .copy(); + //normalMat.multiply(transforms.peek().getNormal()); + + Matrix4f modelMat = input.peek() + .getModel() + .copy(); + Matrix4f localTransforms = transforms.peek() - .getModel(); - t.multiply(localTransforms); + .getModel(); + modelMat.multiply(localTransforms); if (shouldLight && lightTransform != null) { skyLightCache.clear(); @@ -112,26 +96,39 @@ public class SuperByteBuffer { byte g = getG(buffer, i); byte b = getB(buffer, i); byte a = getA(buffer, i); + float normalX = getNX(buffer, i) / 127f; + float normalY = getNY(buffer, i) / 127f; + float normalZ = getNZ(buffer, i) / 127f; + + float staticDiffuse = LightUtil.diffuseLight(normalX, normalY, normalZ); + normal.set(normalX, normalY, normalZ); + normal.transform(normalMat); + float instanceDiffuse = LightUtil.diffuseLight(normal.getX(), normal.getY(), normal.getZ()); pos.set(x, y, z, 1F); - pos.transform(t); + pos.transform(modelMat); builder.vertex(pos.getX(), pos.getY(), pos.getZ()); + //builder.color((byte) Math.max(0, normal.getX() * 255), (byte) Math.max(0, normal.getY() * 255), (byte) Math.max(0, normal.getZ() * 255), a); if (shouldColor) { - float lum = (r < 0 ? 255 + r : r) / 256f; - builder.color((int) (this.r * lum), (int) (this.g * lum), (int) (this.b * lum), this.a); - } else - builder.color(r, g, b, a); + //float lum = (r < 0 ? 255 + r : r) / 256f; + int colorR = Math.min(255, (int) (((float) this.r) * instanceDiffuse)); + int colorG = Math.min(255, (int) (((float) this.g) * instanceDiffuse)); + int colorB = Math.min(255, (int) (((float) this.b) * instanceDiffuse)); + builder.color(colorR, colorG, colorB, this.a); + } else { + float diffuseMult = instanceDiffuse / staticDiffuse; + int colorR = Math.min(255, (int) (((float) Byte.toUnsignedInt(r)) * diffuseMult)); + int colorG = Math.min(255, (int) (((float) Byte.toUnsignedInt(g)) * diffuseMult)); + int colorB = Math.min(255, (int) (((float) Byte.toUnsignedInt(b)) * diffuseMult)); + builder.color(colorR, colorG, colorB, a); + } float u = getU(buffer, i); float v = getV(buffer, i); - if (shouldShiftUV) { - float targetU = spriteShift.getTarget() - .getInterpolatedU((getUnInterpolatedU(spriteShift.getOriginal(), u) / sheetSize) + uTarget * 16); - float targetV = spriteShift.getTarget() - .getInterpolatedV((getUnInterpolatedV(spriteShift.getOriginal(), v) / sheetSize) + vTarget * 16); - builder.texture(targetU, targetV); + if (spriteShiftFunc != null) { + spriteShiftFunc.shift(builder, u, v); } else builder.texture(u, v); @@ -141,20 +138,26 @@ public class SuperByteBuffer { lightPos.set(((x - f) * 15 / 16f) + f, (y - f) * 15 / 16f + f, (z - f) * 15 / 16f + f, 1F); lightPos.transform(localTransforms); lightPos.transform(lightTransform); + light = getLight(Minecraft.getInstance().world, lightPos); + if (otherBlockLight >= 0) { + light = ContraptionRenderDispatcher.getMaxBlockLight(light, otherBlockLight); + } } builder.light(light); } else builder.light(getLight(buffer, i)); - builder.normal(getNX(buffer, i), getNY(buffer, i), getNZ(buffer, i)) + builder.normal(normal.getX(), normal.getY(), normal.getZ()) .endVertex(); } transforms = new MatrixStack(); - shouldShiftUV = false; + + spriteShiftFunc = null; shouldColor = false; shouldLight = false; + otherBlockLight = -1; } public SuperByteBuffer translate(double x, double y, double z) { @@ -180,20 +183,29 @@ public class SuperByteBuffer { } public SuperByteBuffer shiftUV(SpriteShiftEntry entry) { - shouldShiftUV = true; - spriteShift = entry; - uTarget = 0; - vTarget = 0; - sheetSize = 1; + this.spriteShiftFunc = (builder, u, v) -> { + float targetU = entry.getTarget().getInterpolatedU((getUnInterpolatedU(entry.getOriginal(), u))); + float targetV = entry.getTarget().getInterpolatedV((getUnInterpolatedV(entry.getOriginal(), v))); + builder.texture(targetU, targetV); + }; + return this; + } + + public SuperByteBuffer shiftUVScrolling(SpriteShiftEntry entry, float scrollV) { + this.spriteShiftFunc = (builder, u, v) -> { + float targetU = u - entry.getOriginal().getMinU() + entry.getTarget().getMinU(); + float targetV = v - entry.getOriginal().getMinV() + entry.getTarget().getMinV() + scrollV; + builder.texture(targetU, targetV); + }; return this; } public SuperByteBuffer shiftUVtoSheet(SpriteShiftEntry entry, float uTarget, float vTarget, int sheetSize) { - shouldShiftUV = true; - spriteShift = entry; - this.uTarget = uTarget; - this.vTarget = vTarget; - this.sheetSize = sheetSize; + this.spriteShiftFunc = (builder, u, v) -> { + float targetU = entry.getTarget().getInterpolatedU((getUnInterpolatedU(entry.getOriginal(), u) / sheetSize) + uTarget * 16); + float targetV = entry.getTarget().getInterpolatedV((getUnInterpolatedV(entry.getOriginal(), v) / sheetSize) + vTarget * 16); + builder.texture(targetU, targetV); + }; return this; } @@ -210,6 +222,13 @@ public class SuperByteBuffer { return this; } + public SuperByteBuffer light(Matrix4f lightTransform, int otherBlockLight) { + shouldLight = true; + this.lightTransform = lightTransform; + this.otherBlockLight = otherBlockLight; + return this; + } + public SuperByteBuffer color(int color) { shouldColor = true; r = ((color >> 16) & 0xFF); @@ -219,66 +238,6 @@ public class SuperByteBuffer { return this; } - protected int vertexCount(ByteBuffer buffer) { - return ((Buffer) buffer).limit() / formatSize; - } - - protected int getBufferPosition(int vertexIndex) { - return vertexIndex * formatSize; - } - - protected float getX(ByteBuffer buffer, int index) { - return buffer.getFloat(getBufferPosition(index)); - } - - protected float getY(ByteBuffer buffer, int index) { - return buffer.getFloat(getBufferPosition(index) + 4); - } - - protected float getZ(ByteBuffer buffer, int index) { - return buffer.getFloat(getBufferPosition(index) + 8); - } - - protected byte getR(ByteBuffer buffer, int index) { - return buffer.get(getBufferPosition(index) + 12); - } - - protected byte getG(ByteBuffer buffer, int index) { - return buffer.get(getBufferPosition(index) + 13); - } - - protected byte getB(ByteBuffer buffer, int index) { - return buffer.get(getBufferPosition(index) + 14); - } - - protected byte getA(ByteBuffer buffer, int index) { - return buffer.get(getBufferPosition(index) + 15); - } - - protected float getU(ByteBuffer buffer, int index) { - return buffer.getFloat(getBufferPosition(index) + 16); - } - - protected float getV(ByteBuffer buffer, int index) { - return buffer.getFloat(getBufferPosition(index) + 20); - } - - protected int getLight(ByteBuffer buffer, int index) { - return buffer.getInt(getBufferPosition(index) + 24); - } - - protected byte getNX(ByteBuffer buffer, int index) { - return buffer.get(getBufferPosition(index) + 28); - } - - protected byte getNY(ByteBuffer buffer, int index) { - return buffer.get(getBufferPosition(index) + 29); - } - - protected byte getNZ(ByteBuffer buffer, int index) { - return buffer.get(getBufferPosition(index) + 30); - } - private static int getLight(World world, Vector4f lightPos) { BlockPos.Mutable pos = new BlockPos.Mutable(); double sky = 0, block = 0; @@ -301,4 +260,9 @@ public class SuperByteBuffer { return ((Buffer) template).limit() == 0; } + @FunctionalInterface + public interface SpriteShiftFunc { + void shift(IVertexBuilder builder, float u, float v); + } + } diff --git a/src/main/java/com/simibubi/create/foundation/utility/SuperByteBufferCache.java b/src/main/java/com/simibubi/create/foundation/render/SuperByteBufferCache.java similarity index 76% rename from src/main/java/com/simibubi/create/foundation/utility/SuperByteBufferCache.java rename to src/main/java/com/simibubi/create/foundation/render/SuperByteBufferCache.java index f37b65912..ab9e0fafa 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/SuperByteBufferCache.java +++ b/src/main/java/com/simibubi/create/foundation/render/SuperByteBufferCache.java @@ -1,11 +1,11 @@ -package com.simibubi.create.foundation.utility; +package com.simibubi.create.foundation.render; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; +import com.simibubi.create.foundation.utility.VirtualEmptyModelData; import org.apache.commons.lang3.tuple.Pair; import org.lwjgl.opengl.GL11; @@ -27,20 +27,13 @@ import net.minecraft.util.math.BlockPos; public class SuperByteBufferCache { - public static class Compartment { - } - - public static final Compartment GENERIC_TILE = new Compartment<>(); - public static final Compartment PARTIAL = new Compartment<>(); - public static final Compartment> DIRECTIONAL_PARTIAL = new Compartment<>(); - Map, Cache> cache; public SuperByteBufferCache() { cache = new HashMap<>(); - registerCompartment(GENERIC_TILE); - registerCompartment(PARTIAL); - registerCompartment(DIRECTIONAL_PARTIAL); + registerCompartment(Compartment.GENERIC_TILE); + registerCompartment(Compartment.PARTIAL); + registerCompartment(Compartment.DIRECTIONAL_PARTIAL); } public SuperByteBuffer renderBlock(BlockState toRender) { @@ -48,24 +41,23 @@ public class SuperByteBufferCache { } public SuperByteBuffer renderPartial(AllBlockPartials partial, BlockState referenceState) { - return get(PARTIAL, partial, () -> standardModelRender(partial.get(), referenceState)); + return get(Compartment.PARTIAL, partial, () -> standardModelRender(partial.get(), referenceState)); } - public SuperByteBuffer renderPartial(AllBlockPartials partial, BlockState referenceState, MatrixStack modelTransform) { - return get(PARTIAL, partial, () -> standardModelRender(partial.get(), referenceState, modelTransform)); + return get(Compartment.PARTIAL, partial, () -> standardModelRender(partial.get(), referenceState, modelTransform)); } public SuperByteBuffer renderDirectionalPartial(AllBlockPartials partial, BlockState referenceState, Direction dir) { - return get(DIRECTIONAL_PARTIAL, Pair.of(dir, partial), - () -> standardModelRender(partial.get(), referenceState)); + return get(Compartment.DIRECTIONAL_PARTIAL, Pair.of(dir, partial), + () -> standardModelRender(partial.get(), referenceState)); } public SuperByteBuffer renderDirectionalPartial(AllBlockPartials partial, BlockState referenceState, Direction dir, MatrixStack modelTransform) { - return get(DIRECTIONAL_PARTIAL, Pair.of(dir, partial), - () -> standardModelRender(partial.get(), referenceState, modelTransform)); + return get(Compartment.DIRECTIONAL_PARTIAL, Pair.of(dir, partial), + () -> standardModelRender(partial.get(), referenceState, modelTransform)); } public SuperByteBuffer renderBlockIn(Compartment compartment, BlockState toRender) { @@ -73,7 +65,7 @@ public class SuperByteBufferCache { } SuperByteBuffer getGeneric(BlockState key, Supplier supplier) { - return get(GENERIC_TILE, key, supplier); + return get(Compartment.GENERIC_TILE, key, supplier); } public SuperByteBuffer get(Compartment compartment, T key, Supplier supplier) { @@ -108,19 +100,24 @@ public class SuperByteBufferCache { } private SuperByteBuffer standardModelRender(IBakedModel model, BlockState referenceState, MatrixStack ms) { + BufferBuilder builder = getBufferBuilder(model, referenceState, ms); + + return new SuperByteBuffer(builder); + } + + public static BufferBuilder getBufferBuilder(IBakedModel model, BlockState referenceState, MatrixStack ms) { Minecraft mc = Minecraft.getInstance(); BlockRendererDispatcher dispatcher = mc.getBlockRendererDispatcher(); BlockModelRenderer blockRenderer = dispatcher.getBlockModelRenderer(); BufferBuilder builder = new BufferBuilder(512); builder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK); - blockRenderer.renderModel(mc.world, model, referenceState, BlockPos.ZERO.up(255), ms, builder, true, - mc.world.rand, 42, OverlayTexture.DEFAULT_UV, VirtualEmptyModelData.INSTANCE); + blockRenderer.renderModel(mc.world, model, referenceState, BlockPos.ZERO.up(255), ms, builder, true, mc.world.rand, 42, OverlayTexture.DEFAULT_UV, VirtualEmptyModelData.INSTANCE); builder.finishDrawing(); - - return new SuperByteBuffer(builder); + return builder; } + public void invalidate() { cache.forEach((comp, cache) -> cache.invalidateAll()); } diff --git a/src/main/java/com/simibubi/create/foundation/render/TemplateBuffer.java b/src/main/java/com/simibubi/create/foundation/render/TemplateBuffer.java new file mode 100644 index 000000000..d16702d08 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/TemplateBuffer.java @@ -0,0 +1,95 @@ +package com.simibubi.create.foundation.render; + +import com.mojang.datafixers.util.Pair; +import net.minecraft.client.renderer.BufferBuilder; + +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class TemplateBuffer { + protected ByteBuffer template; + protected int formatSize; + protected int vertexCount; + + public TemplateBuffer(BufferBuilder buf) { + Pair state = buf.popData(); + ByteBuffer rendered = state.getSecond(); + rendered.order(ByteOrder.nativeOrder()); // Vanilla bug, endianness does not carry over into sliced buffers + + formatSize = buf.getVertexFormat() + .getSize(); + vertexCount = state.getFirst().getCount(); + int size = vertexCount * formatSize; + + template = ByteBuffer.allocate(size); + template.order(rendered.order()); + ((Buffer)template).limit(((Buffer)rendered).limit()); + template.put(rendered); + ((Buffer)template).rewind(); + } + + public boolean isEmpty() { + return ((Buffer) template).limit() == 0; + } + + protected int vertexCount(ByteBuffer buffer) { + return ((Buffer)buffer).limit() / formatSize; + } + + protected int getBufferPosition(int vertexIndex) { + return vertexIndex * formatSize; + } + + protected float getX(ByteBuffer buffer, int index) { + return buffer.getFloat(getBufferPosition(index)); + } + + protected float getY(ByteBuffer buffer, int index) { + return buffer.getFloat(getBufferPosition(index) + 4); + } + + protected float getZ(ByteBuffer buffer, int index) { + return buffer.getFloat(getBufferPosition(index) + 8); + } + + protected byte getR(ByteBuffer buffer, int index) { + return buffer.get(getBufferPosition(index) + 12); + } + + protected byte getG(ByteBuffer buffer, int index) { + return buffer.get(getBufferPosition(index) + 13); + } + + protected byte getB(ByteBuffer buffer, int index) { + return buffer.get(getBufferPosition(index) + 14); + } + + protected byte getA(ByteBuffer buffer, int index) { + return buffer.get(getBufferPosition(index) + 15); + } + + protected float getU(ByteBuffer buffer, int index) { + return buffer.getFloat(getBufferPosition(index) + 16); + } + + protected float getV(ByteBuffer buffer, int index) { + return buffer.getFloat(getBufferPosition(index) + 20); + } + + protected int getLight(ByteBuffer buffer, int index) { + return buffer.getInt(getBufferPosition(index) + 24); + } + + protected byte getNX(ByteBuffer buffer, int index) { + return buffer.get(getBufferPosition(index) + 28); + } + + protected byte getNY(ByteBuffer buffer, int index) { + return buffer.get(getBufferPosition(index) + 29); + } + + protected byte getNZ(ByteBuffer buffer, int index) { + return buffer.get(getBufferPosition(index) + 30); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/TileEntityRenderHelper.java b/src/main/java/com/simibubi/create/foundation/render/TileEntityRenderHelper.java similarity index 62% rename from src/main/java/com/simibubi/create/foundation/utility/TileEntityRenderHelper.java rename to src/main/java/com/simibubi/create/foundation/render/TileEntityRenderHelper.java index ea9e6e361..45f4667d6 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/TileEntityRenderHelper.java +++ b/src/main/java/com/simibubi/create/foundation/render/TileEntityRenderHelper.java @@ -1,16 +1,13 @@ -package com.simibubi.create.foundation.utility; - -import java.util.Iterator; +package com.simibubi.create.foundation.render; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.Create; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.foundation.config.AllConfigs; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.Matrix4f; -import net.minecraft.client.renderer.Vector4f; -import net.minecraft.client.renderer.WorldRenderer; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.MatrixStacker; +import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld; +import net.minecraft.client.renderer.*; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; @@ -18,17 +15,26 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import java.util.Iterator; + public class TileEntityRenderHelper { public static void renderTileEntities(World world, Iterable customRenderTEs, MatrixStack ms, MatrixStack localTransform, IRenderTypeBuffer buffer) { - float pt = Minecraft.getInstance() - .getRenderPartialTicks(); + + renderTileEntities(world, null, customRenderTEs, ms, localTransform, buffer); + } + + public static void renderTileEntities(World world, PlacementSimulationWorld renderWorld, Iterable customRenderTEs, MatrixStack ms, + MatrixStack localTransform, IRenderTypeBuffer buffer) { + float pt = AnimationTickHolder.getPartialTicks(); Matrix4f matrix = localTransform.peek() .getModel(); for (Iterator iterator = customRenderTEs.iterator(); iterator.hasNext();) { TileEntity tileEntity = iterator.next(); + //if (tileEntity instanceof IInstanceRendered) continue; // TODO: some things still need to render + TileEntityRenderer renderer = TileEntityRendererDispatcher.instance.getRenderer(tileEntity); if (renderer == null) { iterator.remove(); @@ -44,8 +50,10 @@ public class TileEntityRenderHelper { Vector4f vec = new Vector4f(pos.getX() + .5f, pos.getY() + .5f, pos.getZ() + .5f, 1); vec.transform(matrix); BlockPos lightPos = new BlockPos(vec.getX(), vec.getY(), vec.getZ()); - renderer.render(tileEntity, pt, ms, buffer, WorldRenderer.getLightmapCoordinates(world, lightPos), - OverlayTexture.DEFAULT_UV); + int worldLight = ContraptionRenderDispatcher.getLightOnContraption(world, renderWorld, pos, lightPos); + + renderer.render(tileEntity, pt, ms, buffer, worldLight, + OverlayTexture.DEFAULT_UV); ms.pop(); } catch (Exception e) { diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/Backend.java b/src/main/java/com/simibubi/create/foundation/render/backend/Backend.java new file mode 100644 index 000000000..5218b3a98 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/Backend.java @@ -0,0 +1,192 @@ +package com.simibubi.create.foundation.render.backend; + +import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.render.backend.gl.shader.GlProgram; +import com.simibubi.create.foundation.render.backend.gl.shader.GlShader; +import com.simibubi.create.foundation.render.backend.gl.shader.ProgramSpec; +import com.simibubi.create.foundation.render.backend.gl.shader.ShaderType; +import com.simibubi.create.foundation.render.backend.gl.versioned.GlVersioned; +import com.simibubi.create.foundation.render.backend.gl.versioned.MapBuffer; +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 { + public static final Logger log = LogManager.getLogger(Backend.class); + public static final FloatBuffer MATRIX_BUFFER = MemoryUtil.memAllocFloat(16); + + private static final Map> registry = new HashMap<>(); + private static final Map, GlProgram> programs = new HashMap<>(); + + private static boolean enabled; + + public static GLCapabilities capabilities; + private static MapBuffer mapBuffer; + + public Backend() { + throw new IllegalStateException(); + } + + public static void mapBuffer(int target, int offset, int length, Consumer upload) { + mapBuffer.mapBuffer(target, offset, length, upload); + } + + /** + * Register a shader program. TODO: replace with forge registry? + */ + public static

> 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 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 The type of the versioning enum. + * @return The first defined enum variant to return true. + */ + public static & GlVersioned> V getLatest(Class 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 The type of the versioning enum. + * @return The first defined enum variant to return true. + */ + public static & GlVersioned> V getLatest(Class 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 boolean canUseInstancing() { + return enabled && gl33(); + } + + public static boolean canUseVBOs() { + return enabled && gl20(); + } + + public static boolean available() { + return enabled && gl20(); + } + + public static boolean gl33() { + return capabilities.OpenGL33; + } + + public static boolean gl20() { + return capabilities.OpenGL20; + } + + 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) return; + + IResourceManager manager = mc.getResourceManager(); + + if (manager instanceof IReloadableResourceManager) { + ISelectiveResourceReloadListener listener = Backend::onResourceManagerReload; + ((IReloadableResourceManager) manager).addReloadListener(listener); + } + } + + private static void onResourceManagerReload(IResourceManager manager, Predicate predicate) { + if (predicate.test(VanillaResourceType.SHADERS)) { + capabilities = GL.createCapabilities(); + mapBuffer = getLatest(MapBuffer.class); + + OptifineHandler.refresh(); + refresh(); + + if (gl20()) { + + programs.values().forEach(GlProgram::delete); + programs.clear(); + for (ProgramSpec shader : registry.values()) { + loadProgram(manager, shader); + } + } + } + } + + public static void refresh() { + enabled = AllConfigs.CLIENT.experimentalRendering.get() && !OptifineHandler.usingShaders(); + } + + private static

> 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); + + GlProgram.Builder builder = GlProgram.builder(programSpec.name).attachShader(vert).attachShader(frag); + + programSpec.attributes.forEach(builder::addAttribute); + + P program = builder.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); + } + } + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/BufferedModel.java b/src/main/java/com/simibubi/create/foundation/render/backend/BufferedModel.java new file mode 100644 index 000000000..d209fd857 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/BufferedModel.java @@ -0,0 +1,122 @@ +package com.simibubi.create.foundation.render.backend; + +import com.simibubi.create.foundation.render.TemplateBuffer; +import com.simibubi.create.foundation.render.backend.gl.GlPrimitiveType; +import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; +import com.simibubi.create.foundation.render.backend.gl.GlBuffer; +import net.minecraft.client.renderer.BufferBuilder; +import org.lwjgl.opengl.GL15; +import org.lwjgl.opengl.GL20; + +import java.nio.ByteBuffer; + +public abstract class BufferedModel extends TemplateBuffer { + + protected GlBuffer ebo; + protected GlBuffer modelVBO; + protected boolean removed; + + public BufferedModel(BufferBuilder buf) { + super(buf); + if (vertexCount > 0) init(); + } + + protected void init() { + + modelVBO = new GlBuffer(GL20.GL_ARRAY_BUFFER); + + modelVBO.with(vbo -> initModel()); + + ebo = createEBO(); + } + + protected void initModel() { + int stride = getModelFormat().getStride(); + int invariantSize = vertexCount * stride; + + // allocate the buffer on the gpu + GL15.glBufferData(GL15.GL_ARRAY_BUFFER, invariantSize, GL15.GL_STATIC_DRAW); + + // mirror it in system memory so we can write to it + modelVBO.map(invariantSize, buffer -> { + for (int i = 0; i < vertexCount; i++) { + copyVertex(buffer, i); + } + }); + } + + protected final GlBuffer createEBO() { + GlBuffer ebo = new GlBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER); + + int indicesSize = vertexCount * GlPrimitiveType.USHORT.getSize(); + + ebo.bind(); + + GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indicesSize, GL15.GL_STATIC_DRAW); + ebo.map(indicesSize, indices -> { + for (int i = 0; i < vertexCount; i++) { + indices.putShort((short) i); + } + }); + + ebo.unbind(); + + return ebo; + } + + protected abstract void copyVertex(ByteBuffer to, int index); + + protected abstract VertexFormat getModelFormat(); + + protected int getTotalShaderAttributeCount() { + return getModelFormat().getShaderAttributeCount(); + } + + /** + * Renders this model, checking first if it should actually be rendered. + */ + public final void render() { + if (vertexCount == 0 || removed) return; + + doRender(); + } + + /** + * Override this. + */ + protected void doRender() { + modelVBO.bind(); + ebo.bind(); + + setupAttributes(); + GL20.glDrawElements(GL20.GL_QUADS, vertexCount, GlPrimitiveType.USHORT.getGlConstant(), 0); + + int numAttributes = getTotalShaderAttributeCount(); + for (int i = 0; i <= numAttributes; i++) { + GL20.glDisableVertexAttribArray(i); + } + + ebo.unbind(); + modelVBO.unbind(); + } + + protected void setupAttributes() { + int numAttributes = getTotalShaderAttributeCount(); + for (int i = 0; i <= numAttributes; i++) { + GL20.glEnableVertexAttribArray(i); + } + + getModelFormat().vertexAttribPointers(0); + } + + public void delete() { + removed = true; + if (vertexCount > 0) { + RenderWork.enqueue(this::deleteInternal); + } + } + + protected void deleteInternal() { + modelVBO.delete(); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/FastRenderDispatcher.java b/src/main/java/com/simibubi/create/foundation/render/backend/FastRenderDispatcher.java new file mode 100644 index 000000000..4e7955e85 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/FastRenderDispatcher.java @@ -0,0 +1,126 @@ +package com.simibubi.create.foundation.render.backend; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import com.simibubi.create.CreateClient; +import com.simibubi.create.content.contraptions.KineticDebugger; +import com.simibubi.create.content.schematics.SchematicWorld; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.WorldAttached; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.player.ClientPlayerEntity; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.Matrix4f; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.Vector3f; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.potion.Effects; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; +import org.lwjgl.opengl.GL11; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; + +public class FastRenderDispatcher { + + public static WorldAttached> queuedUpdates = new WorldAttached<>(ConcurrentHashMap::newKeySet); + + private static Matrix4f projectionMatrixThisFrame = null; + + public static void endFrame() { + projectionMatrixThisFrame = null; + } + + public static void enqueueUpdate(TileEntity te) { + queuedUpdates.get(te.getWorld()).add(te); + } + + public static void tick() { + ClientWorld world = Minecraft.getInstance().world; + + CreateClient.kineticRenderer.tick(); + + ConcurrentHashMap.KeySetView map = queuedUpdates.get(world); + map + .forEach(te -> { + map.remove(te); + + CreateClient.kineticRenderer.update(te); + }); + } + + public static boolean available() { + return Backend.canUseInstancing(); + } + + public static boolean available(World world) { + return Backend.canUseInstancing() && !(world instanceof SchematicWorld); + } + + public static int getDebugMode() { + return KineticDebugger.isActive() ? 1 : 0; + } + + public static void refresh() { + RenderWork.enqueue(Minecraft.getInstance().worldRenderer::loadRenderers); + } + + public static void renderLayer(RenderType layer, Matrix4f viewProjection, double cameraX, double cameraY, double cameraZ) { + if (!Backend.canUseInstancing()) return; + + layer.startDrawing(); + + RenderSystem.enableDepthTest(); + RenderSystem.enableCull(); + GL11.glCullFace(GL11.GL_BACK); + CreateClient.kineticRenderer.render(layer, viewProjection, cameraX, cameraY, cameraZ); + RenderSystem.disableCull(); + //RenderSystem.disableDepthTest(); + + layer.endDrawing(); + } + + // copied from GameRenderer.renderWorld + public static Matrix4f getProjectionMatrix() { + if (projectionMatrixThisFrame != null) return projectionMatrixThisFrame; + + float partialTicks = AnimationTickHolder.getPartialTicks(); + Minecraft mc = Minecraft.getInstance(); + GameRenderer gameRenderer = mc.gameRenderer; + ClientPlayerEntity player = mc.player; + + MatrixStack matrixstack = new MatrixStack(); + matrixstack.peek().getModel().multiply(gameRenderer.func_228382_a_(gameRenderer.getActiveRenderInfo(), partialTicks, true)); + gameRenderer.bobViewWhenHurt(matrixstack, partialTicks); + if (mc.gameSettings.viewBobbing) { + gameRenderer.bobView(matrixstack, partialTicks); + } + + float portalTime = MathHelper.lerp(partialTicks, player.prevTimeInPortal, player.timeInPortal); + if (portalTime > 0.0F) { + int i = 20; + if (player.isPotionActive(Effects.NAUSEA)) { + i = 7; + } + + float f1 = 5.0F / (portalTime * portalTime + 5.0F) - portalTime * 0.04F; + f1 = f1 * f1; + Vector3f vector3f = new Vector3f(0.0F, MathHelper.SQRT_2 / 2.0F, MathHelper.SQRT_2 / 2.0F); + matrixstack.multiply(vector3f.getDegreesQuaternion(((float)gameRenderer.rendererUpdateCount + partialTicks) * (float)i)); + matrixstack.scale(1.0F / f1, 1.0F, 1.0F); + float f2 = -((float)gameRenderer.rendererUpdateCount + partialTicks) * (float)i; + matrixstack.multiply(vector3f.getDegreesQuaternion(f2)); + } + + Matrix4f matrix4f = matrixstack.peek().getModel(); + gameRenderer.func_228379_a_(matrix4f); + + projectionMatrixThisFrame = matrix4f; + return projectionMatrixThisFrame; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/OptifineHandler.java b/src/main/java/com/simibubi/create/foundation/render/backend/OptifineHandler.java new file mode 100644 index 000000000..8e35a2016 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/OptifineHandler.java @@ -0,0 +1,82 @@ +package com.simibubi.create.foundation.render.backend; + +import net.minecraft.client.Minecraft; + +import java.io.*; +import java.util.Optional; + +public class OptifineHandler { + public static final String OPTIFINE_ROOT_PACKAGE = "net.optifine"; + public static final String SHADER_PACKAGE = "net.optifine.shaders"; + + private static Package optifine; + private static OptifineHandler handler; + + public final boolean usingShaders; + + public OptifineHandler(boolean usingShaders) { + this.usingShaders = usingShaders; + } + + /** + * Get information about the current Optifine configuration. + * @return {@link Optional#empty()} if Optifine is not installed. + */ + public static Optional get() { + return Optional.ofNullable(handler); + } + + public static boolean optifineInstalled() { + return optifine != null; + } + + public static boolean usingShaders() { + return OptifineHandler.get() + .map(OptifineHandler::isUsingShaders) + .orElse(false); + } + + public static void init() { + optifine = Package.getPackage(OPTIFINE_ROOT_PACKAGE); + + 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 -> { + String line = it.replaceAll("\\s", ""); + if (line.startsWith("shaderPack=")) { + String setting = line.substring("shaderPack=".length()); + + return setting.equals("OFF") || setting.equals("(internal)"); + } + return false; + }); + } catch (FileNotFoundException e) { + Backend.log.info("No shader config found."); + } + + handler = new OptifineHandler(!shadersOff); + } + + public boolean isUsingShaders() { + return usingShaders; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/RenderWork.java b/src/main/java/com/simibubi/create/foundation/render/backend/RenderWork.java new file mode 100644 index 000000000..5a44845f6 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/RenderWork.java @@ -0,0 +1,21 @@ +package com.simibubi.create.foundation.render.backend; + +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +public class RenderWork { + private static final Queue runs = new ConcurrentLinkedQueue<>(); + + public static void runAll() { + while (!runs.isEmpty()) { + runs.remove().run(); + } + } + + /** + * Queue work to be executed at the end of a frame + */ + public static void enqueue(Runnable run) { + runs.add(run); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/BasicProgram.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/BasicProgram.java new file mode 100644 index 000000000..260921c56 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/BasicProgram.java @@ -0,0 +1,59 @@ +package com.simibubi.create.foundation.render.backend.gl; + +import com.simibubi.create.foundation.render.backend.Backend; +import com.simibubi.create.foundation.render.backend.gl.shader.GlProgram; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import net.minecraft.client.renderer.Matrix4f; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL20; + +public class BasicProgram extends GlProgram { + protected final int uTime; + protected final int uViewProjection; + protected final int uDebug; + protected final int uCameraPos; + protected final int uFogRange; + protected final int uFogColor; + + protected int uBlockAtlas; + protected int uLightMap; + + public BasicProgram(ResourceLocation name, int handle) { + super(name, handle); + uTime = getUniformLocation("uTime"); + uViewProjection = getUniformLocation("uViewProjection"); + uDebug = getUniformLocation("uDebug"); + uCameraPos = getUniformLocation("uCameraPos"); + uFogRange = getUniformLocation("uFogRange"); + uFogColor = getUniformLocation("uFogColor"); + + bind(); + registerSamplers(); + unbind(); + } + + protected void registerSamplers() { + uBlockAtlas = setSamplerBinding("uBlockAtlas", 0); + uLightMap = setSamplerBinding("uLightMap", 2); + } + + public void bind(Matrix4f viewProjection, double camX, double camY, double camZ, int debugMode) { + super.bind(); + + GL20.glUniform1i(uDebug, debugMode); + GL20.glUniform1f(uTime, AnimationTickHolder.getRenderTick()); + + uploadMatrixUniform(uViewProjection, viewProjection); + GL20.glUniform3f(uCameraPos, (float) camX, (float) camY, (float) camZ); + + GL20.glUniform2f(uFogRange, GlFog.getFogStart(), GlFog.getFogEnd()); + GL20.glUniform4fv(uFogColor, GlFog.FOG_COLOR); + } + + protected static void uploadMatrixUniform(int uniform, Matrix4f mat) { + Backend.MATRIX_BUFFER.position(0); + mat.write(Backend.MATRIX_BUFFER); + Backend.MATRIX_BUFFER.rewind(); + GL20.glUniformMatrix4fv(uniform, false, Backend.MATRIX_BUFFER); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlBuffer.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlBuffer.java new file mode 100644 index 000000000..c94c38828 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlBuffer.java @@ -0,0 +1,47 @@ +package com.simibubi.create.foundation.render.backend.gl; + +import com.simibubi.create.foundation.render.backend.Backend; +import org.lwjgl.opengl.GL20; + +import java.nio.ByteBuffer; +import java.util.function.Consumer; + +public class GlBuffer extends GlObject { + + protected final int bufferType; + + public GlBuffer(int bufferType) { + setHandle(GL20.glGenBuffers()); + this.bufferType = bufferType; + } + + public int getBufferType() { + return bufferType; + } + + public void bind() { + GL20.glBindBuffer(bufferType, handle()); + } + + public void unbind() { + GL20.glBindBuffer(bufferType, 0); + } + + public void with(Consumer action) { + bind(); + action.accept(this); + unbind(); + } + + public void map(int length, Consumer upload) { + Backend.mapBuffer(bufferType, 0, length, upload); + } + + public void map(int offset, int length, Consumer upload) { + Backend.mapBuffer(bufferType, offset, length, upload); + } + + protected void deleteInternal(int handle) { + GL20.glDeleteBuffers(handle); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlFog.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlFog.java new file mode 100644 index 000000000..220abfd1b --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlFog.java @@ -0,0 +1,29 @@ +package com.simibubi.create.foundation.render.backend.gl; + +import com.mojang.blaze3d.platform.GlStateManager; +import org.lwjgl.opengl.GL15; +import org.lwjgl.opengl.GL20; + +public class GlFog { + public static float[] FOG_COLOR = new float[] {0, 0, 0, 0}; + + public static boolean fogEnabled() { + return GlStateManager.FOG.field_179049_a.field_179201_b; + } + + public static int getFogMode() { + return GlStateManager.FOG.field_179047_b; + } + + public static float getFogDensity() { + return GlStateManager.FOG.field_179048_c; + } + + public static float getFogEnd() { + return GlStateManager.FOG.field_179046_e; + } + + public static float getFogStart() { + return GlStateManager.FOG.field_179045_d; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlObject.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlObject.java new file mode 100644 index 000000000..ef34e5ebe --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlObject.java @@ -0,0 +1,43 @@ +package com.simibubi.create.foundation.render.backend.gl; + +// Utility class for safely dealing with gl object handles. +public abstract class GlObject { + private static final int INVALID_HANDLE = Integer.MIN_VALUE; + + private int handle = INVALID_HANDLE; + + protected final void setHandle(int handle) { + this.handle = handle; + } + + public final int handle() { + this.checkHandle(); + + return this.handle; + } + + protected final void checkHandle() { + if (!this.isHandleValid()) { + throw new IllegalStateException("Handle is not valid"); + } + } + + protected final boolean isHandleValid() { + return this.handle != INVALID_HANDLE; + } + + protected final void invalidateHandle() { + this.handle = INVALID_HANDLE; + } + + public final void delete() { + if (!isHandleValid()) { + throw new IllegalStateException("Handle already deleted."); + } + + deleteInternal(handle); + invalidateHandle(); + } + + protected abstract void deleteInternal(int handle); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlPrimitiveType.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlPrimitiveType.java new file mode 100644 index 000000000..5e069fabf --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlPrimitiveType.java @@ -0,0 +1,37 @@ +package com.simibubi.create.foundation.render.backend.gl; + +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +@OnlyIn(Dist.CLIENT) +public enum GlPrimitiveType { + FLOAT(4, "float", 5126), + UBYTE(1, "ubyte", 5121), + BYTE(1, "byte", 5120), + USHORT(2, "ushort", 5123), + SHORT(2, "short", 5122), + UINT(4, "uint", 5125), + INT(4, "int", 5124); + + private final int size; + private final String displayName; + private final int glConstant; + + GlPrimitiveType(int p_i46095_3_, String p_i46095_4_, int p_i46095_5_) { + this.size = p_i46095_3_; + this.displayName = p_i46095_4_; + this.glConstant = p_i46095_5_; + } + + public int getSize() { + return this.size; + } + + public String getDisplayName() { + return this.displayName; + } + + public int getGlConstant() { + return this.glConstant; + } +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlTexture.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlTexture.java new file mode 100644 index 000000000..30b5d3f0f --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlTexture.java @@ -0,0 +1,25 @@ +package com.simibubi.create.foundation.render.backend.gl; + +import org.lwjgl.opengl.GL20; + +public class GlTexture extends GlObject { + private final int textureType; + + public GlTexture(int textureType) { + this.textureType = textureType; + setHandle(GL20.glGenTextures()); + } + + @Override + protected void deleteInternal(int handle) { + GL20.glDeleteTextures(handle); + } + + public void bind() { + GL20.glBindTexture(textureType, handle()); + } + + public void unbind() { + GL20.glBindTexture(textureType, 0); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlVertexArray.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlVertexArray.java new file mode 100644 index 000000000..2d024c6d2 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/GlVertexArray.java @@ -0,0 +1,29 @@ +package com.simibubi.create.foundation.render.backend.gl; + +import org.lwjgl.opengl.GL30; + +import java.util.function.Consumer; + +public class GlVertexArray extends GlObject { + public GlVertexArray() { + setHandle(GL30.glGenVertexArrays()); + } + + public void bind() { + GL30.glBindVertexArray(handle()); + } + + public void unbind() { + GL30.glBindVertexArray(0); + } + + public void with(Consumer action) { + bind(); + action.accept(this); + unbind(); + } + + protected void deleteInternal(int handle) { + GL30.glDeleteVertexArrays(handle); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/CommonAttributes.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/CommonAttributes.java new file mode 100644 index 000000000..d3fd9d48e --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/CommonAttributes.java @@ -0,0 +1,21 @@ +package com.simibubi.create.foundation.render.backend.gl.attrib; + +import com.simibubi.create.foundation.render.backend.gl.GlPrimitiveType; + +public class CommonAttributes { + + public static final VertexAttribSpec MAT4 = new VertexAttribSpec(GlPrimitiveType.FLOAT, 16); + public static final VertexAttribSpec VEC4 = new VertexAttribSpec(GlPrimitiveType.FLOAT, 4); + public static final VertexAttribSpec VEC3 = new VertexAttribSpec(GlPrimitiveType.FLOAT, 3); + public static final VertexAttribSpec VEC2 = new VertexAttribSpec(GlPrimitiveType.FLOAT, 2); + public static final VertexAttribSpec FLOAT = new VertexAttribSpec(GlPrimitiveType.FLOAT, 1); + + public static final VertexAttribSpec NORMAL = new VertexAttribSpec(GlPrimitiveType.BYTE, 3, true); + public static final VertexAttribSpec UV = new VertexAttribSpec(GlPrimitiveType.FLOAT, 2); + + public static final VertexAttribSpec RGBA = new VertexAttribSpec(GlPrimitiveType.UBYTE, 4, true); + public static final VertexAttribSpec RGB = new VertexAttribSpec(GlPrimitiveType.UBYTE, 3, true); + public static final VertexAttribSpec LIGHT = new VertexAttribSpec(GlPrimitiveType.UBYTE, 2, true); + + public static final VertexAttribSpec NORMALIZED_BYTE = new VertexAttribSpec(GlPrimitiveType.BYTE, 1, true); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/IVertexAttrib.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/IVertexAttrib.java new file mode 100644 index 000000000..5c77620f9 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/IVertexAttrib.java @@ -0,0 +1,12 @@ +package com.simibubi.create.foundation.render.backend.gl.attrib; + +public interface IVertexAttrib { + + String attribName(); + + VertexAttribSpec attribSpec(); + + int getDivisor(); + + int getBufferIndex(); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/ModelVertexAttributes.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/ModelVertexAttributes.java new file mode 100644 index 000000000..960289fd6 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/ModelVertexAttributes.java @@ -0,0 +1,36 @@ +package com.simibubi.create.foundation.render.backend.gl.attrib; + +public enum ModelVertexAttributes implements IVertexAttrib { + VERTEX_POSITION("aPos", CommonAttributes.VEC3), + NORMAL("aNormal", CommonAttributes.NORMAL), + TEXTURE("aTexCoords", CommonAttributes.UV), + ; + + private final String name; + private final VertexAttribSpec spec; + + ModelVertexAttributes(String name, VertexAttribSpec spec) { + this.name = name; + this.spec = spec; + } + + @Override + public String attribName() { + return name; + } + + @Override + public VertexAttribSpec attribSpec() { + return spec; + } + + @Override + public int getDivisor() { + return 0; + } + + @Override + public int getBufferIndex() { + return 0; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/VertexAttribSpec.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/VertexAttribSpec.java new file mode 100644 index 000000000..709508c90 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/VertexAttribSpec.java @@ -0,0 +1,37 @@ +package com.simibubi.create.foundation.render.backend.gl.attrib; + +import com.simibubi.create.foundation.render.backend.gl.GlPrimitiveType; +import org.lwjgl.opengl.GL20; + +public class VertexAttribSpec { + + private final GlPrimitiveType type; + private final int count; + private final int size; + private final int attributeCount; + private final boolean normalized; + + public VertexAttribSpec(GlPrimitiveType type, int count) { + this(type, count, false); + } + + public VertexAttribSpec(GlPrimitiveType type, int count, boolean normalized) { + this.type = type; + this.count = count; + this.size = type.getSize() * count; + this.attributeCount = (this.size + 15) / 16; // ceiling division. GLSL vertex attributes can only be 16 bytes wide + this.normalized = normalized; + } + + public void vertexAttribPointer(int stride, int index, int pointer) { + GL20.glVertexAttribPointer(index, count, type.getGlConstant(), normalized, stride, pointer); + } + + public int getSize() { + return size; + } + + public int getAttributeCount() { + return attributeCount; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/VertexFormat.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/VertexFormat.java new file mode 100644 index 000000000..3929e3354 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/attrib/VertexFormat.java @@ -0,0 +1,65 @@ +package com.simibubi.create.foundation.render.backend.gl.attrib; + +import java.util.ArrayList; +import java.util.Arrays; + +public class VertexFormat { + + private final ArrayList allAttributes; + + private final int numAttributes; + private final int stride; + + public VertexFormat(ArrayList allAttributes) { + this.allAttributes = allAttributes; + + int numAttributes = 0, stride = 0; + for (IVertexAttrib attrib : allAttributes) { + VertexAttribSpec spec = attrib.attribSpec(); + numAttributes += spec.getAttributeCount(); + stride += spec.getSize(); + } + this.numAttributes = numAttributes; + this.stride = stride; + } + + public int getShaderAttributeCount() { + return numAttributes; + } + + public int getStride() { + return stride; + } + + public void vertexAttribPointers(int index) { + int offset = 0; + for (IVertexAttrib attrib : this.allAttributes) { + VertexAttribSpec spec = attrib.attribSpec(); + spec.vertexAttribPointer(stride, index, offset); + index += spec.getAttributeCount(); + offset += spec.getSize(); + } + } + + public static Builder builder() { + return new Builder(); + } + + + public static class Builder { + private final ArrayList allAttributes; + + public Builder() { + allAttributes = new ArrayList<>(); + } + + public & IVertexAttrib> Builder addAttributes(Class attribEnum) { + allAttributes.addAll(Arrays.asList(attribEnum.getEnumConstants())); + return this; + } + + public VertexFormat build() { + return new VertexFormat(allAttributes); + } + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GLSLType.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GLSLType.java new file mode 100644 index 000000000..80dc2fa16 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GLSLType.java @@ -0,0 +1,45 @@ +package com.simibubi.create.foundation.render.backend.gl.shader; + +import com.simibubi.create.foundation.render.backend.gl.GlPrimitiveType; + +public class GLSLType { + public static final GLSLType FLOAT = new GLSLType("mat4", GlPrimitiveType.FLOAT, 16); + public static final GLSLType VEC2 = new GLSLType("vec4", GlPrimitiveType.FLOAT, 4); + public static final GLSLType VEC3 = new GLSLType("vec3", GlPrimitiveType.FLOAT, 3); + public static final GLSLType VEC4 = new GLSLType("vec2", GlPrimitiveType.FLOAT, 2); + public static final GLSLType MAT4 = new GLSLType("float", GlPrimitiveType.FLOAT, 1); + + private final String symbol; + private final GlPrimitiveType base; + private final int count; + private final int size; + private final int attributeCount; + + public GLSLType(String symbol, GlPrimitiveType base, int count) { + this.symbol = symbol; + this.base = base; + this.count = count; + this.size = base.getSize() * count; + this.attributeCount = (this.size + 15) / 16; // ceiling division. GLSL vertex attributes can only be 16 bytes wide + } + + public String getSymbol() { + return symbol; + } + + public GlPrimitiveType getBase() { + return base; + } + + public int getCount() { + return count; + } + + public int getSize() { + return size; + } + + public int getAttributeCount() { + return attributeCount; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlProgram.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlProgram.java new file mode 100644 index 000000000..790bb4c5a --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlProgram.java @@ -0,0 +1,122 @@ +package com.simibubi.create.foundation.render.backend.gl.shader; + +import com.simibubi.create.foundation.render.backend.gl.GlObject; +import com.simibubi.create.foundation.render.backend.gl.attrib.IVertexAttrib; +import com.simibubi.create.foundation.render.backend.Backend; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL20; + +public abstract class GlProgram extends GlObject { + + public final ResourceLocation name; + + protected GlProgram(ResourceLocation name, int handle) { + setHandle(handle); + this.name = name; + } + + public static Builder builder(ResourceLocation name) { + return new Builder(name); + } + + public void bind() { + GL20.glUseProgram(handle()); + } + + public void unbind() { + GL20.glUseProgram(0); + } + + /** + * 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 + */ + public int getUniformLocation(String uniform) { + int index = GL20.glGetUniformLocation(this.handle(), uniform); + + if (index < 0) { + Backend.log.warn("No active uniform '{}' exists in program '{}'. Could be unused.", uniform, this.name); + } + + return index; + } + + /** + * Binds a sampler uniform to the given texture unit. + * @param name The name of the sampler uniform. + * @param binding The index of the texture unit. + * @return The sampler uniform's index. + * @throws NullPointerException If no uniform exists with the given name. + */ + public int setSamplerBinding(String name, int binding) { + int samplerUniform = getUniformLocation(name); + + if (samplerUniform >= 0) { + GL20.glUniform1i(samplerUniform, binding); + } + + return samplerUniform; + } + + @Override + protected void deleteInternal(int handle) { + GL20.glDeleteProgram(handle); + } + + public static class Builder { + private final ResourceLocation name; + private final int program; + + private int attributeIndex; + + public Builder(ResourceLocation name) { + this.name = name; + this.program = GL20.glCreateProgram(); + } + + public Builder attachShader(GlShader shader) { + GL20.glAttachShader(this.program, shader.handle()); + + return this; + } + + public Builder addAttribute(A attrib) { + GL20.glBindAttribLocation(this.program, attributeIndex, attrib.attribName()); + attributeIndex += attrib.attribSpec().getAttributeCount(); + return this; + } + + /** + * Links the attached shaders to this program and returns a user-defined container which wraps the shader + * program. This container can, for example, provide methods for updating the specific uniforms of that shader + * set. + * + * @param factory The factory which will create the shader program's container + * @param

The type which should be instantiated with the new program's handle + * @return An instantiated shader container as provided by the factory + */ + public

P build(ProgramFactory

factory) { + GL20.glLinkProgram(this.program); + + String log = GL20.glGetProgramInfoLog(this.program); + + if (!log.isEmpty()) { + Backend.log.warn("Program link log for " + this.name + ": " + log); + } + + int result = GL20.glGetProgrami(this.program, GL20.GL_LINK_STATUS); + + if (result != GL20.GL_TRUE) { + throw new RuntimeException("Shader program linking failed, see log for details"); + } + + return factory.create(this.name, this.program); + } + } + + @FunctionalInterface + public interface ProgramFactory

{ + P create(ResourceLocation name, int handle); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlShader.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlShader.java new file mode 100644 index 000000000..fa0fa48f2 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlShader.java @@ -0,0 +1,52 @@ +package com.simibubi.create.foundation.render.backend.gl.shader; + +import com.simibubi.create.foundation.render.backend.gl.GlObject; +import com.simibubi.create.foundation.render.backend.Backend; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL20; + +public class GlShader extends GlObject { + + public final ResourceLocation name; + public final ShaderType type; + + public GlShader(ShaderType type, ResourceLocation name, String source, PreProcessor preProcessor) { + this.type = type; + this.name = name; + int handle = GL20.glCreateShader(type.glEnum); + + if (preProcessor != null) { + source = preProcessor.process(source); + Backend.log.info("Preprocessor run on " + name);// + ":\n" + source); + } + + GL20.glShaderSource(handle, source); + GL20.glCompileShader(handle); + + String log = GL20.glGetShaderInfoLog(handle); + + if (!log.isEmpty()) { + Backend.log.warn("Shader compilation log for " + name + ": " + log); + } + + if (GL20.glGetShaderi(handle, GL20.GL_COMPILE_STATUS) != GL20.GL_TRUE) { + throw new RuntimeException("Could not compile shader"); + } + + setHandle(handle); + } + + @Override + protected void deleteInternal(int handle) { + GL20.glDeleteShader(handle); + } + + @FunctionalInterface + public interface PreProcessor { + String process(String source); + + default PreProcessor andThen(PreProcessor that) { + return source -> that.process(this.process(source)); + } + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramSpec.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramSpec.java new file mode 100644 index 000000000..3e98a70df --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramSpec.java @@ -0,0 +1,88 @@ +package com.simibubi.create.foundation.render.backend.gl.shader; + +import com.simibubi.create.Create; +import com.simibubi.create.foundation.render.backend.gl.attrib.IVertexAttrib; +import net.minecraft.util.ResourceLocation; + +import java.util.ArrayList; +import java.util.Arrays; + +public class ProgramSpec

{ + + public final ResourceLocation name; + public final ResourceLocation vert; + public final ResourceLocation frag; + + public final ShaderConstants defines; + + public final GlProgram.ProgramFactory

factory; + + public final ArrayList attributes; + + public static

Builder

builder(String name, GlProgram.ProgramFactory

factory) { + return builder(new ResourceLocation(Create.ID, name), factory); + } + + public static

Builder

builder(ResourceLocation name, GlProgram.ProgramFactory

factory) { + return new Builder<>(name, factory); + } + + public ProgramSpec(ResourceLocation name, ResourceLocation vert, ResourceLocation frag, GlProgram.ProgramFactory

factory, ShaderConstants defines, ArrayList attributes) { + this.name = name; + this.vert = vert; + this.frag = frag; + this.defines = defines; + + + this.factory = factory; + this.attributes = attributes; + } + + public ResourceLocation getVert() { + return vert; + } + + public ResourceLocation getFrag() { + return frag; + } + + public static class Builder

{ + private ResourceLocation vert; + private ResourceLocation frag; + private ShaderConstants defines = null; + + private final ResourceLocation name; + private final GlProgram.ProgramFactory

factory; + private final ArrayList attributes; + + public Builder(ResourceLocation name, GlProgram.ProgramFactory

factory) { + this.name = name; + this.factory = factory; + attributes = new ArrayList<>(); + } + + public Builder

setVert(ResourceLocation vert) { + this.vert = vert; + return this; + } + + public Builder

setFrag(ResourceLocation frag) { + this.frag = frag; + return this; + } + + public Builder

setDefines(ShaderConstants defines) { + this.defines = defines; + return this; + } + + public & IVertexAttrib> Builder

addAttributes(Class attributeEnum) { + attributes.addAll(Arrays.asList(attributeEnum.getEnumConstants())); + return this; + } + + public ProgramSpec

createProgramSpec() { + return new ProgramSpec<>(name, vert, frag, factory, defines, attributes); + } + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ShaderCallback.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ShaderCallback.java new file mode 100644 index 000000000..b410d91ff --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ShaderCallback.java @@ -0,0 +1,17 @@ +package com.simibubi.create.foundation.render.backend.gl.shader; + +/** + * A Callback for when a shader is called. Used to define shader uniforms. + */ +@FunctionalInterface +public interface ShaderCallback

{ + + void call(P program); + + default ShaderCallback

andThen(ShaderCallback

other) { + return program -> { + call(program); + other.call(program); + }; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ShaderConstants.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ShaderConstants.java new file mode 100644 index 000000000..3f1ed6c09 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ShaderConstants.java @@ -0,0 +1,46 @@ +package com.simibubi.create.foundation.render.backend.gl.shader; + +import java.io.BufferedReader; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class ShaderConstants implements GlShader.PreProcessor { + + private final ArrayList defines; + + public ShaderConstants() { + defines = new ArrayList<>(); + } + + public static ShaderConstants define(String def) { + return new ShaderConstants().def(def); + } + + public ShaderConstants def(String def) { + defines.add(def); + return this; + } + + public ArrayList getDefines() { + return defines; + } + + public Stream directives() { + return defines.stream().map(it -> "#define " + it); + } + + @Override + public String process(String source) { + return new BufferedReader(new StringReader(source)).lines().flatMap(line -> { + Stream map = Stream.of(line); + + if (line.startsWith("#version")) { + map = Stream.concat(map, directives()); + } + + return map; + }).collect(Collectors.joining("\n")); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ShaderType.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ShaderType.java new file mode 100644 index 000000000..b90f15cca --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ShaderType.java @@ -0,0 +1,15 @@ +package com.simibubi.create.foundation.render.backend.gl.shader; + +import org.lwjgl.opengl.GL20; + +public enum ShaderType { + VERTEX(GL20.GL_VERTEX_SHADER), + FRAGMENT(GL20.GL_FRAGMENT_SHADER), + ; + + public final int glEnum; + + ShaderType(int glEnum) { + this.glEnum = glEnum; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ShaderUniforms.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ShaderUniforms.java new file mode 100644 index 000000000..8a85d1c24 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ShaderUniforms.java @@ -0,0 +1,12 @@ +package com.simibubi.create.foundation.render.backend.gl.shader; + +import java.util.HashMap; +import java.util.Map; + +public class ShaderUniforms { + private final Map uniforms; + + public ShaderUniforms() { + this.uniforms = new HashMap<>(); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlVersioned.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlVersioned.java new file mode 100644 index 000000000..53d929ea0 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/GlVersioned.java @@ -0,0 +1,8 @@ +package com.simibubi.create.foundation.render.backend.gl.versioned; + +import org.lwjgl.opengl.GLCapabilities; + + +public interface GlVersioned { + boolean supported(GLCapabilities caps); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/MapBuffer.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/MapBuffer.java new file mode 100644 index 000000000..f1249223a --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/versioned/MapBuffer.java @@ -0,0 +1,72 @@ +package com.simibubi.create.foundation.render.backend.gl.versioned; + +import org.lwjgl.opengl.*; + +import java.nio.ByteBuffer; +import java.util.function.Consumer; + +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 upload) { + ByteBuffer buffer = GL30.glMapBufferRange(target, offset, length, GL30.GL_MAP_WRITE_BIT | GL30.GL_MAP_INVALIDATE_RANGE_BIT); + + upload.accept(buffer); + buffer.rewind(); + + GL30.glUnmapBuffer(target); + } + }, + 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 upload) { + ByteBuffer buffer = ARBMapBufferRange.glMapBufferRange(target, offset, length, GL30.GL_MAP_WRITE_BIT | GL30.GL_MAP_INVALIDATE_RANGE_BIT); + + upload.accept(buffer); + buffer.rewind(); + + GL30.glUnmapBuffer(target); + } + }, + GL15_MAP { + @Override + public boolean supported(GLCapabilities caps) { + return caps.OpenGL15; + } + + @Override + public void mapBuffer(int target, int offset, int length, Consumer upload) { + ByteBuffer buffer = GL15.glMapBuffer(target, GL15.GL_WRITE_ONLY); + + buffer.position(offset); + upload.accept(buffer); + buffer.rewind(); + GL15.glUnmapBuffer(target); + } + }, + UNSUPPORTED { + @Override + public boolean supported(GLCapabilities caps) { + return true; + } + + @Override + public void mapBuffer(int target, int offset, int length, Consumer upload) { + throw new UnsupportedOperationException("glMapBuffer not supported"); + } + }; + + + public abstract void mapBuffer(int target, int offset, int length, Consumer upload); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/IInstanceRendered.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/IInstanceRendered.java new file mode 100644 index 000000000..a1558446f --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/IInstanceRendered.java @@ -0,0 +1,9 @@ +package com.simibubi.create.foundation.render.backend.instancing; + +import com.simibubi.create.foundation.render.backend.light.ILightListener; + +public interface IInstanceRendered extends ILightListener { + default boolean shouldRenderAsTE() { + return false; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/IRendererFactory.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/IRendererFactory.java new file mode 100644 index 000000000..196e029d8 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/IRendererFactory.java @@ -0,0 +1,8 @@ +package com.simibubi.create.foundation.render.backend.instancing; + +import net.minecraft.tileentity.TileEntity; + +@FunctionalInterface +public interface IRendererFactory { + TileEntityInstance create(InstancedTileRenderer manager, T te); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstanceData.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstanceData.java new file mode 100644 index 000000000..2facfb415 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstanceData.java @@ -0,0 +1,51 @@ +package com.simibubi.create.foundation.render.backend.instancing; + +import java.nio.ByteBuffer; + +public abstract class InstanceData { + + protected final InstancedModel owner; + + protected InstanceData(InstancedModel owner) { + this.owner = owner; + } + + public abstract void write(ByteBuffer buf); + + public void putVec4(ByteBuffer buf, float x, float y, float z, float w) { + put(buf, x); + put(buf, y); + put(buf, z); + put(buf, w); + } + + public void putVec3(ByteBuffer buf, float x, float y, float z) { + put(buf, x); + put(buf, y); + put(buf, z); + } + + public void putVec2(ByteBuffer buf, float x, float y) { + put(buf, x); + put(buf, y); + } + + public void putVec3(ByteBuffer buf, byte x, byte y, byte z) { + put(buf, x); + put(buf, y); + put(buf, z); + } + + public void putVec2(ByteBuffer buf, byte x, byte y) { + put(buf, x); + put(buf, y); + } + + public void put(ByteBuffer buf, byte b) { + buf.put(b); + } + + public void put(ByteBuffer buf, float f) { + buf.putFloat(f); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstanceKey.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstanceKey.java new file mode 100644 index 000000000..166bf8e56 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstanceKey.java @@ -0,0 +1,31 @@ +package com.simibubi.create.foundation.render.backend.instancing; + +import java.util.function.Consumer; + +public class InstanceKey { + public static final int INVALID = -1; + + InstancedModel model; + int index; + + public InstanceKey(InstancedModel model, int index) { + this.model = model; + this.index = index; + } + + void invalidate() { + index = INVALID; + } + + public boolean isValid() { + return index != INVALID; + } + + public void modifyInstance(Consumer edit) { + model.modifyInstance(this, edit); + } + + public void delete() { + model.deleteInstance(this); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedModel.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedModel.java new file mode 100644 index 000000000..c82c6bd38 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedModel.java @@ -0,0 +1,216 @@ +package com.simibubi.create.foundation.render.backend.instancing; + + +import com.simibubi.create.foundation.render.backend.BufferedModel; +import com.simibubi.create.foundation.render.RenderMath; +import com.simibubi.create.foundation.render.backend.gl.GlVertexArray; +import com.simibubi.create.foundation.render.backend.gl.GlBuffer; +import com.simibubi.create.foundation.render.backend.gl.attrib.VertexFormat; +import com.simibubi.create.foundation.render.backend.gl.attrib.ModelVertexAttributes; +import net.minecraft.client.renderer.BufferBuilder; +import org.lwjgl.opengl.*; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.function.Consumer; + +public abstract class InstancedModel extends BufferedModel { + public static final VertexFormat FORMAT = VertexFormat.builder().addAttributes(ModelVertexAttributes.class).build(); + + public final InstancedTileRenderer renderer; + + protected GlVertexArray vao; + protected GlBuffer instanceVBO; + protected int glBufferSize = -1; + protected int glInstanceCount = 0; + + protected final ArrayList> keys = new ArrayList<>(); + protected final ArrayList data = new ArrayList<>(); + protected int minIndexChanged = -1; + protected int maxIndexChanged = -1; + + public InstancedModel(InstancedTileRenderer renderer, BufferBuilder buf) { + super(buf); + this.renderer = renderer; + } + + @Override + protected void init() { + vao = new GlVertexArray(); + instanceVBO = new GlBuffer(GL20.GL_ARRAY_BUFFER); + + vao.with(vao -> super.init()); + } + + @Override + protected void initModel() { + super.initModel(); + setupAttributes(); + } + + public int instanceCount() { + return data.size(); + } + + public boolean isEmpty() { + return instanceCount() == 0; + } + + protected void deleteInternal() { + keys.forEach(InstanceKey::invalidate); + super.deleteInternal(); + + instanceVBO.delete(); + vao.delete(); + } + + protected abstract D newInstance(); + + public synchronized void deleteInstance(InstanceKey key) { + verifyKey(key); + + int index = key.index; + + keys.remove(index); + data.remove(index); + + for (int i = index; i < keys.size(); i++) { + keys.get(i).index--; + } + + maxIndexChanged = keys.size() - 1; + markIndexChanged(Math.min(maxIndexChanged, index)); + + key.invalidate(); + } + + public synchronized void modifyInstance(InstanceKey key, Consumer edit) { + verifyKey(key); + + D data = this.data.get(key.index); + + edit.accept(data); + + markIndexChanged(key.index); + } + + public synchronized InstanceKey setupInstance(Consumer setup) { + D instanceData = newInstance(); + setup.accept(instanceData); + + InstanceKey key = new InstanceKey<>(this, data.size()); + data.add(instanceData); + keys.add(key); + + markIndexChanged(key.index); + + return key; + } + + protected void doRender() { + vao.with(vao -> { + renderSetup(); + GL31.glDrawArraysInstanced(GL11.GL_QUADS, 0, vertexCount, glInstanceCount); + }); + } + + protected void renderSetup() { + if (minIndexChanged < 0 || data.isEmpty()) return; + + VertexFormat instanceFormat = getInstanceFormat(); + + int stride = instanceFormat.getStride(); + int newInstanceCount = instanceCount(); + int instanceSize = RenderMath.nextPowerOf2((newInstanceCount + 1) * stride); + + instanceVBO.with(vbo -> { + // this probably changes enough that it's not worth reallocating the entire buffer every time. + if (instanceSize > glBufferSize) { + GL15.glBufferData(vbo.getBufferType(), instanceSize, GL15.GL_STATIC_DRAW); + glBufferSize = instanceSize; + minIndexChanged = 0; + maxIndexChanged = newInstanceCount - 1; + } + + int offset = minIndexChanged * stride; + int length = (1 + maxIndexChanged - minIndexChanged) * stride; + + vbo.map(offset, length, buffer -> { + for (int i = minIndexChanged; i <= maxIndexChanged; i++) { + data.get(i).write(buffer); + } + }); + + if (newInstanceCount < glInstanceCount) { + int clearFrom = (maxIndexChanged + 1) * stride; + int clearTo = (glInstanceCount) * stride; + vbo.map(clearFrom, clearTo - clearFrom, buffer -> { + for (int i = clearFrom; i < clearTo; i++) { + buffer.put((byte) 0); + } + }); + } + + glInstanceCount = newInstanceCount; + + int staticAttributes = getModelFormat().getShaderAttributeCount(); + instanceFormat.vertexAttribPointers(staticAttributes); + + for (int i = 0; i < instanceFormat.getShaderAttributeCount(); i++) { + GL33.glVertexAttribDivisor(i + staticAttributes, 1); + } + }); + + minIndexChanged = -1; + maxIndexChanged = -1; + } + + protected void markIndexChanged(int index) { + if (minIndexChanged < 0) { + minIndexChanged = index; + } else if (index < minIndexChanged) { + minIndexChanged = index; + } + + if (maxIndexChanged < 0) { + maxIndexChanged = index; + } else if (index > maxIndexChanged) { + maxIndexChanged = index; + } + } + + protected final void verifyKey(InstanceKey key) { + if (key.model != this) throw new IllegalStateException("Provided key does not belong to model."); + + if (!key.isValid()) throw new IllegalStateException("Provided key has been invalidated."); + + if (key.index >= data.size()) throw new IndexOutOfBoundsException("Key points out of bounds. (" + key.index + " > " + (data.size() - 1) + ")"); + + if (keys.get(key.index) != key) throw new IllegalStateException("Key desync!!"); + } + + @Override + protected void copyVertex(ByteBuffer constant, int i) { + constant.putFloat(getX(template, i)); + constant.putFloat(getY(template, i)); + constant.putFloat(getZ(template, i)); + + constant.put(getNX(template, i)); + constant.put(getNY(template, i)); + constant.put(getNZ(template, i)); + + constant.putFloat(getU(template, i)); + constant.putFloat(getV(template, i)); + } + + @Override + protected VertexFormat getModelFormat() { + return FORMAT; + } + + protected abstract VertexFormat getInstanceFormat(); + + protected int getTotalShaderAttributeCount() { + return getInstanceFormat().getShaderAttributeCount() + super.getTotalShaderAttributeCount(); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedTileRenderRegistry.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedTileRenderRegistry.java new file mode 100644 index 000000000..fd731a8e2 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedTileRenderRegistry.java @@ -0,0 +1,29 @@ +package com.simibubi.create.foundation.render.backend.instancing; + +import com.google.common.collect.Maps; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; + +import javax.annotation.Nullable; +import java.util.Map; + +public class InstancedTileRenderRegistry { + public static final InstancedTileRenderRegistry instance = new InstancedTileRenderRegistry(); + + private final Map, IRendererFactory> renderers = Maps.newHashMap(); + + public void register(TileEntityType type, IRendererFactory rendererFactory) { + this.renderers.put(type, rendererFactory); + } + + @SuppressWarnings("unchecked") + @Nullable + public TileEntityInstance create(InstancedTileRenderer manager, T tile) { + TileEntityType type = tile.getType(); + IRendererFactory factory = (IRendererFactory) this.renderers.get(type); + + if (factory == null) return null; + else return factory.create(manager, tile); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedTileRenderer.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedTileRenderer.java new file mode 100644 index 000000000..ab30eaa36 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedTileRenderer.java @@ -0,0 +1,159 @@ +package com.simibubi.create.foundation.render.backend.instancing; + +import com.simibubi.create.CreateClient; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; +import com.simibubi.create.foundation.render.backend.gl.BasicProgram; +import com.simibubi.create.foundation.render.backend.Backend; +import com.simibubi.create.foundation.render.backend.gl.shader.ShaderCallback; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.WorldAttached; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.Matrix4f; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public abstract class InstancedTileRenderer

{ + public static WorldAttached> addedLastTick = new WorldAttached<>(ConcurrentHashMap::new); + + protected Map> instances = new HashMap<>(); + + protected Map, RenderMaterial> materials = new HashMap<>(); + + protected InstancedTileRenderer() { + registerMaterials(); + } + + public abstract BlockPos getOriginCoordinate(); + + public abstract void registerMaterials(); + + public void tick() { + ClientWorld world = Minecraft.getInstance().world; + + int ticks = AnimationTickHolder.getTicks(); + + ConcurrentHashMap map = addedLastTick.get(world); + map + .entrySet() + .stream() + .filter(it -> ticks - it.getValue() > 10) + .map(Map.Entry::getKey) + .forEach(te -> { + map.remove(te); + + onLightUpdate(te); + }); + + + // Clean up twice a second. This doesn't have to happen every tick, + // but this does need to be run to ensure we don't miss anything. + if (ticks % 10 == 0) { + clean(); + } + } + + @SuppressWarnings("unchecked") + public > RenderMaterial getMaterial(MaterialType materialType) { + return (RenderMaterial) materials.get(materialType); + } + + @Nullable + public TileEntityInstance getInstance(T tile) { + return getInstance(tile, true); + } + + @SuppressWarnings("unchecked") + @Nullable + public TileEntityInstance getInstance(T tile, boolean create) { + if (!Backend.canUseInstancing()) return null; + + TileEntityInstance instance = instances.get(tile); + + if (instance != null) { + return (TileEntityInstance) instance; + } else if (create) { + TileEntityInstance renderer = InstancedTileRenderRegistry.instance.create(this, tile); + + if (renderer != null) { + addedLastTick.get(tile.getWorld()).put(tile, AnimationTickHolder.getTicks()); + instances.put(tile, renderer); + } + + return renderer; + } else { + return null; + } + } + + public void onLightUpdate(T tile) { + if (!Backend.canUseInstancing()) return; + + if (tile instanceof IInstanceRendered) { + TileEntityInstance instance = getInstance(tile, false); + + if (instance != null) + instance.updateLight(); + } + } + + public void add(T tile) { + if (!Backend.canUseInstancing()) return; + + if (tile instanceof IInstanceRendered) { + getInstance(tile); + } + } + + public void update(T tile) { + if (!Backend.canUseInstancing()) return; + + if (tile instanceof IInstanceRendered) { + TileEntityInstance instance = getInstance(tile, false); + + if (instance != null) + instance.update(); + } + } + + public void remove(T tile) { + if (!Backend.canUseInstancing()) return; + + if (tile instanceof IInstanceRendered) { + TileEntityInstance instance = getInstance(tile, false); + + if (instance != null) { + instance.remove(); + instances.remove(tile); + } + } + } + + public void clean() { + instances.keySet().stream().filter(TileEntity::isRemoved).forEach(instances::remove); + } + + public void invalidate() { + for (RenderMaterial material : materials.values()) { + material.delete(); + } + instances.clear(); + } + + public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ) { + render(layer, viewProjection, camX, camY, camZ, null); + } + + public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ, ShaderCallback

callback) { + for (RenderMaterial material : materials.values()) { + if (material.canRenderInLayer(layer)) + material.render(layer, viewProjection, camX, camY, camZ, callback); + } + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/MaterialType.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/MaterialType.java new file mode 100644 index 000000000..48ade4b2a --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/MaterialType.java @@ -0,0 +1,3 @@ +package com.simibubi.create.foundation.render.backend.instancing; + +public class MaterialType { } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/ModelFactory.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/ModelFactory.java new file mode 100644 index 000000000..61d7e36ff --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/ModelFactory.java @@ -0,0 +1,8 @@ +package com.simibubi.create.foundation.render.backend.instancing; + +import net.minecraft.client.renderer.BufferBuilder; + +@FunctionalInterface +public interface ModelFactory> { + B makeModel(InstancedTileRenderer renderer, BufferBuilder buf); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/RenderMaterial.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/RenderMaterial.java new file mode 100644 index 000000000..1234f3900 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/RenderMaterial.java @@ -0,0 +1,150 @@ +package com.simibubi.create.foundation.render.backend.instancing; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; +import com.simibubi.create.foundation.render.Compartment; +import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; +import com.simibubi.create.foundation.render.SuperByteBufferCache; +import com.simibubi.create.foundation.render.backend.gl.BasicProgram; +import com.simibubi.create.foundation.render.backend.Backend; +import com.simibubi.create.foundation.render.backend.gl.shader.ProgramSpec; +import com.simibubi.create.foundation.render.backend.gl.shader.ShaderCallback; +import net.minecraft.block.BlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BlockRendererDispatcher; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.Matrix4f; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.util.Direction; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import static com.simibubi.create.foundation.render.Compartment.PARTIAL; + +public class RenderMaterial

> { + + protected final InstancedTileRenderer renderer; + protected final Map, Cache> models; + protected final ModelFactory factory; + protected final ProgramSpec

programSpec; + protected final Predicate layerPredicate; + + /** + * Creates a material that renders in the default layer (CUTOUT_MIPPED) + */ + public RenderMaterial(InstancedTileRenderer renderer, ProgramSpec

programSpec, ModelFactory factory) { + this(renderer, programSpec, factory, type -> type == RenderType.getCutoutMipped()); + } + + public RenderMaterial(InstancedTileRenderer renderer, ProgramSpec

programSpec, ModelFactory factory, Predicate layerPredicate) { + this.renderer = renderer; + this.models = new HashMap<>(); + this.factory = factory; + this.programSpec = programSpec; + this.layerPredicate = layerPredicate; + registerCompartment(Compartment.PARTIAL); + registerCompartment(Compartment.DIRECTIONAL_PARTIAL); + registerCompartment(KineticTileEntityRenderer.KINETIC_TILE); + } + + public boolean canRenderInLayer(RenderType layer) { + return layerPredicate.test(layer); + } + + public void render(RenderType layer, Matrix4f projection, double camX, double camY, double camZ) { + render(layer, projection, camX, camY, camZ, null); + } + + public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ, ShaderCallback

setup) { + P program = Backend.getProgram(programSpec); + program.bind(viewProjection, camX, camY, camZ, FastRenderDispatcher.getDebugMode()); + + if (setup != null) setup.call(program); + + makeRenderCalls(); + teardown(); + } + + public void teardown() {} + + public void delete() { + runOnAll(InstancedModel::delete); + models.values().forEach(Cache::invalidateAll); + } + + protected void makeRenderCalls() { + for (Cache cache : models.values()) { + for (MODEL model : cache.asMap().values()) { + if (!model.isEmpty()) { + model.render(); + } + } + } + } + + public void runOnAll(Consumer f) { + for (Cache cache : models.values()) { + for (MODEL model : cache.asMap().values()) { + f.accept(model); + } + } + } + + public void registerCompartment(Compartment instance) { + models.put(instance, CacheBuilder.newBuilder().build()); + } + + public MODEL getModel(AllBlockPartials partial, BlockState referenceState) { + return get(PARTIAL, partial, () -> buildModel(partial.get(), referenceState)); + } + + public MODEL getModel(AllBlockPartials partial, BlockState referenceState, Direction dir) { + return get(Compartment.DIRECTIONAL_PARTIAL, Pair.of(dir, partial), + () -> buildModel(partial.get(), referenceState)); + } + + public MODEL getModel(AllBlockPartials partial, BlockState referenceState, Direction dir, Supplier modelTransform) { + return get(Compartment.DIRECTIONAL_PARTIAL, Pair.of(dir, partial), + () -> buildModel(partial.get(), referenceState, modelTransform.get())); + } + + public MODEL getModel(Compartment compartment, BlockState toRender) { + return get(compartment, toRender, () -> buildModel(toRender)); + } + + public MODEL get(Compartment compartment, T key, Supplier supplier) { + Cache compartmentCache = models.get(compartment); + try { + return compartmentCache.get(key, supplier::get); + } catch (ExecutionException e) { + e.printStackTrace(); + return null; + } + } + + private MODEL buildModel(BlockState renderedState) { + BlockRendererDispatcher dispatcher = Minecraft.getInstance().getBlockRendererDispatcher(); + return buildModel(dispatcher.getModelForState(renderedState), renderedState); + } + + private MODEL buildModel(IBakedModel model, BlockState renderedState) { + return buildModel(model, renderedState, new MatrixStack()); + } + + private MODEL buildModel(IBakedModel model, BlockState referenceState, MatrixStack ms) { + BufferBuilder builder = SuperByteBufferCache.getBufferBuilder(model, referenceState, ms); + + return factory.makeModel(renderer, builder); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/TileEntityInstance.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/TileEntityInstance.java new file mode 100644 index 000000000..ed4b1f162 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/TileEntityInstance.java @@ -0,0 +1,56 @@ +package com.simibubi.create.foundation.render.backend.instancing; + +import net.minecraft.block.BlockState; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public abstract class TileEntityInstance { + + protected final InstancedTileRenderer modelManager; + protected final T tile; + protected final World world; + protected final BlockPos pos; + protected BlockState lastState; + + public TileEntityInstance(InstancedTileRenderer modelManager, T tile) { + this.modelManager = modelManager; + this.tile = tile; + this.world = tile.getWorld(); + this.pos = tile.getPos(); + this.lastState = tile.getBlockState(); + init(); + } + + public final void update() { + BlockState currentState = tile.getBlockState(); + if (lastState == currentState) { + onUpdate(); + } else { + remove(); + lastState = currentState; + init(); + } + } + + /** + * Acquire all {@link InstanceKey}s and initialize any data you may need to calculate the instance properties. + */ + protected abstract void init(); + + /** + * Update changed instance data using the {@link InstanceKey}s you got in {@link #init()}. + * You don't have to update light data. That should be done in {@link #updateLight()} + */ + protected abstract void onUpdate(); + + /** + * Called when a light update occurs in the world. If your model needs it, update light here. + */ + public void updateLight() { } + + /** + * Call {@link InstanceKey#delete()} on all acquired keys. + */ + public abstract void remove(); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/light/CoordinateConsumer.java b/src/main/java/com/simibubi/create/foundation/render/backend/light/CoordinateConsumer.java new file mode 100644 index 000000000..4011c19e0 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/light/CoordinateConsumer.java @@ -0,0 +1,6 @@ +package com.simibubi.create.foundation.render.backend.light; + +@FunctionalInterface +public interface CoordinateConsumer { + void consume(int x, int y, int z); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/light/EmptyLighter.java b/src/main/java/com/simibubi/create/foundation/render/backend/light/EmptyLighter.java new file mode 100644 index 000000000..b58653899 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/light/EmptyLighter.java @@ -0,0 +1,16 @@ +package com.simibubi.create.foundation.render.backend.light; + +import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; + +// so other contraptions don't crash before they have a lighter +public class EmptyLighter extends ContraptionLighter { + public EmptyLighter(Contraption contraption) { + super(contraption); + } + + @Override + public GridAlignedBB getContraptionBounds() { + return new GridAlignedBB(0, 0, 0, 1, 1, 1); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/light/GridAlignedBB.java b/src/main/java/com/simibubi/create/foundation/render/backend/light/GridAlignedBB.java new file mode 100644 index 000000000..e9bf8b6ee --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/light/GridAlignedBB.java @@ -0,0 +1,281 @@ +package com.simibubi.create.foundation.render.backend.light; + +import com.simibubi.create.foundation.render.RenderMath; +import net.minecraft.util.Direction; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.SectionPos; +import net.minecraft.util.math.Vec3i; + +import static com.simibubi.create.foundation.render.RenderMath.isPowerOf2; + +public class GridAlignedBB { + public int minX; + public int minY; + public int minZ; + public int maxX; + public int maxY; + public int maxZ; + + public GridAlignedBB(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { + this.minX = minX; + this.minY = minY; + this.minZ = minZ; + this.maxX = maxX; + this.maxY = maxY; + this.maxZ = maxZ; + } + + public static GridAlignedBB ofRadius(int radius) { + return new GridAlignedBB(-radius, -radius, -radius, radius + 1, radius + 1, radius + 1); + } + + public static GridAlignedBB copy(GridAlignedBB bb) { + return new GridAlignedBB(bb.minX, bb.minY, bb.minZ, bb.maxX, bb.maxY, bb.maxZ); + } + + public static GridAlignedBB fromAABB(AxisAlignedBB aabb) { + int minX = (int) Math.floor(aabb.minX); + int minY = (int) Math.floor(aabb.minY); + int minZ = (int) Math.floor(aabb.minZ); + int maxX = (int) Math.ceil(aabb.maxX); + int maxY = (int) Math.ceil(aabb.maxY); + int maxZ = (int) Math.ceil(aabb.maxZ); + return new GridAlignedBB(minX, minY, minZ, maxX, maxY, maxZ); + } + + public static GridAlignedBB fromSection(SectionPos pos) { + return new GridAlignedBB(pos.getWorldStartX(), + pos.getWorldStartY(), + pos.getWorldStartZ(), + pos.getWorldEndX() + 1, + pos.getWorldEndY() + 1, + pos.getWorldEndZ() + 1); + } + + public static AxisAlignedBB toAABB(GridAlignedBB bb) { + return new AxisAlignedBB(bb.minX, bb.minY, bb.minZ, bb.maxX, bb.maxY, bb.maxZ); + } + + public GridAlignedBB copy() { + return copy(this); + } + + public boolean sameAs(GridAlignedBB other) { + return minX == other.minX && + minY == other.minY && + minZ == other.minZ && + maxX == other.maxX && + maxY == other.maxY && + maxZ == other.maxZ; + } + + public int sizeX() { + return maxX - minX; + } + + public int sizeY() { + return maxY - minY; + } + + public int sizeZ() { + return maxZ - minZ; + } + + public int volume() { + return sizeX() * sizeY() * sizeZ(); + } + + public boolean empty() { + // if any dimension has side length 0 this box contains no volume + return minX == maxX || + minY == maxY || + minZ == maxZ; + } + + public void translate(Vec3i by) { + translate(by.getX(), by.getY(), by.getZ()); + } + + public void translate(int x, int y, int z) { + minX += x; + maxX += x; + minY += y; + maxY += y; + minZ += z; + maxZ += z; + } + + public void mirrorAbout(Direction.Axis axis) { + Vec3i axisVec = Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, axis).getDirectionVec(); + int flipX = axisVec.getX() - 1; + int flipY = axisVec.getY() - 1; + int flipZ = axisVec.getZ() - 1; + + int maxX = this.maxX * flipX; + int maxY = this.maxY * flipY; + int maxZ = this.maxZ * flipZ; + this.maxX = this.minX * flipX; + this.maxY = this.minY * flipY; + this.maxZ = this.minZ * flipZ; + this.minX = maxX; + this.minY = maxY; + this.minZ = maxZ; + } + + /** + * Grow this bounding box to have power of 2 side length, scaling from the center. + */ + public void nextPowerOf2Centered() { + int sizeX = sizeX(); + int sizeY = sizeY(); + int sizeZ = sizeZ(); + + int newSizeX = RenderMath.nextPowerOf2(sizeX); + int newSizeY = RenderMath.nextPowerOf2(sizeY); + int newSizeZ = RenderMath.nextPowerOf2(sizeZ); + + int diffX = newSizeX - sizeX; + int diffY = newSizeY - sizeY; + int diffZ = newSizeZ - sizeZ; + + minX -= diffX / 2; // floor division for the minimums + minY -= diffY / 2; + minZ -= diffZ / 2; + maxX += (diffX + 1) / 2; // ceiling divison for the maximums + maxY += (diffY + 1) / 2; + maxZ += (diffZ + 1) / 2; + } + + /** + * Grow this bounding box to have power of 2 side lengths, scaling from the minimum coords. + */ + public void nextPowerOf2() { + int sizeX = RenderMath.nextPowerOf2(sizeX()); + int sizeY = RenderMath.nextPowerOf2(sizeY()); + int sizeZ = RenderMath.nextPowerOf2(sizeZ()); + + this.maxX = this.minX + sizeX; + this.maxY = this.minY + sizeY; + this.maxZ = this.minZ + sizeZ; + } + + public boolean hasPowerOf2Sides() { + // this is only true if all individual side lengths are powers of 2 + return isPowerOf2(volume()); + } + + public void grow(int s) { + this.grow(s, s, s); + } + + public void grow(int x, int y, int z) { + minX -= x; + minY -= y; + minZ -= z; + maxX += x; + maxY += y; + maxZ += z; + } + + public GridAlignedBB intersect(GridAlignedBB other) { + int minX = Math.max(this.minX, other.minX); + int minY = Math.max(this.minY, other.minY); + int minZ = Math.max(this.minZ, other.minZ); + int maxX = Math.min(this.maxX, other.maxX); + int maxY = Math.min(this.maxY, other.maxY); + int maxZ = Math.min(this.maxZ, other.maxZ); + return new GridAlignedBB(minX, minY, minZ, maxX, maxY, maxZ); + } + + public void intersectAssign(GridAlignedBB other) { + this.minX = Math.max(this.minX, other.minX); + this.minY = Math.max(this.minY, other.minY); + this.minZ = Math.max(this.minZ, other.minZ); + this.maxX = Math.min(this.maxX, other.maxX); + this.maxY = Math.min(this.maxY, other.maxY); + this.maxZ = Math.min(this.maxZ, other.maxZ); + } + + public GridAlignedBB union(GridAlignedBB other) { + int minX = Math.min(this.minX, other.minX); + int minY = Math.min(this.minY, other.minY); + int minZ = Math.min(this.minZ, other.minZ); + int maxX = Math.max(this.maxX, other.maxX); + int maxY = Math.max(this.maxY, other.maxY); + int maxZ = Math.max(this.maxZ, other.maxZ); + return new GridAlignedBB(minX, minY, minZ, maxX, maxY, maxZ); + } + + public void unionAssign(GridAlignedBB other) { + this.minX = Math.min(this.minX, other.minX); + this.minY = Math.min(this.minY, other.minY); + this.minZ = Math.min(this.minZ, other.minZ); + this.maxX = Math.max(this.maxX, other.maxX); + this.maxY = Math.max(this.maxY, other.maxY); + this.maxZ = Math.max(this.maxZ, other.maxZ); + } + + public void unionAssign(AxisAlignedBB other) { + this.minX = Math.min(this.minX, (int) Math.floor(other.minX)); + this.minY = Math.min(this.minY, (int) Math.floor(other.minY)); + this.minZ = Math.min(this.minZ, (int) Math.floor(other.minZ)); + this.maxX = Math.max(this.maxX, (int) Math.ceil(other.maxX)); + this.maxY = Math.max(this.maxY, (int) Math.ceil(other.maxY)); + this.maxZ = Math.max(this.maxZ, (int) Math.ceil(other.maxZ)); + } + + public boolean intersects(GridAlignedBB other) { + return this.intersects(other.minX, other.minY, other.minZ, other.maxX, other.maxY, other.maxZ); + } + + public boolean contains(GridAlignedBB other) { + return other.minX >= this.minX && + other.maxX <= this.maxX && + other.minY >= this.minY && + other.maxY <= this.maxY && + other.minZ >= this.minZ && + other.maxZ <= this.maxZ; + } + + public boolean isContainedBy(GridAlignedBB other) { + return other.contains(this); + } + + public boolean intersects(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { + return this.minX < maxX && this.maxX > minX && this.minY < maxY && this.maxY > minY && this.minZ < maxZ && this.maxZ > minZ; + } + + public void forEachContained(CoordinateConsumer func) { + if (empty()) return; + + for (int x = minX; x < maxX; x++) { + for (int y = Math.max(minY, 0); y < Math.min(maxY, 255); y++) { // clamp to world height limits + for (int z = minZ; z < maxZ; z++) { + func.consume(x, y, z); + } + } + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + GridAlignedBB that = (GridAlignedBB) o; + + return this.sameAs(that); + } + + @Override + public int hashCode() { + int result = minX; + result = 31 * result + minY; + result = 31 * result + minZ; + result = 31 * result + maxX; + result = 31 * result + maxY; + result = 31 * result + maxZ; + return result; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/light/ILightListener.java b/src/main/java/com/simibubi/create/foundation/render/backend/light/ILightListener.java new file mode 100644 index 000000000..5fd2ff8bd --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/light/ILightListener.java @@ -0,0 +1,5 @@ +package com.simibubi.create.foundation.render.backend.light; + +public interface ILightListener { + void onChunkLightUpdate(); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/light/LightVolume.java b/src/main/java/com/simibubi/create/foundation/render/backend/light/LightVolume.java new file mode 100644 index 000000000..97f12c48f --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/light/LightVolume.java @@ -0,0 +1,286 @@ +package com.simibubi.create.foundation.render.backend.light; + +import com.simibubi.create.foundation.render.backend.RenderWork; +import com.simibubi.create.foundation.render.backend.gl.GlTexture; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.SectionPos; +import net.minecraft.world.ILightReader; +import net.minecraft.world.LightType; +import org.lwjgl.opengl.*; +import org.lwjgl.system.MemoryUtil; + +import java.nio.ByteBuffer; + +public class LightVolume { + + private GridAlignedBB sampleVolume; + private GridAlignedBB textureVolume; + private ByteBuffer lightData; + + private boolean bufferDirty; + private boolean removed; + + private final GlTexture glTexture; + + public LightVolume(GridAlignedBB sampleVolume) { + setSampleVolume(sampleVolume); + + this.glTexture = new GlTexture(GL20.GL_TEXTURE_3D); + this.lightData = MemoryUtil.memAlloc(this.textureVolume.volume() * 2); // TODO: reduce this to span only sampleVolume + + // allocate space for the texture + GL20.glActiveTexture(GL20.GL_TEXTURE4); + glTexture.bind(); + + int sizeX = textureVolume.sizeX(); + int sizeY = textureVolume.sizeY(); + int sizeZ = textureVolume.sizeZ(); + GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL40.GL_RG8, sizeX, sizeY, sizeZ, 0, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, 0); + + glTexture.unbind(); + GL20.glActiveTexture(GL20.GL_TEXTURE0); + } + + private void setSampleVolume(GridAlignedBB sampleVolume) { + this.sampleVolume = sampleVolume; + this.textureVolume = sampleVolume.copy(); + this.textureVolume.nextPowerOf2Centered(); + } + + public GridAlignedBB getTextureVolume() { + return GridAlignedBB.copy(textureVolume); + } + + public GridAlignedBB getSampleVolume() { + return GridAlignedBB.copy(sampleVolume); + } + + public int getMinX() { + return textureVolume.minX; + } + + public int getMinY() { + return textureVolume.minY; + } + + public int getMinZ() { + return textureVolume.minZ; + } + + public int getMaxX() { + return textureVolume.maxX; + } + + public int getMaxY() { + return textureVolume.maxY; + } + + public int getMaxZ() { + return textureVolume.maxZ; + } + + public int getSizeX() { + return textureVolume.sizeX(); + } + + public int getSizeY() { + return textureVolume.sizeY(); + } + + public int getSizeZ() { + return textureVolume.sizeZ(); + } + + public void move(ILightReader world, GridAlignedBB newSampleVolume) { + if (textureVolume.contains(newSampleVolume)) { + if (newSampleVolume.intersects(sampleVolume)) { + GridAlignedBB newArea = newSampleVolume.intersect(sampleVolume); + sampleVolume = newSampleVolume; + + copyLight(world, newArea); + } else { + sampleVolume = newSampleVolume; + initialize(world); + } + } else { + setSampleVolume(newSampleVolume); + int volume = textureVolume.volume(); + if (volume * 2 > lightData.capacity()) { + lightData = MemoryUtil.memRealloc(lightData, volume * 2); + } + initialize(world); + } + } + + public void notifyLightUpdate(ILightReader world, LightType type, SectionPos location) { + GridAlignedBB changedVolume = GridAlignedBB.fromSection(location); + if (!changedVolume.intersects(sampleVolume)) + return; + changedVolume.intersectAssign(sampleVolume); // compute the region contained by us that has dirty lighting data. + + if (type == LightType.BLOCK) copyBlock(world, changedVolume); + else if (type == LightType.SKY) copySky(world, changedVolume); + } + + /** + * Completely (re)populate this volume with block and sky lighting data. + * This is expensive and should be avoided. + */ + public void initialize(ILightReader world) { + BlockPos.Mutable pos = new BlockPos.Mutable(); + + int shiftX = textureVolume.minX; + int shiftY = textureVolume.minY; + int shiftZ = textureVolume.minZ; + + sampleVolume.forEachContained((x, y, z) -> { + pos.setPos(x, y, z); + + int blockLight = world.getLightLevel(LightType.BLOCK, pos); + int skyLight = world.getLightLevel(LightType.SKY, pos); + + writeLight(x - shiftX, y - shiftY, z - shiftZ, blockLight, skyLight); + }); + + bufferDirty = true; + } + + /** + * Copy block light from the world into this volume. + * @param worldVolume the region in the world to copy data from. + */ + public void copyBlock(ILightReader world, GridAlignedBB worldVolume) { + BlockPos.Mutable pos = new BlockPos.Mutable(); + + int xShift = textureVolume.minX; + int yShift = textureVolume.minY; + int zShift = textureVolume.minZ; + + worldVolume.forEachContained((x, y, z) -> { + pos.setPos(x, y, z); + + int light = world.getLightLevel(LightType.BLOCK, pos); + + writeBlock(x - xShift, y - yShift, z - zShift, light); + }); + + bufferDirty = true; + } + + /** + * Copy sky light from the world into this volume. + * @param worldVolume the region in the world to copy data from. + */ + public void copySky(ILightReader world, GridAlignedBB worldVolume) { + BlockPos.Mutable pos = new BlockPos.Mutable(); + + int xShift = textureVolume.minX; + int yShift = textureVolume.minY; + int zShift = textureVolume.minZ; + + worldVolume.forEachContained((x, y, z) -> { + pos.setPos(x, y, z); + + int light = world.getLightLevel(LightType.SKY, pos); + + writeSky(x - xShift, y - yShift, z - zShift, light); + }); + + bufferDirty = true; + } + + /** + * Copy all light from the world into this volume. + * @param worldVolume the region in the world to copy data from. + */ + public void copyLight(ILightReader world, GridAlignedBB worldVolume) { + BlockPos.Mutable pos = new BlockPos.Mutable(); + + int xShift = textureVolume.minX; + int yShift = textureVolume.minY; + int zShift = textureVolume.minZ; + + worldVolume.forEachContained((x, y, z) -> { + pos.setPos(x, y, z); + + int block = world.getLightLevel(LightType.BLOCK, pos); + int sky = world.getLightLevel(LightType.SKY, pos); + + writeLight(x - xShift, y - yShift, z - zShift, block, sky); + }); + + bufferDirty = true; + } + + public void bind() { + // just in case something goes wrong or we accidentally call this before this volume is properly disposed of. + if (lightData == null || removed) return; + + GL13.glActiveTexture(GL40.GL_TEXTURE4); + glTexture.bind(); + GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MIN_FILTER, GL13.GL_LINEAR); + GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MAG_FILTER, GL13.GL_LINEAR); + GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_S, GL20.GL_MIRRORED_REPEAT); + GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_R, GL20.GL_MIRRORED_REPEAT); + GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_T, GL20.GL_MIRRORED_REPEAT); + + uploadTexture(); + } + + private void uploadTexture() { + if (bufferDirty) { + GL20.glPixelStorei(GL20.GL_UNPACK_ROW_LENGTH, 0); + GL20.glPixelStorei(GL20.GL_UNPACK_SKIP_PIXELS, 0); + GL20.glPixelStorei(GL20.GL_UNPACK_SKIP_ROWS, 0); + GL20.glPixelStorei(GL20.GL_UNPACK_SKIP_IMAGES, 0); + GL20.glPixelStorei(GL20.GL_UNPACK_IMAGE_HEIGHT, 0); + GL20.glPixelStorei(GL20.GL_UNPACK_ALIGNMENT, 2); + int sizeX = textureVolume.sizeX(); + int sizeY = textureVolume.sizeY(); + int sizeZ = textureVolume.sizeZ(); + + GL12.glTexSubImage3D(GL12.GL_TEXTURE_3D, 0, 0, 0, 0, sizeX, sizeY, sizeZ, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, lightData); + + GL20.glPixelStorei(GL20.GL_UNPACK_ALIGNMENT, 4); // 4 is the default + bufferDirty = false; + } + } + + public void unbind() { + glTexture.unbind(); + } + + public void delete() { + removed = true; + RenderWork.enqueue(() -> { + glTexture.delete(); + MemoryUtil.memFree(lightData); + lightData = null; + }); + } + + private void writeLight(int x, int y, int z, int block, int sky) { + byte b = (byte) ((block & 0xF) << 4); + byte s = (byte) ((sky & 0xF) << 4); + + int i = index(x, y, z); + lightData.put(i, b); + lightData.put(i + 1, s); + } + + private void writeBlock(int x, int y, int z, int block) { + byte b = (byte) ((block & 0xF) << 4); + + lightData.put(index(x, y, z), b); + } + + private void writeSky(int x, int y, int z, int sky) { + byte b = (byte) ((sky & 0xF) << 4); + + lightData.put(index(x, y, z) + 1, b); + } + + private int index(int x, int y, int z) { + return (x + textureVolume.sizeX() * (y + z * textureVolume.sizeY())) * 2; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/light/LightVolumeDebugger.java b/src/main/java/com/simibubi/create/foundation/render/backend/light/LightVolumeDebugger.java new file mode 100644 index 000000000..63395a69a --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/light/LightVolumeDebugger.java @@ -0,0 +1,34 @@ +package com.simibubi.create.foundation.render.backend.light; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; +import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; +import com.simibubi.create.foundation.utility.Pair; +import com.simibubi.create.foundation.utility.outliner.AABBOutline; + +import java.util.ArrayList; + +public class LightVolumeDebugger { + public static void render(MatrixStack ms, SuperRenderTypeBuffer buffer) { + ContraptionRenderDispatcher.renderers.values() + .stream() + .flatMap(r -> { + GridAlignedBB texture = r.getLighter().lightVolume.getTextureVolume(); + GridAlignedBB sample = r.getLighter().lightVolume.getSampleVolume(); + + ArrayList> pairs = new ArrayList<>(2); + + pairs.add(Pair.of(texture, 0xFFFFFF)); + pairs.add(Pair.of(sample, 0xFFFF00)); + + return pairs.stream(); + }) + .map(pair -> { + AABBOutline outline = new AABBOutline(GridAlignedBB.toAABB(pair.getFirst())); + + outline.getParams().colored(pair.getSecond()); + return outline; + }) + .forEach(outline -> outline.render(ms, buffer)); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/renderer/ColoredOverlayTileEntityRenderer.java b/src/main/java/com/simibubi/create/foundation/tileEntity/renderer/ColoredOverlayTileEntityRenderer.java index b8bc4b733..23df51f8f 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/renderer/ColoredOverlayTileEntityRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/renderer/ColoredOverlayTileEntityRenderer.java @@ -1,7 +1,7 @@ package com.simibubi.create.foundation.tileEntity.renderer; import com.mojang.blaze3d.matrix.MatrixStack; -import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.IRenderTypeBuffer; diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/renderer/SafeTileEntityRenderer.java b/src/main/java/com/simibubi/create/foundation/tileEntity/renderer/SafeTileEntityRenderer.java index 6c02f67f9..bc4c0de82 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/renderer/SafeTileEntityRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/renderer/SafeTileEntityRenderer.java @@ -7,6 +7,7 @@ import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.client.model.pipeline.LightUtil; public abstract class SafeTileEntityRenderer extends TileEntityRenderer { diff --git a/src/main/java/com/simibubi/create/foundation/utility/AnimationTickHolder.java b/src/main/java/com/simibubi/create/foundation/utility/AnimationTickHolder.java index 01f01de38..4b8f410c5 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/AnimationTickHolder.java +++ b/src/main/java/com/simibubi/create/foundation/utility/AnimationTickHolder.java @@ -4,14 +4,28 @@ import net.minecraft.client.Minecraft; public class AnimationTickHolder { - public static int ticks; + private static int ticks; + + public static void reset() { + ticks = 0; + } public static void tick() { - ticks++; + if (!Minecraft.getInstance().isGamePaused()) { + ticks = (ticks + 1) % 1_728_000; // wrap around every 24 hours so we maintain enough floating point precision + } } public static float getRenderTick() { - return ticks + Minecraft.getInstance().getRenderPartialTicks(); + return getTicks() + getPartialTicks(); } + public static float getPartialTicks() { + Minecraft mc = Minecraft.getInstance(); + return (mc.isGamePaused() ? mc.renderPartialTicksPaused : mc.getRenderPartialTicks()); + } + + public static int getTicks() { + return ticks; + } } diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/ChasingAABBOutline.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/ChasingAABBOutline.java index 2fcacb96a..931b2affb 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/outliner/ChasingAABBOutline.java +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/ChasingAABBOutline.java @@ -2,8 +2,7 @@ package com.simibubi.create.foundation.utility.outliner; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; - -import net.minecraft.client.Minecraft; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.MathHelper; @@ -30,8 +29,7 @@ public class ChasingAABBOutline extends AABBOutline { @Override public void render(MatrixStack ms, SuperRenderTypeBuffer buffer) { - renderBB(ms, buffer, interpolateBBs(prevBB, bb, Minecraft.getInstance() - .getRenderPartialTicks())); + renderBB(ms, buffer, interpolateBBs(prevBB, bb, AnimationTickHolder.getPartialTicks())); } private static AxisAlignedBB interpolateBBs(AxisAlignedBB current, AxisAlignedBB target, float pt) { diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/LineOutline.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/LineOutline.java index 3f3a307ab..e76bbc56d 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/outliner/LineOutline.java +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/LineOutline.java @@ -2,8 +2,7 @@ package com.simibubi.create.foundation.utility.outliner; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; - -import net.minecraft.client.Minecraft; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -47,8 +46,7 @@ public class LineOutline extends Outline { @Override public void render(MatrixStack ms, SuperRenderTypeBuffer buffer) { - float pt = Minecraft.getInstance() - .getRenderPartialTicks(); + float pt = AnimationTickHolder.getPartialTicks(); float distanceToTarget = 1 - MathHelper.lerp(pt, prevProgress, progress); Vec3d start = end.add(this.start.subtract(end) .scale(distanceToTarget)); diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java index 9c442b89d..61a210cb5 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java @@ -3,6 +3,7 @@ package com.simibubi.create.foundation.utility.outliner; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; import com.simibubi.create.foundation.tileEntity.behaviour.ValueBox; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.outliner.LineOutline.EndChasingLineOutline; import com.simibubi.create.foundation.utility.outliner.Outline.OutlineParams; import net.minecraft.client.Minecraft; @@ -150,8 +151,7 @@ public class Outliner { float fadeticks = OutlineEntry.fadeTicks; float lastAlpha = prevTicks >= 0 ? 1 : 1 + (prevTicks / fadeticks); float currentAlpha = 1 + (entry.ticksTillRemoval / fadeticks); - float alpha = MathHelper.lerp(Minecraft.getInstance() - .getRenderPartialTicks(), lastAlpha, currentAlpha); + float alpha = MathHelper.lerp(AnimationTickHolder.getPartialTicks(), lastAlpha, currentAlpha); outline.params.alpha = alpha * alpha * alpha; if (outline.params.alpha < 1 / 8f) diff --git a/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/PlacementSimulationWorld.java b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/PlacementSimulationWorld.java index ee209d16f..8e8d71b3c 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/PlacementSimulationWorld.java +++ b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/PlacementSimulationWorld.java @@ -2,24 +2,44 @@ package com.simibubi.create.foundation.utility.worldWrappers; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.function.Predicate; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.SectionPos; import net.minecraft.world.World; +import net.minecraft.world.lighting.WorldLightManager; public class PlacementSimulationWorld extends WrappedWorld { public HashMap blocksAdded; public HashMap tesAdded; + public HashSet spannedChunks; + public WorldLightManager lighter; + public WrappedChunkProvider chunkProvider; + private final BlockPos.Mutable scratch = new BlockPos.Mutable(); + public PlacementSimulationWorld(World wrapped) { - super(wrapped); + this(wrapped, new WrappedChunkProvider()); + } + + public PlacementSimulationWorld(World wrapped, WrappedChunkProvider chunkProvider) { + super(wrapped, chunkProvider); + this.chunkProvider = chunkProvider.setWorld(this); + spannedChunks = new HashSet<>(); + lighter = new WorldLightManager(chunkProvider, true, false); // blockLight, skyLight blocksAdded = new HashMap<>(); tesAdded = new HashMap<>(); } + @Override + public WorldLightManager getLightingProvider() { + return lighter; + } + public void setTileEntities(Collection tileEntities) { tesAdded.clear(); tileEntities.forEach(te -> tesAdded.put(te.getPos(), te)); @@ -31,6 +51,15 @@ public class PlacementSimulationWorld extends WrappedWorld { @Override public boolean setBlockState(BlockPos pos, BlockState newState, int flags) { + + SectionPos sectionPos = SectionPos.from(pos); + + if (spannedChunks.add(sectionPos)) { + lighter.updateSectionStatus(sectionPos, false); + } + + lighter.checkBlock(pos); + blocksAdded.put(pos, newState); return true; } @@ -60,11 +89,17 @@ public class PlacementSimulationWorld extends WrappedWorld { return true; } + public BlockState getBlockState(int x, int y, int z) { + return getBlockState(scratch.setPos(x, y, z)); + } + @Override public BlockState getBlockState(BlockPos pos) { - if (blocksAdded.containsKey(pos)) - return blocksAdded.get(pos); - return Blocks.AIR.getDefaultState(); + BlockState state = blocksAdded.get(pos); + if (state != null) + return state; + else + return Blocks.AIR.getDefaultState(); } } diff --git a/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/WrappedChunkProvider.java b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/WrappedChunkProvider.java new file mode 100644 index 000000000..e34d5cb11 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/WrappedChunkProvider.java @@ -0,0 +1,82 @@ +package com.simibubi.create.foundation.utility.worldWrappers; + +import com.simibubi.create.foundation.utility.worldWrappers.chunk.WrappedChunk; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.chunk.AbstractChunkProvider; +import net.minecraft.world.chunk.ChunkStatus; +import net.minecraft.world.chunk.IChunk; +import net.minecraft.world.chunk.IChunkLightProvider; +import net.minecraft.world.lighting.WorldLightManager; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; +import java.util.function.BooleanSupplier; +import java.util.stream.Stream; + +public class WrappedChunkProvider extends AbstractChunkProvider { + private PlacementSimulationWorld world; + + public HashMap chunks; + + public WrappedChunkProvider setWorld(PlacementSimulationWorld world) { + this.world = world; + this.chunks = new HashMap<>(); + return this; + } + + public Stream getLightSources() { + return world.blocksAdded + .entrySet() + .stream() + .filter(it -> it.getValue().getLightValue(world, it.getKey()) != 0) + .map(Map.Entry::getKey); + } + + @Nullable + @Override + public IBlockReader getChunkForLight(int x, int z) { + return getChunk(x, z); + } + + @Override + public IBlockReader getWorld() { + return world; + } + + @Nullable + @Override + public IChunk getChunk(int x, int z, ChunkStatus status, boolean p_212849_4_) { + return getChunk(x, z); + } + + public WrappedChunk getChunk(int x, int z) { + long pos = ChunkPos.asLong(x, z); + + WrappedChunk chunk = chunks.get(pos); + + if (chunk == null) { + chunk = new WrappedChunk(world, x, z); + chunks.put(pos, chunk); + } + + return chunk; + } + + @Override + public void tick(BooleanSupplier p_217207_1_) { + + } + + @Override + public String makeString() { + return "WrappedChunkProvider"; + } + + @Override + public WorldLightManager getLightManager() { + return world.getLightingProvider(); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/WrappedWorld.java b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/WrappedWorld.java index b198db079..e986bf8bd 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/WrappedWorld.java +++ b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/WrappedWorld.java @@ -19,18 +19,30 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.ITickList; import net.minecraft.world.World; import net.minecraft.world.biome.Biome; +import net.minecraft.world.lighting.WorldLightManager; import net.minecraft.world.storage.MapData; public class WrappedWorld extends World { protected World world; + public WrappedWorld(World world, WrappedChunkProvider provider) { + super(world.getWorldInfo(), world.getDimension().getType(), (w, d) -> provider, + world.getProfiler(), world.isRemote); + this.world = world; + } + public WrappedWorld(World world) { super(world.getWorldInfo(), world.getDimension().getType(), (w, d) -> world.getChunkProvider(), world.getProfiler(), world.isRemote); this.world = world; } + @Override + public WorldLightManager getLightingProvider() { + return super.getLightingProvider(); + } + @Override public World getWorld() { return world; diff --git a/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/chunk/WrappedChunk.java b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/chunk/WrappedChunk.java new file mode 100644 index 000000000..e21d3d044 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/chunk/WrappedChunk.java @@ -0,0 +1,258 @@ +package com.simibubi.create.foundation.utility.worldWrappers.chunk; + +import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld; +import com.simibubi.create.foundation.utility.worldWrappers.WrappedWorld; +import it.unimi.dsi.fastutil.longs.LongSet; +import it.unimi.dsi.fastutil.shorts.ShortList; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.entity.Entity; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.IFluidState; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.palette.UpgradeData; +import net.minecraft.world.ITickList; +import net.minecraft.world.biome.BiomeContainer; +import net.minecraft.world.chunk.ChunkSection; +import net.minecraft.world.chunk.ChunkStatus; +import net.minecraft.world.chunk.IChunk; +import net.minecraft.world.gen.Heightmap; +import net.minecraft.world.gen.feature.structure.StructureStart; + +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; + +public class WrappedChunk implements IChunk { + + final PlacementSimulationWorld world; + boolean needsLight; + final int x; + final int z; + final ChunkPos pos; + + private final ChunkSection[] sections; + + public WrappedChunk(PlacementSimulationWorld world, int x, int z) { + this.world = world; + this.needsLight = true; + this.x = x; + this.z = z; + this.pos = new ChunkPos(x, z); + + this.sections = new ChunkSection[16]; + + for (int i = 0; i < 16; i++) { + sections[i] = new WrappedChunkSection(this, i << 4); + } + } + + @Override + public Stream getLightSources() { + return world.blocksAdded + .entrySet() + .stream() + .filter(it -> { + BlockPos blockPos = it.getKey(); + boolean chunkContains = blockPos.getX() >> 4 == x && blockPos.getZ() >> 4 == z; + return chunkContains && it.getValue().getLightValue(world, blockPos) != 0; + }) + .map(Map.Entry::getKey); + } + + @Override + public ChunkSection[] getSections() { + return sections; + } + + @Nullable + @Override + public BlockState setBlockState(BlockPos p_177436_1_, BlockState p_177436_2_, boolean p_177436_3_) { + return null; + } + + @Override + public void addTileEntity(BlockPos p_177426_1_, TileEntity p_177426_2_) { + + } + + @Override + public void addEntity(Entity p_76612_1_) { + + } + + @Override + public Set getTileEntitiesPos() { + return null; + } + + @Override + public Collection> func_217311_f() { + return null; + } + + @Override + public void setHeightmap(Heightmap.Type p_201607_1_, long[] p_201607_2_) { + + } + + @Override + public Heightmap getHeightmap(Heightmap.Type p_217303_1_) { + return null; + } + + @Override + public int getTopBlockY(Heightmap.Type p_201576_1_, int p_201576_2_, int p_201576_3_) { + return 0; + } + + @Override + public ChunkPos getPos() { + return null; + } + + @Override + public void setLastSaveTime(long p_177432_1_) { + + } + + @Override + public Map getStructureStarts() { + return null; + } + + @Override + public void setStructureStarts(Map p_201612_1_) { + + } + + @Nullable + @Override + public BiomeContainer getBiomeArray() { + return null; + } + + @Override + public void setModified(boolean p_177427_1_) { + + } + + @Override + public boolean isModified() { + return false; + } + + @Override + public ChunkStatus getStatus() { + return null; + } + + @Override + public void removeTileEntity(BlockPos p_177425_1_) { + + } + + @Override + public ShortList[] getPackedPositions() { + return new ShortList[0]; + } + + @Nullable + @Override + public CompoundNBT getDeferredTileEntity(BlockPos p_201579_1_) { + return null; + } + + @Nullable + @Override + public CompoundNBT func_223134_j(BlockPos p_223134_1_) { + return null; + } + + @Override + public ITickList getBlocksToBeTicked() { + return null; + } + + @Override + public ITickList getFluidsToBeTicked() { + return null; + } + + @Override + public UpgradeData getUpgradeData() { + return null; + } + + @Override + public void setInhabitedTime(long p_177415_1_) { + + } + + @Override + public long getInhabitedTime() { + return 0; + } + + @Override + public boolean hasLight() { + return needsLight; + } + + @Override + public void setLight(boolean needsLight) { + this.needsLight = needsLight; + } + + @Nullable + @Override + public TileEntity getTileEntity(BlockPos pos) { + return null; + } + + @Override + public BlockState getBlockState(BlockPos pos) { + return world.getBlockState(pos); + } + + @Override + public IFluidState getFluidState(BlockPos pos) { + return null; + } + + @Nullable + @Override + public StructureStart getStructureStart(String p_201585_1_) { + return null; + } + + @Override + public void putStructureStart(String p_201584_1_, StructureStart p_201584_2_) { + + } + + @Override + public LongSet getStructureReferences(String p_201578_1_) { + return null; + } + + @Override + public void addStructureReference(String p_201583_1_, long p_201583_2_) { + + } + + @Override + public Map getStructureReferences() { + return null; + } + + @Override + public void setStructureReferences(Map p_201606_1_) { + + } +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/chunk/WrappedChunkSection.java b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/chunk/WrappedChunkSection.java new file mode 100644 index 000000000..e5e90594d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/chunk/WrappedChunkSection.java @@ -0,0 +1,32 @@ +package com.simibubi.create.foundation.utility.worldWrappers.chunk; + +import net.minecraft.block.BlockState; +import net.minecraft.world.chunk.ChunkSection; + +public class WrappedChunkSection extends ChunkSection { + + public WrappedChunk owner; + + public final int xStart; + public final int yStart; + public final int zStart; + + public WrappedChunkSection(WrappedChunk owner, int yBase) { + super(yBase); + this.owner = owner; + this.xStart = owner.pos.getXStart(); + this.yStart = yBase; + this.zStart = owner.pos.getZStart(); + } + + @Override + public BlockState getBlockState(int x, int y, int z) { + // ChunkSection#getBlockState expects local chunk coordinates, so we add to get back into world coords. + return owner.world.getBlockState(x + xStart, y + yStart, z + zStart); + } + + @Override + public BlockState setBlockState(int p_177484_1_, int p_177484_2_, int p_177484_3_, BlockState p_177484_4_, boolean p_177484_5_) { + throw new IllegalStateException("Chunk sections should not be mutated in a fake world."); + } +} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 254548d6f..d70fcdb5c 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -25,6 +25,21 @@ public net.minecraft.tileentity.BeaconTileEntity field_174909_f # beamSegments public net.minecraft.world.server.ServerTickList field_205374_d # pendingTickListEntriesHashSet public net.minecraft.world.server.ServerTickList field_205375_e # pendingTickListEntriesTreeSet +# Lightmap information for instanced rendering +public net.minecraft.client.renderer.LightTexture field_205112_c #resourceLocation +public net.minecraft.client.Minecraft field_193996_ah #renderPartialTicksPaused + +# Functions needed to setup a projection matrix +public net.minecraft.client.renderer.GameRenderer field_78529_t #rendererUpdateCount +public net.minecraft.client.renderer.GameRenderer func_228380_a_(Lcom/mojang/blaze3d/matrix/MatrixStack;F)V #bobViewWhenHurt +public net.minecraft.client.renderer.GameRenderer func_228383_b_(Lcom/mojang/blaze3d/matrix/MatrixStack;F)V #bobView + +# Expose fog state to the public +public com.mojang.blaze3d.platform.GlStateManager$FogState +public com.mojang.blaze3d.platform.GlStateManager field_225663_h_ #FOG +public com.mojang.blaze3d.platform.GlStateManager$BooleanState +public com.mojang.blaze3d.platform.GlStateManager$BooleanState field_179201_b #field_179201_b + # GameRenderer public net.minecraft.client.renderer.GameRenderer func_215311_a(Lnet/minecraft/client/renderer/ActiveRenderInfo;FZ)D #getFOVModifier diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 3b69e270c..a77dc0b61 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -14,7 +14,7 @@ Technology that empowers the player.''' [[dependencies.create]] modId="forge" mandatory=true - versionRange="[31.2.0,)" + versionRange="[31.2.44,)" ordering="NONE" side="BOTH" diff --git a/src/main/resources/assets/create/shader/belt.vert b/src/main/resources/assets/create/shader/belt.vert new file mode 100644 index 000000000..c150f012b --- /dev/null +++ b/src/main/resources/assets/create/shader/belt.vert @@ -0,0 +1,106 @@ +#version 110 +#define PI 3.1415926538 + +attribute vec3 aPos; +attribute vec3 aNormal; +attribute vec2 aTexCoords; + +attribute vec3 aInstancePos; +attribute vec2 aLight; +attribute vec3 aNetworkTint; +attribute float aSpeed; +attribute float aOffset; +attribute vec3 aInstanceRot; +attribute vec2 aSourceTexture; +attribute vec4 aScrollTexture; +attribute float aScrollMult; + +varying vec2 TexCoords; +varying vec4 Color; +varying float Diffuse; +varying vec2 Light; + +#if defined(CONTRAPTION) +varying vec3 BoxCoord; + +uniform vec3 uLightBoxSize; +uniform vec3 uLightBoxMin; +uniform mat4 uModel; +#endif + +uniform float uTime; +uniform mat4 uViewProjection; +uniform int uDebug; + +uniform vec3 uCameraPos; +varying float FragDistance; + +mat4 rotate(vec3 axis, float angle) { + float s = sin(angle); + float c = cos(angle); + float oc = 1. - c; + + return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0., + oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0., + oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0., + 0., 0., 0., 1.); +} + +float diffuse(vec3 normal) { + float x = normal.x; + float y = normal.y; + float z = normal.z; + return min(x * x * .6 + y * y * ((3. + y) / 4.) + z * z * .8, 1.); +} + +mat4 rotation(vec3 rot) { + return rotate(vec3(0., 1., 0.), rot.y) * rotate(vec3(0., 0., 1.), rot.z) * rotate(vec3(1., 0., 0.), rot.x); +} + +mat4 localRotation() { + vec3 rot = fract(aInstanceRot / 360.) * PI * 2.; + return rotation(rot); +} + +void main() { + mat4 localRotation = localRotation(); + vec4 worldPos = localRotation * vec4(aPos - .5, 1.) + vec4(aInstancePos + .5, 0.); + + #ifdef CONTRAPTION + worldPos = uModel * worldPos; + mat4 normalMat = uModel * localRotation; + + BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize; + FragDistance = length(worldPos.xyz); + #else + mat4 normalMat = localRotation; + + FragDistance = length(worldPos.xyz - uCameraPos); + #endif + + vec3 norm = normalize(normalMat * vec4(aNormal, 0.)).xyz; + + float scrollSize = aScrollTexture.w - aScrollTexture.y; + float scroll = fract(aSpeed * uTime / (36. * 16.) + aOffset) * scrollSize * aScrollMult; + + Diffuse = diffuse(norm); + TexCoords = aTexCoords - aSourceTexture + aScrollTexture.xy + vec2(0, scroll); + Light = aLight; + gl_Position = uViewProjection * worldPos; + + #ifdef CONTRAPTION + if (uDebug == 2) { + Color = vec4(norm, 1.); + } else { + Color = vec4(1.); + } + #else + if (uDebug == 1) { + Color = vec4(aNetworkTint, 1.); + } else if (uDebug == 2) { + Color = vec4(norm, 1.); + } else { + Color = vec4(1.); + } + #endif +} diff --git a/src/main/resources/assets/create/shader/contraption.frag b/src/main/resources/assets/create/shader/contraption.frag new file mode 100644 index 000000000..5d90b40ff --- /dev/null +++ b/src/main/resources/assets/create/shader/contraption.frag @@ -0,0 +1,33 @@ +#version 110 + +varying vec2 TexCoords; +varying vec4 Color; +varying float Diffuse; +varying vec2 Light; +varying float FragDistance; + +varying vec3 BoxCoord; + +uniform vec2 uFogRange; +uniform vec4 uFogColor; + +uniform sampler2D uBlockAtlas; +uniform sampler2D uLightMap; +uniform sampler3D uLightVolume; + +vec4 light() { + vec2 lm = texture3D(uLightVolume, BoxCoord).rg * 0.9375 + 0.03125; + return texture2D(uLightMap, max(lm, Light)); +} + +void main() { + vec4 tex = texture2D(uBlockAtlas, TexCoords); + + vec4 color = vec4(tex.rgb * light().rgb * Diffuse * Color.rgb, tex.a); + + float fog = (uFogRange.y - FragDistance) / (uFogRange.y - uFogRange.x); + fog = clamp(fog, 0., 1.); + + gl_FragColor = mix(uFogColor, color, fog); + gl_FragColor.a = color.a; +} \ No newline at end of file diff --git a/src/main/resources/assets/create/shader/contraption_actor.vert b/src/main/resources/assets/create/shader/contraption_actor.vert new file mode 100644 index 000000000..7dbae771c --- /dev/null +++ b/src/main/resources/assets/create/shader/contraption_actor.vert @@ -0,0 +1,88 @@ +#version 110 +#define PI 3.1415926538 +// model data +attribute vec3 aPos; +attribute vec3 aNormal; +attribute vec2 aTexCoords; + +// instance data +attribute vec3 aInstancePos; +attribute vec2 aModelLight; +attribute float aOffset; +attribute vec3 aAxis; +attribute vec3 aInstanceRot; +attribute vec3 aRotationCenter; + + +varying float Diffuse; +varying vec2 TexCoords; +varying vec4 Color; +varying vec3 BoxCoord; +varying vec2 Light; + +uniform vec3 uLightBoxSize; +uniform vec3 uLightBoxMin; +uniform mat4 uModel; + +uniform float uTime; +uniform mat4 uViewProjection; +uniform int uDebug; + +uniform vec3 uCameraPos; +varying float FragDistance; + +mat4 rotate(vec3 axis, float angle) { + float s = sin(angle); + float c = cos(angle); + float oc = 1. - c; + + return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0., + oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0., + oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0., + 0., 0., 0., 1.); +} + +float diffuse(vec3 normal) { + float x = normal.x; + float y = normal.y; + float z = normal.z; + return min(x * x * .6 + y * y * ((3. + y) / 4.) + z * z * .8, 1.); +} + +mat4 rotation(vec3 rot) { + return rotate(vec3(0., 1., 0.), rot.y) * rotate(vec3(0., 0., 1.), rot.z) * rotate(vec3(1., 0., 0.), rot.x); +} + +mat4 kineticRotation() { + const float speed = -20.; + float degrees = aOffset + uTime * speed * -3./10.; + float angle = fract(degrees / 360.) * PI * 2.; + + return rotate(normalize(aAxis), angle); +} + +void main() { + mat4 kineticRotation = kineticRotation(); + vec4 localPos = kineticRotation * vec4(aPos - aRotationCenter, 1.) + vec4(aRotationCenter, 0.); + + vec3 rot = fract(aInstanceRot / 360.) * PI * 2.; + mat4 localRot = rotation(rot); + localPos = localRot * vec4(localPos.xyz - .5, 1.) + vec4(aInstancePos + .5, 0.); + + vec4 worldPos = uModel * localPos; + + vec3 norm = normalize(uModel * localRot * kineticRotation * vec4(aNormal, 0.)).xyz; + + BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize; + Diffuse = diffuse(norm); + TexCoords = aTexCoords; + Light = aModelLight; + FragDistance = length(worldPos.xyz); + gl_Position = uViewProjection * worldPos; + + if (uDebug == 2) { + Color = vec4(norm, 1.); + } else { + Color = vec4(1.); + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/shader/contraption_structure.vert b/src/main/resources/assets/create/shader/contraption_structure.vert new file mode 100644 index 000000000..a665ea8ff --- /dev/null +++ b/src/main/resources/assets/create/shader/contraption_structure.vert @@ -0,0 +1,63 @@ +#version 110 +#define PI 3.1415926538 + +attribute vec3 aPos; +attribute vec3 aNormal; +attribute vec2 aTexCoords; +attribute vec4 aColor; +attribute vec2 aModelLight; + +varying float Diffuse; +varying vec2 TexCoords; +varying vec4 Color; +varying vec3 BoxCoord; +varying vec2 Light; + +uniform vec3 uLightBoxSize; +uniform vec3 uLightBoxMin; +uniform mat4 uModel; + +uniform float uTime; +uniform mat4 uViewProjection; +uniform int uDebug; + +uniform vec3 uCameraPos; +varying float FragDistance; + +mat4 rotate(vec3 axis, float angle) { + float s = sin(angle); + float c = cos(angle); + float oc = 1. - c; + + return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0., + oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0., + oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0., + 0., 0., 0., 1.); +} + +float diffuse(vec3 normal) { + float x = normal.x; + float y = normal.y; + float z = normal.z; + return min(x * x * .6 + y * y * ((3. + y) / 4.) + z * z * .8, 1.); +} + +void main() { + vec4 viewPos = uModel * vec4(aPos, 1.); + + vec3 norm = (uModel * vec4(aNormal, 0.)).xyz; + + BoxCoord = (viewPos.xyz - uLightBoxMin) / uLightBoxSize; + Diffuse = diffuse(norm); + Color = aColor / diffuse(aNormal); + TexCoords = aTexCoords; + Light = aModelLight; + FragDistance = length(viewPos.xyz); + gl_Position = uViewProjection * viewPos; + + if (uDebug == 2) { + Color = vec4(norm, 1.); + } else { + Color = aColor / diffuse(aNormal); + } +} diff --git a/src/main/resources/assets/create/shader/instanced.frag b/src/main/resources/assets/create/shader/instanced.frag new file mode 100644 index 000000000..cb85241f5 --- /dev/null +++ b/src/main/resources/assets/create/shader/instanced.frag @@ -0,0 +1,30 @@ +#version 110 + +varying vec2 TexCoords; +varying vec2 Light; +varying float Diffuse; +varying vec4 Color; +varying float FragDistance; + +uniform vec2 uFogRange; +uniform vec4 uFogColor; + +uniform sampler2D uBlockAtlas; +uniform sampler2D uLightMap; + +vec4 light() { + vec2 lm = Light * 0.9375 + 0.03125; + return texture2D(uLightMap, lm); +} + +void main() { + vec4 tex = texture2D(uBlockAtlas, TexCoords); + + vec4 color = vec4(tex.rgb * light().rgb * Diffuse, tex.a) * Color; + + float fog = (uFogRange.y - FragDistance) / (uFogRange.y - uFogRange.x); + fog = clamp(fog, 0., 1.); + + gl_FragColor = mix(uFogColor, color, fog); + gl_FragColor.a = color.a; +} \ No newline at end of file diff --git a/src/main/resources/assets/create/shader/rotating.vert b/src/main/resources/assets/create/shader/rotating.vert new file mode 100644 index 000000000..a1f803139 --- /dev/null +++ b/src/main/resources/assets/create/shader/rotating.vert @@ -0,0 +1,101 @@ +#version 110 +#define PI 3.1415926538 +attribute vec3 aPos; +attribute vec3 aNormal; +attribute vec2 aTexCoords; + +attribute vec3 aInstancePos; +attribute vec2 aLight; +attribute vec3 aNetworkTint; +attribute float aSpeed; +attribute float aOffset; +attribute vec3 aAxis; + +varying vec2 TexCoords; +varying vec4 Color; +varying float Diffuse; +varying vec2 Light; + +#if defined(CONTRAPTION) +varying vec3 BoxCoord; + +uniform vec3 uLightBoxSize; +uniform vec3 uLightBoxMin; +uniform mat4 uModel; +#endif + +uniform float uTime; +uniform mat4 uViewProjection; +uniform int uDebug; + +uniform vec3 uCameraPos; +varying float FragDistance; + +mat4 rotate(vec3 axis, float angle) { + float s = sin(angle); + float c = cos(angle); + float oc = 1. - c; + + return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0., + oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0., + oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0., + 0., 0., 0., 1.); +} + +float diffuse(vec3 normal) { + float x = normal.x; + float y = normal.y; + float z = normal.z; + return min(x * x * .6 + y * y * ((3. + y) / 4.) + z * z * .8, 1.); +} + +mat4 rotation(vec3 rot) { + return rotate(vec3(0., 1., 0.), rot.y) * rotate(vec3(0., 0., 1.), rot.z) * rotate(vec3(1., 0., 0.), rot.x); +} + +mat4 kineticRotation() { + float degrees = aOffset + uTime * aSpeed * -3./10.; + float angle = fract(degrees / 360.) * PI * 2.; + + return rotate(aAxis, angle); +} + +void main() { + mat4 kineticRotation = kineticRotation(); + vec4 worldPos = kineticRotation * vec4(aPos - .5, 1.) + vec4(aInstancePos + .5, 0.); + + #ifdef CONTRAPTION + worldPos = uModel * worldPos; + mat4 normalMat = uModel * kineticRotation; + + BoxCoord = (worldPos.xyz - uLightBoxMin) / uLightBoxSize; + FragDistance = length(worldPos.xyz); + #else + mat4 normalMat = kineticRotation; + + FragDistance = length(worldPos.xyz - uCameraPos); + #endif + + vec3 norm = normalize(normalMat * vec4(aNormal, 0.)).xyz; + + Diffuse = diffuse(norm); + TexCoords = aTexCoords; + Light = aLight; + gl_Position = uViewProjection * worldPos; + + #ifdef CONTRAPTION + if (uDebug == 2) { + Color = vec4(norm, 1.); + } else { + Color = vec4(1.); + } + #else + if (uDebug == 1) { + Color = vec4(aNetworkTint, 1.); + } else if (uDebug == 2) { + Color = vec4(norm, 1.); + } else { + Color = vec4(1.); + } + #endif +} \ No newline at end of file diff --git a/src/main/resources/assets/create/textures/block/belt/black.png b/src/main/resources/assets/create/textures/block/belt/black.png deleted file mode 100644 index 7208c37dc..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/black.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/black_diagonal.png b/src/main/resources/assets/create/textures/block/belt/black_diagonal.png deleted file mode 100644 index 01b7556cb..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/black_diagonal.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/black_diagonal_scroll.png b/src/main/resources/assets/create/textures/block/belt/black_diagonal_scroll.png new file mode 100644 index 000000000..7f09c1f29 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/black_diagonal_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/black_scroll.png b/src/main/resources/assets/create/textures/block/belt/black_scroll.png new file mode 100644 index 000000000..8cc4f7df5 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/black_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/blue.png b/src/main/resources/assets/create/textures/block/belt/blue.png deleted file mode 100644 index 1fde542ce..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/blue.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/blue_diagonal.png b/src/main/resources/assets/create/textures/block/belt/blue_diagonal.png deleted file mode 100644 index 9f09d64cb..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/blue_diagonal.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/blue_diagonal_scroll.png b/src/main/resources/assets/create/textures/block/belt/blue_diagonal_scroll.png new file mode 100644 index 000000000..5da06f8d1 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/blue_diagonal_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/blue_scroll.png b/src/main/resources/assets/create/textures/block/belt/blue_scroll.png new file mode 100644 index 000000000..abaa0bb26 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/blue_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/brown.png b/src/main/resources/assets/create/textures/block/belt/brown.png deleted file mode 100644 index 944db3c46..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/brown.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/brown_diagonal.png b/src/main/resources/assets/create/textures/block/belt/brown_diagonal.png deleted file mode 100644 index 104903161..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/brown_diagonal.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/brown_diagonal_scroll.png b/src/main/resources/assets/create/textures/block/belt/brown_diagonal_scroll.png new file mode 100644 index 000000000..b1f493279 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/brown_diagonal_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/brown_scroll.png b/src/main/resources/assets/create/textures/block/belt/brown_scroll.png new file mode 100644 index 000000000..3b9ae0cb4 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/brown_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/cyan.png b/src/main/resources/assets/create/textures/block/belt/cyan.png deleted file mode 100644 index 414590282..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/cyan.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/cyan_diagonal.png b/src/main/resources/assets/create/textures/block/belt/cyan_diagonal.png deleted file mode 100644 index 3bcf44a87..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/cyan_diagonal.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/cyan_diagonal_scroll.png b/src/main/resources/assets/create/textures/block/belt/cyan_diagonal_scroll.png new file mode 100644 index 000000000..5b313c3cc Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/cyan_diagonal_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/cyan_scroll.png b/src/main/resources/assets/create/textures/block/belt/cyan_scroll.png new file mode 100644 index 000000000..87951f7f2 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/cyan_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/gray.png b/src/main/resources/assets/create/textures/block/belt/gray.png deleted file mode 100644 index f306a29cd..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/gray.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/gray_diagonal.png b/src/main/resources/assets/create/textures/block/belt/gray_diagonal.png deleted file mode 100644 index ff2bdc34c..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/gray_diagonal.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/gray_diagonal_scroll.png b/src/main/resources/assets/create/textures/block/belt/gray_diagonal_scroll.png new file mode 100644 index 000000000..17be8d10e Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/gray_diagonal_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/gray_scroll.png b/src/main/resources/assets/create/textures/block/belt/gray_scroll.png new file mode 100644 index 000000000..5e5e3f17c Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/gray_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/green.png b/src/main/resources/assets/create/textures/block/belt/green.png deleted file mode 100644 index cd41d7c14..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/green.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/green_diagonal.png b/src/main/resources/assets/create/textures/block/belt/green_diagonal.png deleted file mode 100644 index a79967666..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/green_diagonal.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/green_diagonal_scroll.png b/src/main/resources/assets/create/textures/block/belt/green_diagonal_scroll.png new file mode 100644 index 000000000..55f29f0de Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/green_diagonal_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/green_scroll.png b/src/main/resources/assets/create/textures/block/belt/green_scroll.png new file mode 100644 index 000000000..eac299196 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/green_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/light_blue.png b/src/main/resources/assets/create/textures/block/belt/light_blue.png deleted file mode 100644 index c19b5d0c5..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/light_blue.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/light_blue_diagonal.png b/src/main/resources/assets/create/textures/block/belt/light_blue_diagonal.png deleted file mode 100644 index ad344f524..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/light_blue_diagonal.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/light_blue_diagonal_scroll.png b/src/main/resources/assets/create/textures/block/belt/light_blue_diagonal_scroll.png new file mode 100644 index 000000000..162128bac Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/light_blue_diagonal_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/light_blue_scroll.png b/src/main/resources/assets/create/textures/block/belt/light_blue_scroll.png new file mode 100644 index 000000000..946398440 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/light_blue_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/light_gray.png b/src/main/resources/assets/create/textures/block/belt/light_gray.png deleted file mode 100644 index ca67d7c8e..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/light_gray.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/light_gray_diagonal.png b/src/main/resources/assets/create/textures/block/belt/light_gray_diagonal.png deleted file mode 100644 index f9ba32f48..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/light_gray_diagonal.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/light_gray_diagonal_scroll.png b/src/main/resources/assets/create/textures/block/belt/light_gray_diagonal_scroll.png new file mode 100644 index 000000000..0f0ef3be7 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/light_gray_diagonal_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/light_gray_scroll.png b/src/main/resources/assets/create/textures/block/belt/light_gray_scroll.png new file mode 100644 index 000000000..0bc6bca7a Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/light_gray_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/lime.png b/src/main/resources/assets/create/textures/block/belt/lime.png deleted file mode 100644 index ca40f812b..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/lime.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/lime_diagonal.png b/src/main/resources/assets/create/textures/block/belt/lime_diagonal.png deleted file mode 100644 index ac8405b3c..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/lime_diagonal.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/lime_diagonal_scroll.png b/src/main/resources/assets/create/textures/block/belt/lime_diagonal_scroll.png new file mode 100644 index 000000000..8a964537b Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/lime_diagonal_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/lime_scroll.png b/src/main/resources/assets/create/textures/block/belt/lime_scroll.png new file mode 100644 index 000000000..12f08decb Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/lime_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/magenta.png b/src/main/resources/assets/create/textures/block/belt/magenta.png deleted file mode 100644 index 2c751984a..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/magenta.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/magenta_diagonal.png b/src/main/resources/assets/create/textures/block/belt/magenta_diagonal.png deleted file mode 100644 index f7539d185..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/magenta_diagonal.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/magenta_diagonal_scroll.png b/src/main/resources/assets/create/textures/block/belt/magenta_diagonal_scroll.png new file mode 100644 index 000000000..391573768 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/magenta_diagonal_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/magenta_scroll.png b/src/main/resources/assets/create/textures/block/belt/magenta_scroll.png new file mode 100644 index 000000000..97730b8a0 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/magenta_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/orange.png b/src/main/resources/assets/create/textures/block/belt/orange.png deleted file mode 100644 index d4356e978..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/orange.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/orange_diagonal.png b/src/main/resources/assets/create/textures/block/belt/orange_diagonal.png deleted file mode 100644 index 7e774efee..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/orange_diagonal.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/orange_diagonal_scroll.png b/src/main/resources/assets/create/textures/block/belt/orange_diagonal_scroll.png new file mode 100644 index 000000000..9b05628bf Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/orange_diagonal_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/orange_scroll.png b/src/main/resources/assets/create/textures/block/belt/orange_scroll.png new file mode 100644 index 000000000..b17c3706e Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/orange_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/pink.png b/src/main/resources/assets/create/textures/block/belt/pink.png deleted file mode 100644 index e8271fcff..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/pink.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/pink_diagonal.png b/src/main/resources/assets/create/textures/block/belt/pink_diagonal.png deleted file mode 100644 index c4441a5ed..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/pink_diagonal.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/pink_diagonal_scroll.png b/src/main/resources/assets/create/textures/block/belt/pink_diagonal_scroll.png new file mode 100644 index 000000000..cb45cfb80 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/pink_diagonal_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/pink_scroll.png b/src/main/resources/assets/create/textures/block/belt/pink_scroll.png new file mode 100644 index 000000000..f60386562 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/pink_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/purple.png b/src/main/resources/assets/create/textures/block/belt/purple.png deleted file mode 100644 index a34dadade..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/purple.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/purple_diagonal.png b/src/main/resources/assets/create/textures/block/belt/purple_diagonal.png deleted file mode 100644 index a86fbfc6c..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/purple_diagonal.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/purple_diagonal_scroll.png b/src/main/resources/assets/create/textures/block/belt/purple_diagonal_scroll.png new file mode 100644 index 000000000..e88f5ee04 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/purple_diagonal_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/purple_scroll.png b/src/main/resources/assets/create/textures/block/belt/purple_scroll.png new file mode 100644 index 000000000..2a7dd16d5 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/purple_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/red.png b/src/main/resources/assets/create/textures/block/belt/red.png deleted file mode 100644 index 9de781a48..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/red.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/red_diagonal.png b/src/main/resources/assets/create/textures/block/belt/red_diagonal.png deleted file mode 100644 index ec53e50c9..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/red_diagonal.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/red_diagonal_scroll.png b/src/main/resources/assets/create/textures/block/belt/red_diagonal_scroll.png new file mode 100644 index 000000000..611567dde Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/red_diagonal_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/red_scroll.png b/src/main/resources/assets/create/textures/block/belt/red_scroll.png new file mode 100644 index 000000000..c09915c68 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/red_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/white.png b/src/main/resources/assets/create/textures/block/belt/white.png deleted file mode 100644 index 3edb40a1a..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/white.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/white_diagonal.png b/src/main/resources/assets/create/textures/block/belt/white_diagonal.png deleted file mode 100644 index 06694cb35..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/white_diagonal.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/white_diagonal_scroll.png b/src/main/resources/assets/create/textures/block/belt/white_diagonal_scroll.png new file mode 100644 index 000000000..527a647af Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/white_diagonal_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/white_scroll.png b/src/main/resources/assets/create/textures/block/belt/white_scroll.png new file mode 100644 index 000000000..8251b3b1f Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/white_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/yellow.png b/src/main/resources/assets/create/textures/block/belt/yellow.png deleted file mode 100644 index ef615bfcf..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/yellow.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/yellow_diagonal.png b/src/main/resources/assets/create/textures/block/belt/yellow_diagonal.png deleted file mode 100644 index b682d0be3..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt/yellow_diagonal.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt/yellow_diagonal_scroll.png b/src/main/resources/assets/create/textures/block/belt/yellow_diagonal_scroll.png new file mode 100644 index 000000000..d8622414f Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/yellow_diagonal_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt/yellow_scroll.png b/src/main/resources/assets/create/textures/block/belt/yellow_scroll.png new file mode 100644 index 000000000..256e1e45b Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt/yellow_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt_animated.png b/src/main/resources/assets/create/textures/block/belt_animated.png deleted file mode 100644 index 527b162fa..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt_animated.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt_diagonal_animated.png b/src/main/resources/assets/create/textures/block/belt_diagonal_animated.png deleted file mode 100644 index 29a5552d5..000000000 Binary files a/src/main/resources/assets/create/textures/block/belt_diagonal_animated.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/block/belt_diagonal_scroll.png b/src/main/resources/assets/create/textures/block/belt_diagonal_scroll.png new file mode 100644 index 000000000..e8cdb900e Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt_diagonal_scroll.png differ diff --git a/src/main/resources/assets/create/textures/block/belt_scroll.png b/src/main/resources/assets/create/textures/block/belt_scroll.png new file mode 100644 index 000000000..b5081c7d7 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt_scroll.png differ diff --git a/src/main/resources/create.mixins.json b/src/main/resources/create.mixins.json new file mode 100644 index 000000000..e9d682678 --- /dev/null +++ b/src/main/resources/create.mixins.json @@ -0,0 +1,18 @@ +{ + "required": true, + "package": "com.simibubi.create.foundation.mixin", + "compatibilityLevel": "JAVA_8", + "refmap": "create.refmap.json", + "client": [ + "OnRemoveTileMixin", + "ShaderCloseMixin", + "CancelTileEntityRenderMixin", + "LightUpdateMixin", + "RenderHooksMixin", + "FogColorTrackerMixin" + ], + "injectors": { + "defaultRequire": 1 + }, + "minVersion": "0.8" +} \ No newline at end of file