- Go through some TODOs
- Simplify FlatLit interface and directly store packed light
- Rename getters in Events
- Document Effects
- LitVisualStorage: atomics are slow
- BakedModelBufferer: vanilla leaks too, they'll be freed when the game
  exits
This commit is contained in:
Jozufozu 2024-04-02 12:36:40 -07:00
parent 506f2d5158
commit 833fadbbdc
16 changed files with 60 additions and 69 deletions

View file

@ -12,7 +12,7 @@ public final class BeginFrameEvent extends Event {
this.context = context; this.context = context;
} }
public RenderContext getContext() { public RenderContext context() {
return context; return context;
} }
} }

View file

@ -24,11 +24,11 @@ public final class EndClientResourceReloadEvent extends Event implements IModBus
this.error = error; this.error = error;
} }
public Minecraft getMinecraft() { public Minecraft minecraft() {
return minecraft; return minecraft;
} }
public ResourceManager getResourceManager() { public ResourceManager resourceManager() {
return resourceManager; return resourceManager;
} }
@ -36,7 +36,7 @@ public final class EndClientResourceReloadEvent extends Event implements IModBus
return initialReload; return initialReload;
} }
public Optional<Throwable> getError() { public Optional<Throwable> error() {
return error; return error;
} }
} }

View file

@ -17,7 +17,7 @@ public final class ReloadLevelRendererEvent extends Event {
} }
@Nullable @Nullable
public ClientLevel getLevel() { public ClientLevel level() {
return level; return level;
} }
} }

View file

@ -21,31 +21,31 @@ public final class RenderStageEvent extends Event {
this.stage = stage; this.stage = stage;
} }
public RenderContext getContext() { public RenderContext context() {
return context; return context;
} }
public RenderStage getStage() { public RenderStage stage() {
return stage; return stage;
} }
public ClientLevel getLevel() { public ClientLevel level() {
return context.level(); return context.level();
} }
public PoseStack getStack() { public PoseStack stack() {
return context.stack(); return context.stack();
} }
public Matrix4f getViewProjection() { public Matrix4f viewProjection() {
return context.viewProjection(); return context.viewProjection();
} }
public RenderBuffers getBuffers() { public RenderBuffers buffers() {
return context.buffers(); return context.buffers();
} }
public Camera getCamera() { public Camera camera() {
return context.camera(); return context.camera();
} }

View file

@ -2,7 +2,17 @@ package com.jozufozu.flywheel.api.visual;
import com.jozufozu.flywheel.api.visualization.VisualizationContext; import com.jozufozu.flywheel.api.visualization.VisualizationContext;
// TODO: Consider adding LevelAccessor getter /**
* An effect is not attached to any formal game object, but allows you to hook into
* flywheel's systems to render things. They're closely analogous to particles but
* without any built in support for networking.
*/
public interface Effect { public interface Effect {
/**
* Create a visual that will be keyed by this effect object.
*
* @param ctx The visualization context.
* @return An arbitrary EffectVisual.
*/
EffectVisual<?> visualize(VisualizationContext ctx); EffectVisual<?> visualize(VisualizationContext ctx);
} }

View file

