More progress on Fonts and layouts.

This commit is contained in:
Speiger 2025-01-02 23:10:25 +01:00
parent 9ba9e81686
commit 8d7c7d2d97
10 changed files with 285 additions and 24 deletions

View File

@ -47,7 +47,7 @@ public interface ILayoutComponent {
public ArrayFetcher(boolean includeInvisible) { public ArrayFetcher(boolean includeInvisible) {
this.includeInvisible = includeInvisible; this.includeInvisible = includeInvisible;
} }
@Override @Override
public boolean acceptsInvisble() { public boolean acceptsInvisble() {
return includeInvisible; return includeInvisible;
@ -61,8 +61,27 @@ public interface ILayoutComponent {
result[INDEX_MAX_Y] = Math.max(maxY, result[INDEX_MAX_Y]); result[INDEX_MAX_Y] = Math.max(maxY, result[INDEX_MAX_Y]);
} }
public float[] getResult() { public void reset() {
result[0] = Float.MAX_VALUE;
result[1] = Float.MAX_VALUE;
result[2] = -Float.MAX_VALUE;
result[3] = -Float.MAX_VALUE;
}
public void hardReset() {
result = new float[] {Float.MAX_VALUE, Float.MAX_VALUE, -Float.MAX_VALUE, -Float.MAX_VALUE};
}
public float[] result() {
return result; return result;
} }
public float[] unscaledResult(IGuiBox owner) {
float[] unscaled = new float[4];
for(int i = 0;i<4;i++) {
unscaled[i] = result[i] / owner.getScale();
}
return unscaled;
}
} }
} }

View File

@ -10,7 +10,7 @@ import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth.GlythBaker;
import speiger.src.coreengine.rendering.tesselation.buffer.IVertexBuilder; import speiger.src.coreengine.rendering.tesselation.buffer.IVertexBuilder;
public class Font { public class Font {
public static final FontStyle DEFAULT = new FontStyle(AssetLocation.of("default"), 18); public static final FontStyle DEFAULT = new FontStyle(AssetLocation.of("default"), 0, 18F);
Map<AssetLocation, FontGroup> fonts; Map<AssetLocation, FontGroup> fonts;
GlythBaker baker; GlythBaker baker;
@ -30,12 +30,12 @@ public class Font {
} }
} }
public GlythData data(FontStyle font, int codepoint, int style) { public GlythData data(FontStyle font, int codepoint) {
return styledCache[style & 0x3].data(font, codepoint); return styledCache[font.style() & 0x3].data(font, codepoint);
} }
public Glyth glyth(FontStyle font, int codepoint, int style) { public Glyth glyth(FontStyle font, int codepoint) {
return styledCache[style & 0x3].glyth(font, codepoint); return styledCache[font.style() & 0x3].glyth(font, codepoint);
} }
protected FontGroup font(AssetLocation font) { protected FontGroup font(AssetLocation font) {
@ -51,11 +51,11 @@ public class Font {
int previousCodepoint = -1; int previousCodepoint = -1;
for(int i = 0,m=text.length();i<m;) { for(int i = 0,m=text.length();i<m;) {
int codepoint = text.codePointAt(i); int codepoint = text.codePointAt(i);
GlythData data = data(style, codepoint, 0); GlythData data = data(style, codepoint);
if(previousCodepoint != -1) { if(previousCodepoint != -1) {
x -= data.kerning(previousCodepoint); x -= data.kerning(previousCodepoint);
} }
Glyth glyth = glyth(style, codepoint, 0); Glyth glyth = glyth(style, codepoint);
if(glyth.isValid()) { if(glyth.isValid()) {
float minX = glyth.left() + x; float minX = glyth.left() + x;
float minY = glyth.top() + y; float minY = glyth.top() + y;

View File

@ -2,17 +2,57 @@ package speiger.src.coreengine.rendering.gui.font;
import speiger.src.coreengine.assets.AssetLocation; import speiger.src.coreengine.assets.AssetLocation;
public record FontStyle(AssetLocation font, float size) { public record FontStyle(AssetLocation font, int style, float size) {
public static final int REGULAR = 0;
public static final int BOLD = 1;
public static final int ITALIC = 2;
public static final int BOLD_ITCALIC = 3;
public FontStyle {
if(style < 0 || style > 3) throw new IllegalArgumentException("Style can only be between 0-3. Style found: "+style);
}
public FontStyle(AssetLocation font, float size) {
this(font, REGULAR, size);
}
public FontStyle(AssetLocation font, boolean bold, boolean italic, float size) {
this(font, (bold ? BOLD : 0) | (italic ? ITALIC : 0), size);
}
public FontStyle with(AssetLocation font, int style, float size) {
return new FontStyle(font, style, size);
}
public FontStyle with(AssetLocation font, float size) { public FontStyle with(AssetLocation font, float size) {
return new FontStyle(font, size); return new FontStyle(font, style, size);
} }
public FontStyle with(AssetLocation font) { public FontStyle with(AssetLocation font) {
return new FontStyle(font, size); return new FontStyle(font, style, size);
} }
public FontStyle with(float size) { public FontStyle with(float size) {
return new FontStyle(font, size); return new FontStyle(font, style, size);
} }
}
public FontStyle with(int style) {
return new FontStyle(font, style, size);
}
public FontStyle withBold(boolean bold) {
return new FontStyle(font, bold ? (style | BOLD) : (style & ~BOLD), size);
}
public FontStyle withItalic(boolean italic) {
return new FontStyle(font, italic ? (style | ITALIC) : (style & ~ITALIC), size);
}
public boolean bold() {
return (style() & BOLD) != 0;
}
public boolean italic() {
return (style() & ITALIC) != 0;
}
}

View File

@ -1,5 +1,6 @@
package speiger.src.coreengine.rendering.gui.layout.constraints; package speiger.src.coreengine.rendering.gui.layout.constraints;
import java.util.List;
import java.util.function.BooleanSupplier; import java.util.function.BooleanSupplier;
import speiger.src.coreengine.rendering.gui.components.base.GuiComponent; import speiger.src.coreengine.rendering.gui.components.base.GuiComponent;
@ -32,6 +33,26 @@ public class Constraints {
} }
} }
public static record Children(float padding, boolean includeChildOffsets) implements ISimpleConstraint {
public static Children onlyBounds() { return new Children(0F, false); }
public static Children onlyBounds(float padding) { return new Children(padding, false); }
public static Children withPos() { return new Children(0F, true); }
public static Children withPos(float padding) { return new Children(padding, true); }
@Override
public void apply(IGuiBox owner, IGuiBox parent, Target target) {
if(target.isPosition()) return;
float value = 0F;
List<IGuiBox> children = owner.children();
for(int i = 0,m=children.size();i<m;i++) {
IGuiBox child = children.get(i);
value = Math.max(value, child.getBaseX() + (includeChildOffsets() ? child.getBaseWidth() : 0));
}
target.set(owner, value);
}
}
public static record Relative(float value, float padding) implements ISimpleConstraint { public static record Relative(float value, float padding) implements ISimpleConstraint {
public static Relative of(float value) { return new Relative(value, 0F); } public static Relative of(float value) { return new Relative(value, 0F); }

View File

@ -4,6 +4,7 @@ import java.util.function.BooleanSupplier;
import speiger.src.coreengine.rendering.gui.components.base.GuiComponent; import speiger.src.coreengine.rendering.gui.components.base.GuiComponent;
import speiger.src.coreengine.rendering.gui.layout.constraints.Constraints.Center; import speiger.src.coreengine.rendering.gui.layout.constraints.Constraints.Center;
import speiger.src.coreengine.rendering.gui.layout.constraints.Constraints.Children;
import speiger.src.coreengine.rendering.gui.layout.constraints.Constraints.Conditional; import speiger.src.coreengine.rendering.gui.layout.constraints.Constraints.Conditional;
import speiger.src.coreengine.rendering.gui.layout.constraints.Constraints.Parent; import speiger.src.coreengine.rendering.gui.layout.constraints.Constraints.Parent;
import speiger.src.coreengine.rendering.gui.layout.constraints.Constraints.Pixels; import speiger.src.coreengine.rendering.gui.layout.constraints.Constraints.Pixels;
@ -13,7 +14,6 @@ import speiger.src.coreengine.rendering.guiOld.helper.box.IGuiBox;
public interface IConstraint { public interface IConstraint {
public void apply(GuiComponent owner, GuiComponent child, Target target); public void apply(GuiComponent owner, GuiComponent child, Target target);
public static IConstraint pixels(float value) { return Pixels.of(value); } public static IConstraint pixels(float value) { return Pixels.of(value); }
public static IConstraint pixelsInv(float value) { return Pixels.inverted(value); } public static IConstraint pixelsInv(float value) { return Pixels.inverted(value); }
@ -22,6 +22,11 @@ public interface IConstraint {
public static IConstraint parentInv() { return Parent.inverted(); } public static IConstraint parentInv() { return Parent.inverted(); }
public static IConstraint parentInv(float padding) { return Parent.inverted(padding); } public static IConstraint parentInv(float padding) { return Parent.inverted(padding); }
public static IConstraint children() { return Children.onlyBounds(); }
public static IConstraint children(float padding) { return Children.onlyBounds(padding); }
public static IConstraint childrenPos() { return Children.withPos(); }
public static IConstraint childrenPos(float padding) { return Children.withPos(padding); }
public static IConstraint relative(float value) { return Relative.of(value); } public static IConstraint relative(float value) { return Relative.of(value); }
public static IConstraint relative(float value, float padding) { return Relative.of(value, padding); } public static IConstraint relative(float value, float padding) { return Relative.of(value, padding); }
@ -59,8 +64,8 @@ public interface IConstraint {
public float get(IGuiBox box) { public float get(IGuiBox box) {
return switch(this) { return switch(this) {
case X -> box.getMinX(); case X -> box.getBaseX();
case Y -> box.getMinY(); case Y -> box.getBaseY();
case WIDTH -> box.getBaseWidth(); case WIDTH -> box.getBaseWidth();
case HEIGHT -> box.getBaseHeight(); case HEIGHT -> box.getBaseHeight();
}; };

View File

@ -0,0 +1,157 @@
package speiger.src.coreengine.rendering.gui.layout.layouts;
import java.util.List;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.rendering.gui.components.base.GuiComponent;
import speiger.src.coreengine.rendering.gui.components.base.ILayoutComponent.ArrayFetcher;
import speiger.src.coreengine.rendering.guiOld.helper.box.IGuiBox;
public class FlowLayout implements ILayout<Object> {
private static final int ALIGN_DISABLED = -1;
public static final int ALIGN_START = 0;
public static final int ALIGN_CENTER = 1;
public static final int ALIGN_END = 2;
private List<GuiComponent> comps = new ObjectArrayList<>();
protected float xGap;
protected float yGap;
protected int direction = ALIGN_END;
protected int verticalAlignement = ALIGN_DISABLED;
protected boolean includeInvisible = false;
protected boolean isVertical = false;
public FlowLayout(int direction) {
this.direction = direction;
}
public FlowLayout(float xGap, float yGap) {
this.xGap = xGap;
this.yGap = yGap;
}
public FlowLayout(float xGap, float yGap, int direction) {
this.xGap = xGap;
this.yGap = yGap;
this.direction = direction;
}
public FlowLayout verticalAlign(int alignment) {
verticalAlignement = Math.clamp(alignment, -1, 2);
return this;
}
public FlowLayout includeInvisible() {
includeInvisible = true;
return this;
}
public FlowLayout vertical(boolean value) {
isVertical = value;
return this;
}
@Override
public FlowLayout add(GuiComponent comp, Object value) {
comps.add(comp);
return this;
}
@Override
public FlowLayout remove(GuiComponent comp) {
comps.remove(comp);
return this;
}
@Override
public void apply(GuiComponent owner) {
int size = comps.size();
float max = isVertical ? owner.getBox().getBaseHeight() : owner.getBox().getBaseWidth();
float x = xGap;
float y = yGap;
float[] heights = new float[size];
float[] widths = new float[size];
int startIndex = 0;
ArrayFetcher fetcher = new ArrayFetcher(includeInvisible);
for(int i = 0,m=comps.size();i<m;i++) {
comps.get(i).calculateBounds(fetcher);
float[] bounds = fetcher.unscaledResult(owner.getBox());
float width = bounds[2] - bounds[0];
float height = bounds[3] - bounds[1];
widths[i] = width;
heights[i] = height;
if(isVertical) {
if(y + height + yGap > max) {
x += processComponents(startIndex, i, x, max, y, widths, heights);
y = yGap;
startIndex = i;
}
y += height + yGap;
fetcher.reset();
continue;
}
else if(x + width + xGap > max) {
y += processComponents(startIndex, i, y, max, x, widths, heights);
x = xGap;
startIndex = i;
}
x += width + xGap;
fetcher.reset();
}
processComponents(startIndex, size, y, max, x, widths, heights);
}
private void setX(IGuiBox box, float x) {
if(isVertical) box.setY(x);
else box.setX(x);
}
private void setY(IGuiBox box, float y) {
if(isVertical) box.setX(y);
else box.setY(y);
}
private float processComponents(int start, int end, float yStart, float maxWidth, float widthSum, float[] widths, float[] heights) {
float x = calculateStartPos(start, end, maxWidth, widthSum);
float yAligner = 0F;
if(verticalAlignement > 0) {
for(int i = start;i<end;i++) {
yAligner = Math.max(yAligner, isVertical ? (verticalAlignement == 2 ? widths[i] * 0.5F : widths[i]) : (verticalAlignement == 2 ? heights[i] * 0.5F : heights[i]));
}
}
float jump = yAligner;
yAligner += yStart;
for(int i = start;i<end;i++) {
IGuiBox box = comps.get(i).getBox();
setX(box, x);
switch(verticalAlignement) {
case ALIGN_DISABLED: break;
case ALIGN_START: {
setY(box, yStart);
break;
}
case ALIGN_CENTER: {
setY(box, yAligner - heights[i] * 0.5F);
break;
}
case ALIGN_END: {
setY(box, yAligner);
break;
}
}
if(direction == ALIGN_END) x -= widths[i] + (isVertical ? yGap : xGap);
else x += widths[i] + (isVertical ? yGap : xGap);
}
return jump;
}
private float calculateStartPos(int start, int end, float ownerWidth, float widthSum) {
return switch(direction) {
case ALIGN_CENTER -> ownerWidth * 0.5F - widthSum * 0.5F;
case ALIGN_END -> ownerWidth - xGap;
default -> xGap;
};
}
}

View File

@ -1,11 +1,15 @@
package speiger.src.coreengine.rendering.gui.layout.layouts; package speiger.src.coreengine.rendering.gui.layout.layouts;
import java.util.function.Consumer;
import speiger.src.coreengine.rendering.gui.components.base.GuiComponent; import speiger.src.coreengine.rendering.gui.components.base.GuiComponent;
public interface ILayout { public interface ILayout<T> extends Consumer<GuiComponent> {
public default ILayout add(GuiComponent comp) { return add(comp, null); } public default ILayout<T> add(GuiComponent comp) { return add(comp, null); }
public ILayout add(GuiComponent comp, Object value); public ILayout<T> add(GuiComponent comp, T value);
public ILayout remove(GuiComponent comp); public ILayout<T> remove(GuiComponent comp);
public void apply(); public void apply(GuiComponent owner);
@Override
default void accept(GuiComponent t) { apply(t); }
} }

View File

@ -3,10 +3,11 @@ package speiger.src.coreengine.rendering.guiOld.helper.box;
import java.util.List; import java.util.List;
import speiger.src.collections.objects.lists.ObjectArrayList; import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
public class GuiBox implements IGuiBox public class GuiBox implements IGuiBox
{ {
List<IGuiBox> children = new ObjectArrayList<>(); ObjectList<IGuiBox> children = new ObjectArrayList<>();
IGuiBox parent; IGuiBox parent;
float minX; float minX;
@ -62,6 +63,11 @@ public class GuiBox implements IGuiBox
return this; return this;
} }
@Override
public List<IGuiBox> children() {
return children.unmodifiable();
}
@Override @Override
public IGuiBox onChanged() { public IGuiBox onChanged() {
minX = parent == null ? baseX : parent.getMinX(baseX); minX = parent == null ? baseX : parent.getMinX(baseX);

View File

@ -1,5 +1,7 @@
package speiger.src.coreengine.rendering.guiOld.helper.box; package speiger.src.coreengine.rendering.guiOld.helper.box;
import java.util.List;
import speiger.src.coreengine.math.misc.Facing; import speiger.src.coreengine.math.misc.Facing;
import speiger.src.coreengine.math.misc.FacingList; import speiger.src.coreengine.math.misc.FacingList;
@ -8,6 +10,7 @@ public interface IGuiBox extends IScreenBox
public IGuiBox addChild(IGuiBox box); public IGuiBox addChild(IGuiBox box);
public IGuiBox removeChild(IGuiBox box); public IGuiBox removeChild(IGuiBox box);
public IGuiBox clearChildren(); public IGuiBox clearChildren();
public List<IGuiBox> children();
public IGuiBox setParent(IGuiBox box); public IGuiBox setParent(IGuiBox box);
public IGuiBox getParent(); public IGuiBox getParent();
public IGuiBox onChanged(); public IGuiBox onChanged();

View File

@ -3,10 +3,11 @@ package speiger.src.coreengine.rendering.guiOld.helper.box;
import java.util.List; import java.util.List;
import speiger.src.collections.objects.lists.ObjectArrayList; import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
public class ParentBox implements IGuiBox public class ParentBox implements IGuiBox
{ {
List<IGuiBox> children = new ObjectArrayList<>(); ObjectList<IGuiBox> children = new ObjectArrayList<>();
IGuiBox parent; IGuiBox parent;
float minX; float minX;
@ -50,6 +51,11 @@ public class ParentBox implements IGuiBox
return this; return this;
} }
@Override
public List<IGuiBox> children() {
return children.unmodifiable();
}
@Override @Override
public IGuiBox onChanged() { public IGuiBox onChanged() {
for(int i = 0,m=children.size();i<m;i++) { for(int i = 0,m=children.size();i<m;i++) {