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;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.jetbrains.annotations.Nullable;
@ -53,8 +52,6 @@ public final class TextVisual {
private final Matrix4f pose = new Matrix4f();
private FormattedCharSequence text = FormattedCharSequence.EMPTY;
private float x;
private float y;
private int backgroundColor = 0;
private int light;
@ -63,91 +60,60 @@ public final class TextVisual {
.createInstance());
}
public TextVisual addLayer(TextLayer layer) {
layers.add(layer);
return this;
}
public TextVisual addLayers(Collection<TextLayer> layers) {
this.layers.addAll(layers);
return this;
}
public TextVisual layers(Collection<TextLayer> layers) {
public void setup(FormattedCharSequence textLine, List<TextLayer> layers, Matrix4f pose, int light) {
// TODO: probably don't store everything
this.text = textLine;
this.layers.clear();
this.layers.addAll(layers);
return this;
}
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.pose.set(pose);
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();
pose.identity();
text = FormattedCharSequence.EMPTY;
x = 0;
y = 0;
backgroundColor = 0;
light = 0;
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() {
recycler.delete();
}
@ -196,15 +162,13 @@ public final class TextVisual {
private int light;
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.layers = layers;
this.pose = pose;
this.light = light;
this.x = x;
this.y = y;
this.x = 0;
}
public void clear() {
@ -233,7 +197,7 @@ public final class TextVisual {
if (!(glyph instanceof EmptyGlyph)) {
GlyphInstance instance = recycler.get(key(layer, glyphInfo, glyph, bold));
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.light(light);
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.
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()) {
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);
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.light(light);
instance.setChanged();

View file

@ -60,6 +60,8 @@ public class SignVisual extends AbstractBlockEntityVisual<SignBlockEntity> imple
// Most of the time this will be empty.
private final List<TextVisual> obfuscated = new ArrayList<>();
private int packedLight = 0;
private SignText lastFrontText;
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,
// so only do it when it'll actually save some work in obfuscating.
if (isVisible(ctx.frustum())) {
obfuscated.forEach(TextVisual::setup);
obfuscated.forEach(TextVisual::updateObfuscated);
}
}
}
@Override
public void updateLight(float partialTick) {
int packedLight = computePackedLight();
packedLight = computePackedLight();
instances.traverse(instance -> {
instance.light(packedLight)
.setChanged();
@ -142,15 +144,13 @@ public class SignVisual extends AbstractBlockEntityVisual<SignBlockEntity> imple
if (!lastFrontText.hasGlowingText()) {
for (var text : frontTextVisuals) {
text.light(packedLight);
text.setup();
text.updateLight(packedLight);
}
}
if (!lastBackText.hasGlowingText()) {
for (var text : backTextVisuals) {
text.light(packedLight);
text.setup();
text.updateLight(packedLight);
}
}
}
@ -216,12 +216,7 @@ public class SignVisual extends AbstractBlockEntityVisual<SignBlockEntity> imple
float x = (float) (-FONT.width(textLine) / 2);
float y = i * lineHeight - lineDelta;
var textVisual = textVisuals[i].layers(layers)
.text(textLine)
.pos(x, y)
.backgroundColor(0);
var pose = textVisual.pose().set(initialPose);
var pose = new Matrix4f(initialPose);
if (!isFrontText) {
pose.rotateY(Mth.PI);
}
@ -229,13 +224,12 @@ public class SignVisual extends AbstractBlockEntityVisual<SignBlockEntity> imple
var textOffset = getTextOffset();
pose.translate((float) textOffset.x, (float) textOffset.y, (float) textOffset.z);
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)) {
obfuscated.add(textVisual);