Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 22 additions & 7 deletions src/main/java/top/fpsmaster/ui/kit/EdgeCanvas.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import java.util.Deque;

final class EdgeCanvas implements Canvas {
private int clipDepth;
private final Deque<float[]> clips = new ArrayDeque<float[]>();
private final Deque<Float> alpha = new ArrayDeque<Float>();

EdgeCanvas() {
Expand Down Expand Up @@ -98,18 +98,33 @@ public void drawImage(ImageHandle image, float x, float y, float w, float h, int
}

public void pushClip(float x, float y, float w, float h) {
clipDepth++;
GL11.glEnable(GL11.GL_SCISSOR_TEST);
Scissor.apply(x, y, w, h);
float[] parent = clips.peek();
float[] next = parent == null
? new float[] {x, y, w, h}
: Scissor.intersect(parent[0], parent[1], parent[2], parent[3], x, y, w, h);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里只求交 GL scissor。Prism UiFrame.clicked / hovered 仍用原始矩形(Hit.inside / consumePressInBounds),不看这个栈。

Scroll.begin clip 的是列表视口;Performance 设置行的 layout box 仍可以伸出面板。画面被 clip 后,点面板下方或蒙层仍可能点到看不见的开关。

请在 1.8.9 上确认这种误点。若复现,改 Prism 的 hit-test,不要在 Edge 再改一套 clip 语义。

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

开另一个 pr 修复此问题

clips.push(next);
applyClip(next);
}

public void popClip() {
if (clipDepth > 0) {
clipDepth--;
if (clips.isEmpty()) {
return;
}
if (clipDepth == 0) {
clips.pop();
if (clips.isEmpty()) {
GL11.glDisable(GL11.GL_SCISSOR_TEST);
return;
}
applyClip(clips.peek());
}

private static void applyClip(float[] clip) {
GL11.glEnable(GL11.GL_SCISSOR_TEST);
if (clip[2] <= 0f || clip[3] <= 0f) {
GL11.glScissor(0, 0, 0, 0);
return;
}
Scissor.apply(clip[0], clip[1], clip[2], clip[3]);
}

public void pushAlpha(float a) {
Expand Down
24 changes: 24 additions & 0 deletions src/main/java/top/fpsmaster/utils/render/gui/Scissor.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,30 @@
import org.lwjgl.opengl.GL11;

public class Scissor {
/**
* Intersect two axis-aligned rectangles. Width/height are {@code 0} when they
* do not overlap. Used so nested {@code pushClip} calls compose instead of
* replacing the current scissor (expanded ClickGUI modules must stay inside
* the list viewport).
*/
public static float[] intersect(
float ax, float ay, float aw, float ah,
float bx, float by, float bw, float bh
) {
float aRight = ax + Math.max(0f, aw);
float aBottom = ay + Math.max(0f, ah);
float bRight = bx + Math.max(0f, bw);
float bBottom = by + Math.max(0f, bh);
float x = Math.max(ax, bx);
float y = Math.max(ay, by);
return new float[] {
x,
y,
Math.max(0f, Math.min(aRight, bRight) - x),
Math.max(0f, Math.min(aBottom, bBottom) - y)
};
}

public static void apply(float x, float y, float width, float height) {
float scale = UiScale.isActive() ? UiScale.getLayoutScale() : 1.0f;
applyScaled(x, y, width, height, scale);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package top.fpsmaster.utils.render.gui;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;

class ScissorIntersectTest {

@Test
void nestedSettingsClipStaysInsideListViewport() {
// SharedClickGui clips the module list (panel body), then each expanded module
// clips its settings to the card — Performance's card is taller than the panel.
float[] list = {140f, 40f, 330f, 270f};
float[] settings = {146f, 70f, 318f, 950f};
float[] clipped = Scissor.intersect(
list[0], list[1], list[2], list[3],
settings[0], settings[1], settings[2], settings[3]);
assertEquals(146f, clipped[0], 0.01f);
assertEquals(70f, clipped[1], 0.01f);
assertEquals(318f, clipped[2], 0.01f);
assertEquals(240f, clipped[3], 0.01f);
}

@Test
void disjointRectsAreEmpty() {
float[] clipped = Scissor.intersect(0f, 0f, 10f, 10f, 20f, 20f, 5f, 5f);
assertEquals(0f, clipped[2], 0.01f);
assertEquals(0f, clipped[3], 0.01f);
}

@Test
void identicalRectsStayIdentical() {
assertArrayEquals(new float[] {8f, 12f, 40f, 16f},
Scissor.intersect(8f, 12f, 40f, 16f, 8f, 12f, 40f, 16f), 0.01f);
}

@Test
void negativeExtentsDoNotExpandTheOtherRect() {
float[] clipped = Scissor.intersect(0f, 0f, 20f, 20f, 4f, 4f, -8f, 10f);
assertEquals(0f, clipped[2], 0.01f);
}
}
Loading