wip: different heights for jump arrows

Note that this is very incomplete, for two different reasons:
- it's O(n^2) or potentially worse
- it makes the GC work hard (it invokes `new` in
  `LCanvas.DragLayout.layout()`)

For the second reason this does not clearly fit the criteria of
CONTRIBUTING.md, but I have yet to figure out ways to work around this
(or make the algorithm more efficient).
This commit is contained in:
code-explorer786
2024-06-26 10:37:20 +07:00
parent b8c9a05963
commit b58a6bb8d6
4 changed files with 94 additions and 4 deletions

View File

@@ -21,8 +21,10 @@ import mindustry.ui.*;
public class LCanvas extends Table{
public static final int maxJumpsDrawn = 100;
private static final int invalidJump = Integer.MAX_VALUE; // terrible hack
//ew static variables
static LCanvas canvas;
private static boolean dynamicJumpHeights = false;
public DragLayout statements;
public ScrollPane pane;
@@ -108,6 +110,8 @@ public class LCanvas extends Table{
statements = new DragLayout();
jumps = statements.jumps;
dynamicJumpHeights = Core.settings.getBool("dynamicjumpheights", false);
pane = pane(t -> {
t.center();
t.add(statements).pad(2f).center().width(targetWidth);
@@ -196,6 +200,7 @@ public class LCanvas extends Table{
int insertPosition = 0;
boolean invalidated;
public Group jumps = new WidgetGroup();
private Seq<JumpCurve> processedJumps = new Seq<JumpCurve>();
{
setTransform(true);
@@ -251,13 +256,73 @@ public class LCanvas extends Table{
}
}
if(parent != null) parent.invalidateHierarchy();
if(dynamicJumpHeights) setJumpHeights();
if(parent != null) parent.invalidateHierarchy();//don't invalid self
if(parent != null && parent instanceof Table){
setCullingArea(parent.getCullingArea());
}
}
private void setJumpHeights(){
SnapshotSeq<Element> jumpsChildren = jumps.getChildren();
processedJumps.clear();
jumpsChildren.each(e -> {
if(e instanceof JumpCurve e2){
e2.prepareHeight();
if(e2.jumpUIBegin != invalidJump){
processedJumps.add(e2);
}
}
});
processedJumps.sort((a,b) -> a.jumpUIBegin - b.jumpUIBegin);
Seq<JumpCurve> occupiers = new Seq<JumpCurve>();
Bits occupied = new Bits();
for(int i = 0; i < processedJumps.size; i++){
JumpCurve cur = processedJumps.get(i);
occupiers.retainAll(e -> {
if(e.jumpUIEnd > cur.jumpUIBegin) return true;
occupied.clear(e.predHeight);
return false;
});
int h = getJumpHeight(i, occupiers, occupied);
occupiers.add(cur);
occupied.set(h);
}
}
private int getJumpHeight(int index, Seq<JumpCurve> occupiers, Bits occupied){
JumpCurve jmp = processedJumps.get(index);
if(jmp.markedDone) return jmp.predHeight;
// TODO: optimize for LESS cloning
Seq<JumpCurve> tmpOccupiers = new Seq<JumpCurve>(occupiers);
Bits tmpOccupied = new Bits();
tmpOccupied.set(occupied);
int max = -1;
for(int i = index + 1; i < processedJumps.size; i++){
JumpCurve cur = processedJumps.get(i);
if(cur.jumpUIEnd > jmp.jumpUIEnd) continue;
tmpOccupiers.retainAll(e -> {
if(e.jumpUIEnd > cur.jumpUIBegin) return true;
tmpOccupied.clear(e.predHeight);
return false;
});
int h = getJumpHeight(i, tmpOccupiers, tmpOccupied);
tmpOccupiers.add(cur);
tmpOccupied.set(h);
max = Math.max(max, h);
}
jmp.predHeight = occupied.nextClearBit(max + 1);
jmp.markedDone = true;
return jmp.predHeight;
}
@Override
public float getPrefWidth(){
return prefWidth;
@@ -452,12 +517,14 @@ public class LCanvas extends Table{
ClickListener listener;
public JumpCurve curve;
public StatementElem elem;
public JumpButton(Prov<StatementElem> getter, Cons<StatementElem> setter){
public JumpButton(Prov<StatementElem> getter, Cons<StatementElem> setter, StatementElem elem){
super(Tex.logicNode, new ImageButtonStyle(){{
imageUpColor = Color.white;
}});
this.elem = elem;
to = getter;
addListener(listener = new ClickListener());
@@ -518,6 +585,11 @@ public class LCanvas extends Table{
public static class JumpCurve extends Element{
public JumpButton button;
// for jump prediction; see DragLayout
public int predHeight = 0;
public boolean markedDone = false;
public int jumpUIBegin = 0, jumpUIEnd = 0;
public JumpCurve(JumpButton button){
this.button = button;
}
@@ -575,7 +647,7 @@ public class LCanvas extends Table{
Lines.stroke(4f, button.color);
Draw.alpha(parentAlpha);
float dist = 100f;
float dist = 100f + 100f * (float) predHeight;
//square jumps
if(false){
@@ -599,5 +671,20 @@ public class LCanvas extends Table{
x2, y2,
Math.max(18, (int)(Mathf.dst(x, y, x2, y2) / 6)));
}
public void prepareHeight(){
if(this.button.to.get() == null){
this.markedDone = true;
this.predHeight = 0;
this.jumpUIBegin = this.jumpUIEnd = invalidJump;
} else {
this.markedDone = false;
int i = this.button.elem.index;
int j = this.button.to.get().index;
this.jumpUIBegin = Math.min(i,j);
this.jumpUIEnd = Math.max(i,j);
// height will be recalculated later
}
}
}
}

View File

@@ -870,7 +870,7 @@ public class LStatements{
table.table(this::rebuild);
table.add().growX();
table.add(new JumpButton(() -> dest, s -> dest = s)).size(30).right().padLeft(-8);
table.add(new JumpButton(() -> dest, s -> dest = s, this.elem)).size(30).right().padLeft(-8);
String name = name();

View File

@@ -502,6 +502,8 @@ public class SettingsMenuDialog extends BaseDialog{
if(!mobile){
Core.settings.put("swapdiagonal", false);
}
graphics.checkPref("dynamicjumpheights", true);
}
public void exportData(Fi file) throws IOException{