Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transparency not working with Egui/Eframe #4451

Open
GeneralBombe opened this issue May 3, 2024 Discussed in #4446 · 9 comments
Open

Transparency not working with Egui/Eframe #4451

GeneralBombe opened this issue May 3, 2024 Discussed in #4446 · 9 comments

Comments

@GeneralBombe
Copy link

Discussed in #4446

Originally posted by GeneralBombe May 3, 2024
Does anyone know how i can make a window transparent and use as a overlay? I am using egui, eframe and egui_glow. if i switch everytrhing to transparent, i only have a black window, where it should be transparent.
I think the Window Building is not the problem:

fn main() -> eframe::Result<()> {
    env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).

    let native_options = eframe::NativeOptions {
        viewport: egui::ViewportBuilder::default()
            .with_fullscreen(true)
            .with_transparent(true) // Make the window transparent
            .with_decorations(false),
        ..Default::default()
    };

    eframe::run_native(
        "esp",
        native_options,
        Box::new(|cc| Box::new(RustEsp::TemplateApp::new(cc).unwrap())),
    )
}

This is the app.rs i am using:

use std::sync::Arc;

use eframe::{egui_glow, glow};
use egui::{mutex::Mutex, text_selection::visuals, Color32, Vec2};

/// We derive Deserialize/Serialize so we can persist app state on shutdown.
//if we add new fields, give them default values when deserializing old state
pub struct TemplateApp {
    // Example stuff:
    rotating_triangle: Arc<Mutex<RotatingTriangle>>,
    angle: f32,
}



impl TemplateApp {
    /// Called once before the first frame.
    pub fn new<'a>(cc: &'a eframe::CreationContext<'a>) -> Option<Self> {
        let gl = cc.gl.as_ref()?;
        Some(Self {
            rotating_triangle: Arc::new(Mutex::new(RotatingTriangle::new(gl)?)),
            angle: 0.0,
        })
    }


    fn custom_painting(&mut self, ui: &mut egui::Ui) {
        let (rect, response) =
            ui.allocate_exact_size(egui::Vec2::new(ui.available_width()/2.0, ui.available_height()/2.0), egui::Sense::drag());

        self.angle += response.drag_motion().x * 0.01;
        // Clone locals so we can move them into the paint callback:
        let angle = self.angle;
        let rotating_triangle = self.rotating_triangle.clone();

        let cb = egui_glow::CallbackFn::new(move |_info, painter| {
            rotating_triangle.lock().paint(painter.gl(), angle);
        });

        let callback = egui::PaintCallback {
            rect,
            callback: Arc::new(cb),
        };
        ui.painter().add(callback);
    }
}

impl eframe::App for TemplateApp {
    /// Called by the frame work to save state before shutdown.
    fn clear_color(&self, visuals: &egui::Visuals) -> [f32; 4] {
        let u8_array = visuals.panel_fill.to_array();
    // Convert each u8 value to f32
    let f32_array: [f32; 4] = [
        u8_array[0] as f32,
        u8_array[1] as f32,
        u8_array[2] as f32,
        u8_array[3] as f32,
    ];
    f32_array
    }
    /// Called each time the UI needs repainting, which may be many times per s
    /// econd.
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        
        let mut style = (*ctx.style()).clone();
        ctx.set_visuals(egui::Visuals {
            //window_fill: egui::Color32::TRANSPARENT,
            panel_fill: egui::Color32::TRANSPARENT,
            ..Default::default()
        });
        
        
        let my_frame = egui::containers::Frame {
           
            fill: egui::Color32::TRANSPARENT,
            ..Default::default()
        };

        
        egui::CentralPanel::default().show(ctx, |ui| {
            egui::ScrollArea::both()
                .auto_shrink(false)
                .show(ui, |ui| {
                    

                    egui::Frame::canvas(ui.style()).show(ui, |ui| {
                        self.custom_painting(ui);
                    });
                    ui.label("Drag to rotate!");
                    
                });
        });
    }

    fn on_exit(&mut self, gl: Option<&glow::Context>) {
        if let Some(gl) = gl {
            self.rotating_triangle.lock().destroy(gl);
        }
    }
}

struct RotatingTriangle {
    program: glow::Program,
    vertex_array: glow::VertexArray,
}

