checkpoint: progressing on frosted glass panels
This commit is contained in:
154
src/gui_2.py
154
src/gui_2.py
@@ -223,6 +223,7 @@ class App:
|
||||
}
|
||||
|
||||
self.shader_manager = ShaderManager()
|
||||
self.start_time = time.time()
|
||||
|
||||
def _handle_approve_tool(self, user_data=None) -> None:
|
||||
"""UI-level wrapper for approving a pending tool execution ask."""
|
||||
@@ -355,9 +356,18 @@ class App:
|
||||
def _render_frosted_background(self, pos: imgui.ImVec2, size: imgui.ImVec2) -> None:
|
||||
if not theme.get_frosted_glass_enabled(): return
|
||||
if size.x <= 0 or size.y <= 0: return
|
||||
try:
|
||||
ws = immapp.get_window_size()
|
||||
display_size = imgui.ImVec2(float(ws[0]), float(ws[1]))
|
||||
except Exception:
|
||||
display_size = imgui.get_io().display_size
|
||||
|
||||
if display_size.x <= 0 or display_size.y <= 0: return
|
||||
|
||||
uv_min = imgui.ImVec2(pos.x / display_size.x, 1.0 - pos.y / display_size.y)
|
||||
uv_max = imgui.ImVec2((pos.x + size.x) / display_size.x, 1.0 - (pos.y + size.y) / display_size.y)
|
||||
|
||||
if self.shader_manager.blur_tex:
|
||||
imgui.get_window_draw_list().add_image(
|
||||
imgui.ImTextureRef(self.shader_manager.blur_tex),
|
||||
pos,
|
||||
@@ -365,11 +375,41 @@ class App:
|
||||
uv_min,
|
||||
uv_max
|
||||
)
|
||||
else:
|
||||
# Fallback: semi-transparent rectangle to help debug visibility
|
||||
imgui.get_window_draw_list().add_rect_filled(
|
||||
pos,
|
||||
imgui.ImVec2(pos.x + size.x, pos.y + size.y),
|
||||
imgui.get_color_u32(vec4(30, 30, 40, 0.7))
|
||||
)
|
||||
|
||||
# Increase contrast with a 0.2 alpha tint overlay
|
||||
imgui.get_window_draw_list().add_rect_filled(
|
||||
pos,
|
||||
imgui.ImVec2(pos.x + size.x, pos.y + size.y),
|
||||
imgui.get_color_u32(vec4(0, 0, 0, 0.2))
|
||||
)
|
||||
|
||||
def _begin_window(self, name: str, p_open: Any = None, flags: int = 0) -> tuple[bool, Any]:
|
||||
frosted = theme.get_frosted_glass_enabled()
|
||||
if frosted:
|
||||
imgui.push_style_color(imgui.Col_.window_bg, vec4(0, 0, 0, 0))
|
||||
|
||||
expanded, opened = imgui.begin(name, p_open, flags)
|
||||
|
||||
if expanded and frosted:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
|
||||
return expanded, opened
|
||||
|
||||
def _end_window(self) -> None:
|
||||
imgui.end()
|
||||
if theme.get_frosted_glass_enabled():
|
||||
imgui.pop_style_color()
|
||||
def _render_operations_hub(self) -> None:
|
||||
exp, opened = imgui.begin("Operations Hub", self.show_windows["Operations Hub"])
|
||||
exp, opened = self._begin_window("Operations Hub", self.show_windows["Operations Hub"])
|
||||
self.show_windows["Operations Hub"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
imgui.text("Focus Agent:")
|
||||
imgui.same_line()
|
||||
focus_label = self.ui_focus_agent or "All"
|
||||
@@ -416,7 +456,7 @@ class App:
|
||||
self._render_external_tools_panel()
|
||||
imgui.end_tab_item()
|
||||
imgui.end_tab_bar()
|
||||
imgui.end()
|
||||
self._end_window()
|
||||
|
||||
def _show_menus(self) -> None:
|
||||
if imgui.begin_menu("manual slop"):
|
||||
@@ -520,7 +560,7 @@ class App:
|
||||
|
||||
imgui.separator()
|
||||
imgui.text("Frosted Glass")
|
||||
changed_fbr, self.shader_uniforms['frosted_blur_radius'] = imgui.slider_float('Blur Radius', self.shader_uniforms['frosted_blur_radius'], 0.0, 32.0)
|
||||
changed_fbr, self.shader_uniforms['frosted_blur_radius'] = imgui.slider_float('Blur Radius', self.shader_uniforms['frosted_blur_radius'], 0.0, 64.0)
|
||||
if changed_fbr: theme.set_frosted_blur_radius(self.shader_uniforms['frosted_blur_radius'])
|
||||
|
||||
changed_fti, self.shader_uniforms['frosted_tint_intensity'] = imgui.slider_float('Tint Intensity', self.shader_uniforms['frosted_tint_intensity'], 0.0, 1.0)
|
||||
@@ -534,12 +574,31 @@ class App:
|
||||
self._render_custom_title_bar()
|
||||
self._render_shader_live_editor()
|
||||
pushed_prior_tint = False
|
||||
pushed_frosted_style = False
|
||||
|
||||
# Render background shader
|
||||
bg = bg_shader.get_bg()
|
||||
if bg.enabled:
|
||||
frosted_enabled = theme.get_frosted_glass_enabled()
|
||||
if bg.enabled and not frosted_enabled:
|
||||
ws = imgui.get_io().display_size
|
||||
bg.render(ws.x, ws.y)
|
||||
|
||||
if frosted_enabled:
|
||||
ws = imgui.get_io().display_size
|
||||
self.shader_manager.prepare_global_blur(
|
||||
int(ws.x), int(ws.y),
|
||||
self.shader_uniforms['frosted_blur_radius'],
|
||||
self.shader_uniforms['frosted_tint_intensity'],
|
||||
self.shader_uniforms['frosted_opacity'],
|
||||
time.time()
|
||||
)
|
||||
# Draw background texture
|
||||
dl = imgui.get_background_draw_list()
|
||||
dl.add_image(imgui.ImTextureRef(self.shader_manager.scene_tex), (0, 0), (ws.x, ws.y))
|
||||
|
||||
imgui.push_style_color(imgui.Col_.window_bg, vec4(0, 0, 0, 0))
|
||||
pushed_frosted_style = True
|
||||
|
||||
if theme.is_nerv_active():
|
||||
ws = imgui.get_io().display_size
|
||||
self._nerv_alert.update(self.ai_status)
|
||||
@@ -547,14 +606,6 @@ class App:
|
||||
self._nerv_crt.enabled = self.ui_crt_filter
|
||||
self._nerv_crt.render(ws.x, ws.y)
|
||||
|
||||
if theme.get_frosted_glass_enabled():
|
||||
ws = imgui.get_io().display_size
|
||||
self.shader_manager.prepare_global_blur(
|
||||
int(ws.x), int(ws.y),
|
||||
self.shader_uniforms['frosted_blur_radius'],
|
||||
self.shader_uniforms['frosted_tint_intensity'],
|
||||
self.shader_uniforms['frosted_opacity']
|
||||
)
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_gui_func")
|
||||
if self.is_viewing_prior_session:
|
||||
imgui.push_style_color(imgui.Col_.window_bg, vec4(50, 40, 20))
|
||||
@@ -627,10 +678,9 @@ class App:
|
||||
self._tool_log_dirty = False
|
||||
|
||||
if self.show_windows.get("Context Hub", False):
|
||||
exp, opened = imgui.begin("Context Hub", self.show_windows["Context Hub"])
|
||||
exp, opened = self._begin_window("Context Hub", self.show_windows["Context Hub"])
|
||||
self.show_windows["Context Hub"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
if imgui.begin_tab_bar('context_hub_tabs'):
|
||||
if imgui.begin_tab_item('Projects')[0]:
|
||||
self._render_projects_panel()
|
||||
@@ -639,22 +689,20 @@ class App:
|
||||
self._render_paths_panel()
|
||||
imgui.end_tab_item()
|
||||
imgui.end_tab_bar()
|
||||
imgui.end()
|
||||
self._end_window()
|
||||
if self.show_windows.get("Files & Media", False):
|
||||
exp, opened = imgui.begin("Files & Media", self.show_windows["Files & Media"])
|
||||
exp, opened = self._begin_window("Files & Media", self.show_windows["Files & Media"])
|
||||
self.show_windows["Files & Media"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
if imgui.collapsing_header("Files"):
|
||||
self._render_files_panel()
|
||||
if imgui.collapsing_header("Screenshots"):
|
||||
self._render_screenshots_panel()
|
||||
imgui.end()
|
||||
self._end_window()
|
||||
if self.show_windows.get("AI Settings", False):
|
||||
exp, opened = imgui.begin("AI Settings", self.show_windows["AI Settings"])
|
||||
exp, opened = self._begin_window("AI Settings", self.show_windows["AI Settings"])
|
||||
self.show_windows["AI Settings"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_persona_selector_panel()
|
||||
if imgui.collapsing_header("Provider & Model"):
|
||||
self._render_provider_panel()
|
||||
@@ -662,66 +710,58 @@ class App:
|
||||
self._render_system_prompts_panel()
|
||||
self._render_agent_tools_panel()
|
||||
|
||||
imgui.end()
|
||||
self._end_window()
|
||||
if self.ui_separate_usage_analytics and self.show_windows.get("Usage Analytics", False):
|
||||
exp, opened = imgui.begin("Usage Analytics", self.show_windows["Usage Analytics"])
|
||||
exp, opened = self._begin_window("Usage Analytics", self.show_windows["Usage Analytics"])
|
||||
self.show_windows["Usage Analytics"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_usage_analytics_panel()
|
||||
imgui.end()
|
||||
self._end_window()
|
||||
if self.show_windows.get("MMA Dashboard", False):
|
||||
exp, opened = imgui.begin("MMA Dashboard", self.show_windows["MMA Dashboard"])
|
||||
exp, opened = self._begin_window("MMA Dashboard", self.show_windows["MMA Dashboard"])
|
||||
self.show_windows["MMA Dashboard"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_mma_dashboard")
|
||||
self._render_mma_dashboard()
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_mma_dashboard")
|
||||
imgui.end()
|
||||
self._end_window()
|
||||
|
||||
if self.ui_separate_task_dag and self.show_windows.get("Task DAG", False):
|
||||
exp, opened = imgui.begin("Task DAG", self.show_windows["Task DAG"])
|
||||
exp, opened = self._begin_window("Task DAG", self.show_windows["Task DAG"])
|
||||
self.show_windows["Task DAG"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_task_dag_panel()
|
||||
imgui.end()
|
||||
self._end_window()
|
||||
if self.ui_separate_tier1 and self.show_windows.get("Tier 1: Strategy", False):
|
||||
exp, opened = imgui.begin("Tier 1: Strategy", self.show_windows["Tier 1: Strategy"])
|
||||
exp, opened = self._begin_window("Tier 1: Strategy", self.show_windows["Tier 1: Strategy"])
|
||||
self.show_windows["Tier 1: Strategy"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_tier_stream_panel("Tier 1", "Tier 1")
|
||||
imgui.end()
|
||||
self._end_window()
|
||||
if self.ui_separate_tier2 and self.show_windows.get("Tier 2: Tech Lead", False):
|
||||
exp, opened = imgui.begin("Tier 2: Tech Lead", self.show_windows["Tier 2: Tech Lead"])
|
||||
exp, opened = self._begin_window("Tier 2: Tech Lead", self.show_windows["Tier 2: Tech Lead"])
|
||||
self.show_windows["Tier 2: Tech Lead"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_tier_stream_panel("Tier 2", "Tier 2 (Tech Lead)")
|
||||
imgui.end()
|
||||
self._end_window()
|
||||
if self.ui_separate_tier3 and self.show_windows.get("Tier 3: Workers", False):
|
||||
exp, opened = imgui.begin("Tier 3: Workers", self.show_windows["Tier 3: Workers"])
|
||||
exp, opened = self._begin_window("Tier 3: Workers", self.show_windows["Tier 3: Workers"])
|
||||
self.show_windows["Tier 3: Workers"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_tier_stream_panel("Tier 3", None)
|
||||
imgui.end()
|
||||
self._end_window()
|
||||
if self.ui_separate_tier4 and self.show_windows.get("Tier 4: QA", False):
|
||||
exp, opened = imgui.begin("Tier 4: QA", self.show_windows["Tier 4: QA"])
|
||||
exp, opened = self._begin_window("Tier 4: QA", self.show_windows["Tier 4: QA"])
|
||||
self.show_windows["Tier 4: QA"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_tier_stream_panel("Tier 4", "Tier 4 (QA)")
|
||||
imgui.end()
|
||||
self._end_window()
|
||||
if self.show_windows.get("Theme", False):
|
||||
self._render_theme_panel()
|
||||
if self.show_windows.get("Discussion Hub", False):
|
||||
exp, opened = imgui.begin("Discussion Hub", self.show_windows["Discussion Hub"])
|
||||
exp, opened = self._begin_window("Discussion Hub", self.show_windows["Discussion Hub"])
|
||||
self.show_windows["Discussion Hub"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
# Top part for the history
|
||||
imgui.begin_child("HistoryChild", size=(0, -self.ui_discussion_split_h))
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_discussion_panel")
|
||||
@@ -766,41 +806,37 @@ class App:
|
||||
else:
|
||||
imgui.text_disabled("Message & Response panels are detached.")
|
||||
|
||||
imgui.end()
|
||||
self._end_window()
|
||||
if self.show_windows.get("Operations Hub", False):
|
||||
self._render_operations_hub()
|
||||
|
||||
if self.ui_separate_message_panel and self.show_windows.get("Message", False):
|
||||
exp, opened = imgui.begin("Message", self.show_windows["Message"])
|
||||
exp, opened = self._begin_window("Message", self.show_windows["Message"])
|
||||
self.show_windows["Message"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_message_panel()
|
||||
imgui.end()
|
||||
self._end_window()
|
||||
|
||||
if self.ui_separate_response_panel and self.show_windows.get("Response", False):
|
||||
exp, opened = imgui.begin("Response", self.show_windows["Response"])
|
||||
exp, opened = self._begin_window("Response", self.show_windows["Response"])
|
||||
self.show_windows["Response"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_response_panel()
|
||||
imgui.end()
|
||||
self._end_window()
|
||||
|
||||
if self.ui_separate_tool_calls_panel and self.show_windows.get("Tool Calls", False):
|
||||
exp, opened = imgui.begin("Tool Calls", self.show_windows["Tool Calls"])
|
||||
exp, opened = self._begin_window("Tool Calls", self.show_windows["Tool Calls"])
|
||||
self.show_windows["Tool Calls"] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_tool_calls_panel()
|
||||
imgui.end()
|
||||
self._end_window()
|
||||
|
||||
if self.ui_separate_external_tools and self.show_windows.get('External Tools', False):
|
||||
exp, opened = imgui.begin('External Tools', self.show_windows['External Tools'])
|
||||
exp, opened = self._begin_window('External Tools', self.show_windows['External Tools'])
|
||||
self.show_windows['External Tools'] = bool(opened)
|
||||
if exp:
|
||||
self._render_frosted_background(imgui.get_window_pos(), imgui.get_window_size())
|
||||
self._render_external_tools_panel()
|
||||
imgui.end()
|
||||
self._end_window()
|
||||
|
||||
if self.show_windows.get("Log Management", False):
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_log_management")
|
||||
@@ -1083,6 +1119,8 @@ class App:
|
||||
|
||||
if pushed_prior_tint:
|
||||
imgui.pop_style_color()
|
||||
if pushed_frosted_style:
|
||||
imgui.pop_style_color()
|
||||
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_gui_func")
|
||||
|
||||
|
||||
@@ -5,10 +5,14 @@ class ShaderManager:
|
||||
self.program = None
|
||||
self.bg_program = None
|
||||
self.pp_program = None
|
||||
self.blur_program = None
|
||||
self.blur_h_program = None
|
||||
self.blur_v_program = None
|
||||
self.blur_fbo = None
|
||||
self.scene_fbo = None
|
||||
self.temp_fbo = None
|
||||
self.scene_tex = None
|
||||
self.blur_tex = None
|
||||
self.temp_tex = None
|
||||
self.fbo_width = 0
|
||||
self.fbo_height = 0
|
||||
self._vao = None
|
||||
@@ -16,6 +20,11 @@ class ShaderManager:
|
||||
def _ensure_vao(self):
|
||||
if self._vao is None:
|
||||
try:
|
||||
import sys
|
||||
if sys.platform == "win32":
|
||||
self._vao = gl.glGenVertexArrays(1)
|
||||
else:
|
||||
# Some non-win32 environments might not support VAOs or need different handling
|
||||
self._vao = gl.glGenVertexArrays(1)
|
||||
except Exception:
|
||||
pass
|
||||
@@ -25,36 +34,73 @@ class ShaderManager:
|
||||
def setup_capture_fbo(self, width, height):
|
||||
if self.blur_fbo is not None:
|
||||
gl.glDeleteFramebuffers(1, [self.blur_fbo])
|
||||
if self.scene_fbo is not None:
|
||||
gl.glDeleteFramebuffers(1, [self.scene_fbo])
|
||||
if self.temp_fbo is not None:
|
||||
gl.glDeleteFramebuffers(1, [self.temp_fbo])
|
||||
if self.scene_tex is not None:
|
||||
gl.glDeleteTextures(1, [self.scene_tex])
|
||||
if self.blur_tex is not None:
|
||||
gl.glDeleteTextures(1, [self.blur_tex])
|
||||
self.blur_fbo = gl.glGenFramebuffers(1)
|
||||
if self.temp_tex is not None:
|
||||
gl.glDeleteTextures(1, [self.temp_tex])
|
||||
|
||||
self.scene_tex = gl.glGenTextures(1)
|
||||
gl.glBindTexture(gl.GL_TEXTURE_2D, self.scene_tex)
|
||||
gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, width, height, 0, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, None)
|
||||
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR)
|
||||
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR)
|
||||
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP_TO_EDGE)
|
||||
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP_TO_EDGE)
|
||||
|
||||
self.scene_fbo = gl.glGenFramebuffers(1)
|
||||
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.scene_fbo)
|
||||
gl.glFramebufferTexture2D(gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_TEXTURE_2D, self.scene_tex, 0)
|
||||
if gl.glCheckFramebufferStatus(gl.GL_FRAMEBUFFER) != gl.GL_FRAMEBUFFER_COMPLETE:
|
||||
raise RuntimeError("Scene Framebuffer not complete")
|
||||
|
||||
self.temp_tex = gl.glGenTextures(1)
|
||||
gl.glBindTexture(gl.GL_TEXTURE_2D, self.temp_tex)
|
||||
gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, width, height, 0, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, None)
|
||||
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR)
|
||||
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR)
|
||||
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP_TO_EDGE)
|
||||
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP_TO_EDGE)
|
||||
|
||||
self.temp_fbo = gl.glGenFramebuffers(1)
|
||||
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.temp_fbo)
|
||||
gl.glFramebufferTexture2D(gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_TEXTURE_2D, self.temp_tex, 0)
|
||||
if gl.glCheckFramebufferStatus(gl.GL_FRAMEBUFFER) != gl.GL_FRAMEBUFFER_COMPLETE:
|
||||
raise RuntimeError("Temp Framebuffer not complete")
|
||||
|
||||
self.blur_tex = gl.glGenTextures(1)
|
||||
gl.glBindTexture(gl.GL_TEXTURE_2D, self.blur_tex)
|
||||
gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, width, height, 0, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, None)
|
||||
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR)
|
||||
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR)
|
||||
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP_TO_EDGE)
|
||||
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP_TO_EDGE)
|
||||
|
||||
self.blur_fbo = gl.glGenFramebuffers(1)
|
||||
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.blur_fbo)
|
||||
gl.glFramebufferTexture2D(gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_TEXTURE_2D, self.blur_tex, 0)
|
||||
if gl.glCheckFramebufferStatus(gl.GL_FRAMEBUFFER) != gl.GL_FRAMEBUFFER_COMPLETE:
|
||||
raise RuntimeError("Framebuffer not complete")
|
||||
raise RuntimeError("Blur Framebuffer not complete")
|
||||
|
||||
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0)
|
||||
self.fbo_width = width
|
||||
self.fbo_height = height
|
||||
|
||||
def prepare_global_blur(self, width, height, radius, tint, opacity):
|
||||
if self.blur_fbo is None or self.fbo_width != width or self.fbo_height != height:
|
||||
def render_background_to_fbo(self, width, height, time):
|
||||
if self.scene_fbo is None or self.fbo_width != width or self.fbo_height != height:
|
||||
self.setup_capture_fbo(width, height)
|
||||
gl.glBindTexture(gl.GL_TEXTURE_2D, self.scene_tex)
|
||||
gl.glCopyTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, 0, 0, width, height, 0)
|
||||
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.blur_fbo)
|
||||
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.scene_fbo)
|
||||
gl.glViewport(0, 0, width, height)
|
||||
self.render_background(width, height, time)
|
||||
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0)
|
||||
|
||||
def prepare_global_blur(self, width, height, radius, tint, opacity, time):
|
||||
self.render_background_to_fbo(width, height, time)
|
||||
self.render_blur(self.scene_tex, width, height, radius, tint, opacity)
|
||||
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0)
|
||||
|
||||
@@ -140,9 +186,44 @@ void main() {
|
||||
uniform float u_time;
|
||||
uniform vec2 u_resolution;
|
||||
out vec4 FragColor;
|
||||
|
||||
float hash(vec2 p) {
|
||||
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
|
||||
}
|
||||
|
||||
float noise(vec2 p) {
|
||||
vec2 i = floor(p);
|
||||
vec2 f = fract(p);
|
||||
vec2 u = f * f * (3.0 - 2.0 * f);
|
||||
return mix(mix(hash(i + vec2(0.0, 0.0)), hash(i + vec2(1.0, 0.0)), u.x),
|
||||
mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), u.x), u.y);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 uv = gl_FragCoord.xy / u_resolution.xy;
|
||||
vec3 col = 0.5 + 0.5 * cos(u_time + uv.xyx + vec3(0, 2, 4));
|
||||
vec2 p = uv * 2.0 - 1.0;
|
||||
p.x *= u_resolution.x / u_resolution.y;
|
||||
|
||||
// Deep sea background gradient (dark blue)
|
||||
vec3 col = mix(vec3(0.01, 0.03, 0.08), vec3(0.0, 0.08, 0.15), uv.y);
|
||||
|
||||
// Moving blobs / caustics
|
||||
float n = 0.0;
|
||||
float t = u_time * 0.15;
|
||||
n += noise(p * 1.2 + vec2(t * 0.8, t * 0.5)) * 0.4;
|
||||
n += noise(p * 2.5 - vec2(t * 0.4, t * 0.9)) * 0.2;
|
||||
|
||||
col += vec3(0.05, 0.12, 0.22) * n;
|
||||
|
||||
// Bright highlights (caustics approximation)
|
||||
float c = 0.0;
|
||||
for(int i=0; i<3; i++) {
|
||||
vec2 p2 = p * (float(i) + 1.0) * 0.4;
|
||||
p2 += vec2(sin(t + p2.y * 1.5), cos(t + p2.x * 1.5));
|
||||
c += abs(0.015 / (length(p2) - 0.4));
|
||||
}
|
||||
col += vec3(0.1, 0.25, 0.45) * c * 0.12;
|
||||
|
||||
FragColor = vec4(col, 1.0);
|
||||
}
|
||||
"""
|
||||
@@ -236,56 +317,88 @@ void main() {
|
||||
v_uv = uvs[gl_VertexID];
|
||||
}
|
||||
"""
|
||||
fragment_src = """
|
||||
fragment_src_h = """
|
||||
#version 330 core
|
||||
in vec2 v_uv;
|
||||
uniform sampler2D u_texture;
|
||||
uniform float u_blur_radius;
|
||||
uniform vec2 u_direction;
|
||||
out vec4 FragColor;
|
||||
void main() {
|
||||
float weight[5] = float[](0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216);
|
||||
vec2 res = vec2(textureSize(u_texture, 0));
|
||||
vec2 tex_offset = (u_blur_radius / res) * u_direction * 2.5; // Multiplied by 2.5 for milky effect
|
||||
vec4 result = texture(u_texture, v_uv) * weight[0];
|
||||
for(int i = 1; i < 5; ++i) {
|
||||
result += texture(u_texture, v_uv + tex_offset * float(i)) * weight[i];
|
||||
result += texture(u_texture, v_uv - tex_offset * float(i)) * weight[i];
|
||||
}
|
||||
FragColor = result;
|
||||
}
|
||||
"""
|
||||
fragment_src_v = """
|
||||
#version 330 core
|
||||
in vec2 v_uv;
|
||||
uniform sampler2D u_texture;
|
||||
uniform float u_blur_radius;
|
||||
uniform vec2 u_direction;
|
||||
uniform float u_tint_intensity;
|
||||
uniform float u_opacity;
|
||||
out vec4 FragColor;
|
||||
void main() {
|
||||
float weight[5] = float[](0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216);
|
||||
vec2 res = vec2(textureSize(u_texture, 0));
|
||||
vec2 offset = u_blur_radius / res;
|
||||
vec4 sum = vec4(0.0);
|
||||
sum += texture(u_texture, v_uv) * 0.1839;
|
||||
sum += texture(u_texture, v_uv + vec2(offset.x, 0.0)) * 0.1114;
|
||||
sum += texture(u_texture, v_uv + vec2(-offset.x, 0.0)) * 0.1114;
|
||||
sum += texture(u_texture, v_uv + vec2(0.0, offset.y)) * 0.1114;
|
||||
sum += texture(u_texture, v_uv + vec2(0.0, -offset.y)) * 0.1114;
|
||||
sum += texture(u_texture, v_uv + vec2(offset.x, offset.y)) * 0.0677;
|
||||
sum += texture(u_texture, v_uv + vec2(-offset.x, offset.y)) * 0.0677;
|
||||
sum += texture(u_texture, v_uv + vec2(offset.x, -offset.y)) * 0.0677;
|
||||
sum += texture(u_texture, v_uv + vec2(-offset.x, -offset.y)) * 0.0677;
|
||||
sum += texture(u_texture, v_uv + vec2(offset.x * 2.0, 0.0)) * 0.0248;
|
||||
sum += texture(u_texture, v_uv + vec2(-offset.x * 2.0, 0.0)) * 0.0248;
|
||||
sum += texture(u_texture, v_uv + vec2(0.0, offset.y * 2.0)) * 0.0248;
|
||||
sum += texture(u_texture, v_uv + vec2(0.0, -offset.y * 2.0)) * 0.0248;
|
||||
vec3 tinted = mix(sum.rgb, vec3(1.0), u_tint_intensity);
|
||||
FragColor = vec4(tinted, sum.a * u_opacity);
|
||||
vec2 tex_offset = (u_blur_radius / res) * u_direction * 2.5; // Multiplied by 2.5 for milky effect
|
||||
vec4 result = texture(u_texture, v_uv) * weight[0];
|
||||
for(int i = 1; i < 5; ++i) {
|
||||
result += texture(u_texture, v_uv + tex_offset * float(i)) * weight[i];
|
||||
result += texture(u_texture, v_uv - tex_offset * float(i)) * weight[i];
|
||||
}
|
||||
vec3 tint_color = vec3(0.05, 0.07, 0.12); // Slightly deeper tint
|
||||
vec3 tinted = mix(result.rgb, tint_color, u_tint_intensity);
|
||||
FragColor = vec4(tinted, result.a * u_opacity);
|
||||
}
|
||||
"""
|
||||
self.blur_program = self.compile_shader(vertex_src, fragment_src)
|
||||
self.blur_h_program = self.compile_shader(vertex_src, fragment_src_h)
|
||||
self.blur_v_program = self.compile_shader(vertex_src, fragment_src_v)
|
||||
|
||||
def render_blur(self, texture_id, width, height, radius, tint, opacity):
|
||||
if not self.blur_program:
|
||||
if not self.blur_h_program or not self.blur_v_program:
|
||||
return
|
||||
gl.glUseProgram(self.blur_program)
|
||||
|
||||
self._ensure_vao()
|
||||
|
||||
# Pass 1: Horizontal blur to temp_fbo
|
||||
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.temp_fbo)
|
||||
gl.glViewport(0, 0, width, height)
|
||||
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
|
||||
|
||||
gl.glUseProgram(self.blur_h_program)
|
||||
gl.glActiveTexture(gl.GL_TEXTURE0)
|
||||
gl.glBindTexture(gl.GL_TEXTURE_2D, texture_id)
|
||||
u_tex_loc = gl.glGetUniformLocation(self.blur_program, "u_texture")
|
||||
if u_tex_loc != -1:
|
||||
gl.glUniform1i(u_tex_loc, 0)
|
||||
u_radius_loc = gl.glGetUniformLocation(self.blur_program, "u_blur_radius")
|
||||
if u_radius_loc != -1:
|
||||
gl.glUniform1f(u_radius_loc, float(radius))
|
||||
u_tint_loc = gl.glGetUniformLocation(self.blur_program, "u_tint_intensity")
|
||||
if u_tint_loc != -1:
|
||||
gl.glUniform1f(u_tint_loc, float(tint))
|
||||
u_opacity_loc = gl.glGetUniformLocation(self.blur_program, "u_opacity")
|
||||
if u_opacity_loc != -1:
|
||||
gl.glUniform1f(u_opacity_loc, float(opacity))
|
||||
self._ensure_vao()
|
||||
|
||||
gl.glUniform1i(gl.glGetUniformLocation(self.blur_h_program, "u_texture"), 0)
|
||||
gl.glUniform1f(gl.glGetUniformLocation(self.blur_h_program, "u_blur_radius"), float(radius))
|
||||
gl.glUniform2f(gl.glGetUniformLocation(self.blur_h_program, "u_direction"), 1.0, 0.0)
|
||||
|
||||
gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 4)
|
||||
|
||||
# Pass 2: Vertical blur to blur_fbo
|
||||
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.blur_fbo)
|
||||
gl.glViewport(0, 0, width, height)
|
||||
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
|
||||
|
||||
gl.glUseProgram(self.blur_v_program)
|
||||
gl.glActiveTexture(gl.GL_TEXTURE0)
|
||||
gl.glBindTexture(gl.GL_TEXTURE_2D, self.temp_tex)
|
||||
|
||||
gl.glUniform1i(gl.glGetUniformLocation(self.blur_v_program, "u_texture"), 0)
|
||||
gl.glUniform1f(gl.glGetUniformLocation(self.blur_v_program, "u_blur_radius"), float(radius))
|
||||
gl.glUniform2f(gl.glGetUniformLocation(self.blur_v_program, "u_direction"), 0.0, 1.0)
|
||||
gl.glUniform1f(gl.glGetUniformLocation(self.blur_v_program, "u_tint_intensity"), float(tint))
|
||||
gl.glUniform1f(gl.glGetUniformLocation(self.blur_v_program, "u_opacity"), float(opacity))
|
||||
|
||||
gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 4)
|
||||
|
||||
gl.glBindTexture(gl.GL_TEXTURE_2D, 0)
|
||||
gl.glUseProgram(0)
|
||||
|
||||
@@ -4,8 +4,8 @@ import OpenGL.GL as gl
|
||||
|
||||
def test_shader_manager_fbo_initialization():
|
||||
with patch("src.shader_manager.gl") as mock_gl:
|
||||
mock_gl.glGenFramebuffers.return_value = 1
|
||||
mock_gl.glGenTextures.return_value = 2
|
||||
mock_gl.glGenFramebuffers.side_effect = [1, 2]
|
||||
mock_gl.glGenTextures.side_effect = [3, 4]
|
||||
mock_gl.glCheckFramebufferStatus.return_value = mock_gl.GL_FRAMEBUFFER_COMPLETE
|
||||
|
||||
from src.shader_manager import ShaderManager
|
||||
@@ -13,15 +13,19 @@ def test_shader_manager_fbo_initialization():
|
||||
|
||||
manager.setup_capture_fbo(800, 600)
|
||||
|
||||
assert manager.capture_fbo == 1
|
||||
assert manager.capture_tex == 2
|
||||
assert mock_gl.glGenFramebuffers.called
|
||||
assert mock_gl.glGenTextures.called
|
||||
assert mock_gl.glCheckFramebufferStatus.called
|
||||
assert manager.scene_fbo == 1
|
||||
assert manager.blur_fbo == 2
|
||||
assert manager.scene_tex == 3
|
||||
assert manager.blur_tex == 4
|
||||
assert mock_gl.glGenFramebuffers.call_count == 2
|
||||
assert mock_gl.glGenTextures.call_count == 2
|
||||
assert mock_gl.glCheckFramebufferStatus.call_count == 2
|
||||
|
||||
def test_shader_manager_capture_lifecycle():
|
||||
with patch("src.shader_manager.gl") as mock_gl:
|
||||
mock_gl.glCheckFramebufferStatus.return_value = mock_gl.GL_FRAMEBUFFER_COMPLETE
|
||||
mock_gl.glGenFramebuffers.side_effect = [1, 2]
|
||||
mock_gl.glGenTextures.side_effect = [3, 4]
|
||||
from src.shader_manager import ShaderManager
|
||||
manager = ShaderManager()
|
||||
|
||||
@@ -29,7 +33,8 @@ def test_shader_manager_capture_lifecycle():
|
||||
manager.capture_begin(1024, 768)
|
||||
assert manager.fbo_width == 1024
|
||||
assert manager.fbo_height == 768
|
||||
assert mock_gl.glBindFramebuffer.called
|
||||
# Should bind the blur FBO
|
||||
mock_gl.glBindFramebuffer.assert_any_call(mock_gl.GL_FRAMEBUFFER, manager.blur_fbo)
|
||||
|
||||
mock_gl.glBindFramebuffer.reset_mock()
|
||||
manager.capture_end()
|
||||
|
||||
@@ -1,28 +1,89 @@
|
||||
import pytest
|
||||
import time
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
def test_gui_frosted_background_call():
|
||||
# Mock ShaderManager and OpenGL functions
|
||||
with patch("src.gui_2.ShaderManager") as mock_sm_class, \
|
||||
patch("src.gui_2.gl") as mock_gl, \
|
||||
patch("src.gui_2.imgui") as mock_imgui:
|
||||
patch("src.gui_2.imgui") as mock_imgui, \
|
||||
patch("src.gui_2.theme") as mock_theme:
|
||||
|
||||
mock_sm = mock_sm_class.return_value
|
||||
mock_sm.fbo_width = 0
|
||||
mock_sm.fbo_height = 0
|
||||
mock_sm.capture_tex = 1
|
||||
mock_sm.blur_tex = 2
|
||||
mock_theme.get_frosted_glass_enabled.return_value = True
|
||||
|
||||
mock_imgui.get_io().display_size = MagicMock(x=1920, y=1080)
|
||||
|
||||
from src.gui_2 import App
|
||||
with patch.object(App, '__init__', return_value=None):
|
||||
app = App()
|
||||
app.shader_manager = mock_sm
|
||||
|
||||
# Simulate frame
|
||||
app._render_frosted_background(pos=MagicMock(x=10, y=10), size=MagicMock(x=100, y=100))
|
||||
|
||||
assert mock_sm.setup_capture_fbo.called
|
||||
assert mock_gl.glCopyTexImage2D.called
|
||||
assert mock_sm.render_blur.called
|
||||
assert mock_sm.capture_begin.called
|
||||
assert mock_sm.capture_end.called
|
||||
# Now it should only call add_image
|
||||
assert mock_imgui.get_window_draw_list().add_image.called
|
||||
# It no longer calls these
|
||||
assert not mock_sm.setup_capture_fbo.called
|
||||
assert not mock_sm.render_blur.called
|
||||
assert not mock_sm.capture_begin.called
|
||||
assert not mock_sm.capture_end.called
|
||||
|
||||
def test_gui_global_blur_call():
|
||||
with patch("src.gui_2.ShaderManager") as mock_sm_class, \
|
||||
patch("src.gui_2.imgui") as mock_imgui, \
|
||||
patch("src.gui_2.theme") as mock_theme, \
|
||||
patch("src.gui_2.bg_shader") as mock_bg:
|
||||
|
||||
mock_sm = mock_sm_class.return_value
|
||||
mock_theme.get_frosted_glass_enabled.return_value = True
|
||||
mock_theme.is_nerv_active.return_value = False
|
||||
mock_imgui.get_io().display_size = MagicMock(x=1920, y=1080)
|
||||
mock_bg.get_bg.return_value = MagicMock(enabled=False)
|
||||
|
||||
from src.gui_2 import App
|
||||
with patch.object(App, '__init__', return_value=None):
|
||||
app = App()
|
||||
app.shader_manager = mock_sm
|
||||
app.shader_uniforms = {
|
||||
'frosted_blur_radius': 10.0,
|
||||
'frosted_tint_intensity': 0.5,
|
||||
'frosted_opacity': 0.8
|
||||
}
|
||||
app.ai_status = "idle"
|
||||
app.ui_crt_filter = False
|
||||
app.controller = MagicMock()
|
||||
app.perf_profiling_enabled = False
|
||||
app.is_viewing_prior_session = False
|
||||
app.config = {}
|
||||
app.project = {}
|
||||
app.show_windows = {}
|
||||
app.ui_auto_scroll_comms = False
|
||||
app._comms_log_dirty = False
|
||||
app._tool_log_dirty = False
|
||||
app._pending_comms_lock = MagicMock()
|
||||
app._pending_comms = []
|
||||
app.ui_focus_agent = None
|
||||
app._last_ui_focus_agent = None
|
||||
app.perf_monitor = MagicMock()
|
||||
app._process_pending_gui_tasks = MagicMock()
|
||||
app._process_pending_history_adds = MagicMock()
|
||||
app._render_track_proposal_modal = MagicMock()
|
||||
app._render_patch_modal = MagicMock()
|
||||
app._render_save_preset_modal = MagicMock()
|
||||
app._render_preset_manager_window = MagicMock()
|
||||
app._render_tool_preset_manager_window = MagicMock()
|
||||
app._render_persona_editor_window = MagicMock()
|
||||
app._last_autosave = time.time()
|
||||
app._autosave_interval = 60
|
||||
app._render_custom_title_bar = MagicMock()
|
||||
app._render_shader_live_editor = MagicMock()
|
||||
|
||||
try:
|
||||
app._gui_func()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
assert mock_sm.prepare_global_blur.called
|
||||
|
||||
Reference in New Issue
Block a user