Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add text visuals to optimize sign and nametag rendering #262

Open
wants to merge 14 commits into
base: 1.20/dev
Choose a base branch
from
2 changes: 2 additions & 0 deletions common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ jarSets {
dependencies {
modCompileOnly("net.fabricmc:fabric-loader:${property("fabric_loader_version")}")

compileOnly(annotationProcessor("io.github.llamalad7:mixinextras-common:0.4.1")!!)

testImplementation("org.junit.jupiter:junit-jupiter:5.8.1")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.util.List;

import com.mojang.blaze3d.systems.RenderSystem;

import dev.engine_room.flywheel.api.RenderContext;
import dev.engine_room.flywheel.api.backend.Engine;
import dev.engine_room.flywheel.api.instance.Instance;
Expand Down Expand Up @@ -90,6 +92,8 @@ public void onLightUpdate(SectionPos sectionPos, LightLayer layer) {
@Override
public void setupRender(RenderContext context) {
try (var state = GlStateTracker.getRestoreState()) {
// Process the render queue for font updates
RenderSystem.replayQueue();
Uniforms.update(context);
environmentStorage.flush();
drawManager.flush(lightStorage, environmentStorage);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ out vec3 flw_vertexNormal;
out float flw_distance;

FlwMaterial flw_material;

#define flw_vertexId gl_VertexID
Original file line number Diff line number Diff line change
Expand Up @@ -87,38 +87,46 @@ bool _flw_isVisible(uint instanceIndex, uint modelIndex) {
transformBoundingSphere(flw_view, center, radius);

vec4 aabb;
if (projectSphere(center, radius, _flw_cullData.znear, _flw_cullData.P00, _flw_cullData.P11, aabb))
{
float width = (aabb.z - aabb.x) * _flw_cullData.pyramidWidth;
float height = (aabb.w - aabb.y) * _flw_cullData.pyramidHeight;
if (projectSphere(center, radius, _flw_cullData.znear, _flw_cullData.P00, _flw_cullData.P11, aabb)) {
vec2 size = aabb.zw - aabb.xy;

int level = clamp(int(ceil(log2(max(width, height)))), 0, _flw_cullData.pyramidLevels);
vec2 sizeInPixels = size * flw_viewportSize;

ivec2 levelSize = textureSize(_flw_depthPyramid, level);
// Cull objects that are less than a pixel in size. Could probably make this configurable.
isVisible = isVisible && any(greaterThan(sizeInPixels, vec2(1.)));

ivec4 levelSizePair = ivec4(levelSize, levelSize);
if (isVisible) {
float width = size.x * _flw_cullData.pyramidWidth;
float height = size.y * _flw_cullData.pyramidHeight;

ivec4 bounds = ivec4(aabb * vec4(levelSizePair));
int level = clamp(int(ceil(log2(max(width, height)))), 0, _flw_cullData.pyramidLevels);

// Clamp to the texture bounds.
// Since we're not going through a sampler out of bounds texel fetches will return 0.
bounds = clamp(bounds, ivec4(0), levelSizePair);
ivec2 levelSize = textureSize(_flw_depthPyramid, level);

float depth01 = texelFetch(_flw_depthPyramid, bounds.xw, level).r;
float depth11 = texelFetch(_flw_depthPyramid, bounds.zw, level).r;
float depth10 = texelFetch(_flw_depthPyramid, bounds.zy, level).r;
float depth00 = texelFetch(_flw_depthPyramid, bounds.xy, level).r;
ivec4 levelSizePair = ivec4(levelSize, levelSize);

float depth;
if (_flw_cullData.useMin == 0) {
depth = max(max(depth00, depth01), max(depth10, depth11));
} else {
depth = min(min(depth00, depth01), min(depth10, depth11));
}
ivec4 bounds = ivec4(aabb * vec4(levelSizePair));

// Clamp to the texture bounds.
// Since we're not going through a sampler out of bounds texel fetches will return 0.
bounds = clamp(bounds, ivec4(0), levelSizePair);

float depth01 = texelFetch(_flw_depthPyramid, bounds.xw, level).r;
float depth11 = texelFetch(_flw_depthPyramid, bounds.zw, level).r;
float depth10 = texelFetch(_flw_depthPyramid, bounds.zy, level).r;
float depth00 = texelFetch(_flw_depthPyramid, bounds.xy, level).r;

float depthSphere = 1. + _flw_cullData.znear / (center.z + radius);
float depth;
if (_flw_cullData.useMin == 0) {
depth = max(max(depth00, depth01), max(depth10, depth11));
} else {
depth = min(min(depth00, depth01), min(depth10, depth11));
}

isVisible = isVisible && depthSphere <= depth;
float depthSphere = 1. + _flw_cullData.znear / (center.z + radius);

isVisible = isVisible && depthSphere <= depth;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import dev.engine_room.flywheel.api.instance.InstanceHandle;
import dev.engine_room.flywheel.api.instance.InstanceType;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.util.FastColor;

public abstract class ColoredLitInstance extends AbstractInstance implements FlatLit {
Expand All @@ -11,7 +10,6 @@ public abstract class ColoredLitInstance extends AbstractInstance implements Fla
public byte blue = (byte) 0xFF;
public byte alpha = (byte) 0xFF;

public int overlay = OverlayTexture.NO_OVERLAY;
public int light = 0;

public ColoredLitInstance(InstanceType<? extends ColoredLitInstance> type, InstanceHandle handle) {
Expand Down Expand Up @@ -49,9 +47,12 @@ public ColoredLitInstance color(byte red, byte green, byte blue) {
return this;
}

public ColoredLitInstance overlay(int overlay) {
this.overlay = overlay;
return this;
public ColoredLitInstance color(float red, float green, float blue, float alpha) {
return color((byte) (red * 255f), (byte) (green * 255f), (byte) (blue * 255f), (byte) (alpha * 255f));
}

public ColoredLitInstance color(float red, float green, float blue) {
return color((byte) (red * 255f), (byte) (green * 255f), (byte) (blue * 255f));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package dev.engine_room.flywheel.lib.instance;

import dev.engine_room.flywheel.api.instance.InstanceHandle;
import dev.engine_room.flywheel.api.instance.InstanceType;
import net.minecraft.client.renderer.texture.OverlayTexture;

public abstract class ColoredLitOverlayInstance extends ColoredLitInstance {
public int overlay = OverlayTexture.NO_OVERLAY;

public ColoredLitOverlayInstance(InstanceType<? extends ColoredLitOverlayInstance> type, InstanceHandle handle) {
super(type, handle);
}

public ColoredLitOverlayInstance overlay(int overlay) {
this.overlay = overlay;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package dev.engine_room.flywheel.lib.instance;

import org.joml.Matrix4f;
import org.joml.Matrix4fc;

import dev.engine_room.flywheel.api.instance.InstanceHandle;
import dev.engine_room.flywheel.api.instance.InstanceType;
import dev.engine_room.flywheel.lib.internal.BakedGlyphExtension;
import dev.engine_room.flywheel.lib.internal.FlwLibLink;
import dev.engine_room.flywheel.lib.math.DataPacker;
import net.minecraft.client.gui.font.glyphs.BakedGlyph;

public class GlyphInstance extends ColoredLitInstance {
// Skew x by 1 - 0.25 * y
// Note that columns are written as rows.
private static final Matrix4fc ITALIC_SKEW = new Matrix4f(1, 0, 0, 0, -0.25f, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);

public final Matrix4f pose = new Matrix4f();

public int packedUs;
public int packedVs;

public GlyphInstance(InstanceType<? extends GlyphInstance> type, InstanceHandle handle) {
super(type, handle);
}

public GlyphInstance setGlyph(BakedGlyph glyph, Matrix4fc initialPose, float x, float y, boolean italic) {
var glyphExtension = FlwLibLink.INSTANCE.getBakedGlyphExtension(glyph);
setUvs(glyphExtension);

float left = glyphExtension.flywheel$left();
float up = glyphExtension.flywheel$up();

pose.set(initialPose);
pose.translate(x, y, 0.0f);

if (italic) {
pose.mul(ITALIC_SKEW);
}

pose.translate(left, up - 3.0f, 0.0f);

return this;
}

public GlyphInstance setEffect(BakedGlyph glyph, Matrix4fc initialPose, float x0, float y0, float x1, float y1, float depth) {
var glyphExtension = FlwLibLink.INSTANCE.getBakedGlyphExtension(glyph);
setUvs(glyphExtension);

pose.set(initialPose);
pose.translate(x0, y0, depth);
pose.scale(x1 - x0, y1 - y0, 1.0f);

return this;
}

private void setUvs(BakedGlyphExtension glyphExtension) {
float u0 = glyphExtension.flywheel$u0();
float u1 = glyphExtension.flywheel$u1();
float v0 = glyphExtension.flywheel$v0();
float v1 = glyphExtension.flywheel$v1();

// Need to make sure at least u0/v0 don't get their sign bit extended in the cast.
// It causes u1/v1 to be completely saturated.
packedUs = (Short.toUnsignedInt(DataPacker.packNormU16(u1)) << 16) | Short.toUnsignedInt(DataPacker.packNormU16(u0));
packedVs = (Short.toUnsignedInt(DataPacker.packNormU16(v1)) << 16) | Short.toUnsignedInt(DataPacker.packNormU16(v0));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,27 @@ public final class InstanceTypes {
.cullShader(Flywheel.rl("instance/cull/shadow.glsl"))
.build();

public static final InstanceType<GlyphInstance> GLYPH = SimpleInstanceType.builder(GlyphInstance::new)
.layout(LayoutBuilder.create()
.matrix("pose", FloatRepr.FLOAT, 4)
.vector("u0u1v0v1", FloatRepr.NORMALIZED_UNSIGNED_SHORT, 4)
.vector("color", FloatRepr.NORMALIZED_UNSIGNED_BYTE, 4)
.vector("light", FloatRepr.UNSIGNED_SHORT, 2)
.build())
.writer((ptr, instance) -> {
ExtraMemoryOps.putMatrix4f(ptr, instance.pose);
ExtraMemoryOps.put2x16(ptr + 64, instance.packedUs);
ExtraMemoryOps.put2x16(ptr + 68, instance.packedVs);
MemoryUtil.memPutByte(ptr + 72, instance.red);
MemoryUtil.memPutByte(ptr + 73, instance.green);
MemoryUtil.memPutByte(ptr + 74, instance.blue);
MemoryUtil.memPutByte(ptr + 75, instance.alpha);
ExtraMemoryOps.put2x16(ptr + 76, instance.light);
})
.vertexShader(Flywheel.rl("instance/glyph.vert"))
.cullShader(Flywheel.rl("instance/cull/glyph.glsl"))
.build();

private InstanceTypes() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import net.minecraft.core.Vec3i;
import net.minecraft.world.phys.Vec3;

public class OrientedInstance extends ColoredLitInstance implements Rotate<OrientedInstance> {
public class OrientedInstance extends ColoredLitOverlayInstance implements Rotate<OrientedInstance> {
public float posX;
public float posY;
public float posZ;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import dev.engine_room.flywheel.lib.transform.Transform;
import net.minecraft.util.Mth;

public class PosedInstance extends ColoredLitInstance implements Transform<PosedInstance> {
public class PosedInstance extends ColoredLitOverlayInstance implements Transform<PosedInstance> {
public final Matrix4f pose = new Matrix4f();
public final Matrix3f normal = new Matrix3f();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import dev.engine_room.flywheel.api.instance.InstanceType;
import dev.engine_room.flywheel.lib.transform.Affine;

public class TransformedInstance extends ColoredLitInstance implements Affine<TransformedInstance> {
public class TransformedInstance extends ColoredLitOverlayInstance implements Affine<TransformedInstance> {
public final Matrix4f pose = new Matrix4f();

public TransformedInstance(InstanceType<? extends TransformedInstance> type, InstanceHandle handle) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package dev.engine_room.flywheel.lib.internal;

import net.minecraft.resources.ResourceLocation;

public interface BakedGlyphExtension {
float flywheel$u0();

float flywheel$u1();

float flywheel$v0();

float flywheel$v1();

float flywheel$left();

float flywheel$right();

float flywheel$up();

float flywheel$down();

ResourceLocation flywheel$texture();

void flywheel$texture(ResourceLocation location);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@

import dev.engine_room.flywheel.api.internal.DependencyInjection;
import dev.engine_room.flywheel.lib.transform.PoseTransformStack;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.font.FontSet;
import net.minecraft.client.gui.font.glyphs.BakedGlyph;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.resources.ResourceLocation;

public interface FlwLibLink {
FlwLibLink INSTANCE = DependencyInjection.load(FlwLibLink.class, "dev.engine_room.flywheel.impl.FlwLibLinkImpl");
Expand All @@ -24,4 +28,10 @@ public interface FlwLibLink {
void compileModelPart(ModelPart part, PoseStack.Pose pose, VertexConsumer consumer, int light, int overlay, float red, float green, float blue, float alpha);

Deque<PoseStack.Pose> getPoseStack(PoseStack stack);

FontSet getFontSet(Font font, ResourceLocation loc);

boolean getFilterFishyGlyphs(Font font);

BakedGlyphExtension getBakedGlyphExtension(BakedGlyph glyph);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import dev.engine_room.flywheel.api.Flywheel;
import dev.engine_room.flywheel.api.material.LightShader;

public class LightShaders {
public final class LightShaders {
public static final LightShader SMOOTH_WHEN_EMBEDDED = new SimpleLightShader(Flywheel.rl("light/smooth_when_embedded.glsl"));
public static final LightShader SMOOTH = new SimpleLightShader(Flywheel.rl("light/smooth.glsl"));
public static final LightShader FLAT = new SimpleLightShader(Flywheel.rl("light/flat.glsl"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ public Builder copyFrom(Material material) {
shaders = material.shaders();
fog = material.fog();
cutout = material.cutout();
light = material.light();
texture = material.texture();
blur = material.blur();
mipmap = material.mipmap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,32 @@ public static byte packNormI8(float f) {
public static float unpackNormI8(byte b) {
return (float) b / 127f;
}

/**
* Pack a float as an unsigned, normalized short.
*/
public static short packNormU16(float f) {
return (short) (int) (Mth.clamp(f, 0.0f, 1.0f) * 65535);
}

/**
* Unpack an unsigned, normalized short to a float.
*/
public static float unpackNormU16(short s) {
return (float) (Short.toUnsignedInt(s)) / 65535f;
}

/**
* Pack a float as a signed, normalized byte.
*/
public static short packNormI16(float f) {
return (short) (Mth.clamp(f, -1.0f, 1.0f) * 32767);
}

/**
* Unpack a signed, normalized byte to a float.
*/
public static float unpackNormI16(short s) {
return (float) s / 32767f;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public void delete() {
}

private record FireMesh(TextureAtlasSprite sprite) implements QuadMesh {
private static final Vector4fc BOUNDING_SPHERE = new Vector4f(0, 0.5f, 0, (float) (Math.sqrt(2) * 0.5));
private static final Vector4fc BOUNDING_SPHERE = new Vector4f(0, 0.5f, 0, Mth.SQRT_OF_TWO * 0.5f);

@Override
public int vertexCount() {
Expand Down
Loading