#[allow(unsafe_code)] // we need unsafe code to use glow
impl RotatingTriangle {
    fn new(gl: &glow::Context) -> Option<Self> {
        use glow::HasContext as _;

        let shader_version = egui_glow::ShaderVersion::get(gl);

        unsafe {
            let program = gl.create_program().expect("Cannot create program");

            if !shader_version.is_new_shader_interface() {
                log::warn!(
                    "Custom 3D painting hasn't been ported to {:?}",
                    shader_version
                );
                return None;
            }

            let (vertex_shader_source, fragment_shader_source) = (
                r#"
                    const vec2 verts[3] = vec2[3](
                        vec2(0.0, 1.0),
                        vec2(-1.0, -1.0),
                        vec2(1.0, -1.0)
                    );
                    const vec4 colors[3] = vec4[3](
                        vec4(1.0, 0.0, 0.0, 1.0),
                        vec4(0.0, 1.0, 0.0, 1.0),
                        vec4(0.0, 0.0, 1.0, 1.0)
                    );
                    out vec4 v_color;
                    uniform float u_angle;
                    void main() {
                        v_color = colors[gl_VertexID];
                        gl_Position = vec4(verts[gl_VertexID], 0.0, 1.0);
                        gl_Position.x *= cos(u_angle);
                    }
                "#,
                r#"
                precision mediump float;

                uniform float backgroundAlpha; // Alpha value for background transparency
                
                in vec4 v_color;
                out vec4 out_color;
                
                void main() {
                    // Check if the color is black
                    if (all(equal(v_color.rgb, vec3(0.0)))) {
                        // Set alpha to backgroundAlpha for black pixels
                        out_color = v_color;

                    } else {
                        // Keep original color for non-black pixels#
                        out_color = vec4(0.0, 200.0, 0.0, backgroundAlpha);

                    }
                }
                
                "#,
            );

            let shader_sources = [
                (glow::VERTEX_SHADER, vertex_shader_source),
                (glow::FRAGMENT_SHADER, fragment_shader_source),
            ];

            let shaders: Vec<_> = shader_sources
                .iter()
                .map(|(shader_type, shader_source)| {
                    let shader = gl
                        .create_shader(*shader_type)
                        .expect("Cannot create shader");
                    gl.shader_source(
                        shader,
                        &format!(
                            "{}\n{}",
                            shader_version.version_declaration(),
                            shader_source
                        ),
                    );
                    gl.compile_shader(shader);
                    assert!(
                        gl.get_shader_compile_status(shader),
                        "Failed to compile custom_3d_glow {shader_type}: {}",
                        gl.get_shader_info_log(shader)
                    );

                    gl.attach_shader(program, shader);
                    shader
                })
                .collect();

            gl.link_program(program);
            assert!(
                gl.get_program_link_status(program),
                "{}",
                gl.get_program_info_log(program)
            );

            for shader in shaders {
                gl.detach_shader(program, shader);
                gl.delete_shader(shader);
            }

            let vertex_array = gl
                .create_vertex_array()
                .expect("Cannot create vertex array");

            unsafe {
                gl.enable(glow::BLEND);
                gl.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA);
            }

            Some(Self {
                program,
                vertex_array,
            })
        }
    }

    fn destroy(&self, gl: &glow::Context) {
        use glow::HasContext as _;
        unsafe {
            gl.delete_program(self.program);
            gl.delete_vertex_array(self.vertex_array);
        }
    }

    fn paint(&self, gl: &glow::Context, angle: f32) {
        use glow::HasContext as _;
        
        unsafe {
            //gl.clear_color(0.0, 0.0, 200.0, 0.0);
            //gl.clear(glow::COLOR_BUFFER_BIT);
            gl.use_program(Some(self.program));
            gl.uniform_1_f32(
                gl.get_uniform_location(self.program, "u_angle").as_ref(),
                angle,
            );
            
            
            gl.bind_vertex_array(Some(self.vertex_array));
            gl.draw_arrays(glow::TRIANGLES, 0, 3);
            
            
        }
    }
}

All colors work except transparent, thats why im thinking its eframe, but i really do not understand what the issue is.
Also in alt tab, it shows as transparent(i think). The eframe window is fullscreen:

4feda3e3-d014-4e11-93c7-6e4e77fa6bfd

I am not sure if the issue is ony my side or not, but i'd appreciate any help!

@rustbasic
Copy link
Contributor

rustbasic commented May 3, 2024

Try fill like this:

        let panel_frame = egui::Frame {
            fill: egui::Color32::TRANSPARENT,
            ..Default::default()
        };

OR

        let panel_frame = egui::Frame {
            fill: egui::Color32::from_rgba_premultiplied(0, 0, 0, 50),
            ..Default::default()
        };

@GeneralBombe
Copy link
Author

Try fill like this:

        let panel_frame = egui::Frame {
            fill: egui::Color32::TRANSPARENT,
            ..Default::default()
        };

OR

        let panel_frame = egui::Frame {
            fill: egui::Color32::from_rgba_premultiplied(0, 0, 0, 50),
            ..Default::default()
        };

Hmmm, still does not work. Also i somehow don't get a windowed window, only fullscreen.
Do you have a idea what the issue is?
I tried it with this:

