53aa1914453028353486c88d0db62ee7d91b781f

Author
outfoxxed <outfoxxed@outfoxxed.me>
Committer
outfoxxed <outfoxxed@outfoxxed.me>
Date

Message

add blur to tabs

Closes #138

Diff

  1diff --git a/CHANGELOG.md b/CHANGELOG.md
  2index f23978f187f0a42b48fd34d7ed2b4840376d682e..bd12816c474bc586f1daf8411ba51531bcc53f40 100644
  3--- a/CHANGELOG.md
  4+++ b/CHANGELOG.md
  5@@ -2,9 +2,9 @@
  6 
  7 # Upcoming
  8 
  9-- Added configurable borders to tabs
 10+- Added configurable borders and blurred backgrounds to tabs.
 11 - Renamed `hy3:tabs:rounding` to `hy3:tabs:radius`.
 12-- Changed default tab style
 13+- Changed default tab style.
 14 
 15 # hl0.46.0 and before
 16 
 17diff --git a/CMakeLists.txt b/CMakeLists.txt
 18index 59297b5ca850b34b6b86628cc8292e5c6b10c3ad..12d2a4b0c5818b99a402a945ec4ae3db9eb4787c 100644
 19--- a/CMakeLists.txt
 20+++ b/CMakeLists.txt
 21@@ -24,11 +24,11 @@ add_library(hy3 SHARED
 22 	src/render.cpp
 23 )
 24 
 25-configure_file(src/simple_quad.vert ${CMAKE_CURRENT_BINARY_DIR}/src/simple_quad.vert COPYONLY)
 26-file(READ ${CMAKE_CURRENT_BINARY_DIR}/src/simple_quad.vert SHADER_SIMPLE_QUAD)
 27+configure_file(src/tab.vert ${CMAKE_CURRENT_BINARY_DIR}/src/tab.vert COPYONLY)
 28+file(READ ${CMAKE_CURRENT_BINARY_DIR}/src/tab.vert SHADER_TAB_VERT)
 29 
 30-configure_file(src/border_rect.frag ${CMAKE_CURRENT_BINARY_DIR}/src/border_rect.frag COPYONLY)
 31-file(READ ${CMAKE_CURRENT_BINARY_DIR}/src/border_rect.frag SHADER_BORDER_RECT)
 32+configure_file(src/tab.frag ${CMAKE_CURRENT_BINARY_DIR}/src/tab.frag COPYONLY)
 33+file(READ ${CMAKE_CURRENT_BINARY_DIR}/src/tab.frag SHADER_TAB_FRAG)
 34 
 35 configure_file(src/shader_content.hpp.in src/shader_content.hpp @ONLY)
 36 target_include_directories(hy3 PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
 37diff --git a/README.md b/README.md
 38index 740215e64d5f8d37b04e08f4b8c99dd85c79f23d..16b5c13bc23da36afcd14b83332e4f277df1ce27 100644
 39--- a/README.md
 40+++ b/README.md
 41@@ -280,6 +280,14 @@ plugin {
 42       col.inactive = <color> # default: rgba(30303090)
 43 	  col.border.inactive = <color> # default: rgba(505050b0)
 44       col.text.inactive = <color> # default: rgba(ffffffff)
 45+
 46+	  # if tab backgrounds should be blurred
 47+	  # Blur is only visible when the above colors are not opaque.
 48+	  blur = <bool> # default: true
 49+
 50+	  # opacity multiplier for tabs
 51+	  # Applies to blur as well as the given colors.
 52+	  opacity = <float> # default: 1.0
 53     }
 54 
 55     # autotiling settings
 56diff --git a/src/TabGroup.cpp b/src/TabGroup.cpp
 57index 01b0695e3412e75557a73933fb8a4448c3249283..c9ac3250bb2ca53b47e20fa5ca8cf5c57a87e238 100644
 58--- a/src/TabGroup.cpp
 59+++ b/src/TabGroup.cpp
 60@@ -125,6 +125,8 @@ void Hy3TabBarEntry::render(float scale, CBox& box, float opacity_mul) {
 61 	// clang-format off
 62 	static const auto s_radius = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:radius");
 63 	static const auto border_width = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:border_width");
 64+	static const auto s_opacity = ConfigValue<Hyprlang::FLOAT>("plugin:hy3:tabs:opacity");
 65+	static const auto blur = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:blur");
 66 	static const auto col_active = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.active");
 67 	static const auto col_border_active = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.border.active");
 68 	static const auto col_urgent = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.urgent");
 69@@ -157,15 +159,21 @@ void Hy3TabBarEntry::render(float scale, CBox& box, float opacity_mul) {
 70 	    CHyprColor(*col_border_inactive)
 71 	);
 72 
 73-	color.a *= opacity;
 74-	border_color.a *= opacity;
 75-
 76 	box.round();
 77 
 78 	// sometimes enabled before our renderer is called
 79 	glDisable(GL_SCISSOR_TEST);
 80 
 81-	Hy3Render::renderBorderRect(box, color, border_color, *border_width, radius);
 82+	Hy3Render::renderTab(
 83+	    box,
 84+	    opacity * *s_opacity,
 85+	    *blur,
 86+	    color,
 87+	    border_color,
 88+	    *border_width,
 89+	    radius
 90+	);
 91+
 92 	this->renderText(scale, box, opacity);
 93 }
 94 
 95diff --git a/src/main.cpp b/src/main.cpp
 96index 87c39b0b54d1058b63c55b7b2d20740b4048f009..f984a67f52f1e443505402eac659ca0e962f86fc 100644
 97--- a/src/main.cpp
 98+++ b/src/main.cpp
 99@@ -2,6 +2,7 @@
100 #include <hyprland/src/config/ConfigDataValues.hpp>
101 #include <hyprland/src/plugins/PluginAPI.hpp>
102 #include <hyprland/src/version.h>
103+#include <hyprlang.hpp>
104 
105 #include "SelectionHook.hpp"
106 #include "dispatchers.hpp"
107@@ -30,6 +31,7 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
108 #define CONF(NAME, TYPE, VALUE)                                                                    \
109 	HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:" NAME, Hyprlang::CConfigValue((TYPE) VALUE))
110 
111+	using Hyprlang::FLOAT;
112 	using Hyprlang::INT;
113 	using Hyprlang::STRING;
114 
115@@ -50,12 +52,14 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
116 	CONF("tabs:text_font", STRING, "Sans");
117 	CONF("tabs:text_height", INT, 8);
118 	CONF("tabs:text_padding", INT, 3);
119-	CONF("tabs:col.active", INT, 0xb050a0e0);
120-	CONF("tabs:col.border.active", INT, 0xb070b0c0);
121-	CONF("tabs:col.urgent", INT, 0xb0ff4f4f);
122-	CONF("tabs:col.border.urgent", INT, 0xb0ff8080);
123-	CONF("tabs:col.inactive", INT, 0x90303030);
124-	CONF("tabs:col.border.inactive", INT, 0xb0505050);
125+	CONF("tabs:opacity", FLOAT, 1.0);
126+	CONF("tabs:blur", INT, 1);
127+	CONF("tabs:col.active", INT, 0xff50a0e0);
128+	CONF("tabs:col.border.active", INT, 0xff70b0c0);
129+	CONF("tabs:col.urgent", INT, 0xffff4f4f);
130+	CONF("tabs:col.border.urgent", INT, 0xffff8080);
131+	CONF("tabs:col.inactive", INT, 0x50303030);
132+	CONF("tabs:col.border.inactive", INT, 0x90505050);
133 	CONF("tabs:col.text.active", INT, 0xff000000);
134 	CONF("tabs:col.text.urgent", INT, 0xff000000);
135 	CONF("tabs:col.text.inactive", INT, 0xffffffff);
136diff --git a/src/render.cpp b/src/render.cpp
137index db30cea440f777252aaec9e330fe6488ce46e7d3..a557a1777a65e2cac7b719f22ebe5aa1b26f2558 100644
138--- a/src/render.cpp
139+++ b/src/render.cpp
140@@ -3,26 +3,32 @@
141 #include <GLES2/gl2.h>
142 #include <hyprland/src/helpers/math/Math.hpp>
143 #include <hyprland/src/render/OpenGL.hpp>
144+#include <hyprutils/math/Vector2D.hpp>
145 
146 #include "shaders.hpp"
147 
148-void Hy3Render::renderBorderRect(
149+void Hy3Render::renderTab(
150     const CBox& box,
151+    float opacity,
152+    bool blur,
153     const CHyprColor& fillColor,
154     const CHyprColor& borderColor,
155     int borderWidth,
156     int radius
157 ) {
158-	static auto& shader = Hy3Shaders::instance()->border_rect;
159+	static auto& shader = Hy3Shaders::instance()->tab;
160 	auto& rdata = g_pHyprOpenGL->m_RenderData;
161 
162 	auto rbox = box;
163 	rdata.renderModif.applyToBox(rbox);
164 
165+	const auto& monitorSize = rdata.pMonitor->vecTransformedSize;
166+	auto monitorBox = CBox {Vector2D(), monitorSize};
167+
168 	auto matrix = rdata.monitorProjection.projectBox(
169-	    rbox,
170+	    monitorBox,
171 	    wlTransformToHyprutils(invertTransform(rdata.pMonitor->transform)),
172-	    rbox.rot
173+	    monitorBox.rot
174 	);
175 
176 	auto glMatrix = rdata.projection.copy().multiply(matrix);
177@@ -36,6 +42,18 @@ void Hy3Render::renderBorderRect(
178 	glUniformMatrix3fv(shader.proj, 1, GL_FALSE, glMatrix.getMatrix().data());
179 #endif
180 
181+	WP<CTexture> blurTex;
182+
183+	if (blur) {
184+		blurTex = rdata.pCurrentMonData->blurFB.getTexture();
185+
186+		glActiveTexture(GL_TEXTURE0);
187+		glBindTexture(blurTex->m_iTarget, blurTex->m_iTexID);
188+		glUniform1i(shader.blurTex, 0);
189+	}
190+
191+	glUniform1i(shader.applyBlur, blur);
192+
193 	// premultiplied
194 	glUniform4f(
195 	    shader.fillColor,
196@@ -55,7 +73,10 @@ void Hy3Render::renderBorderRect(
197 		);
198 	}
199 
200+	glUniform2f(shader.monitorSize, monitorSize.x, monitorSize.y);
201+	glUniform2f(shader.pixelOffset, rbox.x, rbox.y);
202 	glUniform2f(shader.pixelSize, rbox.w, rbox.h);
203+	glUniform1f(shader.opacity, opacity);
204 	glUniform1f(shader.outerRadius, radius);
205 	glUniform1f(shader.borderWidth, borderWidth);
206 
207@@ -65,4 +86,8 @@ void Hy3Render::renderBorderRect(
208 	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
209 
210 	glDisableVertexAttribArray(shader.posAttrib);
211+
212+	if (blur) {
213+		glBindTexture(blurTex->m_iTarget, 0);
214+	}
215 }
216diff --git a/src/render.hpp b/src/render.hpp
217index 6efdf1d1e27dc60163d88c4be424d1f5b0744236..f9aefe8fa4a2d5e7e2560b38c5665ddee608563e 100644
218--- a/src/render.hpp
219+++ b/src/render.hpp
220@@ -4,8 +4,10 @@
221 
222 class Hy3Render {
223 public:
224-	static void renderBorderRect(
225+	static void renderTab(
226 	    const CBox& box,
227+	    float opacity,
228+	    bool blur,
229 	    const CHyprColor& fillColor,
230 	    const CHyprColor& borderColor,
231 	    int borderWidth,
232diff --git a/src/shader_content.hpp.in b/src/shader_content.hpp.in
233index 6e242a452fe1910df06988b1c4ba869ae2418239..8d1d84ae897a9054d38584753da4cd80405bb1fe 100644
234--- a/src/shader_content.hpp.in
235+++ b/src/shader_content.hpp.in
236@@ -1,4 +1,4 @@
237 #include <string_view>
238 
239-constexpr std::string_view SHADER_SIMPLE_QUAD = R"(@SHADER_SIMPLE_QUAD@)";
240-constexpr std::string_view SHADER_BORDER_RECT_FRAG = R"(@SHADER_BORDER_RECT@)";
241+constexpr std::string_view SHADER_TAB_VERT = R"(@SHADER_TAB_VERT@)";
242+constexpr std::string_view SHADER_TAB_FRAG = R"(@SHADER_TAB_FRAG@)";
243diff --git a/src/shaders.cpp b/src/shaders.cpp
244index 88f02f407f817da6cb0608f0dcdfb676e533c059..e5e011d9a11739246c08757e43a0e7c221002f14 100644
245--- a/src/shaders.cpp
246+++ b/src/shaders.cpp
247@@ -8,19 +8,24 @@
248 
249 Hy3Shaders::Hy3Shaders() {
250 	{
251-		auto& s = this->border_rect;
252-		s.program = Hy3Shaders::createProgram(SHADER_SIMPLE_QUAD, SHADER_BORDER_RECT_FRAG);
253+		auto& s = this->tab;
254+		s.program = Hy3Shaders::createProgram(SHADER_TAB_VERT, SHADER_TAB_FRAG);
255 		s.posAttrib = glGetAttribLocation(s.program, "pos");
256 		s.proj = glGetUniformLocation(s.program, "proj");
257+		s.monitorSize = glGetUniformLocation(s.program, "monitorSize");
258+		s.pixelOffset = glGetUniformLocation(s.program, "pixelOffset");
259 		s.pixelSize = glGetUniformLocation(s.program, "pixelSize");
260+		s.applyBlur = glGetUniformLocation(s.program, "applyBlur");
261+		s.blurTex = glGetUniformLocation(s.program, "blurTex");
262+		s.opacity = glGetUniformLocation(s.program, "opacity");
263 		s.fillColor = glGetUniformLocation(s.program, "fillColor");
264 		s.borderColor = glGetUniformLocation(s.program, "borderColor");
265-		s.outerRadius = glGetUniformLocation(s.program, "outerRadius");
266 		s.borderWidth = glGetUniformLocation(s.program, "borderWidth");
267+		s.outerRadius = glGetUniformLocation(s.program, "outerRadius");
268 	}
269 }
270 
271-Hy3Shaders::~Hy3Shaders() { glDeleteProgram(this->border_rect.program); }
272+Hy3Shaders::~Hy3Shaders() { glDeleteProgram(this->tab.program); }
273 
274 Hy3Shaders* Hy3Shaders::instance() {
275 	static auto* INSTANCE = new Hy3Shaders();
276diff --git a/src/shaders.hpp b/src/shaders.hpp
277index 1fb39a003909a8f1e97bdd8f46a5d64f5db980ca..07d331b3e03c3168779403fb82c35f7c0dc8ab19 100644
278--- a/src/shaders.hpp
279+++ b/src/shaders.hpp
280@@ -11,12 +11,17 @@ public:
281 		GLuint program;
282 		GLuint posAttrib;
283 		GLint proj;
284+		GLint monitorSize;
285+		GLint pixelOffset;
286+		GLint pixelSize;
287+		GLint applyBlur;
288+		GLint blurTex;
289+		GLint opacity;
290 		GLint fillColor;
291 		GLint borderColor;
292-		GLint pixelSize;
293-		GLint outerRadius;
294 		GLint borderWidth;
295-	} border_rect;
296+		GLint outerRadius;
297+	} tab;
298 
299 	static Hy3Shaders* instance();
300 
301diff --git a/src/simple_quad.vert b/src/simple_quad.vert
302deleted file mode 100644
303index 0398200e810f607690ba2a0880851c7f8377da64..0000000000000000000000000000000000000000
304--- a/src/simple_quad.vert
305+++ /dev/null
306@@ -1,11 +0,0 @@
307-attribute highp vec2 pos;
308-attribute highp vec2 texcoord;
309-
310-uniform mat3 proj;
311-
312-varying highp vec2 v_texcoord;
313-
314-void main() {
315-	gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);
316-	v_texcoord = pos;
317-}
318diff --git a/src/border_rect.frag b/src/tab.frag
319rename from src/border_rect.frag
320rename to src/tab.frag
321index e2d6684aa8721bcb98f2a6e5f07bc11dfda2c468..49ea01ac5ef35022605afd0ef6a703fdd298aa6b 100644
322--- a/src/border_rect.frag
323+++ b/src/tab.frag
324@@ -1,15 +1,20 @@
325 precision highp float;
326-varying highp vec4 v_color;
327-varying highp vec2 v_texcoord;
328 
329+uniform highp vec2 pixelSize;
330+uniform float opacity;
331 uniform highp vec4 fillColor;
332 uniform highp vec4 borderColor;
333-uniform highp vec2 pixelSize;
334 uniform float outerRadius;
335 uniform float borderWidth;
336 
337+uniform bool applyBlur;
338+uniform sampler2D blurTex;
339+
340+varying highp vec2 pixCoord;
341+varying highp vec2 monitorTexCoord;
342+
343 void main() {
344-	highp vec2 pixCoord = v_texcoord * pixelSize;
345+	float opacityMul = opacity;
346 	highp vec2 cornerDist = min(pixCoord, pixelSize - pixCoord);
347 
348 	gl_FragColor = fillColor;
349@@ -37,7 +42,8 @@ void main() {
350 			dist = sqrt(distSq);
351 			calculatedDist = true;
352 			float normalized = 1.0 - smoothstep(0.0, 1.0, (dist - outerRadius + SMOOTHING_CONSTANT) / (SMOOTHING_CONSTANT_2X));
353-			gl_FragColor = borderColor * normalized;
354+			gl_FragColor = borderColor;
355+			opacityMul *= normalized;
356 		} else if (distSq > innerTest2 * innerTest2) {
357 			gl_FragColor = borderColor;
358 		}
359@@ -50,4 +56,10 @@ void main() {
360 	} else if (cornerDist.x <= borderWidth || cornerDist.y <= borderWidth) {
361 		gl_FragColor = borderColor;
362 	}
363+
364+	if (applyBlur && gl_FragColor.a != 1.0) {
365+		gl_FragColor = gl_FragColor + texture2D(blurTex, monitorTexCoord) * (1.0 - gl_FragColor.a);
366+	}
367+
368+	gl_FragColor *= opacityMul;
369 }
370diff --git a/src/tab.vert b/src/tab.vert
371new file mode 100644
372index 0000000000000000000000000000000000000000..4db84bf136db2133ab038b0c8beb7e2b592263a0
373--- /dev/null
374+++ b/src/tab.vert
375@@ -0,0 +1,15 @@
376+attribute highp vec2 pos;
377+
378+uniform mat3 proj;
379+uniform highp vec2 pixelOffset;
380+uniform highp vec2 pixelSize;
381+uniform highp vec2 monitorSize;
382+
383+varying highp vec2 pixCoord;
384+varying highp vec2 monitorTexCoord;
385+
386+void main() {
387+	pixCoord = pos * pixelSize;
388+	monitorTexCoord = (pixelOffset + pixCoord) / monitorSize;
389+	gl_Position = vec4(proj * vec3(monitorTexCoord, 1.0), 1.0);
390+}