1515import java .nio .file .Path ;
1616import java .util .ArrayList ;
1717import java .util .LinkedHashMap ;
18+ import java .util .List ;
1819import java .util .Objects ;
1920import java .util .stream .Stream ;
2021
@@ -51,11 +52,15 @@ public final class ClickGui
5152
5253 private float [] bgColor = new float [3 ];
5354 private float [] acColor = new float [3 ];
55+ private float [] enabledHackColor = new float [3 ];
56+ private float [] dropdownButtonColor = new float [3 ];
57+ private float [] pinButtonColor = new float [3 ];
5458 private int txtColor ;
5559 private float opacity ;
5660 private float ttOpacity ;
5761 private int maxHeight ;
5862 private int maxSettingsHeight ;
63+ private boolean isolateWindows ;
5964
6065 private String tooltip = "" ;
6166
@@ -130,7 +135,10 @@ public void init()
130135 uiSettings .add (new FeatureButton (WURST .getOtfs ().hackListOtf ));
131136 uiSettings .add (new FeatureButton (WURST .getOtfs ().keybindManagerOtf ));
132137 ClickGuiHack clickGuiHack = WURST .getHax ().clickGuiHack ;
133- Stream <Setting > settings = clickGuiHack .getSettings ().values ().stream ();
138+ uiSettings .add (clickGuiHack .getIsolateWindowsSetting ().getComponent ());
139+ Stream <Setting > settings =
140+ clickGuiHack .getSettings ().values ().stream ().filter (
141+ setting -> setting != clickGuiHack .getIsolateWindowsSetting ());
134142 settings .map (Setting ::getComponent ).forEach (c -> uiSettings .add (c ));
135143 // Removed secondary Chest Search button from UI Settings so Chest
136144 // Search
@@ -580,6 +588,7 @@ public void render(DrawContext context, int mouseX, int mouseY,
580588 matrixStack .pushMatrix ();
581589
582590 tooltip = "" ;
591+ ArrayList <Window > visibleWindows = new ArrayList <>();
583592 for (Window window : windows )
584593 {
585594 if (window .isInvisible ())
@@ -602,10 +611,19 @@ public void render(DrawContext context, int mouseX, int mouseY,
602611 else
603612 window .stopDraggingScrollbar ();
604613
605- context .state .goUpLayer ();
606- renderWindow (context , window , mouseX , mouseY , partialTicks );
614+ visibleWindows .add (window );
607615 }
608616
617+ if (isolateWindows && !visibleWindows .isEmpty ())
618+ renderWindowsWithIsolation (context , visibleWindows , mouseX , mouseY ,
619+ partialTicks );
620+ else
621+ for (Window window : visibleWindows )
622+ {
623+ context .state .goUpLayer ();
624+ renderWindow (context , window , mouseX , mouseY , partialTicks );
625+ }
626+
609627 renderPopups (context , mouseX , mouseY );
610628 renderTooltip (context , mouseX , mouseY );
611629
@@ -679,15 +697,26 @@ public void renderTooltip(DrawContext context, int mouseX, int mouseY)
679697
680698 public void renderPinnedWindows (DrawContext context , float partialTicks )
681699 {
700+ ArrayList <Window > pinnedWindows = new ArrayList <>();
682701 for (Window window : windows )
683702 {
684- if (!window .isPinned () || window .isInvisible ())
685- continue ;
686-
687- context .state .goUpLayer ();
688- renderWindow (context , window , Integer .MIN_VALUE , Integer .MIN_VALUE ,
689- partialTicks );
703+ if (window .isPinned () && !window .isInvisible ())
704+ pinnedWindows .add (window );
690705 }
706+
707+ if (pinnedWindows .isEmpty ())
708+ return ;
709+
710+ if (isolateWindows )
711+ renderWindowsWithIsolation (context , pinnedWindows ,
712+ Integer .MIN_VALUE , Integer .MIN_VALUE , partialTicks );
713+ else
714+ for (Window window : pinnedWindows )
715+ {
716+ context .state .goUpLayer ();
717+ renderWindow (context , window , Integer .MIN_VALUE ,
718+ Integer .MIN_VALUE , partialTicks );
719+ }
691720 }
692721
693722 public void updateColors ()
@@ -698,6 +727,10 @@ public void updateColors()
698727 ttOpacity = clickGui .getTooltipOpacity ();
699728 bgColor = clickGui .getBackgroundColor ();
700729 txtColor = clickGui .getTextColor ();
730+ enabledHackColor = clickGui .getEnabledHackColor ();
731+ dropdownButtonColor = clickGui .getDropdownButtonColor ();
732+ pinButtonColor = clickGui .getPinButtonColor ();
733+ isolateWindows = clickGui .isWindowIsolationEnabled ();
701734 maxHeight = clickGui .getMaxHeight ();
702735 maxSettingsHeight = clickGui .getMaxSettingsHeight ();
703736
@@ -910,11 +943,95 @@ public float[] getAcColor()
910943 return acColor ;
911944 }
912945
946+ public float [] getEnabledHackColor ()
947+ {
948+ return enabledHackColor ;
949+ }
950+
913951 public int getTxtColor ()
914952 {
915953 return txtColor ;
916954 }
917955
956+ public float [] getDropdownButtonColor ()
957+ {
958+ return dropdownButtonColor ;
959+ }
960+
961+ public float [] getPinButtonColor ()
962+ {
963+ return pinButtonColor ;
964+ }
965+
966+ public boolean isWindowIsolationEnabled ()
967+ {
968+ return isolateWindows ;
969+ }
970+
971+ private void renderWindowsWithIsolation (DrawContext context ,
972+ List <Window > windowsToRender , int mouseX , int mouseY ,
973+ float partialTicks )
974+ {
975+ List <List <Rect >> occlusionMasks = buildOcclusionMasks (windowsToRender );
976+
977+ for (int i = 0 ; i < windowsToRender .size (); i ++)
978+ {
979+ Window window = windowsToRender .get (i );
980+ List <Rect > visibleAreas =
981+ computeVisibleAreas (window , occlusionMasks .get (i ));
982+
983+ if (visibleAreas .isEmpty ())
984+ continue ;
985+
986+ for (Rect rect : visibleAreas )
987+ {
988+ context .enableScissor (rect .x1 , rect .y1 , rect .x2 , rect .y2 );
989+ context .state .goUpLayer ();
990+ renderWindow (context , window , mouseX , mouseY , partialTicks );
991+ context .disableScissor ();
992+ }
993+ }
994+ }
995+
996+ private List <List <Rect >> buildOcclusionMasks (List <Window > windowsToRender )
997+ {
998+ ArrayList <List <Rect >> masks = new ArrayList <>(windowsToRender .size ());
999+ for (int i = 0 ; i < windowsToRender .size (); i ++)
1000+ masks .add (new ArrayList <>());
1001+
1002+ ArrayList <Rect > accumulated = new ArrayList <>();
1003+ for (int i = windowsToRender .size () - 1 ; i >= 0 ; i --)
1004+ {
1005+ ArrayList <Rect > copy = new ArrayList <>(accumulated .size ());
1006+ for (Rect rect : accumulated )
1007+ copy .add (rect .copy ());
1008+ masks .set (i , copy );
1009+
1010+ accumulated .add (Rect .fromWindow (windowsToRender .get (i )));
1011+ }
1012+
1013+ return masks ;
1014+ }
1015+
1016+ private List <Rect > computeVisibleAreas (Window window , List <Rect > occluders )
1017+ {
1018+ ArrayList <Rect > visible = new ArrayList <>();
1019+ visible .add (Rect .fromWindow (window ));
1020+
1021+ for (Rect occluder : occluders )
1022+ visible = subtractRectangles (visible , occluder );
1023+
1024+ return visible ;
1025+ }
1026+
1027+ private ArrayList <Rect > subtractRectangles (List <Rect > source , Rect occluder )
1028+ {
1029+ ArrayList <Rect > result = new ArrayList <>();
1030+ for (Rect rect : source )
1031+ result .addAll (rect .subtract (occluder ));
1032+ return result ;
1033+ }
1034+
9181035 public float getOpacity ()
9191036 {
9201037 return opacity ;
@@ -930,6 +1047,72 @@ public void setTooltip(String tooltip)
9301047 this .tooltip = Objects .requireNonNull (tooltip );
9311048 }
9321049
1050+ private static final class Rect
1051+ {
1052+ final int x1 ;
1053+ final int y1 ;
1054+ final int x2 ;
1055+ final int y2 ;
1056+
1057+ Rect (int x1 , int y1 , int x2 , int y2 )
1058+ {
1059+ this .x1 = x1 ;
1060+ this .y1 = y1 ;
1061+ this .x2 = x2 ;
1062+ this .y2 = y2 ;
1063+ }
1064+
1065+ static Rect fromWindow (Window window )
1066+ {
1067+ int x1 = window .getX ();
1068+ int y1 = window .getY ();
1069+ int width = window .getWidth ();
1070+ int height = window .isMinimized () ? 13 : window .getHeight ();
1071+ return new Rect (x1 , y1 , x1 + width , y1 + height );
1072+ }
1073+
1074+ Rect copy ()
1075+ {
1076+ return new Rect (x1 , y1 , x2 , y2 );
1077+ }
1078+
1079+ List <Rect > subtract (Rect other )
1080+ {
1081+ ArrayList <Rect > pieces = new ArrayList <>();
1082+ if (!intersects (other ))
1083+ {
1084+ pieces .add (this );
1085+ return pieces ;
1086+ }
1087+
1088+ int ox1 = Math .max (x1 , other .x1 );
1089+ int oy1 = Math .max (y1 , other .y1 );
1090+ int ox2 = Math .min (x2 , other .x2 );
1091+ int oy2 = Math .min (y2 , other .y2 );
1092+
1093+ if (oy1 > y1 )
1094+ pieces .add (new Rect (x1 , y1 , x2 , oy1 ));
1095+ if (oy2 < y2 )
1096+ pieces .add (new Rect (x1 , oy2 , x2 , y2 ));
1097+
1098+ if (oy1 < oy2 )
1099+ {
1100+ if (ox1 > x1 )
1101+ pieces .add (new Rect (x1 , oy1 , ox1 , oy2 ));
1102+ if (ox2 < x2 )
1103+ pieces .add (new Rect (ox2 , oy1 , x2 , oy2 ));
1104+ }
1105+
1106+ return pieces ;
1107+ }
1108+
1109+ private boolean intersects (Rect other )
1110+ {
1111+ return x1 < other .x2 && x2 > other .x1 && y1 < other .y2
1112+ && y2 > other .y1 ;
1113+ }
1114+ }
1115+
9331116 public void addWindow (Window window )
9341117 {
9351118 windows .add (window );
0 commit comments