@ -71,7 +71,8 @@ public final class BackendManagerImpl {
} }
public static void onEndClientResourceReload(EndClientResourceReloadEvent event) { public static void onEndClientResourceReload(EndClientResourceReloadEvent event) {
if (event.getError().isPresent()) { if (event.error()
.isPresent()) {
return; return;
} }
@ -82,7 +83,7 @@ public final class BackendManagerImpl {
public static void onReloadLevelRenderer(ReloadLevelRendererEvent event) { public static void onReloadLevelRenderer(ReloadLevelRendererEvent event) {
chooseBackend(); chooseBackend();
ClientLevel level = event.getLevel(); ClientLevel level = event.level();
if (level != null) { if (level != null) {
VisualizationManagerImpl.reset(level); VisualizationManagerImpl.reset(level);
} }

View file

@ -36,23 +36,25 @@ public final class VisualizationEventHandler {
} }
public static void onBeginFrame(BeginFrameEvent event) { public static void onBeginFrame(BeginFrameEvent event) {
ClientLevel level = event.getContext().level(); ClientLevel level = event.context()
.level();
VisualizationManagerImpl manager = VisualizationManagerImpl.get(level); VisualizationManagerImpl manager = VisualizationManagerImpl.get(level);
if (manager == null) { if (manager == null) {
return; return;
} }
manager.beginFrame(event.getContext()); manager.beginFrame(event.context());
} }
public static void onRenderStage(RenderStageEvent event) { public static void onRenderStage(RenderStageEvent event) {
ClientLevel level = event.getContext().level(); ClientLevel level = event.context()
.level();
VisualizationManagerImpl manager = VisualizationManagerImpl.get(level); VisualizationManagerImpl manager = VisualizationManagerImpl.get(level);
if (manager == null) { if (manager == null) {
return; return;
} }
manager.renderStage(event.getContext(), event.getStage()); manager.renderStage(event.context(), event.stage());
} }
public static void onEntityJoinLevel(EntityJoinLevelEvent event) { public static void onEntityJoinLevel(EntityJoinLevelEvent event) {

View file

@ -167,8 +167,7 @@ public class LitVisualStorage {
} }
} }
// Breaking this into 2 separate cases allows us to avoid the sync overhead in the common case. // Breaking this into 2 separate cases allows us to avoid the overhead of atomics in the common case.
// TODO: is it faster to only use the synced variant to avoid virtual dispatches?
sealed interface Updater { sealed interface Updater {
void updateLight(long updateId); void updateLight(long updateId);

View file

@ -12,8 +12,7 @@ public abstract class ColoredLitInstance extends AbstractInstance implements Fla
public byte b = (byte) 0xFF; public byte b = (byte) 0xFF;
public byte a = (byte) 0xFF; public byte a = (byte) 0xFF;
public byte blockLight; public int packedLight;
public byte skyLight;
public int overlay = OverlayTexture.NO_OVERLAY; public int overlay = OverlayTexture.NO_OVERLAY;
@ -58,22 +57,16 @@ public abstract class ColoredLitInstance extends AbstractInstance implements Fla
} }
@Override @Override
public ColoredLitInstance setBlockLight(int blockLight) { public ColoredLitInstance light(int blockLight, int skyLight) {
this.blockLight = (byte) blockLight; return light(LightTexture.pack(blockLight, skyLight));
return this;
} }
@Override @Override
public ColoredLitInstance setSkyLight(int skyLight) { public ColoredLitInstance light(int packedLight) {
this.skyLight = (byte) skyLight; this.packedLight = packedLight;
return this; return this;
} }
@Override
public int getPackedLight() {
return LightTexture.pack(blockLight, skyLight);
}
public ColoredLitInstance setOverlay(int overlay) { public ColoredLitInstance setOverlay(int overlay) {
this.overlay = overlay; this.overlay = overlay;
return this; return this;

View file

@ -2,38 +2,25 @@ package com.jozufozu.flywheel.lib.instance;
import com.jozufozu.flywheel.api.instance.Instance; import com.jozufozu.flywheel.api.instance.Instance;
import net.minecraft.core.BlockPos; import net.minecraft.client.renderer.LightTexture;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.LightLayer;
/** /**
* An interface that implementors of {@link Instance} should also implement * An interface that implementors of {@link Instance} should also implement
* if they wish to make use of Flywheel's provided light update methods. * if they wish to make use of Flywheel's provided light update methods.
* <p>
* This only covers flat lighting, smooth lighting is still TODO.
*/ */
public interface FlatLit extends Instance { public interface FlatLit extends Instance {
/** /**
* @param blockLight An integer in the range [0, 15] representing the * Set the block and sky light values for this instance.
* amount of block light this instance should receive. * @param blockLight Block light value
* @return {@code this} * @param skyLight Sky light value
* @return {@code this} for chaining
*/ */
FlatLit setBlockLight(int blockLight); FlatLit light(int blockLight, int skyLight);
/** /**
* @param skyLight An integer in the range [0, 15] representing the * Set the packed light value for this instance.
* amount of sky light this instance should receive. * @param packedLight Packed block and sky light per {@link LightTexture#pack(int, int)}
* @return {@code this} * @return {@code this} for chaining
*/ */
FlatLit setSkyLight(int skyLight); FlatLit light(int packedLight);
default FlatLit setLight(int blockLight, int skyLight) {
return setBlockLight(blockLight).setSkyLight(skyLight);
}
default FlatLit updateLight(BlockAndTintGetter level, BlockPos pos) {
return setLight(level.getBrightness(LightLayer.BLOCK, pos), level.getBrightness(LightLayer.SKY, pos));
}
int getPackedLight();
} }

View file

@ -26,8 +26,8 @@ public final class InstanceTypes {
MemoryUtil.memPutByte(ptr + 3, instance.a); MemoryUtil.memPutByte(ptr + 3, instance.a);
MemoryUtil.memPutShort(ptr + 4, (short) (instance.overlay & 0xFFFF)); MemoryUtil.memPutShort(ptr + 4, (short) (instance.overlay & 0xFFFF));
MemoryUtil.memPutShort(ptr + 6, (short) (instance.overlay >> 16 & 0xFFFF)); MemoryUtil.memPutShort(ptr + 6, (short) (instance.overlay >> 16 & 0xFFFF));
MemoryUtil.memPutShort(ptr + 8, (short) (Byte.toUnsignedInt(instance.blockLight) << 4)); MemoryUtil.memPutShort(ptr + 8, (short) (instance.packedLight & 0xFFFF));
MemoryUtil.memPutShort(ptr + 10, (short) (Byte.toUnsignedInt(instance.skyLight) << 4)); MemoryUtil.memPutShort(ptr + 10, (short) (instance.packedLight >> 16 & 0xFFFF));
MatrixMath.writeUnsafe(instance.model, ptr + 12); MatrixMath.writeUnsafe(instance.model, ptr + 12);
MatrixMath.writeUnsafe(instance.normal, ptr + 76); MatrixMath.writeUnsafe(instance.normal, ptr + 76);
}) })
@ -51,8 +51,8 @@ public final class InstanceTypes {
MemoryUtil.memPutByte(ptr + 3, instance.a); MemoryUtil.memPutByte(ptr + 3, instance.a);
MemoryUtil.memPutShort(ptr + 4, (short) (instance.overlay & 0xFFFF)); MemoryUtil.memPutShort(ptr + 4, (short) (instance.overlay & 0xFFFF));
MemoryUtil.memPutShort(ptr + 6, (short) (instance.overlay >> 16 & 0xFFFF)); MemoryUtil.memPutShort(ptr + 6, (short) (instance.overlay >> 16 & 0xFFFF));
MemoryUtil.memPutShort(ptr + 8, (short) (Byte.toUnsignedInt(instance.blockLight) << 4)); MemoryUtil.memPutShort(ptr + 8, (short) (instance.packedLight & 0xFFFF));
MemoryUtil.memPutShort(ptr + 10, (short) (Byte.toUnsignedInt(instance.skyLight) << 4)); MemoryUtil.memPutShort(ptr + 10, (short) (instance.packedLight >> 16 & 0xFFFF));
MemoryUtil.memPutFloat(ptr + 12, instance.posX); MemoryUtil.memPutFloat(ptr + 12, instance.posX);
MemoryUtil.memPutFloat(ptr + 16, instance.posY); MemoryUtil.memPutFloat(ptr + 16, instance.posY);
MemoryUtil.memPutFloat(ptr + 20, instance.posZ); MemoryUtil.memPutFloat(ptr + 20, instance.posZ);

View file

@ -147,7 +147,6 @@ final class BakedModelBufferer {
{ {
for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) { for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) {
var renderType = CHUNK_LAYERS[layerIndex]; var renderType = CHUNK_LAYERS[layerIndex];
// FIXME: We leak the memory owned by the BufferBuilder here.
var buffer = new BufferBuilder(renderType.bufferSize()); var buffer = new BufferBuilder(renderType.bufferSize());
emitters[layerIndex] = new MeshEmitter(buffer, renderType); emitters[layerIndex] = new MeshEmitter(buffer, renderType);
} }

View file

@ -61,8 +61,8 @@ public abstract class AbstractVisual implements Visual {
continue; continue;
} }
instance.setLight(block, sky); instance.light(block, sky)
instance.handle() .handle()
.setChanged(); .setChanged();
} }
} }
@ -73,7 +73,7 @@ public abstract class AbstractVisual implements Visual {
protected void relight(int block, int sky, Stream<? extends @Nullable FlatLit> instances) { protected void relight(int block, int sky, Stream<? extends @Nullable FlatLit> instances) {
instances.filter(Objects::nonNull) instances.filter(Objects::nonNull)
.forEach(instance -> instance.setLight(block, sky) .forEach(instance -> instance.light(block, sky)
.handle() .handle()
.setChanged()); .setChanged());
} }
@ -87,7 +87,7 @@ public abstract class AbstractVisual implements Visual {
if (instance == null) { if (instance == null) {
continue; continue;
} }
instance.setLight(block, sky) instance.light(block, sky)
.handle() .handle()
.setChanged(); .setChanged();
} }

