From 3934c3facb85ec867c738da02e7497c8ca409aaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 12 Mar 2026 18:27:07 +0100 Subject: [PATCH] Split MMPX texture upscaling shader into regular and advanced The newer one, improved by CrashGG, will not load on many older devices due to complexity. --- assets/lang/ar_AE.ini | 1 + assets/lang/az_AZ.ini | 3 +- assets/lang/be_BY.ini | 1 + assets/lang/bg_BG.ini | 1 + assets/lang/ca_ES.ini | 1 + assets/lang/cz_CZ.ini | 1 + assets/lang/da_DK.ini | 1 + assets/lang/de_DE.ini | 1 + assets/lang/dr_ID.ini | 1 + assets/lang/en_US.ini | 1 + assets/lang/es_ES.ini | 1 + assets/lang/es_LA.ini | 1 + assets/lang/fa_IR.ini | 1 + assets/lang/fi_FI.ini | 1 + assets/lang/fr_FR.ini | 1 + assets/lang/gl_ES.ini | 1 + assets/lang/gr_EL.ini | 1 + assets/lang/he_IL.ini | 1 + assets/lang/he_IL_invert.ini | 1 + assets/lang/hr_HR.ini | 1 + assets/lang/hu_HU.ini | 1 + assets/lang/id_ID.ini | 1 + assets/lang/it_IT.ini | 1 + assets/lang/ja_JP.ini | 1 + assets/lang/jv_ID.ini | 1 + assets/lang/ko_KR.ini | 3 +- assets/lang/ku_SO.ini | 1 + assets/lang/lo_LA.ini | 1 + assets/lang/lt-LT.ini | 1 + assets/lang/ms_MY.ini | 1 + assets/lang/nl_NL.ini | 1 + assets/lang/no_NO.ini | 1 + assets/lang/pl_PL.ini | 1 + assets/lang/pt_BR.ini | 1 + assets/lang/pt_PT.ini | 1 + assets/lang/ro_RO.ini | 1 + assets/lang/ru_RU.ini | 1 + assets/lang/sv_SE.ini | 1 + assets/lang/tg_PH.ini | 1 + assets/lang/th_TH.ini | 1 + assets/lang/tr_TR.ini | 1 + assets/lang/uk_UA.ini | 1 + assets/lang/vi_VN.ini | 1 + assets/lang/zh_CN.ini | 1 + assets/lang/zh_TW.ini | 1 + assets/shaders/defaultshaders.ini | 6 + assets/shaders/tex_mmpx.csh | 1323 ++--------------------------- assets/shaders/tex_mmpx_adv.csh | 1273 +++++++++++++++++++++++++++ 48 files changed, 1407 insertions(+), 1244 deletions(-) create mode 100644 assets/shaders/tex_mmpx_adv.csh diff --git a/assets/lang/ar_AE.ini b/assets/lang/ar_AE.ini index b8c1b4a880..9e4b120eca 100644 --- a/assets/lang/ar_AE.ini +++ b/assets/lang/ar_AE.ini @@ -1527,6 +1527,7 @@ Off = معطل TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/az_AZ.ini b/assets/lang/az_AZ.ini index 9f16b1a213..4e0d5a4973 100644 --- a/assets/lang/az_AZ.ini +++ b/assets/lang/az_AZ.ini @@ -979,7 +979,7 @@ Allow speed control while connected (not recommended) = Qoşulu ikən sürət y AM: Data from Unknown Port = AM: Bilinməyən Port Veriləni Auto = Özbaşına Autoconfigure = Özü-görkəmləniş -Change proAdhocServer Address = ad hoc qulluqçu IP adresini dəyiş +Change proAdhocServer Address = Ad hoc qulluqçu IP adresini dəyiş Change proAdhocServer address hint = (localhost = çoxlu örnək) ChangeMacSaveConfirm = Yeni MAC adresi yaradılsın? ChangeMacSaveWarning = Bir sıra oyun qorunuş verilənini yükləyərkən MAC adresi yoxlayır, buna görə bu, köhnə qorunuşları korlaya bilər. @@ -1519,6 +1519,7 @@ Off = Sönülüdür TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/be_BY.ini b/assets/lang/be_BY.ini index ba4b034afb..f263f13034 100644 --- a/assets/lang/be_BY.ini +++ b/assets/lang/be_BY.ini @@ -1519,6 +1519,7 @@ Off = Выкл. TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Search] No settings matched '%1' = Няма адпаведных налад '%1' diff --git a/assets/lang/bg_BG.ini b/assets/lang/bg_BG.ini index a9b0ff227d..fc835dd5eb 100644 --- a/assets/lang/bg_BG.ini +++ b/assets/lang/bg_BG.ini @@ -1519,6 +1519,7 @@ Off = Изключено TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/ca_ES.ini b/assets/lang/ca_ES.ini index 8e4ee68153..a71d47a0a7 100644 --- a/assets/lang/ca_ES.ini +++ b/assets/lang/ca_ES.ini @@ -1519,6 +1519,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/cz_CZ.ini b/assets/lang/cz_CZ.ini index a05a2d6401..4b6242a06d 100644 --- a/assets/lang/cz_CZ.ini +++ b/assets/lang/cz_CZ.ini @@ -1519,6 +1519,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/da_DK.ini b/assets/lang/da_DK.ini index 6dcaa22452..6893f6be8c 100644 --- a/assets/lang/da_DK.ini +++ b/assets/lang/da_DK.ini @@ -1519,6 +1519,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/de_DE.ini b/assets/lang/de_DE.ini index 77ceeb881b..9d61a6d713 100644 --- a/assets/lang/de_DE.ini +++ b/assets/lang/de_DE.ini @@ -1518,6 +1518,7 @@ Off = Aus TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpin diff --git a/assets/lang/dr_ID.ini b/assets/lang/dr_ID.ini index 41f67035ce..5c78678d3c 100644 --- a/assets/lang/dr_ID.ini +++ b/assets/lang/dr_ID.ini @@ -1519,6 +1519,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index e23c316c79..be12bb1309 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -1543,6 +1543,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Search] No settings matched '%1' = No settings matched '%1' diff --git a/assets/lang/es_ES.ini b/assets/lang/es_ES.ini index 96193eaf6b..063761a06a 100644 --- a/assets/lang/es_ES.ini +++ b/assets/lang/es_ES.ini @@ -1520,6 +1520,7 @@ Off = Deshabilitar Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ TexMMPX = TexMMPX +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpino diff --git a/assets/lang/es_LA.ini b/assets/lang/es_LA.ini index ca2c82193d..52aeb58984 100644 --- a/assets/lang/es_LA.ini +++ b/assets/lang/es_LA.ini @@ -1521,6 +1521,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/fa_IR.ini b/assets/lang/fa_IR.ini index db52de630e..08c4e51977 100644 --- a/assets/lang/fa_IR.ini +++ b/assets/lang/fa_IR.ini @@ -1519,6 +1519,7 @@ Off = خاموش TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/fi_FI.ini b/assets/lang/fi_FI.ini index 75f2bbc09f..e5fb9bdc73 100644 --- a/assets/lang/fi_FI.ini +++ b/assets/lang/fi_FI.ini @@ -1519,6 +1519,7 @@ Off = Pois TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/fr_FR.ini b/assets/lang/fr_FR.ini index 01e1305db5..9fd9f4c99e 100644 --- a/assets/lang/fr_FR.ini +++ b/assets/lang/fr_FR.ini @@ -1510,6 +1510,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/gl_ES.ini b/assets/lang/gl_ES.ini index 92e0aa593c..97f81c8167 100644 --- a/assets/lang/gl_ES.ini +++ b/assets/lang/gl_ES.ini @@ -1519,6 +1519,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/gr_EL.ini b/assets/lang/gr_EL.ini index f0f97f1ea2..24d16807c2 100644 --- a/assets/lang/gr_EL.ini +++ b/assets/lang/gr_EL.ini @@ -1519,6 +1519,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/he_IL.ini b/assets/lang/he_IL.ini index 7b7d91c9f7..9d096e865a 100644 --- a/assets/lang/he_IL.ini +++ b/assets/lang/he_IL.ini @@ -1519,6 +1519,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/he_IL_invert.ini b/assets/lang/he_IL_invert.ini index 0576325757..bf8e4a6777 100644 --- a/assets/lang/he_IL_invert.ini +++ b/assets/lang/he_IL_invert.ini @@ -1519,6 +1519,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/hr_HR.ini b/assets/lang/hr_HR.ini index 03fb121444..022452c4fd 100644 --- a/assets/lang/hr_HR.ini +++ b/assets/lang/hr_HR.ini @@ -1519,6 +1519,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/hu_HU.ini b/assets/lang/hu_HU.ini index 062e6c1235..c564e46304 100644 --- a/assets/lang/hu_HU.ini +++ b/assets/lang/hu_HU.ini @@ -1519,6 +1519,7 @@ Off = Kikapcsolva TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/id_ID.ini b/assets/lang/id_ID.ini index 69a206577f..72699b77ef 100644 --- a/assets/lang/id_ID.ini +++ b/assets/lang/id_ID.ini @@ -1519,6 +1519,7 @@ Off = Mati TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/it_IT.ini b/assets/lang/it_IT.ini index 049d42b4de..9acac1519e 100644 --- a/assets/lang/it_IT.ini +++ b/assets/lang/it_IT.ini @@ -1523,6 +1523,7 @@ Off = Disattiva TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/ja_JP.ini b/assets/lang/ja_JP.ini index 23af12c276..02289f694c 100644 --- a/assets/lang/ja_JP.ini +++ b/assets/lang/ja_JP.ini @@ -1519,6 +1519,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = 高山 diff --git a/assets/lang/jv_ID.ini b/assets/lang/jv_ID.ini index 517abb89e3..23bb8f22d7 100644 --- a/assets/lang/jv_ID.ini +++ b/assets/lang/jv_ID.ini @@ -1519,6 +1519,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/ko_KR.ini b/assets/lang/ko_KR.ini index e32c150e74..f68e2f50eb 100644 --- a/assets/lang/ko_KR.ini +++ b/assets/lang/ko_KR.ini @@ -949,7 +949,7 @@ Autoconfigure = 자동구성 Change proAdhocServer address hint = (로컬호스트 = 다중 인스턴스) ChangeMacSaveConfirm = 새로운 MAC 주소를 생성하겠습니까? ChangeMacSaveWarning = 일부 게임은 저장 데이터를 불러올 때 MAC 주소를 확인하므로 이전 저장이 손상될 수 있습니다. -Change proAdhocServer Address = ad hoc 서버 IP 주소 변경 +Change proAdhocServer Address = Ad hoc 서버 IP 주소 변경 Chat = 채팅 Chat Button Position = 채팅 버튼 위치 Chat Here = 여기에서 채팅 @@ -1519,6 +1519,7 @@ Off = 끔 TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Search] No settings matched '%1' = '%1'과(와) 일치하는 설정이 없음 diff --git a/assets/lang/ku_SO.ini b/assets/lang/ku_SO.ini index f059a57751..6fada7a125 100644 --- a/assets/lang/ku_SO.ini +++ b/assets/lang/ku_SO.ini @@ -1533,6 +1533,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Search] No settings matched '%1' = No settings matched '%1' diff --git a/assets/lang/lo_LA.ini b/assets/lang/lo_LA.ini index 3d266bb0af..ad12cbba76 100644 --- a/assets/lang/lo_LA.ini +++ b/assets/lang/lo_LA.ini @@ -1519,6 +1519,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/lt-LT.ini b/assets/lang/lt-LT.ini index ab4fabe9ab..3fc12b1f2e 100644 --- a/assets/lang/lt-LT.ini +++ b/assets/lang/lt-LT.ini @@ -1519,6 +1519,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/ms_MY.ini b/assets/lang/ms_MY.ini index 42e3228ea8..aa44515344 100644 --- a/assets/lang/ms_MY.ini +++ b/assets/lang/ms_MY.ini @@ -1519,6 +1519,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/nl_NL.ini b/assets/lang/nl_NL.ini index 7aa99124eb..671bd39522 100644 --- a/assets/lang/nl_NL.ini +++ b/assets/lang/nl_NL.ini @@ -1519,6 +1519,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/no_NO.ini b/assets/lang/no_NO.ini index 4ef7be6f08..c56df8fbc4 100644 --- a/assets/lang/no_NO.ini +++ b/assets/lang/no_NO.ini @@ -1519,6 +1519,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpin diff --git a/assets/lang/pl_PL.ini b/assets/lang/pl_PL.ini index 9c9cb48850..1925102728 100644 --- a/assets/lang/pl_PL.ini +++ b/assets/lang/pl_PL.ini @@ -1527,6 +1527,7 @@ Off = Wył. TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini index f5f2bb7534..897cf3cd7b 100644 --- a/assets/lang/pt_BR.ini +++ b/assets/lang/pt_BR.ini @@ -1543,6 +1543,7 @@ Off = Desligado TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Search] No settings matched '%1' = Nenhuma das configurações combinou com o '%1' diff --git a/assets/lang/pt_PT.ini b/assets/lang/pt_PT.ini index b748ee4fa2..bf5a113873 100644 --- a/assets/lang/pt_PT.ini +++ b/assets/lang/pt_PT.ini @@ -1544,6 +1544,7 @@ Off = Desativado TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Search] No settings matched '%1' = Nenhuma das definições se parece com '%1' diff --git a/assets/lang/ro_RO.ini b/assets/lang/ro_RO.ini index 947f10733f..40ddae4ae3 100644 --- a/assets/lang/ro_RO.ini +++ b/assets/lang/ro_RO.ini @@ -1520,6 +1520,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/ru_RU.ini b/assets/lang/ru_RU.ini index db6401bd40..a9027028cc 100644 --- a/assets/lang/ru_RU.ini +++ b/assets/lang/ru_RU.ini @@ -1519,6 +1519,7 @@ Off = Выкл. TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index eb97c656dd..b939147694 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -1520,6 +1520,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpin diff --git a/assets/lang/tg_PH.ini b/assets/lang/tg_PH.ini index 6a9af5c949..ae4e410871 100644 --- a/assets/lang/tg_PH.ini +++ b/assets/lang/tg_PH.ini @@ -1522,6 +1522,7 @@ Off = Nakapatay TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/th_TH.ini b/assets/lang/th_TH.ini index 45b32274d8..74714068af 100644 --- a/assets/lang/th_TH.ini +++ b/assets/lang/th_TH.ini @@ -1560,6 +1560,7 @@ Off = ปิด TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = อัลไพน์ diff --git a/assets/lang/tr_TR.ini b/assets/lang/tr_TR.ini index d77d354230..c237dbf942 100644 --- a/assets/lang/tr_TR.ini +++ b/assets/lang/tr_TR.ini @@ -1520,6 +1520,7 @@ Off = Kapalı TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/uk_UA.ini b/assets/lang/uk_UA.ini index 37ca26f4fc..b531181f41 100644 --- a/assets/lang/uk_UA.ini +++ b/assets/lang/uk_UA.ini @@ -1519,6 +1519,7 @@ Off = Вимкнути TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/vi_VN.ini b/assets/lang/vi_VN.ini index efeb7f9e31..02e78abd34 100644 --- a/assets/lang/vi_VN.ini +++ b/assets/lang/vi_VN.ini @@ -1519,6 +1519,7 @@ Off = Off TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini index 2aa914327b..355ff7456b 100644 --- a/assets/lang/zh_CN.ini +++ b/assets/lang/zh_CN.ini @@ -1513,6 +1513,7 @@ Off = 关闭 TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Themes] Alpine = Alpine diff --git a/assets/lang/zh_TW.ini b/assets/lang/zh_TW.ini index cae9743e03..7653cd0076 100644 --- a/assets/lang/zh_TW.ini +++ b/assets/lang/zh_TW.ini @@ -1519,6 +1519,7 @@ Off = 關閉 TexMMPX = TexMMPX Tex2xBRZ = Tex2xBRZ Tex4xBRZ = Tex4xBRZ +TexMMPXAdvanced = TexMMPXAdvanced [Search] No settings matched '%1' = 沒有與「%1」相符的設定 diff --git a/assets/shaders/defaultshaders.ini b/assets/shaders/defaultshaders.ini index b51c8101e7..68413f2dbf 100644 --- a/assets/shaders/defaultshaders.ini +++ b/assets/shaders/defaultshaders.ini @@ -212,6 +212,12 @@ Name=MMPX (2x) Author=Morgan McGuire and Mara Gagiu Compute=tex_mmpx.csh Scale=2 +[TexMMPXAdvanced] +Type=Texture +Name=MMPX Advanced (2x) +Author=CrashGG, Morgan McGuire and Mara Gagiu +Compute=tex_mmpx_adv.csh +Scale=2 VendorBlacklist=Apple [RedBlue] Type=StereoToMono diff --git a/assets/shaders/tex_mmpx.csh b/assets/shaders/tex_mmpx.csh index 8b86ca27a2..4016d7d270 100644 --- a/assets/shaders/tex_mmpx.csh +++ b/assets/shaders/tex_mmpx.csh @@ -2,1272 +2,111 @@ Copyright 2020 Morgan McGuire & Mara Gagiu. Provided under the Open Source MIT license https://opensource.org/licenses/MIT + See js-demo.html for the commented source code. + This is an optimized GLSL port of that version by Morgan McGuire and Mara Gagiu. - 2025 Enhanced by CrashGG. */ // Performs 2x upscaling. -/* If we took an image as input, we could use a sampler to do the clamping. But we decode - low-bpp texture data directly, so... +#define ABGR8 uint - use readColoru to read uint format color data from texture/framebuffer. - in ppsspp ,readColorf(p) eq unpackUnorm4x8(readColoru(p)),It is not actually read directly. -*/ - -uint src(int x, int y) { - - // Legacy clamp approach: return center pixel consistently when coordinates out of bounds - //return readColoru(uvec2(clamp(x, 0, params.width - 1), clamp(y, 0, params.height - 1))); - - // Improved out-of-bounds detection: check if coordinates are within valid range first. - // Return transparent color immediately if out of bounds. - return (x >= 0 && x < params.width && y >= 0 && y < params.height) - ? readColoru(uvec2(x, y)) - : 0u; +// If we took an image as input, we could use a sampler to do the clamping. But we decode +// low-bpp texture data directly, so... +ABGR8 src(int x, int y) { + return readColoru(uvec2(clamp(x, 0, params.width - 1), clamp(y, 0, params.height - 1))); } - -// RGB perceptual weight + alpha segmentation -float luma(vec4 col) { - - // BT.601 standard (CRT era) - result divided by 10, range [0.0 - 0.1] - float rgbsum =dot(col.rgb, vec3(0.0299, 0.0587, 0.0114)); - - // Subsequent fractional extraction *10 removes alpha weighting - float alphafactor = - (col.a > 0.854102) ? 1.0 : // 2x short golden ratio (larger segment) - (col.a > 0.618034) ? 2.0 : // 1x golden ratio - (col.a > 0.381966) ? 3.0 : // 1x short golden ratio - (col.a > 0.145898) ? 4.0 : // 2x short golden ratio - (col.a > 0.002) ? 5.0 : 8.0; // Fully transparent - - return rgbsum + alphafactor; - +uint luma(ABGR8 C) { + uint alpha = (C & 0xFF000000u) >> 24; + return (((C & 0x00FF0000u) >> 16) + ((C & 0x0000FF00u) >> 8) + (C & 0x000000FFu) + 1u) * (256u - alpha); } -/* Constant explanations: -0.145898 : 2x short golden ratio of 1.0 -0.0638587 : Squared value after 2x short golden ratio on RGB Euclidean distance -0.024391856 : Squared value after 2x short golden ratio + 1x golden ratio on RGB Euclidean distance -0.00931686 : Squared value after 3x short golden ratio on RGB Euclidean distance -0.001359312 : Squared value after 4x short golden ratio on RGB Euclidean distance -0.4377 : Squared value after 1x short golden ratio on RGB Euclidean distance -0.75 : Squared value after halving RGB Euclidean distance -*/ -// Pixel similarity check LV1 -bool sim1(vec4 col1, vec4 col2) { - - vec4 diff = col1 - col2; - vec4 absdiff = abs(diff); - - // 1. Fast component difference check - if ( absdiff.r > 0.1 || absdiff.g > 0.1 || absdiff.b > 0.1 || absdiff.a > 0.145898 ) return false; // xxx.alpha - - // 2. Fast squared distance check - float dot_diff = dot(diff.rgb, diff.rgb); // xxx.alpha - if (dot_diff < 0.001359312) return true; - - // 3. Gradual pixel check - float min_diff = min(diff.r, min(diff.g, diff.b)); - float max_diff = max(diff.r, max(diff.g, diff.b)); - if ( max_diff-min_diff>0.096 ) return false; // Exit if difference exceeds int24 - if ( max_diff-min_diff<0.024 && dot_diff<0.024391856) return true; // Consider gradual pixel if difference ≤ int6. Relax threshold by one level. - - // 4. Grayscale pixel check - float sum1 = dot(col1.rgb, vec3(1.0)); // Sum of RGB channels //xxx.alpha - float sum2 = dot(col2.rgb, vec3(1.0)); //xxx.alpha - float avg1 = sum1 * 0.3333333; - float avg2 = sum2 * 0.3333333; - - vec3 graydiff1 = col1.rgb - vec3(avg1); //xxx.alpha - vec3 graydiff2 = col2.rgb - vec3(avg2); //xxx.alpha - float dotgray1 = dot(graydiff1,graydiff1); - float dotgray2 = dot(graydiff2,graydiff2); - // 0.002: Max single-channel difference allowed is int13 when avg=20. - // 0.0004: Max single-channel difference allowed is int6, or int3+4 for dual channels - float tolerance1 = avg1<0.08 ? 0.002 : 0.0004; - float tolerance2 = avg2<0.08 ? 0.002 : 0.0004; - // 0.078 limits max green channel value to 19 (perceptible threshold to human eye) - bool Col1isGray = sum1<0.078||dotgray10.381966) return false; - - // 1. Clamp RGB dark areas - vec3 clampCol1 = max(col1.rgb, vec3(0.078)); //xxx.alpha - vec3 clampCol2 = max(col2.rgb, vec3(0.078)); //xxx.alpha - - vec3 clampdiff = clampCol1 - clampCol2; - - // 2x short + 1x, 2x short golden ratio of RGB Euclidean distance between two points - float dotdist = Lv==2 ? 0.024391856 : 0.0638587; - - return dot(clampdiff, clampdiff) < dotdist; +bool all_eq3(ABGR8 B, ABGR8 A0, ABGR8 A1, ABGR8 A2) { + return ((B ^ A0) | (B ^ A1) | (B ^ A2)) == 0u; } -bool sim2(vec4 colC1, uint C1, uint C2) { - if (C1==C2) return true; - return sim2n3(colC1, unpackUnorm4x8(C2), 2); +bool all_eq4(ABGR8 B, ABGR8 A0, ABGR8 A1, ABGR8 A2, ABGR8 A3) { + return ((B ^ A0) | (B ^ A1) | (B ^ A2) | (B ^ A3)) == 0u; } -bool sim3(vec4 col1, vec4 col2) { - return sim2n3(col1, col2, 3); +bool any_eq3(ABGR8 B, ABGR8 A0, ABGR8 A1, ABGR8 A2) { + return B == A0 || B == A1 || B == A2; } -bool mixcheck(vec4 col1, vec4 col2) { - - // Do not mix if either is transparent //xxx.alpha - bool col1alpha0 = col1.a < 0.003; - bool col2alpha0 = col2.a < 0.003; - if (col1alpha0!=col2alpha0) return false; - - // Cannot mix if transparency difference exceeds 50% //xxx.alpha - if (abs(col1.a - col2.a)>0.5) return false; - - vec3 diff = col1.rgb - col2.rgb; - - // Gradual pixel check - float min_diff = min(diff.r, min(diff.g, diff.b)); - float max_diff = max(diff.r, max(diff.g, diff.b)); - if ( max_diff-min_diff>0.618034 ) return false; - - float dot_diff = dot(diff, diff); - if( max_diff-min_diff<0.024 && dot_diff<0.75) return true; // 0.020 ≤ int5 0.024 ≤ int6 - - // Accumulate positive/negative values separately using max/min - float team_pos = abs(dot(max(diff, 0.0), vec3(1.0))); - float team_neg = abs(dot(min(diff, 0.0), vec3(1.0))); - // Find opposing channels and add to squared distance for judgment - float team_rebel = min(team_pos, team_neg); - // Empirical: At least 3x opposing channel value needs to be added. (+1x to break even, +2x to form increasing trend) - return dot_diff + team_rebel*team_rebel*3.0 < 0.4377; +bool none_eq2(ABGR8 B, ABGR8 A0, ABGR8 A1) { + return (B != A0) && (B != A1); } -// RGB must be identical, small alpha channel difference allowed -bool eq(uint C1, uint C2){ - if (C1 == C2) return true; - - uint rgbC1 = C1 & 0x00FFFFFFu; - uint rgbC2 = C2 & 0x00FFFFFFu; - - if (rgbC1 != rgbC2) return false; - - uint alphaC1 = C1 >> 24; - uint alphaC2 = C2 >> 24; - - // Note: abs(alphaC1-alphaC2) cannot be used with uint! - uint alphaDiff = (alphaC1 > alphaC2) ? (alphaC1 - alphaC2) : (alphaC2 - alphaC1); - - return alphaDiff < 38u; //2x short golden ratio of 255u - +bool none_eq4(ABGR8 B, ABGR8 A0, ABGR8 A1, ABGR8 A2, ABGR8 A3) { + return B != A0 && B != A1 && B != A2 && B != A3; } -#define noteq(a,b) (a!=b) - -bool vec_noteq(vec4 col1, vec4 col2) { - vec4 diff = abs(col1 - col2); - // Allow total RGB channel difference of int2, alpha channel difference of int5 - return dot(diff.rgb, vec3(1.0)) > 0.008 || diff.a > 0.021286; -} - -bool all_eq2(uint B, uint A0, uint A1) { - return (eq(B,A0) && eq(B,A1)); -} - -bool any_eq2(uint B, uint A0, uint A1) { - return (eq(B,A0) || eq(B,A1)); -} - -bool any_eq3(uint B, uint A0, uint A1, uint A2) { - return (eq(B,A0) || eq(B,A1) || eq(B,A2)); -} - -bool none_eq2(uint B, uint A0, uint A1) { - return (noteq(B,A0) && noteq(B,A1)); -} - -// Pre-define -//#define testcolor vec4(1.0, 0.0, 1.0, 1.0) // Magenta -//#define testcolor2 vec4(0.0, 1.0, 1.0, 1.0) // Cyan -//#define testcolor3 vec4(1.0, 1.0, 0.0, 1.0) // Yellow -//#define testcolor4 vec4(1.0, 1.0, 1.0, 1.0) // White - -#define slopeBAD vec4(2.0) -#define theEXIT vec4(4.0) -#define slopOFF vec4(8.0) -#define Mix382 mix(colX,colE,0.381966) -#define Mix618 mix(colX,colE,0.618034) -#define Mix854 mix(colX,colE,0.8541) -#define Mix382off Mix382+slopOFF -#define Mix618off Mix618+slopOFF -#define Mix854off Mix854+slopOFF -#define Xoff colX+slopOFF -#define checkblack(col) ((col).g < 0.078 && (col).r < 0.1 && (col).b < 0.1) -#define diffEB abs(El-Bl) -#define diffED abs(El-Dl) -#define writeJKLM writeColorf(destXY,J);writeColorf(destXY+ivec2(1,0),K);writeColorf(destXY+ivec2(0,1),L);writeColorf(destXY+ivec2(1,1),M) - -//pin zz -// Concave + Cross shape - weak blending (weak/none) -vec4 admixC(vec4 colX, vec4 colE) { - // Transparent pixels already filtered in main line - - bool mixok = mixcheck(colX, colE); - - return mixok ? Mix618 : colE; - -} - -// K shape - forced weak blending (weak/weaker) -vec4 admixK(vec4 colX, vec4 colE) { - // Transparent pixels already filtered in main line - - bool mixok = mixcheck(colX, colE); - - return mixok ? Mix618 : Mix854; - -} - -// L shape 2:1 slope - extension of main corner -// Note: This rule requires all 4 pixels on the slope to be identical. Otherwise, various visual artifacts will appear! -vec4 admixL(vec4 colX, vec4 colE, vec4 colS) { - - // Check eqX,E: originally captured large number of duplicate pixels, now filtered via slopeok in main line. - - // If target X differs from reference S (sample), it means blending has already occurred once. - // Copy directly without re-blending - if (vec_noteq(colX, colS)) return colX; - - bool mixok = mixcheck(colX, colE); - - return mixok ? Mix382 : colX; -} - -/******************************************************************************************************************************************** - * main slope + X cross-processing mechanism * - *******************************************************************************************************************************************/ -vec4 admixX(uint A, uint B, uint C, uint D, uint E, uint F, uint G, uint H, uint I, uint P, uint PA, uint PC, uint Q, uint QA, uint QG, uint R, uint RC, uint RI, uint S, uint SG, uint SI, uint AA, uint CC, uint GG, float El, float Bl, float Dl, float Fl, float Hl, vec4 colE, vec4 colB, vec4 colD) { - - // xxx.alpha - // 1. Normal rule: center E has higher luma - transparency in BD is illogical - // 2. B/D may be transparent when E-A are identical, but using transparent B/D to cut solid crossed E-A violates design - if (colB.a<0.002||colD.a<0.002) return slopeBAD; - - bool eq_B_C = eq(B, C); - bool eq_D_G = eq(D, G); - - // Exit if surrounded by straight walls on both sides - if (eq_B_C && eq_D_G) return slopeBAD; - - //Pre-declare - bool eq_A_B; bool eq_A_D; bool eq_A_P; bool eq_A_Q; - bool eq_B_P; bool eq_B_PA; bool eq_B_PC; - bool eq_D_Q; bool eq_D_QA; bool eq_D_QG; - bool eq_E_F; bool eq_E_H; bool eq_E_I; bool En3; - bool B_slope; bool B_tower; bool B_wall; - bool D_slope; bool D_tower; bool D_wall; - vec4 colX; bool Xisblack; - bool mixok; - - bool eq_B_D = eq(B,D); - bool eq_E_A = eq(E,A); - - #define comboA3 eq_A_P && eq_A_Q - #define En4square En3 && eq_E_I - - // E is nearly transparent but not fully transparent - mostly edges //xxx.alpha - bool EalphaL = colE.a <0.381966 && colE.a >0.002; - - // Remove alpha channel weighting - Bl = fract(Bl) *10.0; - Dl = fract(Dl) *10.0; - El = fract(El) *10.0; - Fl = fract(Fl) *10.0; - Hl = fract(Hl) *10.0; - -/*========================================= - B != D - ==================================== zz */ -if (!eq_B_D){ - - // Exit if E-A equality violates preset logic - if (eq_E_A) return slopeBAD; - - // Exit if B/D differ significantly (greater than E's difference with either side) - float diffBD = abs(Bl-Dl); - if (diffBD > diffEB || diffBD > diffED) return slopeBAD; - - // Avoid single-pixel font edges being squeezed by black background on both sides - // (Brightness difference between font and background usually exceeds 0.5) - // Note: If BD are not equal, cannot use average for judgment - both must meet black condition - Xisblack = checkblack(colB) && checkblack(colD); - if ( Xisblack && El >0.5 && (Fl<0.078 || Hl<0.078) ) return theEXIT; - -// Exclusion rule before original logic (triangle vertices cannot protrude) - eq_A_B = eq(A,B); - if ( !Xisblack && eq_A_B && eq_D_G && eq(B,P) ) return slopeBAD; - - eq_A_D = eq(A,D); - if ( !Xisblack && eq_A_D && eq_B_C && eq(D,Q) ) return slopeBAD; - - // B/D unconnected to any? Not applicable here (eliminates some artifacts but loses shapes, - // especially non-native pixel art like Double Dragon attract mode character sprites) - - // X is blend of B/D - colX = mix(colB, colD, 0.5); - colX.a = min(colB.a, colD.a); // xxx.alpha - - mixok = mixcheck(colX,colE); - - eq_A_P = eq(A,P); - eq_A_Q = eq(A,Q); - // A-side triple consecutive (eq_A_P && eq_A_Q) - high priority - if (comboA3) return mixok ? Mix382off : Xoff; - - // Official original rule - if ( eq(E,C) || eq(E,G) ) return mixok ? Mix382off : Xoff; - - // Enhanced original rule 1 - good at capturing trends, but enhanced 2 cannot be used (wall bypass issue) - if ( !eq_D_G&&eq(E,QG)&&sim2(colE,E,G) || !eq_B_C&&eq(E,PC)&&sim2(colE,E,C) ) return mixok ? Mix382off : Xoff; - - - // Exclude "3-pixel single-side wall" case - if (!Xisblack){ - if ( eq_A_B&&eq_B_C || eq_A_D&&eq_D_G ) return slopeBAD; - } - - //xxx.alpha - if (EalphaL) return mixok ? Mix382off : Xoff; - - // F-H inline trend (includes En3) - placed after wall rules since blocked by 3-pixel wall rule - if ( eq(F,H) ) return mixok ? Mix382off : Xoff; - - // Remaining "2-pixel single-side wall" and unlogical single pixels - abandon - return slopeBAD; -} // B != D - -/******* B == D prepare *******/ - - // Avoid single-pixel font edges being squeezed by black background on both sides - Xisblack = checkblack(colB); - if ( Xisblack && El >0.5 && (Fl<0.078 || Hl<0.078) ) return theEXIT; - - colX = colB; - colX.a = min(colB.a , colD.a); - - bool eq_E_C = eq(E,C); - bool eq_E_G = eq(E,G); - bool sim_EC = eq_E_C || sim2n3(colE,unpackUnorm4x8(C),2); - bool sim_EG = eq_E_G || sim2n3(colE,unpackUnorm4x8(G),2); - - bool ThickBorder; - - -/*=============================================== - Original main rule (sim2 enhanced) - ========================================== zz */ -if ( (sim_EC || sim_EG) && !eq_E_A ){ - -/* Logic: - 1. Handle non-blending for continuous border shapes - 2. Special handling for long slopes - 3. Original rules - 4. Handle E-area inline (En4, En3, F-H etc.), remaining single strip and single pixel - 5. Handle L-shaped inner single strip and outer single strip - 5. Default fallback return -*/ - - eq_A_B = eq(B,A); - eq_B_P = eq(B,P); - eq_B_PC = eq(B,PC); - eq_B_PA = eq(B,PA); - eq_D_Q = eq(D,Q); - eq_D_QG = eq(D,QG); - eq_D_QA = eq(D,QA); - B_slope = eq_B_PC && !eq_B_P && !eq_B_C; - B_tower = eq_B_P && !eq_B_PC && !eq_B_C && !eq_B_PA; - D_slope = eq_D_QG && !eq_D_Q && !eq_D_G; - D_tower = eq_D_Q && !eq_D_QG && !eq_D_G && !eq_D_QA; - - - // B+ D+ each extend shape (strong shape) - no blending, return Xoff - if ( (B_slope||B_tower) && (D_slope||D_tower) && !eq_A_B) return Xoff; - - - eq_A_P = eq(A, P); - eq_A_Q = eq(A, Q); - mixok = mixcheck(colX,colE); - ThickBorder = eq_A_B && (eq_A_P||eq_A_Q|| eq(A,AA)&&(eq_B_PA||eq_D_QA)); - if (ThickBorder && !Xisblack) mixok=false; - - // A-side triple consecutive (eq_A_P && eq_A_Q) - if (comboA3) { - if (!eq_A_B) return Xoff; - else mixok=false; - } - - // XE_messL B-D-E L-shape with sim2 high similarity WIP - // bool XE_messL = (eq_B_C && !sim_EG || eq_D_G && !sim_EC) ; - - eq_E_F = eq(E, F); - B_wall = eq_B_C && !eq_B_PC && !eq_B_P; - - // Long slope (clear, non-thick solid edge - strong trend!) - // Special condition for long slopes - if ( B_wall && D_tower ) { - if (eq_E_G || sim_EG&&eq(E,QG) ) { // Original rule + enhanced original - if (eq_A_B) return mixok ? Mix382 : colX; // Has thickness - return colX; // Hollow - } - // Clear Z-shaped snake - exclude eq_A_B + XE_messL ??? - //if (eq_A_B && !XE_messL) return ; // Poor effect - if (eq_A_B) return slopeBAD; - // 2-pixel with subsequent long slope - if (eq_E_F ) return colX; - // 1-pixel without subsequent long slope - return Xoff; - } - - eq_E_H = eq(E, H); - D_wall = eq_D_G && !eq_D_QG && !eq_D_Q; - - if ( B_tower && D_wall ) { - if (eq_E_C || sim_EC&&eq(E,PC) ) { // Original rule + enhanced original - if (eq_A_B) return mixok ? Mix382 : colX; // Has thickness - return colX; // Hollow - } - // Clear Z-shaped snake - exclude eq_A_B + XE_messL ??? - //if (eq_A_B && !XE_messL) return ; // Poor effect - if (eq_A_B) return slopeBAD; - // 2-pixel with subsequent long slope - if (eq_E_H ) return colX; - // 1-pixel without subsequent long slope - return Xoff; - } - - - // Official original rule (placed after special shapes - special shapes have designated no-blending!) - if (eq_E_C || eq_E_G) return mixok ? Mix382 : colX; - - // Enhanced original rule 1 - if (sim_EG&&!eq_D_G&&eq(E,QG) || sim_EC&&!eq_B_C&&eq(E,PC)) return mixok ? Mix382off : Xoff; - - // Enhanced original rule 2 - if (sim_EC && sim_EG) return mixok ? Mix382off : Xoff; - - - // F-H inline trend (skip En4, En3) - if ( eq(F,H) ) return mixok ? Mix382off : Xoff; - - // Relaxed rule for final long slope cleanup (non-clear shapes) - // Empirical: This block handles different slopes than F-H. Default to break-even unless cube shape. - if (eq_B_C && eq_D_Q) { - // Exit for double cube - if (eq_B_P && eq_B_PC && eq_A_B && eq_D_QA && !eq_D_QG && eq_E_F && eq(H,I) ) return theEXIT; - - return mixok ? Mix382off : Xoff; - } - - if ( eq_D_G && eq_B_P) { - // Exit for double cube - if (eq_D_Q && eq_D_QG && eq_A_B && eq_B_PA && !eq_B_PC && eq_E_H && eq(F,I) ) return theEXIT; - - return mixok ? Mix382off : Xoff; - } - - eq_E_I = eq(E, I); - - // Exit for clear L-shaped corner with inner parallel single strip - if (eq_A_B && !ThickBorder && !eq_E_I ) { - if (B_wall && eq_E_F) return theEXIT; - if (D_wall && eq_E_H) return theEXIT; - } - - // Early return if colors are similar (skip next step) - if (mixok) return Mix382off; - if (EalphaL) return mixok ? Mix382off : Xoff; //xxx.alpha - - // Exit for hollow L-shaped corner with outer single strip (any direction) - fixes font edge issues - if ( !eq_A_B && (eq_E_F||eq_E_H) && !eq_E_I) { - if (B_tower && !eq_D_Q && !eq_D_QG) return theEXIT; - if (D_tower && !eq_B_P && !eq_B_PC) return theEXIT; - } - - // Fallback handling - return mixok ? Mix382off : Xoff; - -} // sim2 base - - -/*=================================================== - E - A cross - ============================================== zz */ -if (eq_E_A) { - - // Cross ✕ judgment requires "region" and "trend" concepts - tighter conditions for different regions - - // No need to exit for unconnected B/D! ! ! - - eq_E_F = eq(E, F); - eq_E_H = eq(E, H); - eq_E_I = eq(E, I); - - En3 = eq_E_F&&eq_E_H; - - // Special shape: square (En3 && eq_E_I) - if ( En4square ) { - if( noteq(G,H) && noteq(C,F) // Independent clear 4-pixel square / 6-pixel rectangle (both sides meet) - && (eq(H,S) == eq(I,SI) && eq(F,R) == eq(I,RI)) ) return theEXIT; - //else return mixok ? mix(X,E,0.381966) : X; Note: Do not return directly. Need to enter chessboard scoring rule, - // as adjacent B/D areas may also form bubbles with squares - } - - // Special shape: dot pattern - // Empirical 1: !eq_E_F, !eq_E_H - do not use !sim (loses some shapes) - // Empirical 2: Force blending (otherwise lose shapes - Horse from Gouketsuji Ichizoku, Saturday Night Slam Masters 2) - - bool Eisblack = checkblack(colE); - mixok = mixcheck(colX,colE); - - // 1. Dot pattern center - if ( eq_E_C && eq_E_G && eq_E_I && !eq_E_F && !eq_E_H ) { - - // Exit if center E is black (KOF '96 power bar, Punisher's belt) - avoid over-blending with high contrast - if (Eisblack) return theEXIT; - // Empirical 1: Do not capture black B points (normal logic entry) - // Empirical 2: No need to check eq_F_H separately (95%+ probability) + layered gradient in power bar, 0.5 fallback blending - return mixok ? Mix382off : Mix618off; - } - - eq_A_P = eq(A,P); - eq_A_Q = eq(A,Q); - eq_B_PA = eq(B,PA); - - // 2. Dot pattern edge - if ( eq_A_P && eq_A_Q && eq(A,AA) && noteq(A,PA) && noteq(A,QA) ) { - if (Eisblack) return theEXIT; - - // Layered gradient edge - use strong blending - if ( !eq_B_PA && eq(PA,QA) ) return mixok ? Mix382off : Mix618off; - // Remaining perfect cross - definitely dot pattern edge, use weak blending - // Fallback weak blending - no need to specify power bar border case separately - return mixok ? Mix618off : Mix854off; - } - - // xxx.alpha - if (colE.a<0.002) return colX; - - eq_D_QA = eq(D,QA); - eq_D_QG = eq(D,QG); - eq_B_PC = eq(B,PC); - - // 3. Half dot pattern - usually shadow expression on outline edges, use weak blending - if ( eq_E_C && eq_E_G && eq_A_P && eq_A_Q && - (eq_B_PC || eq_D_QG) && - eq_D_QA && eq_B_PA) { - //if (Eisblack) return ; Unnecessary - - return mixok ? Mix618off : Mix854off; - } - - // 4. Quarter dot pattern - prone to ugly "pinkie effect" (Guile's Sonic Boom in SF2, Dino Crisis select screen) - - if ( eq_E_C && eq_E_G && eq_A_P - && eq_B_PA &&eq_D_QA && eq_D_QG - && eq_E_H - ) return mixok ? Mix618off : Mix854off; - - if ( eq_E_C && eq_E_G && eq_A_Q - && eq_B_PA &&eq_D_QA && eq_B_PC - && eq_E_F - ) return mixok ? Mix618off : Mix854off; - - - // E-side triple consecutive (must come after dot pattern) - if ( eq_E_C && eq_E_G ) return Xoff; - - // A-side triple consecutive (eq_A_P && eq_A_Q) - must come after dot pattern. - // Prefer blending over direct copy since E-A are identical - if (comboA3) return mixok ? Mix382off : Xoff; - - - // B-D part of long slope - eq_B_P = eq(B,P); - eq_D_Q = eq(D,Q); - B_wall = eq_B_C && !eq_B_P; - B_tower = eq_B_P && !eq_B_C; - D_tower = eq_D_Q && !eq_D_G; - D_wall = eq_D_G && !eq_D_Q; - - int scoreE = 0; int scoreB = 0; int scoreD = 0; int scoreZ = 0; - - -// E B D area chessboard scoring rule - -// E Zone - if (En3) { - scoreE += 1; - if (B_wall || B_tower || D_tower || D_wall) scoreZ = 1; - } - - if (eq_E_C) { - scoreE += 1; - scoreE += int(eq_E_F); - } - - if (eq_E_G) { - scoreE += 1; - scoreE += int(eq_E_H); - - } - - if (scoreE==0) { - // Single strip - if (eq_E_F ||eq_E_H) return theEXIT; - } - - if ( eq(F,H) ) { - scoreE += 1; - if ( scoreZ==0 && B_wall && (eq(F,R) || eq(G,H) || eq(F,I)) ) scoreZ = 1; - if ( scoreZ==0 && D_wall && (eq(C,F) || eq(H,S) || eq(F,I)) ) scoreZ = 1; - } - - - #define Bn3 eq_B_P&&eq_B_C - #define Dn3 eq_D_G&&eq_D_Q - -// B Zone - scoreB -= int(Bn3); - scoreB -= int(eq(C,P)); - if (scoreB < 0) scoreZ = 0; - - if (eq_B_PA) { - scoreB -= 1; - scoreB -= int(eq_B_P); //Replace eq(P,PA) - } - -// D Zone - scoreD -= int(Dn3); - scoreD -= int(eq(G,Q)); - if (scoreD < 0) scoreZ = 0; - - if (eq_D_QA) { - scoreD -= 1; - scoreD -= int(eq_D_Q); //Replace eq(Q,QA) - } - - int scoreFinal = scoreE + scoreB + scoreD + scoreZ ; - - if (scoreE >= 1 && scoreB >= 0 && scoreD >=0) scoreFinal += 1; - - if (scoreFinal >= 2) return colX; - - if (scoreFinal == 1) return mixok ? Mix382 : colX; - - // Final supplement: total score 0, no deductions in B/D areas - forms long slope shape - if (scoreB >= 0 && scoreD >=0) { - if (B_wall&&D_tower) return colX; - if (B_tower&&D_wall) return colX; - } - - return slopeBAD; - -} // eq_E_A - - -/*========================================================= - F - H / B+ D+ extension new rule - ==================================================== zz */ - -// This block differs from sim block - center point and related En4square/BD are naturally isolated by a wall -// Therefore judgment rules differ from sim side - - eq_B_P = eq(B, P); - eq_B_PC = eq(B, PC); - eq_D_Q = eq(D, Q); - eq_D_QG = eq(D, QG); - - // Exit if B/D unconnected to any (Empirical: required for this branch block) - if ( !eq_B_C && !eq_B_P && !eq_B_PC && !eq_D_G && !eq_D_Q && !eq_D_QG ) return slopeBAD; - - mixok = mixcheck(colX,colE); - eq_E_I = eq(E, I); - - // Exit if center E is single high-contrast pixel - // Tighten threshold if E is highlight - float E_lumDiff = El > 0.92 ? 0.145898 : 0.381966; - // Large difference with surroundings - if ( !mixok && !eq_E_I && !EalphaL && abs(El-Fl)>E_lumDiff && abs(El-Hl)>E_lumDiff ) return slopeBAD; //xxx.alpha - - - eq_A_B = eq(A, B); - eq_A_P = eq(A, P); - eq_A_Q = eq(A, Q); - eq_B_PA = eq(B,PA); - eq_D_QA = eq(D,QA); - - ThickBorder = eq_A_B && (eq_A_P||eq_A_Q|| eq(A,AA)&&(eq_B_PA||eq_D_QA)); - - if (ThickBorder && !Xisblack) mixok=false; - - B_slope = eq_B_PC && !eq_B_P && !eq_B_C; - B_tower = eq_B_P && !eq_B_PC && !eq_B_C && !eq_B_PA; - D_slope = eq_D_QG && !eq_D_Q && !eq_D_G; - D_tower = eq_D_Q && !eq_D_QG && !eq_D_G && !eq_D_QA; - - if (!eq_A_B) { - // B + D + each extend shape - // Empirical 1: Looser conditions for one side if the other has clear shape - // Empirical 2: Outer side of "厂" shape break-even, inner side not break-even (can be tower but not wall) - if ( (B_slope||B_tower) && (eq_D_QG&&!eq_D_G||D_tower) ) return Xoff; - if ( (D_slope||D_tower) && (eq_B_PC&&!eq_B_C||B_tower) ) return Xoff; - - // A-side triple consecutive (eq_A_P && eq_A_Q) - high priority - if (comboA3) return Xoff; - - // combo 2x2 as supplement to above - if ( B_slope && eq_A_P ) return mixok ? Mix382off : Xoff; - if ( D_slope && eq_A_Q ) return mixok ? Mix382off : Xoff; - } - - eq_E_F = eq(E, F); - B_wall = eq_B_C && !eq_B_PC && !eq_B_P; - - // Long slope (clear, non-solid edge - strong trend!) - // Special condition for long slopes - if ( B_wall && D_tower ) { - if (eq_A_B ) return slopeBAD; - if (eq_E_F ) return colX; //wip: Test direct X no blending - return mixok ? Mix382off : Xoff; - } - - eq_E_H = eq(E, H); - D_wall = eq_D_G && !eq_D_QG&& !eq_D_Q; - - if ( B_tower && D_wall ) { - if (eq_A_B ) return slopeBAD; - if (eq_E_H ) return colX; - return mixok ? Mix382off : Xoff; - } - - - bool sim_X_E = sim3(colX,colE); - bool eq_G_H = eq(G, H); - bool eq_C_F = eq(C, F); - bool eq_H_S = eq(H, S); - bool eq_F_R = eq(F, R); - - En3 = eq_E_F&&eq_E_H; - - // 4-pixel rectangle inside wall (En3 && eq_E_I) - if ( En4square ) { // This square detection must come after previous rule - if (sim_X_E) return mixok ? Mix382off : Xoff; - // Exit for solid L-shaped inner wrap (fixes font edge corners and non-rounded building corners (Mega Man 7)) - if ( (eq_B_C || eq_D_G) && eq_A_B ) return theEXIT; - //if (eq_H_S && eq_F_R) return theEXIT; // Extend both sides - // L-shaped inner wrap (hollow corner) / high-contrast independent clear 4-pixel square / 6-pixel rectangle (note rectangle edges) - if ( ( eq_B_C&&!eq_G_H || eq_D_G&&!eq_C_F || !eq_G_H&&!eq_C_F&&diffEB>0.5) && (eq_H_S == eq(I, SI) && eq_F_R == eq(I, RI)) ) return theEXIT; - - return mixok ? Mix382off : Xoff; - } - - // Triangle inside wall - if ( En3 ) { - if (sim_X_E) return mixok ? Mix382off : Xoff; - if (eq_H_S && eq_F_R) return theEXIT; // Extend both sides (building edges) - // Inner curve - if (eq_B_C || eq_D_G) return mixok ? Mix382off : Xoff; - // Direct return if has thickness (Z-shaped snake can break-even outer curve below) - if (eq_A_B) return mixok ? Mix382off : Xoff; - // Outer curve - if (eq_B_P || eq_D_Q) return theEXIT; - - return mixok ? Mix382off : Xoff; - // Final two rules based on experience - principle: connect inner L curve, not outer (Jimmy's eyebrows in Double Dragon) - } - - // F - H - // Principle: connect inner L curve, not outer - if ( eq(F,H) ) { - if (sim_X_E||EalphaL) return mixok ? Mix382off : Xoff; //xxx.alpha - // Exit for solid L-shaped inner wrap - avoid single pixel squeezed by symmetric double wrap - if ( eq_B_C && eq_A_B && (eq_G_H||!eq_F_R) &&eq(F, I) ) return slopeBAD; - if ( eq_D_G && eq_A_B && (eq_C_F||!eq_H_S) &&eq(F, I) ) return slopeBAD; - - //Inner curve - if (eq_B_C && (eq_F_R||eq_G_H||eq(F, I))) return mixok ? Mix382off : Xoff; - if (eq_D_G && (eq_C_F||eq_H_S||eq(F, I))) return mixok ? Mix382off : Xoff; - // E-I F-H cross breaks trend - if (eq_E_I) return slopeBAD; - // Outer Z-shape - if (eq_B_P && eq_A_B) return mixok ? Mix382off : Xoff; - if (eq_D_Q && eq_A_B) return mixok ? Mix382off : Xoff; - // Outer curve - unless opposite side forms long L-shaped trend - if (eq_B_P && (eq_C_F&&eq_H_S)) return mixok ? Mix382off : Xoff; - if (eq_D_Q && (eq_F_R&&eq_G_H)) return mixok ? Mix382off : Xoff; - - return slopeBAD; - } - - - // Relaxed rule for final long slope cleanup (non-clear shapes) - // Note: This block handles different slopes than sim2 block - exit for solid corners - if ( eq_B_C && eq_D_Q || eq_D_G && eq_B_P) { - // Note: Clear eq_A_B first - otherwise single edge pixels get "corner cut" (eternal secret) - if (eq_A_B) return theEXIT; - return mixok ? Mix382off : Xoff; - } - - - // A-side triple consecutive - NEVER use without !eq_A_B ! ! ! ! ! ! ! ! - // if (comboA3) return X+slopeOFF; - - - // One more check for B + D bidirectional extension - higher priority than inner/outer L single strip below - if ( (B_slope||B_tower) && (eq_D_QG&&!eq_D_G||D_tower) ) return Xoff; - if ( (D_slope||D_tower) && (eq_B_PC&&!eq_B_C||B_tower) ) return Xoff; - - - // Exit for clear L-shaped corner with inner single strip (sim_X_E no exemption) - if (eq_A_B && !ThickBorder && !eq_E_I ) { - - if (B_wall && eq_E_F) return theEXIT; - if (D_wall && eq_E_H) return theEXIT; - } - -if (sim_X_E||EalphaL) return mixok ? Mix382off : Xoff; //xxx.alpha - // Exit for hollow L-shaped corner with outer single strip (connect inner corner, not outer) - // Empirical: Avoids font edge cutting (Captain Commando) - if ( (B_tower || D_tower) && (eq_E_F||eq_E_H) && !eq_A_B && !eq_E_I) return theEXIT; - - // Final individual extension check for B or D - - // Maximum distance usable for slope - if ( B_slope && !eq_A_B && eq(PC,CC) && noteq(PC,RC)) return mixok ? Mix382off : Xoff; - if ( D_slope && !eq_A_B && eq(QG,GG) && noteq(QG,SG)) return mixok ? Mix382off : Xoff; - - // Slope can use one less judgment point if X-E are close, with internal logic restrictions - if ( mixok && !eq_A_B ) { - if ( B_slope && (!eq_C_F||eq(F,RC)) ) return Mix382off; - if ( D_slope && (!eq_G_H||eq(H,SG)) ) return Mix382off; - } - - // Exclude single strip for Z-shaped snake below (necessary) - if ((eq_E_F||eq_E_H) && !eq_E_I ) return theEXIT; - - // Z-shaped snake (eq_A_B has thickness, one side is tower (can be wall/slope) but other side cannot be tower/wall (naturally prohibited)) - if ( eq_B_P && !eq_B_PA && !eq_D_Q && eq_A_B) return mixok ? Mix382off : Xoff; - if ( eq_D_Q && !eq_D_QA && !eq_B_P && eq_A_B) return mixok ? Mix382off : Xoff; - - return theEXIT; - -} // admixX - -vec4 admixS(uint A, uint B, uint C, uint D, uint E, uint F, uint G, uint H, uint I, uint R, uint RC, uint RI, uint S, uint SG, uint SI, uint II, bool eq_B_D, bool eq_E_D, float El, float Bl, vec4 colE, vec4 colF) { - - // ABC . - // QD🄴 🅵 🆁 Zone 4 - // 🅶 🅷 I - // S - // Empirical 1: sim E B(C) conforms to original logic - E single pixel won't look abrupt when inserted by saw in practice - // Empirical 2: Can E equal I? Yes! - - if (any_eq2(F,C,I)) return colE; - //if (any_eq3(F,A,C,I)) return colE; - - if (eq(R, RI) && noteq(R,I)) return colE; - if (eq(H, S) && noteq(H,I)) return colE; - - if ( eq(R, RC) || eq(G,SG) ) return colE; - - // Remove alpha channel weighting - Bl = fract(Bl) *10.0; - El = fract(El) *10.0; - - if ( ( eq_B_D&&eq(B,C)&&diffEB<0.381966 || eq_E_D&&sim2(colE,E,C) ) && - (any_eq3(I,H,S,RI) || eq(SI,RI)&¬eq(I,II)) ) return colF; - - return colE; -} - - -//////////////////////////////////////////// main line /////////////////////////////////////////////// pin zz - void applyScaling(uvec2 xy) { int srcX = int(xy.x); int srcY = int(xy.y); + + ABGR8 A = src(srcX - 1, srcY - 1), B = src(srcX, srcY - 1), C = src(srcX + 1, srcY - 1); + ABGR8 D = src(srcX - 1, srcY + 0), E = src(srcX, srcY + 0), F = src(srcX + 1, srcY + 0); + ABGR8 G = src(srcX - 1, srcY + 1), H = src(srcX, srcY + 1), I = src(srcX + 1, srcY + 1); + + ABGR8 J = E, K = E, L = E, M = E; + + if (((A ^ E) | (B ^ E) | (C ^ E) | (D ^ E) | (F ^ E) | (G ^ E) | (H ^ E) | (I ^ E)) != 0u) { + ABGR8 P = src(srcX, srcY - 2), S = src(srcX, srcY + 2); + ABGR8 Q = src(srcX - 2, srcY), R = src(srcX + 2, srcY); + ABGR8 Bl = luma(B), Dl = luma(D), El = luma(E), Fl = luma(F), Hl = luma(H); + + // 1:1 slope rules + if ((D == B && D != H && D != F) && (El >= Dl || E == A) && any_eq3(E, A, C, G) && ((El < Dl) || A != D || E != P || E != Q)) J = D; + if ((B == F && B != D && B != H) && (El >= Bl || E == C) && any_eq3(E, A, C, I) && ((El < Bl) || C != B || E != P || E != R)) K = B; + if ((H == D && H != F && H != B) && (El >= Hl || E == G) && any_eq3(E, A, G, I) && ((El < Hl) || G != H || E != S || E != Q)) L = H; + if ((F == H && F != B && F != D) && (El >= Fl || E == I) && any_eq3(E, C, G, I) && ((El < Fl) || I != H || E != R || E != S)) M = F; + + // Intersection rules + if ((E != F && all_eq4(E, C, I, D, Q) && all_eq2(F, B, H)) && (F != src(srcX + 3, srcY))) K = M = F; + if ((E != D && all_eq4(E, A, G, F, R) && all_eq2(D, B, H)) && (D != src(srcX - 3, srcY))) J = L = D; + if ((E != H && all_eq4(E, G, I, B, P) && all_eq2(H, D, F)) && (H != src(srcX, srcY + 3))) L = M = H; + if ((E != B && all_eq4(E, A, C, H, S) && all_eq2(B, D, F)) && (B != src(srcX, srcY - 3))) J = K = B; + if (Bl < El && all_eq4(E, G, H, I, S) && none_eq4(E, A, D, C, F)) J = K = B; + if (Hl < El && all_eq4(E, A, B, C, P) && none_eq4(E, D, G, I, F)) L = M = H; + if (Fl < El && all_eq4(E, A, D, G, Q) && none_eq4(E, B, C, I, H)) K = M = F; + if (Dl < El && all_eq4(E, C, F, I, R) && none_eq4(E, B, A, G, H)) J = L = D; + + // 2:1 slope rules + if (H != B) { + if (H != A && H != E && H != C) { + if (all_eq3(H, G, F, R) && none_eq2(H, D, src(srcX + 2, srcY - 1))) L = M; + if (all_eq3(H, I, D, Q) && none_eq2(H, F, src(srcX - 2, srcY - 1))) M = L; + } + + if (B != I && B != G && B != E) { + if (all_eq3(B, A, F, R) && none_eq2(B, D, src(srcX + 2, srcY + 1))) J = K; + if (all_eq3(B, C, D, Q) && none_eq2(B, F, src(srcX - 2, srcY + 1))) K = J; + } + } // H !== B + + if (F != D) { + if (D != I && D != E && D != C) { + if (all_eq3(D, A, H, S) && none_eq2(D, B, src(srcX + 1, srcY + 2))) J = L; + if (all_eq3(D, G, B, P) && none_eq2(D, H, src(srcX + 1, srcY - 2))) L = J; + } + + if (F != E && F != A && F != G) { + if (all_eq3(F, C, H, S) && none_eq2(F, B, src(srcX - 1, srcY + 2))) K = M; + if (all_eq3(F, I, B, P) && none_eq2(F, H, src(srcX - 1, srcY - 2))) M = K; + } + } // F !== D + } // not constant + + // Write four pixels at once. ivec2 destXY = ivec2(xy) * 2; - - uint E = src(srcX, srcY); - uint B = src(srcX, srcY-1); - uint D = src(srcX-1, srcY); - uint F = src(srcX+1, srcY); - uint H = src(srcX, srcY+1); - - vec4 colE = unpackUnorm4x8(E); - vec4 J = colE, K = colE, L = colE, M = colE; - - bool eq_E_D = eq(E,D); - bool eq_E_F = eq(E,F); - bool eq_E_B = eq(E,B); - bool eq_E_H = eq(E,H); - -// Skip horizontal/vertical 3x1 -if ( eq_E_D && eq_E_F || eq_E_B && eq_E_H) {writeJKLM;return;} - - bool eq_B_H = eq(B,H); - bool eq_D_F = eq(D,F); -// Skip center surrounded by mirrored blocks -if ( eq_B_H && eq_D_F ) {writeJKLM;return;} - - // Capture 5x5 - uint A = src(srcX-1, srcY-1); - uint C = src(srcX+1, srcY-1); - uint G = src(srcX-1, srcY+1); - uint I = src(srcX+1, srcY+1); - uint P = src(srcX, srcY-2); - uint Q = src(srcX-2, srcY); - uint R = src(srcX+2, srcY); - uint S = src(srcX, srcY+2); - - - uint PA = src(srcX-1, srcY-2); - uint PC = src(srcX+1, srcY-2); - uint QA = src(srcX-2, srcY-1); - uint QG = src(srcX-2, srcY+1); // AA PA [P] PC CC - uint RC = src(srcX+2, srcY-1); // ┌──┬──┬──┐ - uint RI = src(srcX+2, srcY+1); // QA │ A │ B │ C │ RC - uint SG = src(srcX-1, srcY+2); // ├──┼──┼──┤ - uint SI = src(srcX+1, srcY+2); // [Q] │ D │ E │ F │ [R] - uint AA = src(srcX-2, srcY-2); // ├──┼──┼──┤ - uint CC = src(srcX+2, srcY-2); // QG │ G │ H │ I │ RI - uint GG = src(srcX-2, srcY+2); // └──┴──┴──┘ - uint II = src(srcX+2, srcY+2); // GG SG [S] SI II - - - vec4 colB = unpackUnorm4x8(B); - vec4 colD = unpackUnorm4x8(D); - vec4 colF = unpackUnorm4x8(F); - vec4 colH = unpackUnorm4x8(H); - - float Bl = luma(colB), Dl = luma(colD), El = luma(colE), Fl = luma(colF), Hl = luma(colH); - - -// 1:1 slope rules (P95) - bool eq_B_D = eq(B,D); - bool eq_B_F = eq(B,F); - bool eq_D_H = eq(D,H); - bool eq_F_H = eq(F,H); - - // Center surrounded by any mirrored blocks - bool oppoPix = eq_B_H || eq_D_F; - // Flag for admixX entry via 1:1 slope rule - bool slope1 = false; bool slope2 = false; bool slope3 = false; bool slope4 = false; - // Standard pixel returned normally via 1:1 slope rule - bool slope1ok = false; bool slope2ok = false; bool slope3ok = false; bool slope4ok = false; - // slopeBAD: entered admixX but (at least one of JKLM) returns E point - // slopOFF: returned with OFF flag - no long slope calculation - bool slopeBAD_flag = false; - - // B - D - if ( (!eq_E_B&&!eq_E_D&&!oppoPix) && (!eq_D_H&&!eq_B_F) && (El>=Dl&&El>=Bl || eq(E,A)) && ( (El 1.0 ) { - if (J.b > 7.0 ) J=J-8.0; //slopOFF - if (J.b == 4.0 ) { - J=colE; - writeJKLM; - return; - } - if (J.b == 2.0 ) J=colE; //slopeBAD - } else slope1ok = true; - } - // B - F - if ( !slope1 && (!eq_E_B&&!eq_E_F&&!oppoPix) && (!eq_B_D&&!eq_F_H) && (El>=Bl&&El>=Fl || eq(E,C)) && ( (El 1.0 ) { - if (K.b > 7.0 ) K=K-8.0; - if (K.b == 4.0 ) { - K=colE; - writeJKLM; - return; - } - if (K.b == 2.0 ) K=colE; - } else {slope2ok = true;} - } - // D - H - if ( !slope1 && (!eq_E_D&&!eq_E_H&&!oppoPix) && (!eq_F_H&&!eq_B_D) && (El>=Hl&&El>=Dl || eq(E,G)) && ((El 1.0 ) { - if (L.b > 7.0 ) L=L-8.0; - if (L.b == 4.0 ) { - L=colE; - writeJKLM; - return; - } - if (L.b == 2.0 ) L=colE; - } else {slope3ok = true;} - } - // F - H - if ( !slope2 && !slope3 && (!eq_E_F&&!eq_E_H&&!oppoPix) && (!eq_B_F&&!eq_D_H) && (El>=Fl&&El>=Hl || eq(E,I)) && ((El 1.0 ) { - if (M.b > 7.0 ) M=M-8.0; - if (M.b == 4.0 ) { - M=colE; - writeJKLM; - return; - } - if (M.b == 2.0 ) M=colE; - } else {slope4ok = true;} - } - - -// long gentle 2:1 slope (P100) - - bool longslope = false; - - if (slope4ok && eq_F_H) { //zone4 long slope - // Extended original rule 1. Pass adjacent pixel to admixL third parameter to prevent double blending - // Extended original rule 2. No L-shape allowed in opposite two-pixel interval unless wall formed - if (eq(G,H) && eq(F,R) && noteq(R, RC) && (noteq(Q,G)||eq(Q, QA))) {L=admixL(M,L,colH); longslope = true;} - // vertical - if (eq(C,F) && eq(H,S) && noteq(S, SG) && (noteq(P,C)||eq(P, PA))) {K=admixL(M,K,colF); longslope = true;} - } - - - if (slope3ok && eq_D_H) { //zone3 long slope - // horizontal - if (eq(D,Q) && eq(H,I) && noteq(Q, QA) && (noteq(R,I)||eq(R, RC))) {M=admixL(L,M,colH); longslope = true;} - // vertical - if (eq(A,D) && eq(H,S) && noteq(S, SI) && (noteq(A,P)||eq(P, PC))) {J=admixL(L,J,colD); longslope = true;} - } - - if (slope2ok && eq_B_F) { //zone2 long slope - // horizontal - if (eq(A,B) && eq(F,R) && noteq(R, RI) && (noteq(A,Q)||eq(Q, QG))) {J=admixL(K,J,colB); longslope = true;} - // vertical - if (eq(F,I) && eq(B,P) && noteq(P, PA) && (noteq(I,S)||eq(S, SG))) {M=admixL(K,M,colF); longslope = true;} - } - - if (slope1ok && eq_B_D) { //zone1 long slope - // horizontal - if (eq(B,C) && eq(D,Q) && noteq(Q, QG) && (noteq(C,R)||eq(R, RI))) {K=admixL(J,K,colB); longslope = true;} - // vertical - if (eq(D,G) && eq(B,P) && noteq(P, PC) && (noteq(G,S)||eq(S, SI))) {L=admixL(J,L,colD); longslope = true;} - } - -// Exit after longslope formation - sawslope rarely forms on diagonal -bool skiprest = longslope; - -bool slopeok = slope1ok||slope2ok||slope3ok||slope4ok; - - -// Note: sawslope cannot exclude slopeOFF (few cases) and slopeBAD (very rare), but can exclude slopeok (strong shape) -if (!skiprest && !oppoPix && !slopeok) { - - - // horizontal bottom - if (!eq_E_H && none_eq2(H,A,C)) { - - // A B C ・ - // Q D 🄴 🅵 🆁 Zone 4 - // 🅶 🅷 I - // S - // (!slope3 && !eq_D_H) clever combination - if ( (!slope2 && !eq_B_F) && (!slope3 && !eq_D_H) && !eq_F_H && - !eq_E_F && (eq_B_D || eq_E_D) && eq(R,H) && eq(F,G) ) { - M = admixS(A,B,C,D,E,F,G,H,I,R,RC,RI,S,SG,SI,II,eq_B_D,eq_E_D,El,Bl,colE,colF); - skiprest = true;} - - // ・ A B C - // 🆀 🅳 🄴 F R Zone 3 - // G 🅷 🅸 - // S - if ( !skiprest && (!slope1 && !eq_B_D) && (!slope4 && !eq_F_H) && !eq_D_H && - !eq_E_D && (eq_B_F || eq_E_F) && eq(Q,H) && eq(D,I) ) { - L = admixS(C,B,A,F,E,D,I,H,G,Q,QA,QG,S,SI,SG,GG,eq_B_F,eq_E_F,El,Bl,colE,colD); - skiprest = true;} - } - - // horizontal up - if ( !skiprest && !eq_E_B && none_eq2(B,G,I)) { - - // P - // 🅐 🅑 C - // QD 🄴 🅵 🆁 Zone 2 - // G H I . - if ( (!slope1 && !eq_B_D) && (!slope4 && !eq_F_H) && !eq_B_F && - !eq_E_F && (eq_D_H || eq_E_D) && eq(B,R) && eq(A,F) ) { - K = admixS(G,H,I,D,E,F,A,B,C,R,RI,RC,P,PA,PC,CC,eq_D_H,eq_E_D,El,Hl,colE,colF); - skiprest = true;} - - // P - // A 🅑 🅲 - // 🆀 🅳 🄴 F R Zone 1 - // . G H I - if ( !skiprest && (!slope2 && !eq_B_F) && (!slope3 && !eq_D_H) && !eq_B_D && - !eq_E_D && (eq_F_H || eq_E_F) && eq(B,Q) && eq(C,D) ) { - J = admixS(I,H,G,F,E,D,C,B,A,Q,QG,QA,P,PC,PA,AA,eq_F_H,eq_E_F,El,Hl,colE,colD); - skiprest = true;} - - } - - // vertical left - if ( !skiprest && !eq_E_D && none_eq2(D,C,I) ) { - - // 🅐 B C - // Q 🅳 🄴 F R - // G 🅷 I Zone 3 - // 🆂 ・ - if ( (!slope1 && !eq_B_D) && (!slope4 && !eq_F_H) && !eq_D_H && - !eq_E_H && (eq_B_F || eq_E_B) && eq(D,S) && eq(A,H) ) { - L = admixS(C,F,I,B,E,H,A,D,G,S,SI,SG,Q,QA,QG,GG,eq_B_F,eq_E_B,El,Fl,colE,colH); - skiprest = true;} - - // 🅟 ・ - // A 🅑 C - // Q 🅳 🄴 F R Zone 1 - // 🅶 HI - if ( !skiprest && (!slope3 && !eq_D_H) && (!slope2 && !eq_B_F) && !eq_B_D && - !eq_E_B && (eq_F_H || eq_E_H) && eq(P,D) && eq(B,G) ) { - J = admixS(I,F,C,H,E,B,G,D,A,P,PC,PA,Q,QG,QA,AA,eq_F_H,eq_E_H,El,Fl,colE,colB); - skiprest = true;} - - } - - // vertical right - if ( !skiprest && !eq_E_F && none_eq2(F,A,G) ) { // right - - // A B 🅲 - // Q D 🄴 🅵 R - // G 🅷 I Zone 4 - // . 🆂 - if ( (!slope2 && !eq_B_F) && (!slope3 && !eq_D_H) && !eq_F_H && - !eq_E_H && (eq_B_D || eq_E_B) && eq(S,F) && eq(H,C) ) { - M = admixS(A,D,G,B,E,H,C,F,I,S,SG,SI,R,RC,RI,II,eq_B_D,eq_E_B,El,Dl,colE,colH); - skiprest = true;} - - // ・ 🅟 - // A 🅑 C - // Q D 🄴 🅵 R Zone 2 - // G H 🅸 - if ( !skiprest && (!slope1 && !eq_B_D) && (!slope4 && !eq_F_H) && !eq_B_F && - !eq_E_B && (eq_D_H || eq_E_H) && eq(P,F) && eq(B,I) ) { - K = admixS(G,D,A,H,E,B,I,F,C,P,PA,PC,R,RI,RC,CC,eq_D_H,eq_E_H,El,Dl,colE,colB); - skiprest = true;} - - } // vertical right -} // sawslope - -// Exit after sawslope formation - legacy approach: skiprest||slopeBAD (also uses slopeOFF (weak) and slopok (strong) but poor effect) -skiprest = skiprest||slope1||slope2||slope3||slope4||El>7.0||Bl>7.0||Dl>7.0||Fl>7.0||Hl>7.0; - -/************************************************** - Concave + Cross shape (P100) - *************************************************/ -// Use approximate pixels for cross star far end - useful for horizontal line + sawtooth and layered gradient shapes. -// E.g. glowing text in SFIII: New Generation intro, Japanese houses in SFZ3 Mix, Fatal Fury: Wild Ambition intro - - vec4 colX; //Define temp X - - if (!skiprest && - Bl= 0 && x < params.width && y >= 0 && y < params.height) + ? readColoru(uvec2(x, y)) + : 0u; +} + + +// RGB perceptual weight + alpha segmentation +float luma(vec4 col) { + + // BT.601 standard (CRT era) - result divided by 10, range [0.0 - 0.1] + float rgbsum =dot(col.rgb, vec3(0.0299, 0.0587, 0.0114)); + + // Subsequent fractional extraction *10 removes alpha weighting + float alphafactor = + (col.a > 0.854102) ? 1.0 : // 2x short golden ratio (larger segment) + (col.a > 0.618034) ? 2.0 : // 1x golden ratio + (col.a > 0.381966) ? 3.0 : // 1x short golden ratio + (col.a > 0.145898) ? 4.0 : // 2x short golden ratio + (col.a > 0.002) ? 5.0 : 8.0; // Fully transparent + + return rgbsum + alphafactor; + +} + +/* Constant explanations: +0.145898 : 2x short golden ratio of 1.0 +0.0638587 : Squared value after 2x short golden ratio on RGB Euclidean distance +0.024391856 : Squared value after 2x short golden ratio + 1x golden ratio on RGB Euclidean distance +0.00931686 : Squared value after 3x short golden ratio on RGB Euclidean distance +0.001359312 : Squared value after 4x short golden ratio on RGB Euclidean distance +0.4377 : Squared value after 1x short golden ratio on RGB Euclidean distance +0.75 : Squared value after halving RGB Euclidean distance +*/ +// Pixel similarity check LV1 +bool sim1(vec4 col1, vec4 col2) { + + vec4 diff = col1 - col2; + vec4 absdiff = abs(diff); + + // 1. Fast component difference check + if ( absdiff.r > 0.1 || absdiff.g > 0.1 || absdiff.b > 0.1 || absdiff.a > 0.145898 ) return false; // xxx.alpha + + // 2. Fast squared distance check + float dot_diff = dot(diff.rgb, diff.rgb); // xxx.alpha + if (dot_diff < 0.001359312) return true; + + // 3. Gradual pixel check + float min_diff = min(diff.r, min(diff.g, diff.b)); + float max_diff = max(diff.r, max(diff.g, diff.b)); + if ( max_diff-min_diff>0.096 ) return false; // Exit if difference exceeds int24 + if ( max_diff-min_diff<0.024 && dot_diff<0.024391856) return true; // Consider gradual pixel if difference ≤ int6. Relax threshold by one level. + + // 4. Grayscale pixel check + float sum1 = dot(col1.rgb, vec3(1.0)); // Sum of RGB channels //xxx.alpha + float sum2 = dot(col2.rgb, vec3(1.0)); //xxx.alpha + float avg1 = sum1 * 0.3333333; + float avg2 = sum2 * 0.3333333; + + vec3 graydiff1 = col1.rgb - vec3(avg1); //xxx.alpha + vec3 graydiff2 = col2.rgb - vec3(avg2); //xxx.alpha + float dotgray1 = dot(graydiff1,graydiff1); + float dotgray2 = dot(graydiff2,graydiff2); + // 0.002: Max single-channel difference allowed is int13 when avg=20. + // 0.0004: Max single-channel difference allowed is int6, or int3+4 for dual channels + float tolerance1 = avg1<0.08 ? 0.002 : 0.0004; + float tolerance2 = avg2<0.08 ? 0.002 : 0.0004; + // 0.078 limits max green channel value to 19 (perceptible threshold to human eye) + bool Col1isGray = sum1<0.078||dotgray10.381966) return false; + + // 1. Clamp RGB dark areas + vec3 clampCol1 = max(col1.rgb, vec3(0.078)); //xxx.alpha + vec3 clampCol2 = max(col2.rgb, vec3(0.078)); //xxx.alpha + + vec3 clampdiff = clampCol1 - clampCol2; + + // 2x short + 1x, 2x short golden ratio of RGB Euclidean distance between two points + float dotdist = Lv==2 ? 0.024391856 : 0.0638587; + + return dot(clampdiff, clampdiff) < dotdist; +} + +bool sim2(vec4 colC1, uint C1, uint C2) { + if (C1==C2) return true; + return sim2n3(colC1, unpackUnorm4x8(C2), 2); +} + +bool sim3(vec4 col1, vec4 col2) { + return sim2n3(col1, col2, 3); +} + +bool mixcheck(vec4 col1, vec4 col2) { + + // Do not mix if either is transparent //xxx.alpha + bool col1alpha0 = col1.a < 0.003; + bool col2alpha0 = col2.a < 0.003; + if (col1alpha0!=col2alpha0) return false; + + // Cannot mix if transparency difference exceeds 50% //xxx.alpha + if (abs(col1.a - col2.a)>0.5) return false; + + vec3 diff = col1.rgb - col2.rgb; + + // Gradual pixel check + float min_diff = min(diff.r, min(diff.g, diff.b)); + float max_diff = max(diff.r, max(diff.g, diff.b)); + if ( max_diff-min_diff>0.618034 ) return false; + + float dot_diff = dot(diff, diff); + if( max_diff-min_diff<0.024 && dot_diff<0.75) return true; // 0.020 ≤ int5 0.024 ≤ int6 + + // Accumulate positive/negative values separately using max/min + float team_pos = abs(dot(max(diff, 0.0), vec3(1.0))); + float team_neg = abs(dot(min(diff, 0.0), vec3(1.0))); + // Find opposing channels and add to squared distance for judgment + float team_rebel = min(team_pos, team_neg); + // Empirical: At least 3x opposing channel value needs to be added. (+1x to break even, +2x to form increasing trend) + return dot_diff + team_rebel*team_rebel*3.0 < 0.4377; +} + +// RGB must be identical, small alpha channel difference allowed +bool eq(uint C1, uint C2){ + if (C1 == C2) return true; + + uint rgbC1 = C1 & 0x00FFFFFFu; + uint rgbC2 = C2 & 0x00FFFFFFu; + + if (rgbC1 != rgbC2) return false; + + uint alphaC1 = C1 >> 24; + uint alphaC2 = C2 >> 24; + + // Note: abs(alphaC1-alphaC2) cannot be used with uint! + uint alphaDiff = (alphaC1 > alphaC2) ? (alphaC1 - alphaC2) : (alphaC2 - alphaC1); + + return alphaDiff < 38u; //2x short golden ratio of 255u + +} + +#define noteq(a,b) (a!=b) + +bool vec_noteq(vec4 col1, vec4 col2) { + vec4 diff = abs(col1 - col2); + // Allow total RGB channel difference of int2, alpha channel difference of int5 + return dot(diff.rgb, vec3(1.0)) > 0.008 || diff.a > 0.021286; +} + +bool all_eq2(uint B, uint A0, uint A1) { + return (eq(B,A0) && eq(B,A1)); +} + +bool any_eq2(uint B, uint A0, uint A1) { + return (eq(B,A0) || eq(B,A1)); +} + +bool any_eq3(uint B, uint A0, uint A1, uint A2) { + return (eq(B,A0) || eq(B,A1) || eq(B,A2)); +} + +bool none_eq2(uint B, uint A0, uint A1) { + return (noteq(B,A0) && noteq(B,A1)); +} + +// Pre-define +//#define testcolor vec4(1.0, 0.0, 1.0, 1.0) // Magenta +//#define testcolor2 vec4(0.0, 1.0, 1.0, 1.0) // Cyan +//#define testcolor3 vec4(1.0, 1.0, 0.0, 1.0) // Yellow +//#define testcolor4 vec4(1.0, 1.0, 1.0, 1.0) // White + +#define slopeBAD vec4(2.0) +#define theEXIT vec4(4.0) +#define slopOFF vec4(8.0) +#define Mix382 mix(colX,colE,0.381966) +#define Mix618 mix(colX,colE,0.618034) +#define Mix854 mix(colX,colE,0.8541) +#define Mix382off Mix382+slopOFF +#define Mix618off Mix618+slopOFF +#define Mix854off Mix854+slopOFF +#define Xoff colX+slopOFF +#define checkblack(col) ((col).g < 0.078 && (col).r < 0.1 && (col).b < 0.1) +#define diffEB abs(El-Bl) +#define diffED abs(El-Dl) +#define writeJKLM writeColorf(destXY,J);writeColorf(destXY+ivec2(1,0),K);writeColorf(destXY+ivec2(0,1),L);writeColorf(destXY+ivec2(1,1),M) + +//pin zz +// Concave + Cross shape - weak blending (weak/none) +vec4 admixC(vec4 colX, vec4 colE) { + // Transparent pixels already filtered in main line + + bool mixok = mixcheck(colX, colE); + + return mixok ? Mix618 : colE; + +} + +// K shape - forced weak blending (weak/weaker) +vec4 admixK(vec4 colX, vec4 colE) { + // Transparent pixels already filtered in main line + + bool mixok = mixcheck(colX, colE); + + return mixok ? Mix618 : Mix854; + +} + +// L shape 2:1 slope - extension of main corner +// Note: This rule requires all 4 pixels on the slope to be identical. Otherwise, various visual artifacts will appear! +vec4 admixL(vec4 colX, vec4 colE, vec4 colS) { + + // Check eqX,E: originally captured large number of duplicate pixels, now filtered via slopeok in main line. + + // If target X differs from reference S (sample), it means blending has already occurred once. + // Copy directly without re-blending + if (vec_noteq(colX, colS)) return colX; + + bool mixok = mixcheck(colX, colE); + + return mixok ? Mix382 : colX; +} + +/******************************************************************************************************************************************** + * main slope + X cross-processing mechanism * + *******************************************************************************************************************************************/ +vec4 admixX(uint A, uint B, uint C, uint D, uint E, uint F, uint G, uint H, uint I, uint P, uint PA, uint PC, uint Q, uint QA, uint QG, uint R, uint RC, uint RI, uint S, uint SG, uint SI, uint AA, uint CC, uint GG, float El, float Bl, float Dl, float Fl, float Hl, vec4 colE, vec4 colB, vec4 colD) { + + // xxx.alpha + // 1. Normal rule: center E has higher luma - transparency in BD is illogical + // 2. B/D may be transparent when E-A are identical, but using transparent B/D to cut solid crossed E-A violates design + if (colB.a<0.002||colD.a<0.002) return slopeBAD; + + bool eq_B_C = eq(B, C); + bool eq_D_G = eq(D, G); + + // Exit if surrounded by straight walls on both sides + if (eq_B_C && eq_D_G) return slopeBAD; + + //Pre-declare + bool eq_A_B; bool eq_A_D; bool eq_A_P; bool eq_A_Q; + bool eq_B_P; bool eq_B_PA; bool eq_B_PC; + bool eq_D_Q; bool eq_D_QA; bool eq_D_QG; + bool eq_E_F; bool eq_E_H; bool eq_E_I; bool En3; + bool B_slope; bool B_tower; bool B_wall; + bool D_slope; bool D_tower; bool D_wall; + vec4 colX; bool Xisblack; + bool mixok; + + bool eq_B_D = eq(B,D); + bool eq_E_A = eq(E,A); + + #define comboA3 eq_A_P && eq_A_Q + #define En4square En3 && eq_E_I + + // E is nearly transparent but not fully transparent - mostly edges //xxx.alpha + bool EalphaL = colE.a <0.381966 && colE.a >0.002; + + // Remove alpha channel weighting + Bl = fract(Bl) *10.0; + Dl = fract(Dl) *10.0; + El = fract(El) *10.0; + Fl = fract(Fl) *10.0; + Hl = fract(Hl) *10.0; + +/*========================================= + B != D + ==================================== zz */ +if (!eq_B_D){ + + // Exit if E-A equality violates preset logic + if (eq_E_A) return slopeBAD; + + // Exit if B/D differ significantly (greater than E's difference with either side) + float diffBD = abs(Bl-Dl); + if (diffBD > diffEB || diffBD > diffED) return slopeBAD; + + // Avoid single-pixel font edges being squeezed by black background on both sides + // (Brightness difference between font and background usually exceeds 0.5) + // Note: If BD are not equal, cannot use average for judgment - both must meet black condition + Xisblack = checkblack(colB) && checkblack(colD); + if ( Xisblack && El >0.5 && (Fl<0.078 || Hl<0.078) ) return theEXIT; + +// Exclusion rule before original logic (triangle vertices cannot protrude) + eq_A_B = eq(A,B); + if ( !Xisblack && eq_A_B && eq_D_G && eq(B,P) ) return slopeBAD; + + eq_A_D = eq(A,D); + if ( !Xisblack && eq_A_D && eq_B_C && eq(D,Q) ) return slopeBAD; + + // B/D unconnected to any? Not applicable here (eliminates some artifacts but loses shapes, + // especially non-native pixel art like Double Dragon attract mode character sprites) + + // X is blend of B/D + colX = mix(colB, colD, 0.5); + colX.a = min(colB.a, colD.a); // xxx.alpha + + mixok = mixcheck(colX,colE); + + eq_A_P = eq(A,P); + eq_A_Q = eq(A,Q); + // A-side triple consecutive (eq_A_P && eq_A_Q) - high priority + if (comboA3) return mixok ? Mix382off : Xoff; + + // Official original rule + if ( eq(E,C) || eq(E,G) ) return mixok ? Mix382off : Xoff; + + // Enhanced original rule 1 - good at capturing trends, but enhanced 2 cannot be used (wall bypass issue) + if ( !eq_D_G&&eq(E,QG)&&sim2(colE,E,G) || !eq_B_C&&eq(E,PC)&&sim2(colE,E,C) ) return mixok ? Mix382off : Xoff; + + + // Exclude "3-pixel single-side wall" case + if (!Xisblack){ + if ( eq_A_B&&eq_B_C || eq_A_D&&eq_D_G ) return slopeBAD; + } + + //xxx.alpha + if (EalphaL) return mixok ? Mix382off : Xoff; + + // F-H inline trend (includes En3) - placed after wall rules since blocked by 3-pixel wall rule + if ( eq(F,H) ) return mixok ? Mix382off : Xoff; + + // Remaining "2-pixel single-side wall" and unlogical single pixels - abandon + return slopeBAD; +} // B != D + +/******* B == D prepare *******/ + + // Avoid single-pixel font edges being squeezed by black background on both sides + Xisblack = checkblack(colB); + if ( Xisblack && El >0.5 && (Fl<0.078 || Hl<0.078) ) return theEXIT; + + colX = colB; + colX.a = min(colB.a , colD.a); + + bool eq_E_C = eq(E,C); + bool eq_E_G = eq(E,G); + bool sim_EC = eq_E_C || sim2n3(colE,unpackUnorm4x8(C),2); + bool sim_EG = eq_E_G || sim2n3(colE,unpackUnorm4x8(G),2); + + bool ThickBorder; + + +/*=============================================== + Original main rule (sim2 enhanced) + ========================================== zz */ +if ( (sim_EC || sim_EG) && !eq_E_A ){ + +/* Logic: + 1. Handle non-blending for continuous border shapes + 2. Special handling for long slopes + 3. Original rules + 4. Handle E-area inline (En4, En3, F-H etc.), remaining single strip and single pixel + 5. Handle L-shaped inner single strip and outer single strip + 5. Default fallback return +*/ + + eq_A_B = eq(B,A); + eq_B_P = eq(B,P); + eq_B_PC = eq(B,PC); + eq_B_PA = eq(B,PA); + eq_D_Q = eq(D,Q); + eq_D_QG = eq(D,QG); + eq_D_QA = eq(D,QA); + B_slope = eq_B_PC && !eq_B_P && !eq_B_C; + B_tower = eq_B_P && !eq_B_PC && !eq_B_C && !eq_B_PA; + D_slope = eq_D_QG && !eq_D_Q && !eq_D_G; + D_tower = eq_D_Q && !eq_D_QG && !eq_D_G && !eq_D_QA; + + + // B+ D+ each extend shape (strong shape) - no blending, return Xoff + if ( (B_slope||B_tower) && (D_slope||D_tower) && !eq_A_B) return Xoff; + + + eq_A_P = eq(A, P); + eq_A_Q = eq(A, Q); + mixok = mixcheck(colX,colE); + ThickBorder = eq_A_B && (eq_A_P||eq_A_Q|| eq(A,AA)&&(eq_B_PA||eq_D_QA)); + if (ThickBorder && !Xisblack) mixok=false; + + // A-side triple consecutive (eq_A_P && eq_A_Q) + if (comboA3) { + if (!eq_A_B) return Xoff; + else mixok=false; + } + + // XE_messL B-D-E L-shape with sim2 high similarity WIP + // bool XE_messL = (eq_B_C && !sim_EG || eq_D_G && !sim_EC) ; + + eq_E_F = eq(E, F); + B_wall = eq_B_C && !eq_B_PC && !eq_B_P; + + // Long slope (clear, non-thick solid edge - strong trend!) + // Special condition for long slopes + if ( B_wall && D_tower ) { + if (eq_E_G || sim_EG&&eq(E,QG) ) { // Original rule + enhanced original + if (eq_A_B) return mixok ? Mix382 : colX; // Has thickness + return colX; // Hollow + } + // Clear Z-shaped snake - exclude eq_A_B + XE_messL ??? + //if (eq_A_B && !XE_messL) return ; // Poor effect + if (eq_A_B) return slopeBAD; + // 2-pixel with subsequent long slope + if (eq_E_F ) return colX; + // 1-pixel without subsequent long slope + return Xoff; + } + + eq_E_H = eq(E, H); + D_wall = eq_D_G && !eq_D_QG && !eq_D_Q; + + if ( B_tower && D_wall ) { + if (eq_E_C || sim_EC&&eq(E,PC) ) { // Original rule + enhanced original + if (eq_A_B) return mixok ? Mix382 : colX; // Has thickness + return colX; // Hollow + } + // Clear Z-shaped snake - exclude eq_A_B + XE_messL ??? + //if (eq_A_B && !XE_messL) return ; // Poor effect + if (eq_A_B) return slopeBAD; + // 2-pixel with subsequent long slope + if (eq_E_H ) return colX; + // 1-pixel without subsequent long slope + return Xoff; + } + + + // Official original rule (placed after special shapes - special shapes have designated no-blending!) + if (eq_E_C || eq_E_G) return mixok ? Mix382 : colX; + + // Enhanced original rule 1 + if (sim_EG&&!eq_D_G&&eq(E,QG) || sim_EC&&!eq_B_C&&eq(E,PC)) return mixok ? Mix382off : Xoff; + + // Enhanced original rule 2 + if (sim_EC && sim_EG) return mixok ? Mix382off : Xoff; + + + // F-H inline trend (skip En4, En3) + if ( eq(F,H) ) return mixok ? Mix382off : Xoff; + + // Relaxed rule for final long slope cleanup (non-clear shapes) + // Empirical: This block handles different slopes than F-H. Default to break-even unless cube shape. + if (eq_B_C && eq_D_Q) { + // Exit for double cube + if (eq_B_P && eq_B_PC && eq_A_B && eq_D_QA && !eq_D_QG && eq_E_F && eq(H,I) ) return theEXIT; + + return mixok ? Mix382off : Xoff; + } + + if ( eq_D_G && eq_B_P) { + // Exit for double cube + if (eq_D_Q && eq_D_QG && eq_A_B && eq_B_PA && !eq_B_PC && eq_E_H && eq(F,I) ) return theEXIT; + + return mixok ? Mix382off : Xoff; + } + + eq_E_I = eq(E, I); + + // Exit for clear L-shaped corner with inner parallel single strip + if (eq_A_B && !ThickBorder && !eq_E_I ) { + if (B_wall && eq_E_F) return theEXIT; + if (D_wall && eq_E_H) return theEXIT; + } + + // Early return if colors are similar (skip next step) + if (mixok) return Mix382off; + if (EalphaL) return mixok ? Mix382off : Xoff; //xxx.alpha + + // Exit for hollow L-shaped corner with outer single strip (any direction) - fixes font edge issues + if ( !eq_A_B && (eq_E_F||eq_E_H) && !eq_E_I) { + if (B_tower && !eq_D_Q && !eq_D_QG) return theEXIT; + if (D_tower && !eq_B_P && !eq_B_PC) return theEXIT; + } + + // Fallback handling + return mixok ? Mix382off : Xoff; + +} // sim2 base + + +/*=================================================== + E - A cross + ============================================== zz */ +if (eq_E_A) { + + // Cross ✕ judgment requires "region" and "trend" concepts - tighter conditions for different regions + + // No need to exit for unconnected B/D! ! ! + + eq_E_F = eq(E, F); + eq_E_H = eq(E, H); + eq_E_I = eq(E, I); + + En3 = eq_E_F&&eq_E_H; + + // Special shape: square (En3 && eq_E_I) + if ( En4square ) { + if( noteq(G,H) && noteq(C,F) // Independent clear 4-pixel square / 6-pixel rectangle (both sides meet) + && (eq(H,S) == eq(I,SI) && eq(F,R) == eq(I,RI)) ) return theEXIT; + //else return mixok ? mix(X,E,0.381966) : X; Note: Do not return directly. Need to enter chessboard scoring rule, + // as adjacent B/D areas may also form bubbles with squares + } + + // Special shape: dot pattern + // Empirical 1: !eq_E_F, !eq_E_H - do not use !sim (loses some shapes) + // Empirical 2: Force blending (otherwise lose shapes - Horse from Gouketsuji Ichizoku, Saturday Night Slam Masters 2) + + bool Eisblack = checkblack(colE); + mixok = mixcheck(colX,colE); + + // 1. Dot pattern center + if ( eq_E_C && eq_E_G && eq_E_I && !eq_E_F && !eq_E_H ) { + + // Exit if center E is black (KOF '96 power bar, Punisher's belt) - avoid over-blending with high contrast + if (Eisblack) return theEXIT; + // Empirical 1: Do not capture black B points (normal logic entry) + // Empirical 2: No need to check eq_F_H separately (95%+ probability) + layered gradient in power bar, 0.5 fallback blending + return mixok ? Mix382off : Mix618off; + } + + eq_A_P = eq(A,P); + eq_A_Q = eq(A,Q); + eq_B_PA = eq(B,PA); + + // 2. Dot pattern edge + if ( eq_A_P && eq_A_Q && eq(A,AA) && noteq(A,PA) && noteq(A,QA) ) { + if (Eisblack) return theEXIT; + + // Layered gradient edge - use strong blending + if ( !eq_B_PA && eq(PA,QA) ) return mixok ? Mix382off : Mix618off; + // Remaining perfect cross - definitely dot pattern edge, use weak blending + // Fallback weak blending - no need to specify power bar border case separately + return mixok ? Mix618off : Mix854off; + } + + // xxx.alpha + if (colE.a<0.002) return colX; + + eq_D_QA = eq(D,QA); + eq_D_QG = eq(D,QG); + eq_B_PC = eq(B,PC); + + // 3. Half dot pattern - usually shadow expression on outline edges, use weak blending + if ( eq_E_C && eq_E_G && eq_A_P && eq_A_Q && + (eq_B_PC || eq_D_QG) && + eq_D_QA && eq_B_PA) { + //if (Eisblack) return ; Unnecessary + + return mixok ? Mix618off : Mix854off; + } + + // 4. Quarter dot pattern - prone to ugly "pinkie effect" (Guile's Sonic Boom in SF2, Dino Crisis select screen) + + if ( eq_E_C && eq_E_G && eq_A_P + && eq_B_PA &&eq_D_QA && eq_D_QG + && eq_E_H + ) return mixok ? Mix618off : Mix854off; + + if ( eq_E_C && eq_E_G && eq_A_Q + && eq_B_PA &&eq_D_QA && eq_B_PC + && eq_E_F + ) return mixok ? Mix618off : Mix854off; + + + // E-side triple consecutive (must come after dot pattern) + if ( eq_E_C && eq_E_G ) return Xoff; + + // A-side triple consecutive (eq_A_P && eq_A_Q) - must come after dot pattern. + // Prefer blending over direct copy since E-A are identical + if (comboA3) return mixok ? Mix382off : Xoff; + + + // B-D part of long slope + eq_B_P = eq(B,P); + eq_D_Q = eq(D,Q); + B_wall = eq_B_C && !eq_B_P; + B_tower = eq_B_P && !eq_B_C; + D_tower = eq_D_Q && !eq_D_G; + D_wall = eq_D_G && !eq_D_Q; + + int scoreE = 0; int scoreB = 0; int scoreD = 0; int scoreZ = 0; + + +// E B D area chessboard scoring rule + +// E Zone + if (En3) { + scoreE += 1; + if (B_wall || B_tower || D_tower || D_wall) scoreZ = 1; + } + + if (eq_E_C) { + scoreE += 1; + scoreE += int(eq_E_F); + } + + if (eq_E_G) { + scoreE += 1; + scoreE += int(eq_E_H); + + } + + if (scoreE==0) { + // Single strip + if (eq_E_F ||eq_E_H) return theEXIT; + } + + if ( eq(F,H) ) { + scoreE += 1; + if ( scoreZ==0 && B_wall && (eq(F,R) || eq(G,H) || eq(F,I)) ) scoreZ = 1; + if ( scoreZ==0 && D_wall && (eq(C,F) || eq(H,S) || eq(F,I)) ) scoreZ = 1; + } + + + #define Bn3 eq_B_P&&eq_B_C + #define Dn3 eq_D_G&&eq_D_Q + +// B Zone + scoreB -= int(Bn3); + scoreB -= int(eq(C,P)); + if (scoreB < 0) scoreZ = 0; + + if (eq_B_PA) { + scoreB -= 1; + scoreB -= int(eq_B_P); //Replace eq(P,PA) + } + +// D Zone + scoreD -= int(Dn3); + scoreD -= int(eq(G,Q)); + if (scoreD < 0) scoreZ = 0; + + if (eq_D_QA) { + scoreD -= 1; + scoreD -= int(eq_D_Q); //Replace eq(Q,QA) + } + + int scoreFinal = scoreE + scoreB + scoreD + scoreZ ; + + if (scoreE >= 1 && scoreB >= 0 && scoreD >=0) scoreFinal += 1; + + if (scoreFinal >= 2) return colX; + + if (scoreFinal == 1) return mixok ? Mix382 : colX; + + // Final supplement: total score 0, no deductions in B/D areas - forms long slope shape + if (scoreB >= 0 && scoreD >=0) { + if (B_wall&&D_tower) return colX; + if (B_tower&&D_wall) return colX; + } + + return slopeBAD; + +} // eq_E_A + + +/*========================================================= + F - H / B+ D+ extension new rule + ==================================================== zz */ + +// This block differs from sim block - center point and related En4square/BD are naturally isolated by a wall +// Therefore judgment rules differ from sim side + + eq_B_P = eq(B, P); + eq_B_PC = eq(B, PC); + eq_D_Q = eq(D, Q); + eq_D_QG = eq(D, QG); + + // Exit if B/D unconnected to any (Empirical: required for this branch block) + if ( !eq_B_C && !eq_B_P && !eq_B_PC && !eq_D_G && !eq_D_Q && !eq_D_QG ) return slopeBAD; + + mixok = mixcheck(colX,colE); + eq_E_I = eq(E, I); + + // Exit if center E is single high-contrast pixel + // Tighten threshold if E is highlight + float E_lumDiff = El > 0.92 ? 0.145898 : 0.381966; + // Large difference with surroundings + if ( !mixok && !eq_E_I && !EalphaL && abs(El-Fl)>E_lumDiff && abs(El-Hl)>E_lumDiff ) return slopeBAD; //xxx.alpha + + + eq_A_B = eq(A, B); + eq_A_P = eq(A, P); + eq_A_Q = eq(A, Q); + eq_B_PA = eq(B,PA); + eq_D_QA = eq(D,QA); + + ThickBorder = eq_A_B && (eq_A_P||eq_A_Q|| eq(A,AA)&&(eq_B_PA||eq_D_QA)); + + if (ThickBorder && !Xisblack) mixok=false; + + B_slope = eq_B_PC && !eq_B_P && !eq_B_C; + B_tower = eq_B_P && !eq_B_PC && !eq_B_C && !eq_B_PA; + D_slope = eq_D_QG && !eq_D_Q && !eq_D_G; + D_tower = eq_D_Q && !eq_D_QG && !eq_D_G && !eq_D_QA; + + if (!eq_A_B) { + // B + D + each extend shape + // Empirical 1: Looser conditions for one side if the other has clear shape + // Empirical 2: Outer side of "厂" shape break-even, inner side not break-even (can be tower but not wall) + if ( (B_slope||B_tower) && (eq_D_QG&&!eq_D_G||D_tower) ) return Xoff; + if ( (D_slope||D_tower) && (eq_B_PC&&!eq_B_C||B_tower) ) return Xoff; + + // A-side triple consecutive (eq_A_P && eq_A_Q) - high priority + if (comboA3) return Xoff; + + // combo 2x2 as supplement to above + if ( B_slope && eq_A_P ) return mixok ? Mix382off : Xoff; + if ( D_slope && eq_A_Q ) return mixok ? Mix382off : Xoff; + } + + eq_E_F = eq(E, F); + B_wall = eq_B_C && !eq_B_PC && !eq_B_P; + + // Long slope (clear, non-solid edge - strong trend!) + // Special condition for long slopes + if ( B_wall && D_tower ) { + if (eq_A_B ) return slopeBAD; + if (eq_E_F ) return colX; //wip: Test direct X no blending + return mixok ? Mix382off : Xoff; + } + + eq_E_H = eq(E, H); + D_wall = eq_D_G && !eq_D_QG&& !eq_D_Q; + + if ( B_tower && D_wall ) { + if (eq_A_B ) return slopeBAD; + if (eq_E_H ) return colX; + return mixok ? Mix382off : Xoff; + } + + + bool sim_X_E = sim3(colX,colE); + bool eq_G_H = eq(G, H); + bool eq_C_F = eq(C, F); + bool eq_H_S = eq(H, S); + bool eq_F_R = eq(F, R); + + En3 = eq_E_F&&eq_E_H; + + // 4-pixel rectangle inside wall (En3 && eq_E_I) + if ( En4square ) { // This square detection must come after previous rule + if (sim_X_E) return mixok ? Mix382off : Xoff; + // Exit for solid L-shaped inner wrap (fixes font edge corners and non-rounded building corners (Mega Man 7)) + if ( (eq_B_C || eq_D_G) && eq_A_B ) return theEXIT; + //if (eq_H_S && eq_F_R) return theEXIT; // Extend both sides + // L-shaped inner wrap (hollow corner) / high-contrast independent clear 4-pixel square / 6-pixel rectangle (note rectangle edges) + if ( ( eq_B_C&&!eq_G_H || eq_D_G&&!eq_C_F || !eq_G_H&&!eq_C_F&&diffEB>0.5) && (eq_H_S == eq(I, SI) && eq_F_R == eq(I, RI)) ) return theEXIT; + + return mixok ? Mix382off : Xoff; + } + + // Triangle inside wall + if ( En3 ) { + if (sim_X_E) return mixok ? Mix382off : Xoff; + if (eq_H_S && eq_F_R) return theEXIT; // Extend both sides (building edges) + // Inner curve + if (eq_B_C || eq_D_G) return mixok ? Mix382off : Xoff; + // Direct return if has thickness (Z-shaped snake can break-even outer curve below) + if (eq_A_B) return mixok ? Mix382off : Xoff; + // Outer curve + if (eq_B_P || eq_D_Q) return theEXIT; + + return mixok ? Mix382off : Xoff; + // Final two rules based on experience - principle: connect inner L curve, not outer (Jimmy's eyebrows in Double Dragon) + } + + // F - H + // Principle: connect inner L curve, not outer + if ( eq(F,H) ) { + if (sim_X_E||EalphaL) return mixok ? Mix382off : Xoff; //xxx.alpha + // Exit for solid L-shaped inner wrap - avoid single pixel squeezed by symmetric double wrap + if ( eq_B_C && eq_A_B && (eq_G_H||!eq_F_R) &&eq(F, I) ) return slopeBAD; + if ( eq_D_G && eq_A_B && (eq_C_F||!eq_H_S) &&eq(F, I) ) return slopeBAD; + + //Inner curve + if (eq_B_C && (eq_F_R||eq_G_H||eq(F, I))) return mixok ? Mix382off : Xoff; + if (eq_D_G && (eq_C_F||eq_H_S||eq(F, I))) return mixok ? Mix382off : Xoff; + // E-I F-H cross breaks trend + if (eq_E_I) return slopeBAD; + // Outer Z-shape + if (eq_B_P && eq_A_B) return mixok ? Mix382off : Xoff; + if (eq_D_Q && eq_A_B) return mixok ? Mix382off : Xoff; + // Outer curve - unless opposite side forms long L-shaped trend + if (eq_B_P && (eq_C_F&&eq_H_S)) return mixok ? Mix382off : Xoff; + if (eq_D_Q && (eq_F_R&&eq_G_H)) return mixok ? Mix382off : Xoff; + + return slopeBAD; + } + + + // Relaxed rule for final long slope cleanup (non-clear shapes) + // Note: This block handles different slopes than sim2 block - exit for solid corners + if ( eq_B_C && eq_D_Q || eq_D_G && eq_B_P) { + // Note: Clear eq_A_B first - otherwise single edge pixels get "corner cut" (eternal secret) + if (eq_A_B) return theEXIT; + return mixok ? Mix382off : Xoff; + } + + + // A-side triple consecutive - NEVER use without !eq_A_B ! ! ! ! ! ! ! ! + // if (comboA3) return X+slopeOFF; + + + // One more check for B + D bidirectional extension - higher priority than inner/outer L single strip below + if ( (B_slope||B_tower) && (eq_D_QG&&!eq_D_G||D_tower) ) return Xoff; + if ( (D_slope||D_tower) && (eq_B_PC&&!eq_B_C||B_tower) ) return Xoff; + + + // Exit for clear L-shaped corner with inner single strip (sim_X_E no exemption) + if (eq_A_B && !ThickBorder && !eq_E_I ) { + + if (B_wall && eq_E_F) return theEXIT; + if (D_wall && eq_E_H) return theEXIT; + } + +if (sim_X_E||EalphaL) return mixok ? Mix382off : Xoff; //xxx.alpha + // Exit for hollow L-shaped corner with outer single strip (connect inner corner, not outer) + // Empirical: Avoids font edge cutting (Captain Commando) + if ( (B_tower || D_tower) && (eq_E_F||eq_E_H) && !eq_A_B && !eq_E_I) return theEXIT; + + // Final individual extension check for B or D + + // Maximum distance usable for slope + if ( B_slope && !eq_A_B && eq(PC,CC) && noteq(PC,RC)) return mixok ? Mix382off : Xoff; + if ( D_slope && !eq_A_B && eq(QG,GG) && noteq(QG,SG)) return mixok ? Mix382off : Xoff; + + // Slope can use one less judgment point if X-E are close, with internal logic restrictions + if ( mixok && !eq_A_B ) { + if ( B_slope && (!eq_C_F||eq(F,RC)) ) return Mix382off; + if ( D_slope && (!eq_G_H||eq(H,SG)) ) return Mix382off; + } + + // Exclude single strip for Z-shaped snake below (necessary) + if ((eq_E_F||eq_E_H) && !eq_E_I ) return theEXIT; + + // Z-shaped snake (eq_A_B has thickness, one side is tower (can be wall/slope) but other side cannot be tower/wall (naturally prohibited)) + if ( eq_B_P && !eq_B_PA && !eq_D_Q && eq_A_B) return mixok ? Mix382off : Xoff; + if ( eq_D_Q && !eq_D_QA && !eq_B_P && eq_A_B) return mixok ? Mix382off : Xoff; + + return theEXIT; + +} // admixX + +vec4 admixS(uint A, uint B, uint C, uint D, uint E, uint F, uint G, uint H, uint I, uint R, uint RC, uint RI, uint S, uint SG, uint SI, uint II, bool eq_B_D, bool eq_E_D, float El, float Bl, vec4 colE, vec4 colF) { + + // ABC . + // QD🄴 🅵 🆁 Zone 4 + // 🅶 🅷 I + // S + // Empirical 1: sim E B(C) conforms to original logic - E single pixel won't look abrupt when inserted by saw in practice + // Empirical 2: Can E equal I? Yes! + + if (any_eq2(F,C,I)) return colE; + //if (any_eq3(F,A,C,I)) return colE; + + if (eq(R, RI) && noteq(R,I)) return colE; + if (eq(H, S) && noteq(H,I)) return colE; + + if ( eq(R, RC) || eq(G,SG) ) return colE; + + // Remove alpha channel weighting + Bl = fract(Bl) *10.0; + El = fract(El) *10.0; + + if ( ( eq_B_D&&eq(B,C)&&diffEB<0.381966 || eq_E_D&&sim2(colE,E,C) ) && + (any_eq3(I,H,S,RI) || eq(SI,RI)&¬eq(I,II)) ) return colF; + + return colE; +} + + +//////////////////////////////////////////// main line /////////////////////////////////////////////// pin zz + +void applyScaling(uvec2 xy) { + int srcX = int(xy.x); + int srcY = int(xy.y); + ivec2 destXY = ivec2(xy) * 2; + + uint E = src(srcX, srcY); + uint B = src(srcX, srcY-1); + uint D = src(srcX-1, srcY); + uint F = src(srcX+1, srcY); + uint H = src(srcX, srcY+1); + + vec4 colE = unpackUnorm4x8(E); + vec4 J = colE, K = colE, L = colE, M = colE; + + bool eq_E_D = eq(E,D); + bool eq_E_F = eq(E,F); + bool eq_E_B = eq(E,B); + bool eq_E_H = eq(E,H); + +// Skip horizontal/vertical 3x1 +if ( eq_E_D && eq_E_F || eq_E_B && eq_E_H) {writeJKLM;return;} + + bool eq_B_H = eq(B,H); + bool eq_D_F = eq(D,F); +// Skip center surrounded by mirrored blocks +if ( eq_B_H && eq_D_F ) {writeJKLM;return;} + + // Capture 5x5 + uint A = src(srcX-1, srcY-1); + uint C = src(srcX+1, srcY-1); + uint G = src(srcX-1, srcY+1); + uint I = src(srcX+1, srcY+1); + uint P = src(srcX, srcY-2); + uint Q = src(srcX-2, srcY); + uint R = src(srcX+2, srcY); + uint S = src(srcX, srcY+2); + + + uint PA = src(srcX-1, srcY-2); + uint PC = src(srcX+1, srcY-2); + uint QA = src(srcX-2, srcY-1); + uint QG = src(srcX-2, srcY+1); // AA PA [P] PC CC + uint RC = src(srcX+2, srcY-1); // ┌──┬──┬──┐ + uint RI = src(srcX+2, srcY+1); // QA │ A │ B │ C │ RC + uint SG = src(srcX-1, srcY+2); // ├──┼──┼──┤ + uint SI = src(srcX+1, srcY+2); // [Q] │ D │ E │ F │ [R] + uint AA = src(srcX-2, srcY-2); // ├──┼──┼──┤ + uint CC = src(srcX+2, srcY-2); // QG │ G │ H │ I │ RI + uint GG = src(srcX-2, srcY+2); // └──┴──┴──┘ + uint II = src(srcX+2, srcY+2); // GG SG [S] SI II + + + vec4 colB = unpackUnorm4x8(B); + vec4 colD = unpackUnorm4x8(D); + vec4 colF = unpackUnorm4x8(F); + vec4 colH = unpackUnorm4x8(H); + + float Bl = luma(colB), Dl = luma(colD), El = luma(colE), Fl = luma(colF), Hl = luma(colH); + + +// 1:1 slope rules (P95) + bool eq_B_D = eq(B,D); + bool eq_B_F = eq(B,F); + bool eq_D_H = eq(D,H); + bool eq_F_H = eq(F,H); + + // Center surrounded by any mirrored blocks + bool oppoPix = eq_B_H || eq_D_F; + // Flag for admixX entry via 1:1 slope rule + bool slope1 = false; bool slope2 = false; bool slope3 = false; bool slope4 = false; + // Standard pixel returned normally via 1:1 slope rule + bool slope1ok = false; bool slope2ok = false; bool slope3ok = false; bool slope4ok = false; + // slopeBAD: entered admixX but (at least one of JKLM) returns E point + // slopOFF: returned with OFF flag - no long slope calculation + bool slopeBAD_flag = false; + + // B - D + if ( (!eq_E_B&&!eq_E_D&&!oppoPix) && (!eq_D_H&&!eq_B_F) && (El>=Dl&&El>=Bl || eq(E,A)) && ( (El 1.0 ) { + if (J.b > 7.0 ) J=J-8.0; //slopOFF + if (J.b == 4.0 ) { + J=colE; + writeJKLM; + return; + } + if (J.b == 2.0 ) J=colE; //slopeBAD + } else slope1ok = true; + } + // B - F + if ( !slope1 && (!eq_E_B&&!eq_E_F&&!oppoPix) && (!eq_B_D&&!eq_F_H) && (El>=Bl&&El>=Fl || eq(E,C)) && ( (El 1.0 ) { + if (K.b > 7.0 ) K=K-8.0; + if (K.b == 4.0 ) { + K=colE; + writeJKLM; + return; + } + if (K.b == 2.0 ) K=colE; + } else {slope2ok = true;} + } + // D - H + if ( !slope1 && (!eq_E_D&&!eq_E_H&&!oppoPix) && (!eq_F_H&&!eq_B_D) && (El>=Hl&&El>=Dl || eq(E,G)) && ((El 1.0 ) { + if (L.b > 7.0 ) L=L-8.0; + if (L.b == 4.0 ) { + L=colE; + writeJKLM; + return; + } + if (L.b == 2.0 ) L=colE; + } else {slope3ok = true;} + } + // F - H + if ( !slope2 && !slope3 && (!eq_E_F&&!eq_E_H&&!oppoPix) && (!eq_B_F&&!eq_D_H) && (El>=Fl&&El>=Hl || eq(E,I)) && ((El 1.0 ) { + if (M.b > 7.0 ) M=M-8.0; + if (M.b == 4.0 ) { + M=colE; + writeJKLM; + return; + } + if (M.b == 2.0 ) M=colE; + } else {slope4ok = true;} + } + + +// long gentle 2:1 slope (P100) + + bool longslope = false; + + if (slope4ok && eq_F_H) { //zone4 long slope + // Extended original rule 1. Pass adjacent pixel to admixL third parameter to prevent double blending + // Extended original rule 2. No L-shape allowed in opposite two-pixel interval unless wall formed + if (eq(G,H) && eq(F,R) && noteq(R, RC) && (noteq(Q,G)||eq(Q, QA))) {L=admixL(M,L,colH); longslope = true;} + // vertical + if (eq(C,F) && eq(H,S) && noteq(S, SG) && (noteq(P,C)||eq(P, PA))) {K=admixL(M,K,colF); longslope = true;} + } + + + if (slope3ok && eq_D_H) { //zone3 long slope + // horizontal + if (eq(D,Q) && eq(H,I) && noteq(Q, QA) && (noteq(R,I)||eq(R, RC))) {M=admixL(L,M,colH); longslope = true;} + // vertical + if (eq(A,D) && eq(H,S) && noteq(S, SI) && (noteq(A,P)||eq(P, PC))) {J=admixL(L,J,colD); longslope = true;} + } + + if (slope2ok && eq_B_F) { //zone2 long slope + // horizontal + if (eq(A,B) && eq(F,R) && noteq(R, RI) && (noteq(A,Q)||eq(Q, QG))) {J=admixL(K,J,colB); longslope = true;} + // vertical + if (eq(F,I) && eq(B,P) && noteq(P, PA) && (noteq(I,S)||eq(S, SG))) {M=admixL(K,M,colF); longslope = true;} + } + + if (slope1ok && eq_B_D) { //zone1 long slope + // horizontal + if (eq(B,C) && eq(D,Q) && noteq(Q, QG) && (noteq(C,R)||eq(R, RI))) {K=admixL(J,K,colB); longslope = true;} + // vertical + if (eq(D,G) && eq(B,P) && noteq(P, PC) && (noteq(G,S)||eq(S, SI))) {L=admixL(J,L,colD); longslope = true;} + } + +// Exit after longslope formation - sawslope rarely forms on diagonal +bool skiprest = longslope; + +bool slopeok = slope1ok||slope2ok||slope3ok||slope4ok; + + +// Note: sawslope cannot exclude slopeOFF (few cases) and slopeBAD (very rare), but can exclude slopeok (strong shape) +if (!skiprest && !oppoPix && !slopeok) { + + + // horizontal bottom + if (!eq_E_H && none_eq2(H,A,C)) { + + // A B C ・ + // Q D 🄴 🅵 🆁 Zone 4 + // 🅶 🅷 I + // S + // (!slope3 && !eq_D_H) clever combination + if ( (!slope2 && !eq_B_F) && (!slope3 && !eq_D_H) && !eq_F_H && + !eq_E_F && (eq_B_D || eq_E_D) && eq(R,H) && eq(F,G) ) { + M = admixS(A,B,C,D,E,F,G,H,I,R,RC,RI,S,SG,SI,II,eq_B_D,eq_E_D,El,Bl,colE,colF); + skiprest = true;} + + // ・ A B C + // 🆀 🅳 🄴 F R Zone 3 + // G 🅷 🅸 + // S + if ( !skiprest && (!slope1 && !eq_B_D) && (!slope4 && !eq_F_H) && !eq_D_H && + !eq_E_D && (eq_B_F || eq_E_F) && eq(Q,H) && eq(D,I) ) { + L = admixS(C,B,A,F,E,D,I,H,G,Q,QA,QG,S,SI,SG,GG,eq_B_F,eq_E_F,El,Bl,colE,colD); + skiprest = true;} + } + + // horizontal up + if ( !skiprest && !eq_E_B && none_eq2(B,G,I)) { + + // P + // 🅐 🅑 C + // QD 🄴 🅵 🆁 Zone 2 + // G H I . + if ( (!slope1 && !eq_B_D) && (!slope4 && !eq_F_H) && !eq_B_F && + !eq_E_F && (eq_D_H || eq_E_D) && eq(B,R) && eq(A,F) ) { + K = admixS(G,H,I,D,E,F,A,B,C,R,RI,RC,P,PA,PC,CC,eq_D_H,eq_E_D,El,Hl,colE,colF); + skiprest = true;} + + // P + // A 🅑 🅲 + // 🆀 🅳 🄴 F R Zone 1 + // . G H I + if ( !skiprest && (!slope2 && !eq_B_F) && (!slope3 && !eq_D_H) && !eq_B_D && + !eq_E_D && (eq_F_H || eq_E_F) && eq(B,Q) && eq(C,D) ) { + J = admixS(I,H,G,F,E,D,C,B,A,Q,QG,QA,P,PC,PA,AA,eq_F_H,eq_E_F,El,Hl,colE,colD); + skiprest = true;} + + } + + // vertical left + if ( !skiprest && !eq_E_D && none_eq2(D,C,I) ) { + + // 🅐 B C + // Q 🅳 🄴 F R + // G 🅷 I Zone 3 + // 🆂 ・ + if ( (!slope1 && !eq_B_D) && (!slope4 && !eq_F_H) && !eq_D_H && + !eq_E_H && (eq_B_F || eq_E_B) && eq(D,S) && eq(A,H) ) { + L = admixS(C,F,I,B,E,H,A,D,G,S,SI,SG,Q,QA,QG,GG,eq_B_F,eq_E_B,El,Fl,colE,colH); + skiprest = true;} + + // 🅟 ・ + // A 🅑 C + // Q 🅳 🄴 F R Zone 1 + // 🅶 HI + if ( !skiprest && (!slope3 && !eq_D_H) && (!slope2 && !eq_B_F) && !eq_B_D && + !eq_E_B && (eq_F_H || eq_E_H) && eq(P,D) && eq(B,G) ) { + J = admixS(I,F,C,H,E,B,G,D,A,P,PC,PA,Q,QG,QA,AA,eq_F_H,eq_E_H,El,Fl,colE,colB); + skiprest = true;} + + } + + // vertical right + if ( !skiprest && !eq_E_F && none_eq2(F,A,G) ) { // right + + // A B 🅲 + // Q D 🄴 🅵 R + // G 🅷 I Zone 4 + // . 🆂 + if ( (!slope2 && !eq_B_F) && (!slope3 && !eq_D_H) && !eq_F_H && + !eq_E_H && (eq_B_D || eq_E_B) && eq(S,F) && eq(H,C) ) { + M = admixS(A,D,G,B,E,H,C,F,I,S,SG,SI,R,RC,RI,II,eq_B_D,eq_E_B,El,Dl,colE,colH); + skiprest = true;} + + // ・ 🅟 + // A 🅑 C + // Q D 🄴 🅵 R Zone 2 + // G H 🅸 + if ( !skiprest && (!slope1 && !eq_B_D) && (!slope4 && !eq_F_H) && !eq_B_F && + !eq_E_B && (eq_D_H || eq_E_H) && eq(P,F) && eq(B,I) ) { + K = admixS(G,D,A,H,E,B,I,F,C,P,PA,PC,R,RI,RC,CC,eq_D_H,eq_E_H,El,Dl,colE,colB); + skiprest = true;} + + } // vertical right +} // sawslope + +// Exit after sawslope formation - legacy approach: skiprest||slopeBAD (also uses slopeOFF (weak) and slopok (strong) but poor effect) +skiprest = skiprest||slope1||slope2||slope3||slope4||El>7.0||Bl>7.0||Dl>7.0||Fl>7.0||Hl>7.0; + +/************************************************** + Concave + Cross shape (P100) + *************************************************/ +// Use approximate pixels for cross star far end - useful for horizontal line + sawtooth and layered gradient shapes. +// E.g. glowing text in SFIII: New Generation intro, Japanese houses in SFZ3 Mix, Fatal Fury: Wild Ambition intro + + vec4 colX; //Define temp X + + if (!skiprest && + Bl