mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-07 02:34:58 +01:00
Glyphing in style
- 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
This commit is contained in:
parent
8f9c57783b
commit
7aefbee9c1
2 changed files with 75 additions and 37 deletions
|
@ -107,7 +107,7 @@ public final class InstanceTypes {
|
||||||
.layout(LayoutBuilder.create()
|
.layout(LayoutBuilder.create()
|
||||||
.matrix("pose", FloatRepr.FLOAT, 4)
|
.matrix("pose", FloatRepr.FLOAT, 4)
|
||||||
.vector("u0u1v0v1", 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)
|
.vector("light", FloatRepr.UNSIGNED_SHORT, 2)
|
||||||
.build())
|
.build())
|
||||||
.writer((ptr, instance) -> {
|
.writer((ptr, instance) -> {
|
||||||
|
|
|
@ -60,16 +60,21 @@ public class TextVisual {
|
||||||
|
|
||||||
public void setup() {
|
public void setup() {
|
||||||
sink.recycler.resetCount();
|
sink.recycler.resetCount();
|
||||||
|
sink.pose = pose;
|
||||||
|
sink.light = light;
|
||||||
|
|
||||||
|
if (with8xOutline) {
|
||||||
sink.x = x;
|
sink.x = x;
|
||||||
sink.y = y;
|
sink.y = y;
|
||||||
sink.dimFactor = dropShadow ? 0.25f : 1.0f;
|
sink.setup(GlyphMode.OUTLINE, this.backgroundColor);
|
||||||
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);
|
content.accept(sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
sink.setup(GlyphMode.SIMPLE, this.color);
|
||||||
|
sink.x = x;
|
||||||
|
sink.y = y;
|
||||||
|
content.accept(sink);
|
||||||
|
|
||||||
sink.recycler.discardExtra();
|
sink.recycler.discardExtra();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,26 +82,36 @@ public class TextVisual {
|
||||||
sink.recycler.delete();
|
sink.recycler.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Sink implements FormattedCharSink {
|
private static class Sink implements FormattedCharSink {
|
||||||
private final SmartRecycler<GlyphModelKey, GlyphInstance> recycler;
|
private final SmartRecycler<GlyphModelKey, GlyphInstance> recycler;
|
||||||
|
|
||||||
Font font;
|
private final Font font;
|
||||||
private float dimFactor;
|
private int light;
|
||||||
|
private Matrix4f pose;
|
||||||
|
private GlyphMode mode = GlyphMode.SIMPLE;
|
||||||
private float r;
|
private float r;
|
||||||
private float g;
|
private float g;
|
||||||
private float b;
|
private float b;
|
||||||
private float a;
|
private float a;
|
||||||
|
|
||||||
// Separate x and y from TextVisual because these advance as we accept glyphs
|
// Separate x and y from TextVisual because these advance as we accept glyphs
|
||||||
float x;
|
private float x;
|
||||||
float y;
|
private float y;
|
||||||
|
|
||||||
private Sink(InstancerProvider instancerProvider) {
|
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());
|
.createInstance());
|
||||||
font = Minecraft.getInstance().font;
|
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
|
@Override
|
||||||
public boolean accept(int i, Style style, int j) {
|
public boolean accept(int i, Style style, int j) {
|
||||||
float b;
|
float b;
|
||||||
|
@ -109,9 +124,9 @@ public class TextVisual {
|
||||||
TextColor textColor = style.getColor();
|
TextColor textColor = style.getColor();
|
||||||
if (textColor != null) {
|
if (textColor != null) {
|
||||||
int color = textColor.getValue();
|
int color = textColor.getValue();
|
||||||
r = (float) (color >> 16 & 0xFF) / 255.0f * this.dimFactor;
|
r = (float) (color >> 16 & 0xFF) / 255.0f * mode.dimFactor;
|
||||||
g = (float) (color >> 8 & 0xFF) / 255.0f * this.dimFactor;
|
g = (float) (color >> 8 & 0xFF) / 255.0f * mode.dimFactor;
|
||||||
b = (float) (color & 0xFF) / 255.0f * this.dimFactor;
|
b = (float) (color & 0xFF) / 255.0f * mode.dimFactor;
|
||||||
} else {
|
} else {
|
||||||
r = this.r;
|
r = this.r;
|
||||||
g = this.g;
|
g = this.g;
|
||||||
|
@ -120,7 +135,7 @@ public class TextVisual {
|
||||||
if (!(bakedGlyph instanceof EmptyGlyph)) {
|
if (!(bakedGlyph instanceof EmptyGlyph)) {
|
||||||
var glyphExtension = FlwLibLink.INSTANCE.getGlyphExtension(bakedGlyph);
|
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.pose.set(pose);
|
||||||
glyph.setGlyph(bakedGlyph, this.x, this.y, style.isItalic());
|
glyph.setGlyph(bakedGlyph, this.x, this.y, style.isItalic());
|
||||||
|
@ -129,7 +144,7 @@ public class TextVisual {
|
||||||
glyph.setChanged();
|
glyph.setChanged();
|
||||||
}
|
}
|
||||||
float advance = glyphInfo.getAdvance(bold);
|
float advance = glyphInfo.getAdvance(bold);
|
||||||
float o = dropShadow ? 1.0f : 0.0f;
|
float o = mode.effectShift;
|
||||||
if (style.isStrikethrough()) {
|
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);
|
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);
|
||||||
}
|
}
|
||||||
|
@ -146,7 +161,7 @@ public class TextVisual {
|
||||||
|
|
||||||
var glyphExtension = FlwLibLink.INSTANCE.getGlyphExtension(bakedGlyph);
|
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.pose.set(pose);
|
||||||
glyph.setEffect(bakedGlyph, x0, y0, x1, y1, depth);
|
glyph.setEffect(bakedGlyph, x0, y0, x1, y1, depth);
|
||||||
|
@ -172,48 +187,71 @@ public class TextVisual {
|
||||||
|
|
||||||
private static final Material GLYPH_MATERIAL = SimpleMaterial.builder()
|
private static final Material GLYPH_MATERIAL = SimpleMaterial.builder()
|
||||||
.cutout(CutoutShaders.ONE_TENTH)
|
.cutout(CutoutShaders.ONE_TENTH)
|
||||||
|
.diffuse(false)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
private record GlyphModelKey(ResourceLocation font, GlyphSettings settings) {
|
private record GlyphModelKey(ResourceLocation font, GlyphSettings settings) {
|
||||||
private Model into() {
|
private Model into() {
|
||||||
return new SingleMeshModel(MESH_CACHE.get(settings), SimpleMaterial.builderOf(GLYPH_MATERIAL)
|
return new SingleMeshModel(MESH_CACHE.get(settings), SimpleMaterial.builderOf(GLYPH_MATERIAL)
|
||||||
.texture(font)
|
.texture(font)
|
||||||
|
.polygonOffset(settings.glyphMode.polygonOffset)
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: probably replace with an enum
|
// This could probably be made a public interface and a TextVisual could render an arbitrary number of layers
|
||||||
private record GlyphSettings(boolean bold, boolean dropShadow, boolean with8xOutline) {
|
private enum GlyphMode {
|
||||||
public GlyphMesh into() {
|
SIMPLE(1, 1, 0, true),
|
||||||
// bold -> x + 1
|
OUTLINE(1, 0, 0, false),
|
||||||
// shadow -> x + 1, y + 1
|
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<>();
|
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 x = -1; x <= 1; ++x) {
|
||||||
for (int y = -1; y <= 1; ++y) {
|
for (int y = -1; y <= 1; ++y) {
|
||||||
if (x == 0 && y == 0) {
|
if (x == 0 && y == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
out.add(new Vector3f(x * ONE_PIXEL, y * ONE_PIXEL, 0));
|
add(out, x * ONE_PIXEL, y * ONE_PIXEL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
break;
|
||||||
out.add(new Vector3f(0, 0, 0));
|
case SHADOW:
|
||||||
}
|
add(out, ONE_PIXEL, ONE_PIXEL);
|
||||||
|
break;
|
||||||
if (bold) {
|
|
||||||
out.add(new Vector3f(ONE_PIXEL, 0, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dropShadow) {
|
|
||||||
out.add(new Vector3f(ONE_PIXEL, ONE_PIXEL, 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new GlyphMesh(out.toArray(new Vector3f[0]));
|
return new GlyphMesh(out.toArray(new Vector3f[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));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue