Skip to content

Commit

Permalink
Glyphing in style
Browse files Browse the repository at this point in the history
- Fix glowing sign rendering
- Use 2 instances per character
- Move most glyph mesh state into the GlyphMode enum
- GlyphSettings now has a GlyphMode and a bold boolean
- Disable diffuse for text
- Render normal text with polygon offset and bias the instancers for
  normal text so they appear in front of shadows or outlines
- Make sink static
- Fix glyph instance color being unnormalized
  • Loading branch information
Jozufozu committed Sep 26, 2024
1 parent 9110e6e commit fa94354
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public final class InstanceTypes {
.layout(LayoutBuilder.create()
.matrix("pose", FloatRepr.FLOAT, 4)
.vector("u0u1v0v1", FloatRepr.FLOAT, 4)
.vector("color", FloatRepr.UNSIGNED_BYTE, 4)
.vector("color", FloatRepr.NORMALIZED_UNSIGNED_BYTE, 4)
.vector("light", FloatRepr.UNSIGNED_SHORT, 2)
.build())
.writer((ptr, instance) -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,43 +60,58 @@ public TextVisual(InstancerProvider provider) {

public void setup() {
sink.recycler.resetCount();
sink.pose = pose;
sink.light = light;

if (with8xOutline) {
sink.x = x;
sink.y = y;
sink.setup(GlyphMode.OUTLINE, this.backgroundColor);
content.accept(sink);
}

sink.setup(GlyphMode.SIMPLE, this.color);
sink.x = x;
sink.y = y;
sink.dimFactor = dropShadow ? 0.25f : 1.0f;
sink.r = (float) (color >> 16 & 0xFF) / 255.0f * sink.dimFactor;
sink.g = (float) (color >> 8 & 0xFF) / 255.0f * sink.dimFactor;
sink.b = (float) (color & 0xFF) / 255.0f * sink.dimFactor;
sink.a = (float) (color >> 24 & 0xFF) / 255.0f;
// FIXME: Need separate instances for the 8x outline and the center.
// Right now we just show the outline.
content.accept(sink);

sink.recycler.discardExtra();
}

public void delete() {
sink.recycler.delete();
}

private class Sink implements FormattedCharSink {
private static class Sink implements FormattedCharSink {
private final SmartRecycler<GlyphModelKey, GlyphInstance> recycler;

Font font;
private float dimFactor;
private final Font font;
private int light;
private Matrix4f pose;
private GlyphMode mode = GlyphMode.SIMPLE;
private float r;
private float g;
private float b;
private float a;

// Separate x and y from TextVisual because these advance as we accept glyphs
float x;
float y;
private float x;
private float y;

private Sink(InstancerProvider instancerProvider) {
recycler = new SmartRecycler<>(key -> instancerProvider.instancer(InstanceTypes.GLYPH, GLYPH_CACHE.get(key))
recycler = new SmartRecycler<>(key -> instancerProvider.instancer(InstanceTypes.GLYPH, GLYPH_CACHE.get(key), key.settings.glyphMode.bias)
.createInstance());
font = Minecraft.getInstance().font;
}

private void setup(GlyphMode mode, int color) {
this.mode = mode;
r = (float) (color >> 16 & 0xFF) / 255.0f * mode.dimFactor;
g = (float) (color >> 8 & 0xFF) / 255.0f * mode.dimFactor;
b = (float) (color & 0xFF) / 255.0f * mode.dimFactor;
a = (float) (color >> 24 & 0xFF) / 255.0f;
}

@Override
public boolean accept(int i, Style style, int j) {
float b;
Expand All @@ -109,9 +124,9 @@ public boolean accept(int i, Style style, int j) {
TextColor textColor = style.getColor();
if (textColor != null) {
int color = textColor.getValue();
r = (float) (color >> 16 & 0xFF) / 255.0f * this.dimFactor;
g = (float) (color >> 8 & 0xFF) / 255.0f * this.dimFactor;
b = (float) (color & 0xFF) / 255.0f * this.dimFactor;
r = (float) (color >> 16 & 0xFF) / 255.0f * mode.dimFactor;
g = (float) (color >> 8 & 0xFF) / 255.0f * mode.dimFactor;
b = (float) (color & 0xFF) / 255.0f * mode.dimFactor;
} else {
r = this.r;
g = this.g;
Expand All @@ -120,7 +135,7 @@ public boolean accept(int i, Style style, int j) {
if (!(bakedGlyph instanceof EmptyGlyph)) {
var glyphExtension = FlwLibLink.INSTANCE.getGlyphExtension(bakedGlyph);

GlyphInstance glyph = recycler.get(new GlyphModelKey(glyphExtension.flywheel$texture(), new GlyphSettings(bold, dropShadow, with8xOutline)));
GlyphInstance glyph = recycler.get(new GlyphModelKey(glyphExtension.flywheel$texture(), new GlyphSettings(mode, bold)));

glyph.pose.set(pose);
glyph.setGlyph(bakedGlyph, this.x, this.y, style.isItalic());
Expand All @@ -129,7 +144,7 @@ public boolean accept(int i, Style style, int j) {
glyph.setChanged();
}
float advance = glyphInfo.getAdvance(bold);
float o = dropShadow ? 1.0f : 0.0f;
float o = mode.effectShift;
if (style.isStrikethrough()) {
this.addEffect(this.x + o - 1.0f, this.y + o + 4.5f, this.x + o + advance, this.y + o + 4.5f - 1.0f, 0.01f, r, g, b, this.a);
}
Expand All @@ -146,7 +161,7 @@ private void addEffect(float x0, float y0, float x1, float y1, float depth, floa

var glyphExtension = FlwLibLink.INSTANCE.getGlyphExtension(bakedGlyph);

GlyphInstance glyph = recycler.get(new GlyphModelKey(glyphExtension.flywheel$texture(), new GlyphSettings(false, dropShadow, with8xOutline)));
GlyphInstance glyph = recycler.get(new GlyphModelKey(glyphExtension.flywheel$texture(), new GlyphSettings(GlyphMode.SIMPLE, false)));

glyph.pose.set(pose);
glyph.setEffect(bakedGlyph, x0, y0, x1, y1, depth);
Expand All @@ -172,47 +187,70 @@ public float finish(int backgroundColor, float x) {

private static final Material GLYPH_MATERIAL = SimpleMaterial.builder()
.cutout(CutoutShaders.ONE_TENTH)
.diffuse(false)
.build();

private record GlyphModelKey(ResourceLocation font, GlyphSettings settings) {
private Model into() {
return new SingleMeshModel(MESH_CACHE.get(settings), SimpleMaterial.builderOf(GLYPH_MATERIAL)
.texture(font)
.polygonOffset(settings.glyphMode.polygonOffset)
.build());
}
}

// FIXME: probably replace with an enum
private record GlyphSettings(boolean bold, boolean dropShadow, boolean with8xOutline) {
public GlyphMesh into() {
// bold -> x + 1
// shadow -> x + 1, y + 1
// This could probably be made a public interface and a TextVisual could render an arbitrary number of layers
private enum GlyphMode {
SIMPLE(1, 1, 0, true),
OUTLINE(1, 0, 0, false),
SHADOW(0.25f, 0, 1, false),
;

private final float dimFactor;
private final int bias;
private final float effectShift;
private final boolean polygonOffset;

GlyphMode(float dimFactor, int bias, float effectShift, boolean polygonOffset) {
this.dimFactor = dimFactor;
this.bias = bias;
this.effectShift = effectShift;
this.polygonOffset = polygonOffset;
}
}

private record GlyphSettings(GlyphMode glyphMode, boolean bold) {
public GlyphMesh into() {
List<Vector3f> out = new ArrayList<>();

if (with8xOutline) {
switch (glyphMode) {
case SIMPLE:
add(out, 0, 0);
break;
case OUTLINE:
for (int x = -1; x <= 1; ++x) {
for (int y = -1; y <= 1; ++y) {
if (x == 0 && y == 0) {
continue;
}

out.add(new Vector3f(x * ONE_PIXEL, y * ONE_PIXEL, 0));
add(out, x * ONE_PIXEL, y * ONE_PIXEL);
}
}
} else {
out.add(new Vector3f(0, 0, 0));
break;
case SHADOW:
add(out, ONE_PIXEL, ONE_PIXEL);
break;
}

if (bold) {
out.add(new Vector3f(ONE_PIXEL, 0, 0));
}
return new GlyphMesh(out.toArray(new Vector3f[0]));
}

if (dropShadow) {
out.add(new Vector3f(ONE_PIXEL, ONE_PIXEL, 0));
private void add(List<Vector3f> out, float x, float y) {
out.add(new Vector3f(x, y, 0));
if (bold) {
out.add(new Vector3f(x + ONE_PIXEL, y, 0));
}

return new GlyphMesh(out.toArray(new Vector3f[0]));
}
}

Expand Down

0 comments on commit fa94354

Please sign in to comment.