Pair down parameters per Pepper's pondering

- Flatten TextVisual API to be less of a parameter container
- This is mostly a surface change
- Do not accept x and y positions, instead force the user to translate
  in their matrix
- Track light from light updates to apply when setting up text
- Add (unoptimized) updateLight, backgroundColor, and updateObfuscated
  methods to TextVisual
This commit is contained in:
Jozufozu 2024-10-09 21:59:52 -07:00
parent c3ac594d37
commit 1091a478e1
2 changed files with 56 additions and 98 deletions

View file

@ -1,7 +1,6 @@
package dev.engine_room.flywheel.lib.visual.text; package dev.engine_room.flywheel.lib.visual.text;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -53,8 +52,6 @@ public final class TextVisual {
private final Matrix4f pose = new Matrix4f(); private final Matrix4f pose = new Matrix4f();
private FormattedCharSequence text = FormattedCharSequence.EMPTY; private FormattedCharSequence text = FormattedCharSequence.EMPTY;
private float x;
private float y;
private int backgroundColor = 0; private int backgroundColor = 0;
private int light; private int light;
@ -63,91 +60,60 @@ public final class TextVisual {
.createInstance()); .createInstance());
} }
public TextVisual addLayer(TextLayer layer) { public void setup(FormattedCharSequence textLine, List<TextLayer> layers, Matrix4f pose, int light) {
layers.add(layer); // TODO: probably don't store everything
return this; this.text = textLine;
}
public TextVisual addLayers(Collection<TextLayer> layers) {
this.layers.addAll(layers);
return this;
}
public TextVisual layers(Collection<TextLayer> layers) {
this.layers.clear(); this.layers.clear();
this.layers.addAll(layers); this.layers.addAll(layers);
return this; this.pose.set(pose);
}
public TextVisual clearLayers() {
layers.clear();
return this;
}
public Matrix4f pose() {
return pose;
}
public TextVisual text(FormattedCharSequence text) {
this.text = text;
return this;
}
public TextVisual x(float x) {
this.x = x;
return this;
}
public TextVisual y(float y) {
this.y = y;
return this;
}
public TextVisual pos(float x, float y) {
this.x = x;
this.y = y;
return this;
}
public TextVisual backgroundColor(int backgroundColor) {
this.backgroundColor = backgroundColor;
return this;
}
public TextVisual light(int light) {
this.light = light; this.light = light;
return this;
setup();
} }
public TextVisual reset() { public void updateObfuscated() {
// TODO: track obfuscated glyphs and update here
setup();
}
public void backgroundColor(int backgroundColor) {
// TODO: don't setup the whole thing
this.backgroundColor = backgroundColor;
setup();
}
public void updateLight(int packedLight) {
// TODO: just iterate over instances and update light
light = packedLight;
setup();
}
private void setup() {
recycler.resetCount();
var sink = SINKS.get();
sink.prepare(recycler, layers, pose, light);
text.accept(sink);
sink.addBackground(backgroundColor, 0, sink.x);
sink.clear();
recycler.discardExtra();
}
private TextVisual reset() {
// TODO: should this be public? what should it do?
layers.clear(); layers.clear();
pose.identity(); pose.identity();
text = FormattedCharSequence.EMPTY; text = FormattedCharSequence.EMPTY;
x = 0;
y = 0;
backgroundColor = 0; backgroundColor = 0;
light = 0; light = 0;
return this; return this;
} }
// TODO: track glyph instances and add method to update only UVs of obfuscated glyphs, method to update only
// background color, and method to only update light
public void setup() {
recycler.resetCount();
var sink = SINKS.get();
sink.prepare(recycler, layers, pose, light, x, y);
text.accept(sink);
sink.addBackground(backgroundColor, x, sink.x);
sink.clear();
recycler.discardExtra();
}
public void delete() { public void delete() {
recycler.delete(); recycler.delete();
} }
@ -196,15 +162,13 @@ public final class TextVisual {
private int light; private int light;
private float x; private float x;
private float y;
public void prepare(SmartRecycler<GlyphInstanceKey, GlyphInstance> recycler, List<TextLayer> layers, Matrix4f pose, int light, float x, float y) { public void prepare(SmartRecycler<GlyphInstanceKey, GlyphInstance> recycler, List<TextLayer> layers, Matrix4f pose, int light) {
this.recycler = recycler; this.recycler = recycler;
this.layers = layers; this.layers = layers;
this.pose = pose; this.pose = pose;
this.light = light; this.light = light;
this.x = x; this.x = 0;
this.y = y;
} }
public void clear() { public void clear() {
@ -233,7 +197,7 @@ public final class TextVisual {
if (!(glyph instanceof EmptyGlyph)) { if (!(glyph instanceof EmptyGlyph)) {
GlyphInstance instance = recycler.get(key(layer, glyphInfo, glyph, bold)); GlyphInstance instance = recycler.get(key(layer, glyphInfo, glyph, bold));
float shadowOffset = glyphInfo.getShadowOffset(); float shadowOffset = glyphInfo.getShadowOffset();
instance.setGlyph(glyph, pose, x + offset.x() * shadowOffset, y + offset.y() * shadowOffset, style.isItalic()); instance.setGlyph(glyph, pose, x + offset.x() * shadowOffset, offset.y() * shadowOffset, style.isItalic());
instance.colorArgb(color); instance.colorArgb(color);
instance.light(light); instance.light(light);
instance.setChanged(); instance.setChanged();
@ -241,10 +205,10 @@ public final class TextVisual {
// SpecialGlyphs.WHITE, which effects use, has a shadowOffset of 1, so don't modify the offset returned by the layer. // SpecialGlyphs.WHITE, which effects use, has a shadowOffset of 1, so don't modify the offset returned by the layer.
if (style.isStrikethrough()) { if (style.isStrikethrough()) {
addEffect(layer, x + offset.x() - 1.0f, y + offset.y() + 4.5f, x + offset.x() + advance, y + offset.y() + 4.5f - 1.0f, 0.01f, color); addEffect(layer, x + offset.x() - 1.0f, offset.y() + 4.5f, x + offset.x() + advance, offset.y() + 4.5f - 1.0f, 0.01f, color);
} }
if (style.isUnderlined()) { if (style.isUnderlined()) {
addEffect(layer, x + offset.x() - 1.0f, y + offset.y() + 9.0f, x + offset.x() + advance, y + offset.y() + 9.0f - 1.0f, 0.01f, color); addEffect(layer, x + offset.x() - 1.0f, offset.y() + 9.0f, x + offset.x() + advance, offset.y() + 9.0f - 1.0f, 0.01f, color);
} }
} }
@ -260,7 +224,7 @@ public final class TextVisual {
var glyphExtension = FlwLibLink.INSTANCE.getBakedGlyphExtension(glyph); var glyphExtension = FlwLibLink.INSTANCE.getBakedGlyphExtension(glyph);
GlyphInstance instance = recycler.get(effectKey(glyphExtension.flywheel$texture(), TextLayer.GlyphMaterial.SEE_THROUGH, 0)); GlyphInstance instance = recycler.get(effectKey(glyphExtension.flywheel$texture(), TextLayer.GlyphMaterial.SEE_THROUGH, 0));
instance.setEffect(glyph, pose, startX - 1.0f, y + 9.0f, endX + 1.0f, y - 1.0f, 0.01f); instance.setEffect(glyph, pose, startX - 1.0f, 9.0f, endX + 1.0f, 1.0f, 0.01f);
instance.colorArgb(backgroundColor); instance.colorArgb(backgroundColor);
instance.light(light); instance.light(light);
instance.setChanged(); instance.setChanged();

View file

@ -60,6 +60,8 @@ public class SignVisual extends AbstractBlockEntityVisual<SignBlockEntity> imple
// Most of the time this will be empty. // Most of the time this will be empty.
private final List<TextVisual> obfuscated = new ArrayList<>(); private final List<TextVisual> obfuscated = new ArrayList<>();
private int packedLight = 0;
private SignText lastFrontText; private SignText lastFrontText;
private SignText lastBackText; private SignText lastBackText;
@ -127,14 +129,14 @@ public class SignVisual extends AbstractBlockEntityVisual<SignBlockEntity> imple
// The is visible check is relatively expensive compared to the boolean checks above, // The is visible check is relatively expensive compared to the boolean checks above,
// so only do it when it'll actually save some work in obfuscating. // so only do it when it'll actually save some work in obfuscating.
if (isVisible(ctx.frustum())) { if (isVisible(ctx.frustum())) {
obfuscated.forEach(TextVisual::setup); obfuscated.forEach(TextVisual::updateObfuscated);
} }
} }
} }
@Override @Override
public void updateLight(float partialTick) { public void updateLight(float partialTick) {
int packedLight = computePackedLight(); packedLight = computePackedLight();
instances.traverse(instance -> { instances.traverse(instance -> {
instance.light(packedLight) instance.light(packedLight)
.setChanged(); .setChanged();
@ -142,15 +144,13 @@ public class SignVisual extends AbstractBlockEntityVisual<SignBlockEntity> imple
if (!lastFrontText.hasGlowingText()) { if (!lastFrontText.hasGlowingText()) {
for (var text : frontTextVisuals) { for (var text : frontTextVisuals) {
text.light(packedLight); text.updateLight(packedLight);
text.setup();
} }
} }
if (!lastBackText.hasGlowingText()) { if (!lastBackText.hasGlowingText()) {
for (var text : backTextVisuals) { for (var text : backTextVisuals) {
text.light(packedLight); text.updateLight(packedLight);
text.setup();
} }
} }
} }
@ -216,12 +216,7 @@ public class SignVisual extends AbstractBlockEntityVisual<SignBlockEntity> imple
float x = (float) (-FONT.width(textLine) / 2); float x = (float) (-FONT.width(textLine) / 2);
float y = i * lineHeight - lineDelta; float y = i * lineHeight - lineDelta;
var textVisual = textVisuals[i].layers(layers) var pose = new Matrix4f(initialPose);
.text(textLine)
.pos(x, y)
.backgroundColor(0);
var pose = textVisual.pose().set(initialPose);
if (!isFrontText) { if (!isFrontText) {
pose.rotateY(Mth.PI); pose.rotateY(Mth.PI);
} }
@ -229,13 +224,12 @@ public class SignVisual extends AbstractBlockEntityVisual<SignBlockEntity> imple
var textOffset = getTextOffset(); var textOffset = getTextOffset();
pose.translate((float) textOffset.x, (float) textOffset.y, (float) textOffset.z); pose.translate((float) textOffset.x, (float) textOffset.y, (float) textOffset.z);
pose.scale(scale, -scale, scale); pose.scale(scale, -scale, scale);
pose.translate(x, y, 0.0f);
if (text.hasGlowingText()) {
textVisual.light(LightTexture.FULL_BRIGHT);
}
// FIXME: incorrect light when going from glowing to non-glowing
textVisual.setup(); var textVisual = textVisuals[i];
int light = text.hasGlowingText() ? LightTexture.FULL_BRIGHT : packedLight;
textVisual.setup(textLine, layers, pose, light);
if (hasObfuscation(textLine)) { if (hasObfuscation(textLine)) {
obfuscated.add(textVisual); obfuscated.add(textVisual);