mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-03-04 06:44:40 +01:00
93 days late
- Add BlazeBurnerVisual - Offload blaze burner's tickAnimation to flywheel when enabled - Add generic scrolling instance type for the flame, to be re-used for belts - Mark flame model json as cutout
This commit is contained in:
parent
3071e46ddc
commit
b3aba93665
9 changed files with 373 additions and 15 deletions
|
@ -175,6 +175,7 @@ import com.simibubi.create.content.processing.basin.BasinBlockEntity;
|
|||
import com.simibubi.create.content.processing.basin.BasinRenderer;
|
||||
import com.simibubi.create.content.processing.burner.BlazeBurnerBlockEntity;
|
||||
import com.simibubi.create.content.processing.burner.BlazeBurnerRenderer;
|
||||
import com.simibubi.create.content.processing.burner.BlazeBurnerVisual;
|
||||
import com.simibubi.create.content.redstone.analogLever.AnalogLeverBlockEntity;
|
||||
import com.simibubi.create.content.redstone.analogLever.AnalogLeverRenderer;
|
||||
import com.simibubi.create.content.redstone.analogLever.AnalogLeverVisual;
|
||||
|
@ -662,6 +663,7 @@ public class AllBlockEntityTypes {
|
|||
|
||||
public static final BlockEntityEntry<BlazeBurnerBlockEntity> HEATER = REGISTRATE
|
||||
.blockEntity("blaze_heater", BlazeBurnerBlockEntity::new)
|
||||
.visual(() -> BlazeBurnerVisual::new, false)
|
||||
.validBlocks(AllBlocks.BLAZE_BURNER)
|
||||
.renderer(() -> BlazeBurnerRenderer::new)
|
||||
.register();
|
||||
|
|
|
@ -14,6 +14,7 @@ import com.simibubi.create.foundation.utility.VecHelper;
|
|||
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
|
||||
import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser;
|
||||
|
||||
import dev.engine_room.flywheel.api.backend.BackendManager;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
@ -75,6 +76,7 @@ public class BlazeBurnerBlockEntity extends SmartBlockEntity {
|
|||
super.tick();
|
||||
|
||||
if (level.isClientSide) {
|
||||
if (shouldTickAnimation())
|
||||
tickAnimation();
|
||||
if (!isVirtual())
|
||||
spawnParticles(getHeatLevelFromBlock(), 1);
|
||||
|
@ -102,7 +104,13 @@ public class BlazeBurnerBlockEntity extends SmartBlockEntity {
|
|||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private void tickAnimation() {
|
||||
private boolean shouldTickAnimation() {
|
||||
// Offload the animation tick to the visual when flywheel in enabled
|
||||
return !BackendManager.isBackendOn();
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
void tickAnimation() {
|
||||
boolean active = getHeatLevelFromBlock().isAtLeast(HeatLevel.FADING) && isValidBlockAbove();
|
||||
|
||||
if (!active) {
|
||||
|
|
|
@ -124,15 +124,7 @@ public class BlazeBurnerRenderer extends SafeBlockEntityRenderer<BlazeBurnerBloc
|
|||
draw(flameBuffer, horizontalAngle, ms, cutout);
|
||||
}
|
||||
|
||||
PartialModel blazeModel;
|
||||
if (heatLevel.isAtLeast(HeatLevel.SEETHING)) {
|
||||
blazeModel = blockAbove ? AllPartialModels.BLAZE_SUPER_ACTIVE : AllPartialModels.BLAZE_SUPER;
|
||||
} else if (heatLevel.isAtLeast(HeatLevel.FADING)) {
|
||||
blazeModel = blockAbove && heatLevel.isAtLeast(HeatLevel.KINDLED) ? AllPartialModels.BLAZE_ACTIVE
|
||||
: AllPartialModels.BLAZE_IDLE;
|
||||
} else {
|
||||
blazeModel = AllPartialModels.BLAZE_INERT;
|
||||
}
|
||||
var blazeModel = getBlazeModel(heatLevel, blockAbove);
|
||||
|
||||
SuperByteBuffer blazeBuffer = CachedBufferer.partial(blazeModel, blockState);
|
||||
if (modelTransform != null)
|
||||
|
@ -195,6 +187,17 @@ public class BlazeBurnerRenderer extends SafeBlockEntityRenderer<BlazeBurnerBloc
|
|||
ms.popPose();
|
||||
}
|
||||
|
||||
public static PartialModel getBlazeModel(HeatLevel heatLevel, boolean blockAbove) {
|
||||
if (heatLevel.isAtLeast(HeatLevel.SEETHING)) {
|
||||
return blockAbove ? AllPartialModels.BLAZE_SUPER_ACTIVE : AllPartialModels.BLAZE_SUPER;
|
||||
} else if (heatLevel.isAtLeast(HeatLevel.FADING)) {
|
||||
return blockAbove && heatLevel.isAtLeast(HeatLevel.KINDLED) ? AllPartialModels.BLAZE_ACTIVE
|
||||
: AllPartialModels.BLAZE_IDLE;
|
||||
} else {
|
||||
return AllPartialModels.BLAZE_INERT;
|
||||
}
|
||||
}
|
||||
|
||||
private static void draw(SuperByteBuffer buffer, float horizontalAngle, PoseStack ms, VertexConsumer vc) {
|
||||
buffer.rotateCentered(horizontalAngle, Direction.UP)
|
||||
.light(LightTexture.FULL_BRIGHT)
|
||||
|
|
|
@ -0,0 +1,256 @@
|
|||
package com.simibubi.create.content.processing.burner;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.simibubi.create.AllPartialModels;
|
||||
import com.simibubi.create.AllSpriteShifts;
|
||||
import com.simibubi.create.foundation.block.render.SpriteShiftEntry;
|
||||
import com.simibubi.create.foundation.render.AllInstanceTypes;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.AnimationTickHolder;
|
||||
|
||||
import dev.engine_room.flywheel.api.instance.Instance;
|
||||
import dev.engine_room.flywheel.api.visual.DynamicVisual;
|
||||
import dev.engine_room.flywheel.api.visual.TickableVisual;
|
||||
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
||||
import dev.engine_room.flywheel.lib.instance.InstanceTypes;
|
||||
import dev.engine_room.flywheel.lib.instance.TransformedInstance;
|
||||
import dev.engine_room.flywheel.lib.model.Models;
|
||||
import dev.engine_room.flywheel.lib.model.baked.PartialModel;
|
||||
import dev.engine_room.flywheel.lib.transform.Translate;
|
||||
import dev.engine_room.flywheel.lib.visual.AbstractBlockEntityVisual;
|
||||
import dev.engine_room.flywheel.lib.visual.SimpleDynamicVisual;
|
||||
import dev.engine_room.flywheel.lib.visual.SimpleTickableVisual;
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.util.Mth;
|
||||
|
||||
public class BlazeBurnerVisual extends AbstractBlockEntityVisual<BlazeBurnerBlockEntity> implements SimpleDynamicVisual, SimpleTickableVisual {
|
||||
|
||||
private final BlazeBurnerBlock.HeatLevel heatLevel;
|
||||
|
||||
private final TransformedInstance head;
|
||||
private final TransformedInstance smallRods;
|
||||
private final TransformedInstance largeRods;
|
||||
|
||||
private final boolean isInert;
|
||||
|
||||
@Nullable
|
||||
private ScrollInstance flame;
|
||||
@Nullable
|
||||
private TransformedInstance goggles;
|
||||
@Nullable
|
||||
private TransformedInstance hat;
|
||||
|
||||
private boolean validBlockAbove;
|
||||
|
||||
public BlazeBurnerVisual(VisualizationContext ctx, BlazeBurnerBlockEntity blockEntity, float partialTick) {
|
||||
super(ctx, blockEntity, partialTick);
|
||||
|
||||
heatLevel = blockEntity.getHeatLevelFromBlock();
|
||||
validBlockAbove = blockEntity.isValidBlockAbove();
|
||||
|
||||
PartialModel blazeModel = BlazeBurnerRenderer.getBlazeModel(heatLevel, validBlockAbove);
|
||||
isInert = blazeModel == AllPartialModels.BLAZE_INERT;
|
||||
|
||||
head = instancerProvider.instancer(InstanceTypes.TRANSFORMED, Models.partial(blazeModel))
|
||||
.createInstance();
|
||||
|
||||
head.light(LightTexture.FULL_BRIGHT);
|
||||
|
||||
if (heatLevel.isAtLeast(BlazeBurnerBlock.HeatLevel.FADING)) {
|
||||
PartialModel rodsModel = heatLevel == BlazeBurnerBlock.HeatLevel.SEETHING ? AllPartialModels.BLAZE_BURNER_SUPER_RODS
|
||||
: AllPartialModels.BLAZE_BURNER_RODS;
|
||||
PartialModel rodsModel2 = heatLevel == BlazeBurnerBlock.HeatLevel.SEETHING ? AllPartialModels.BLAZE_BURNER_SUPER_RODS_2
|
||||
: AllPartialModels.BLAZE_BURNER_RODS_2;
|
||||
|
||||
smallRods = instancerProvider.instancer(InstanceTypes.TRANSFORMED, Models.partial(rodsModel))
|
||||
.createInstance();
|
||||
largeRods = instancerProvider.instancer(InstanceTypes.TRANSFORMED, Models.partial(rodsModel2))
|
||||
.createInstance();
|
||||
|
||||
smallRods.light(LightTexture.FULL_BRIGHT);
|
||||
largeRods.light(LightTexture.FULL_BRIGHT);
|
||||
} else {
|
||||
smallRods = null;
|
||||
largeRods = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(TickableVisual.Context context) {
|
||||
blockEntity.tickAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginFrame(DynamicVisual.Context ctx) {
|
||||
if (!isVisible(ctx.frustum()) || doDistanceLimitThisFrame(ctx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
float animation = blockEntity.headAnimation.getValue(ctx.partialTick()) * .175f;
|
||||
|
||||
boolean validBlockAbove = animation > 0.125f;
|
||||
|
||||
if (validBlockAbove != this.validBlockAbove) {
|
||||
this.validBlockAbove = validBlockAbove;
|
||||
|
||||
PartialModel blazeModel = BlazeBurnerRenderer.getBlazeModel(heatLevel, validBlockAbove);
|
||||
instancerProvider.instancer(InstanceTypes.TRANSFORMED, Models.partial(blazeModel))
|
||||
.stealInstance(head);
|
||||
}
|
||||
|
||||
// Switch between showing/hiding the flame
|
||||
if (validBlockAbove && flame == null) {
|
||||
setupFlameInstance();
|
||||
} else if (!validBlockAbove && flame != null) {
|
||||
flame.delete();
|
||||
flame = null;
|
||||
}
|
||||
|
||||
if (blockEntity.goggles && goggles == null) {
|
||||
goggles = instancerProvider.instancer(InstanceTypes.TRANSFORMED, Models.partial(isInert ? AllPartialModels.BLAZE_GOGGLES_SMALL : AllPartialModels.BLAZE_GOGGLES))
|
||||
.createInstance();
|
||||
goggles.light(LightTexture.FULL_BRIGHT);
|
||||
} else if (!blockEntity.goggles && goggles != null) {
|
||||
goggles.delete();
|
||||
goggles = null;
|
||||
}
|
||||
|
||||
if (blockEntity.hat && hat == null) {
|
||||
hat = instancerProvider.instancer(InstanceTypes.TRANSFORMED, Models.partial(AllPartialModels.TRAIN_HAT))
|
||||
.createInstance();
|
||||
hat.light(LightTexture.FULL_BRIGHT);
|
||||
} else if (!blockEntity.hat && hat != null) {
|
||||
hat.delete();
|
||||
hat = null;
|
||||
}
|
||||
|
||||
var hashCode = blockEntity.hashCode();
|
||||
float time = AnimationTickHolder.getRenderTime(level);
|
||||
float renderTick = time + (hashCode % 13) * 16f;
|
||||
float offsetMult = heatLevel.isAtLeast(BlazeBurnerBlock.HeatLevel.FADING) ? 64 : 16;
|
||||
float offset = Mth.sin((float) ((renderTick / 16f) % (2 * Math.PI))) / offsetMult;
|
||||
float headY = offset - (animation * .75f);
|
||||
|
||||
float horizontalAngle = AngleHelper.rad(blockEntity.headAngle.getValue(ctx.partialTick()));
|
||||
|
||||
head.loadIdentity()
|
||||
.translate(getVisualPosition())
|
||||
.translateY(headY)
|
||||
.translate(Translate.CENTER)
|
||||
.rotateY(horizontalAngle)
|
||||
.translateBack(Translate.CENTER)
|
||||
.setChanged();
|
||||
|
||||
if (goggles != null) {
|
||||
goggles.loadIdentity()
|
||||
.translate(getVisualPosition())
|
||||
.translateY(headY + 8 / 16f)
|
||||
.translate(Translate.CENTER)
|
||||
.rotateY(horizontalAngle)
|
||||
.translateBack(Translate.CENTER)
|
||||
.setChanged();
|
||||
}
|
||||
|
||||
if (hat != null) {
|
||||
hat.loadIdentity()
|
||||
.translate(getVisualPosition())
|
||||
.translateY(headY);
|
||||
if (isInert) {
|
||||
hat.translateY(0.5f)
|
||||
.center()
|
||||
.scale(0.75f)
|
||||
.uncenter();
|
||||
} else {
|
||||
hat.translateY(0.75f);
|
||||
}
|
||||
hat.rotateCentered(horizontalAngle + Mth.PI, Direction.UP)
|
||||
.translate(0.5f, 0, 0.5f)
|
||||
.light(LightTexture.FULL_BRIGHT);
|
||||
|
||||
hat.setChanged();
|
||||
}
|
||||
|
||||
if (smallRods != null) {
|
||||
float offset1 = Mth.sin((float) ((renderTick / 16f + Math.PI) % (2 * Math.PI))) / offsetMult;
|
||||
|
||||
smallRods.loadIdentity()
|
||||
.translate(getVisualPosition())
|
||||
.translateY(offset1 + animation + .125f)
|
||||
.setChanged();
|
||||
}
|
||||
|
||||
if (largeRods != null) {
|
||||
float offset2 = Mth.sin((float) ((renderTick / 16f + Math.PI / 2) % (2 * Math.PI))) / offsetMult;
|
||||
|
||||
largeRods.loadIdentity()
|
||||
.translate(getVisualPosition())
|
||||
.translateY(offset2 + animation - 3 / 16f)
|
||||
.setChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void setupFlameInstance() {
|
||||
flame = instancerProvider.instancer(AllInstanceTypes.SCROLLING, Models.partial(AllPartialModels.BLAZE_BURNER_FLAME))
|
||||
.createInstance();
|
||||
|
||||
flame.position(getVisualPosition())
|
||||
.light(LightTexture.FULL_BRIGHT);
|
||||
|
||||
SpriteShiftEntry spriteShift =
|
||||
heatLevel == BlazeBurnerBlock.HeatLevel.SEETHING ? AllSpriteShifts.SUPER_BURNER_FLAME : AllSpriteShifts.BURNER_FLAME;
|
||||
|
||||
float spriteWidth = spriteShift.getTarget()
|
||||
.getU1()
|
||||
- spriteShift.getTarget()
|
||||
.getU0();
|
||||
|
||||
float spriteHeight = spriteShift.getTarget()
|
||||
.getV1()
|
||||
- spriteShift.getTarget()
|
||||
.getV0();
|
||||
|
||||
float speed = 1 / 32f + 1 / 64f * heatLevel.ordinal();
|
||||
|
||||
flame.speedU = speed / 2;
|
||||
flame.speedV = speed;
|
||||
|
||||
flame.scaleU = spriteWidth / 2;
|
||||
flame.scaleV = spriteHeight / 2;
|
||||
|
||||
flame.diffU = spriteShift.getTarget().getU0() - spriteShift.getOriginal().getU0();
|
||||
flame.diffV = spriteShift.getTarget().getV0() - spriteShift.getOriginal().getV0();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLight(float partialTick) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectCrumblingInstances(Consumer<@Nullable Instance> consumer) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void _delete() {
|
||||
head.delete();
|
||||
if (smallRods != null) {
|
||||
smallRods.delete();
|
||||
}
|
||||
if (largeRods != null) {
|
||||
largeRods.delete();
|
||||
}
|
||||
if (flame != null) {
|
||||
flame.delete();
|
||||
}
|
||||
if (goggles != null) {
|
||||
goggles.delete();
|
||||
}
|
||||
if (hat != null) {
|
||||
hat.delete();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.simibubi.create.content.processing.burner;
|
||||
|
||||
import org.joml.Quaternionf;
|
||||
|
||||
import dev.engine_room.flywheel.api.instance.InstanceHandle;
|
||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||
import dev.engine_room.flywheel.lib.instance.ColoredLitInstance;
|
||||
import net.minecraft.core.Vec3i;
|
||||
|
||||
public class ScrollInstance extends ColoredLitInstance {
|
||||
public float x;
|
||||
public float y;
|
||||
public float z;
|
||||
public final Quaternionf rotation = new Quaternionf();
|
||||
|
||||
public float speedU;
|
||||
public float speedV;
|
||||
|
||||
public float diffU;
|
||||
public float diffV;
|
||||
|
||||
public float scaleU;
|
||||
public float scaleV;
|
||||
|
||||
public ScrollInstance(InstanceType<? extends ColoredLitInstance> type, InstanceHandle handle) {
|
||||
super(type, handle);
|
||||
}
|
||||
|
||||
public ScrollInstance position(Vec3i position) {
|
||||
this.x = position.getX();
|
||||
this.y = position.getY();
|
||||
this.z = position.getZ();
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ import com.simibubi.create.content.contraptions.actors.ActorInstance;
|
|||
import com.simibubi.create.content.kinetics.base.RotatingInstance;
|
||||
import com.simibubi.create.content.kinetics.belt.BeltInstance;
|
||||
import com.simibubi.create.content.logistics.flwdata.FlapInstance;
|
||||
import com.simibubi.create.content.processing.burner.ScrollInstance;
|
||||
|
||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||
import dev.engine_room.flywheel.api.layout.FloatRepr;
|
||||
|
@ -88,6 +89,40 @@ public class AllInstanceTypes {
|
|||
})
|
||||
.register();
|
||||
|
||||
// TODO: use this for belts too
|
||||
public static final InstanceType<ScrollInstance> SCROLLING = SimpleInstanceType.builder(ScrollInstance::new)
|
||||
.cullShader(asResource("instance/cull/scrolling.glsl"))
|
||||
.vertexShader(asResource("instance/scrolling.vert"))
|
||||
.layout(LayoutBuilder.create()
|
||||
.vector("color", FloatRepr.NORMALIZED_UNSIGNED_BYTE, 4)
|
||||
.vector("light", IntegerRepr.SHORT, 2)
|
||||
.vector("overlay", IntegerRepr.SHORT, 2)
|
||||
.vector("pos", FloatRepr.FLOAT, 3)
|
||||
.vector("rotation", FloatRepr.FLOAT, 4)
|
||||
.vector("speed", FloatRepr.FLOAT, 2)
|
||||
.vector("diff", FloatRepr.FLOAT, 2)
|
||||
.vector("scale", FloatRepr.FLOAT, 2)
|
||||
.build())
|
||||
.writer((ptr, instance) -> {
|
||||
MemoryUtil.memPutByte(ptr, instance.r);
|
||||
MemoryUtil.memPutByte(ptr + 1, instance.g);
|
||||
MemoryUtil.memPutByte(ptr + 2, instance.b);
|
||||
MemoryUtil.memPutByte(ptr + 3, instance.a);
|
||||
ExtraMemoryOps.put2x16(ptr + 4, instance.light);
|
||||
ExtraMemoryOps.put2x16(ptr + 8, instance.overlay);
|
||||
MemoryUtil.memPutFloat(ptr + 12, instance.x);
|
||||
MemoryUtil.memPutFloat(ptr + 16, instance.y);
|
||||
MemoryUtil.memPutFloat(ptr + 20, instance.z);
|
||||
ExtraMemoryOps.putQuaternionf(ptr + 24, instance.rotation);
|
||||
MemoryUtil.memPutFloat(ptr + 40, instance.speedU);
|
||||
MemoryUtil.memPutFloat(ptr + 44, instance.speedV);
|
||||
MemoryUtil.memPutFloat(ptr + 48, instance.diffU);
|
||||
MemoryUtil.memPutFloat(ptr + 52, instance.diffV);
|
||||
MemoryUtil.memPutFloat(ptr + 56, instance.scaleU);
|
||||
MemoryUtil.memPutFloat(ptr + 60, instance.scaleV);
|
||||
})
|
||||
.register();
|
||||
|
||||
public static final InstanceType<ActorInstance> ACTOR = SimpleInstanceType.builder(ActorInstance::new)
|
||||
.cullShader(asResource("instance/cull/actor.glsl"))
|
||||
.vertexShader(asResource("instance/actor.vert"))
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
void flw_transformBoundingSphere(in FlwInstance instance, inout vec3 center, inout float radius) {
|
||||
radius += length(center - 0.5);
|
||||
center += instance.pos;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#include "flywheel:util/quaternion.glsl"
|
||||
#include "flywheel:util/matrix.glsl"
|
||||
|
||||
void flw_instanceVertex(in FlwInstance instance) {
|
||||
flw_vertexPos = vec4(rotateByQuaternion(flw_vertexPos.xyz - .5, instance.rotation) + instance.pos + .5, 1.);
|
||||
|
||||
flw_vertexNormal = rotateByQuaternion(flw_vertexNormal, instance.rotation);
|
||||
|
||||
vec2 scroll = fract(instance.speed * flw_renderTicks) * instance.scale;
|
||||
|
||||
flw_vertexTexCoord = flw_vertexTexCoord + instance.diff + scroll;
|
||||
flw_vertexLight = vec2(instance.light) / 256.;
|
||||
flw_vertexOverlay = instance.overlay;
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
"loader": "forge:obj",
|
||||
"flip_v": true,
|
||||
"model": "create:models/block/blaze_burner/blaze_flame.obj",
|
||||
"render_type": "minecraft:cutout",
|
||||
"textures": {
|
||||
"0": "create:block/blaze_burner_flame"
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue