use super::utils::WlSurfaceExt; use crate::{ core::{delta::Delta, destroy_queue, registry::Registry}, nodes::{ drawable::{ model::{MaterialWrapper, ModelPart}, shaders::PANEL_SHADER_BYTES, }, items::camera::TexWrapper, }, }; use once_cell::sync::OnceCell; use parking_lot::Mutex; use send_wrapper::SendWrapper; use smithay::{ backend::renderer::{ gles::{GlesRenderer, GlesTexture}, utils::{import_surface_tree, RendererSurfaceStateUserData}, Renderer, Texture, }, desktop::utils::send_frames_surface_tree, output::Output, reexports::wayland_server::{self, protocol::wl_surface::WlSurface, Resource}, }; use std::{ffi::c_void, sync::Arc, time::Duration}; use stereokit_rust::{ material::{Material, Transparency}, shader::Shader, tex::{Tex, TexAddress, TexFormat, TexSample, TexType}, util::Time, }; pub static CORE_SURFACES: Registry = Registry::new(); pub struct CoreSurfaceData { wl_tex: Option>, } impl Drop for CoreSurfaceData { fn drop(&mut self) { destroy_queue::add(self.wl_tex.take()); } } pub struct CoreSurface { pub weak_surface: wayland_server::Weak, mapped_data: Mutex>, sk_tex: OnceCell>, sk_mat: OnceCell>, material_offset: Mutex>, pub pending_material_applications: Registry, } impl CoreSurface { pub fn add_to(surface: &WlSurface) { let core_surface = CORE_SURFACES.add(CoreSurface { weak_surface: surface.downgrade(), mapped_data: Mutex::new(None), sk_tex: OnceCell::new(), sk_mat: OnceCell::new(), material_offset: Mutex::new(Delta::new(0)), pending_material_applications: Registry::new(), }); surface.insert_data(core_surface); } pub fn from_wl_surface(surf: &WlSurface) -> Option> { surf.get_data() } pub fn process(&self, renderer: &mut GlesRenderer) { let Some(wl_surface) = self.wl_surface() else { return; }; let sk_tex = self.sk_tex.get_or_init(|| { Mutex::new(TexWrapper(Tex::new( TexType::ImageNomips, TexFormat::RGBA32Linear, nanoid::nanoid!(), ))) }); self.sk_mat.get_or_init(|| { let shader = Shader::from_memory(PANEL_SHADER_BYTES).unwrap(); // let _ = renderer.with_context(|c| unsafe { // shader_inject(c, &mut shader, SIMULA_VERT_STR, SIMULA_FRAG_STR) // }); let mut mat = Material::new(shader, None); mat.diffuse_tex(&sk_tex.lock().0); mat.transparency(Transparency::Blend); Mutex::new(MaterialWrapper(mat)) }); // Import all surface buffers into textures if import_surface_tree(renderer, &wl_surface).is_err() { return; } self.update_textures(renderer); self.apply_surface_materials(); } pub fn update_textures(&self, renderer: &mut GlesRenderer) { let Some(wl_surface) = self.wl_surface() else { return; }; let mapped = wl_surface .get_data_raw::(|surface_states| { surface_states.lock().unwrap().buffer().is_some() }) .unwrap_or(false); if !mapped { return; } let mut mapped_data = self.mapped_data.lock(); let Some(smithay_tex) = wl_surface .get_data_raw::(|surface_states| { surface_states .lock() .unwrap() .texture::(renderer.id()) .cloned() }) .flatten() else { return; }; let Some(sk_tex) = self.sk_tex.get() else { return; }; let Some(sk_mat) = self.sk_mat.get() else { return; }; sk_tex .lock() .0 .set_native_surface( smithay_tex.tex_id() as usize as *mut c_void, TexType::ImageNomips, smithay::backend::renderer::gles::ffi::RGBA8.into(), smithay_tex.width() as i32, smithay_tex.height() as i32, 1, false, ) .sample_mode(TexSample::Point) .address_mode(TexAddress::Clamp); if let Some(material_offset) = self.material_offset.lock().delta() { sk_mat.lock().0.queue_offset(*material_offset as i32); } let new_mapped_data = CoreSurfaceData { wl_tex: Some(SendWrapper::new(smithay_tex)), }; *mapped_data = Some(new_mapped_data); } pub fn frame(&self, output: Output) { let Some(wl_surface) = self.wl_surface() else { return; }; send_frames_surface_tree( &wl_surface, &output, Duration::from_secs_f64(Time::get_total_unscaled()), None, |_, _| Some(output.clone()), ); } pub fn set_material_offset(&self, material_offset: u32) { *self.material_offset.lock().value_mut() = material_offset; } pub fn apply_material(&self, model_part: &Arc) { self.pending_material_applications.add_raw(model_part) } fn apply_surface_materials(&self) { if let Some(sk_mat) = self.sk_mat.get() { let sk_mat = sk_mat.lock(); for model_node in self.pending_material_applications.get_valid_contents() { model_node.replace_material_now(&sk_mat.0); } self.pending_material_applications.clear(); } } pub fn wl_surface(&self) -> Option { self.weak_surface.upgrade().ok() } } impl Drop for CoreSurface { fn drop(&mut self) { CORE_SURFACES.remove(self); destroy_queue::add(self.sk_tex.take()); destroy_queue::add(self.sk_mat.take()); } }