View file

@ -56,7 +56,7 @@ public class FireComponent implements EntityComponent {
TransformedInstance instance = context.instancerProvider() TransformedInstance instance = context.instancerProvider()
.instancer(InstanceTypes.TRANSFORMED, model) .instancer(InstanceTypes.TRANSFORMED, model)
.createInstance(); .createInstance();
instance.setBlockLight(LightTexture.block(LightTexture.FULL_BLOCK)); instance.light(LightTexture.FULL_BLOCK);
instance.setChanged(); instance.setChanged();
return instance; return instance;
} }

View file

@ -70,7 +70,7 @@ public class HitboxComponent implements EntityComponent {
TransformedInstance instance = context.instancerProvider() TransformedInstance instance = context.instancerProvider()
.instancer(InstanceTypes.TRANSFORMED, model) .instancer(InstanceTypes.TRANSFORMED, model)
.createInstance(); .createInstance();
instance.setBlockLight(LightTexture.block(LightTexture.FULL_BLOCK)); instance.light(LightTexture.FULL_BLOCK);
instance.setChanged(); instance.setChanged();
return instance; return instance;
} }

View file

@ -21,6 +21,7 @@ import com.jozufozu.flywheel.lib.model.Models;
import com.jozufozu.flywheel.lib.task.ForEachPlan; import com.jozufozu.flywheel.lib.task.ForEachPlan;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.core.Vec3i; import net.minecraft.core.Vec3i;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
@ -271,8 +272,7 @@ public class ExampleEffect implements Effect {
.instancer(InstanceTypes.TRANSFORMED, Models.block(Blocks.SHROOMLIGHT.defaultBlockState())) .instancer(InstanceTypes.TRANSFORMED, Models.block(Blocks.SHROOMLIGHT.defaultBlockState()))
.createInstance(); .createInstance();
instance.setBlockLight(15) instance.light(LightTexture.FULL_BRIGHT);
.setSkyLight(15);
} }
public void _delete() { public void _delete() {