fn main() -> eframe::Result<()> {
    env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).

    let native_options = eframe::NativeOptions {
        viewport: egui::ViewportBuilder::default()
            .with_transparent(true) // Make the window transparent
            .with_decorations(false)
            .with_max_inner_size([200.0, 200.0])
            .with_min_inner_size([100.0,100.0]),
        ..Default::default()
    };

    eframe::run_native(
        "esp",
        native_options,
        Box::new(|cc| Box::new(RustEsp::TemplateApp::new(cc).unwrap())),
    )
}

I am really confused right now.

@rustbasic
Copy link
Contributor

rustbasic commented May 4, 2024

You ask a question, but I don't even know what an your OS is. may be Linux.
There seems to be no problem with Windows 10.
Please find a solution in the form below.

            if ui.button("transparent").clicked() {                                   
                ui.ctx()                                                              
                    .send_viewport_cmd(egui::ViewportCommand::Transparent(false));    
            }                                                                         
                                                                                      
            if ui.button("innersize").clicked() {                                     
                ui.ctx()                                                              
                    .send_viewport_cmd(egui::ViewportCommand::InnerSize(egui::Vec2::new(500.0, 500.0)));
            }                                                                         

@rustbasic
Copy link
Contributor

@GeneralBombe

I tested your source code.
Temporarily use below.
For the remaining functions, try using ViewportCommand.

    let native_options = eframe::NativeOptions {
        viewport: egui::ViewportBuilder::default()
            // .with_fullscreen(true)
            .with_inner_size(egui::vec2(800.0, 600.0))
            // .with_decorations(false)
            .with_transparent(true), // Make the window transparent
        ..Default::default()
    };

@GeneralBombe
Copy link
Author

@rustbasic thank you for now, ill try it later :)

@GeneralBombe
Copy link
Author

@GeneralBombe

I tested your source code. Temporarily use below. For the remaining functions, try using ViewportCommand.

    let native_options = eframe::NativeOptions {
        viewport: egui::ViewportBuilder::default()
            // .with_fullscreen(true)
            .with_inner_size(egui::vec2(800.0, 600.0))
            // .with_decorations(false)
            .with_transparent(true), // Make the window transparent
        ..Default::default()
    };

Hello, yes this works :). But i am still really really really confused. The window is only Transparent if it opens my 2nd monitor (it does not matter if it is set as the main or secondary monitor). Same thing if i try to open the window with glfw ...
Wtf?

@GeneralBombe
Copy link
Author

So i think this issue is not about egui/eframe/glfw but about windows? Really annoying ... I can drag the window to the other monitor and the transparency works ...

@GeneralBombe
Copy link
Author

@rustbasic i got a github email with your quote "Could you please apply the Pull Request below and see if it works as desired, and let me know the results?". I tried to add the branch as dependencie, got this error when i tried to cargo run:
error: failed to select a version for objc-sys. ... required by package objc2 v0.4.1... which satisfies dependencyobjc2 = "^0.4.1"(locked to 0.4.1) of packageglutin v0.31.2... which satisfies dependencyglutin = "^0.31"(locked to 0.31.2) of packageeframe v0.27.2 (https://github.com/rustbasic/egui.git?branch=patch52#267fb5ac)`
... which satisfies git dependency eframe of package eframe_template v0.1.0 (F:\Programming\egui-eframe-playground)
versions that meet the requirements ^0.3.1 (locked to 0.3.2) are: 0.3.2

the package objc-sys links to the native library objc_0_3, but it conflicts with a previous package which links to objc_0_3 as well:
package objc-sys v0.3.3
... which satisfies dependency objc-sys = "^0.3.3" of package objc2 v0.5.1
... which satisfies dependency objc2 = "^0.5.1" of package block2 v0.5.0
... which satisfies dependency block2 = "^0.5.0" of package objc2-app-kit v0.2.0
... which satisfies dependency objc2-app-kit = "^0.2.0" of package eframe v0.27.2 (https://github.com/rustbasic/egui.git?branch=patch52#267fb5ac)
... which satisfies git dependency eframe of package eframe_template v0.1.0 (F:\Programming\egui-eframe-playground)
Only one package in the dependency graph may specify the same links value. This helps ensure that only one copy of a native library is linked in the final binary. Try to adjust your dependencies so that only one package uses the links ='objc-sys' value. For more information, see https://doc.rust-lang.org/cargo/reference/resolver.html#links.
Did i add it correctly as dependencie? eframe = { version = "0.27.0", default-features = false, features = [
"accesskit", # Make egui comptaible with screen readers. NOTE: adds a lot of dependencies.
"default_fonts", # Embed the default egui fonts.
"glow", # Use the glow rendering backend. Alternative: "wgpu".
"persistence", # Enable restoring app state when restarting the app.
], git = "https://github.com/rustbasic/egui.git", branch = "patch52"}`

@rustbasic
Copy link
Contributor

I closed it because I didn't think it could be resolved this way.
Use ViewportCommand to implement the functionality you want as much as possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants