+package eu.svjatoslav.aukio.e3d2.systems.gui;
+
+import eu.svjatoslav.aukio.e3d2.kernel.GuiStore;
+import eu.svjatoslav.aukio.e3d2.kernel.ImageStore;
+import eu.svjatoslav.aukio.e3d2.kernel.SdfFontStore;
+import eu.svjatoslav.aukio.e3d2.kernel.Substrate;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/** World-anchored SDF labels. */
+class LabelPassTest {
+
+ private static Substrate data() {
+ final Substrate data = new Substrate();
+ data.image = new ImageStore(200, 100);
+ data.guiFont = SdfFont.build(48);
+ data.camera.set(0, 0, 0, 0, 0, 100);
+ return data;
+ }
+
+ @Test
+ void projectsWorldAnchorAndReusesGuiLabel() {
+ final Substrate data = data();
+ final LabelPass pass = new LabelPass()
+ .add(0, 0, 100, "X", 0xFF112233);
+
+ pass.apply(data);
+
+ assertEquals(1, data.gui.labels.size());
+ final GuiStore.Label label = data.gui.labels.get(0);
+ final double scale = 30.0 * 100 / (100 * SdfFontStore.CELL);
+ final int width = (int) (data.guiFont.advance['X' - SdfFontStore.FIRST]
+ * scale);
+ assertEquals("X", label.text);
+ assertEquals(0xFF112233, label.argb);
+ assertEquals(scale, label.scale, 1e-9);
+ assertEquals((int) (100 - width / 2.0), label.x);
+ assertEquals((int) (50 + SdfFontStore.CELL * scale * 0.25), label.y);
+
+ pass.apply(data);
+ assertEquals(1, data.gui.labels.size(), "second frame adds no duplicate");
+ assertSame(label, data.gui.labels.get(0), "existing label is updated");
+ }
+
+ @Test
+ void hidesBehindNearPlaneAndRestoresWhenVisible() {
+ final Substrate data = data();
+ final LabelPass pass = new LabelPass().add(0, 0, 4, "X", 0xFFFFFFFF);
+
+ pass.apply(data);
+ assertEquals(1, data.gui.labels.size());
+ assertEquals("", data.gui.labels.get(0).text);
+
+ data.camera.set(0, 0, -96, 0, 0, 100);
+ pass.apply(data);
+ assertEquals("X", data.gui.labels.get(0).text);
+ }
+
+ @Test
+ void missingFontOrImageLeavesGuiUntouched() {
+ final Substrate data = new Substrate();
+ final LabelPass pass = new LabelPass().add(0, 0, 100, "X", 0xFFFFFFFF);
+
+ pass.apply(data);
+ assertTrue(data.gui.labels.isEmpty(), "no font or image");
+
+ data.guiFont = SdfFont.build(48);
+ pass.apply(data);
+ assertTrue(data.gui.labels.isEmpty(), "no image");
+
+ data.guiFont = null;
+ data.image = new ImageStore(200, 100);
+ pass.apply(data);
+ assertTrue(data.gui.labels.isEmpty(), "no font");
+ }
+
+ @Test
+ void distantLabelsShrinkWithoutClamp() {
+ final Substrate data = data();
+ final LabelPass pass = new LabelPass()
+ .add(0, 0, 100, "near", 0xFFFFFFFF)
+ .add(0, 0, 1000, "far", 0xFFFFFFFF);
+
+ pass.apply(data);
+
+ final double nearScale = data.gui.labels.get(0).scale;
+ final double farScale = data.gui.labels.get(1).scale;
+ assertEquals(10.0, nearScale / farScale, 1e-9);
+ assertTrue(farScale < 0.1, "far label is not clamped to a minimum size");
+ }
+}