Transparency (#164)

* Add transparency field to WindowOptions

* Add transparency example

* Implement transparency on Wayland

* Improvements

* [WIP] X11 transparency

* Restructure

* Redox implement transparency

* Update src/lib.rs

Co-Authored-By: Cole Helbling <cole.e.helbling@outlook.com>

* Rust-2018 changes

* Fixed issue

* cargo fmt

* [WIP] Implement alpha transparency for windows

* Staging Windows code

* Transparency is currently unimplemented on Windows

* Add note

* Dont use assertions

* Correction

Co-authored-by: Antonino Siena <a.siena@gmx.de>
Co-authored-by: Cole Helbling <cole.e.helbling@outlook.com>
This commit is contained in:
Antonino Siena 2020-04-15 15:11:23 +02:00 committed by GitHub
parent 29a4c5d9df
commit d2fe8c0469
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 77 additions and 25 deletions

View file

@ -1,6 +1,3 @@
extern crate minifb;
extern crate png;
use minifb::{Key, ScaleMode, Window, WindowOptions}; use minifb::{Key, ScaleMode, Window, WindowOptions};
fn main() { fn main() {

View file

@ -1,5 +1,3 @@
extern crate minifb;
use minifb::{Key, Scale, ScaleMode, Window, WindowOptions}; use minifb::{Key, Scale, ScaleMode, Window, WindowOptions};
const WIDTH: usize = 100; const WIDTH: usize = 100;

View file

@ -1,5 +1,3 @@
extern crate minifb;
use minifb::MENU_KEY_CTRL; use minifb::MENU_KEY_CTRL;
use minifb::{InputCallback, Key, Menu, Scale, Window, WindowOptions}; use minifb::{InputCallback, Key, Menu, Scale, Window, WindowOptions};

View file

@ -1,5 +1,3 @@
extern crate minifb;
use minifb::{Key, MouseButton, MouseMode, Scale, Window, WindowOptions}; use minifb::{Key, MouseButton, MouseMode, Scale, Window, WindowOptions};
const WIDTH: usize = 640; const WIDTH: usize = 640;

View file

@ -1,5 +1,3 @@
extern crate minifb;
use minifb::{Key, Scale, Window, WindowOptions}; use minifb::{Key, Scale, Window, WindowOptions};
fn main() { fn main() {

View file

@ -1,5 +1,3 @@
extern crate minifb;
use minifb::{Key, ScaleMode, Window, WindowOptions}; use minifb::{Key, ScaleMode, Window, WindowOptions};
const WIDTH: usize = 640 / 2; const WIDTH: usize = 640 / 2;

View file

@ -1,5 +1,3 @@
extern crate minifb;
use minifb::{CursorStyle, Key, MouseMode, Scale, Window, WindowOptions}; use minifb::{CursorStyle, Key, MouseMode, Scale, Window, WindowOptions};
const WIDTH: usize = 640; const WIDTH: usize = 640;

24
examples/transparent.rs Normal file
View file

@ -0,0 +1,24 @@
use minifb::{Key, ScaleMode, Window, WindowOptions};
fn main() {
// Allocate the output buffer.
let buf = vec![0x00AAFF33; 320 * 480];
let mut window = Window::new(
"Press ESC to exit",
320,
480,
WindowOptions {
resize: true,
scale_mode: ScaleMode::Center,
borderless: true,
transparency: true,
..WindowOptions::default()
},
)
.expect("Unable to open Window");
while window.is_open() && !window.is_key_down(Key::Escape) {
window.update_with_buffer(&buf, 320, 480).unwrap();
}
}

View file

@ -187,6 +187,10 @@ pub struct WindowOptions {
pub scale_mode: ScaleMode, pub scale_mode: ScaleMode,
/// Should the window be the topmost window (default: false) /// Should the window be the topmost window (default: false)
pub topmost: bool, pub topmost: bool,
/// Specifies whether or not the window is allowed to draw transparent pixels (default: false)
/// Requires borderless to be 'true'
/// TODO: Currently not implemented on Windows and OSX
pub transparency: bool,
} }
impl Window { impl Window {
@ -220,6 +224,11 @@ impl Window {
/// .expect("Unable to open Window"); /// .expect("Unable to open Window");
/// ``` /// ```
pub fn new(name: &str, width: usize, height: usize, opts: WindowOptions) -> Result<Window> { pub fn new(name: &str, width: usize, height: usize, opts: WindowOptions) -> Result<Window> {
if opts.transparency && !opts.borderless {
return Err(Error::WindowCreate(
"Window transparency requires the borderless property".to_owned(),
));
}
imp::Window::new(name, width, height, opts).map(Window) imp::Window::new(name, width, height, opts).map(Window)
} }
@ -993,6 +1002,7 @@ impl Default for WindowOptions {
fn default() -> WindowOptions { fn default() -> WindowOptions {
WindowOptions { WindowOptions {
borderless: false, borderless: false,
transparency: false,
title: true, title: true,
resize: false, resize: false,
scale: Scale::X1, scale: Scale::X1,

View file

@ -67,6 +67,9 @@ impl Window {
if !opts.title { if !opts.title {
window_flags.push(orbclient::WindowFlag::Borderless); window_flags.push(orbclient::WindowFlag::Borderless);
} }
if opts.transparency {
window_flags.push(orbclient::WindowFlag::Transparent);
}
let window_opt = let window_opt =
orbclient::Window::new_flags(-1, -1, window_width, window_height, name, &window_flags); orbclient::Window::new_flags(-1, -1, window_width, window_height, name, &window_flags);

View file

@ -520,7 +520,7 @@ impl Window {
let (display, input) = DisplayInfo::new( let (display, input) = DisplayInfo::new(
(width as i32 * scale, height as i32 * scale), (width as i32 * scale, height as i32 * scale),
false, opts.transparency,
!opts.borderless, !opts.borderless,
)?; )?;

View file

@ -99,8 +99,8 @@ struct DisplayInfo {
} }
impl DisplayInfo { impl DisplayInfo {
fn new() -> Result<DisplayInfo> { fn new(transparency: bool) -> Result<DisplayInfo> {
let mut display = Self::setup()?; let mut display = Self::setup(transparency)?;
display.check_formats()?; display.check_formats()?;
display.check_extensions()?; display.check_extensions()?;
@ -110,7 +110,7 @@ impl DisplayInfo {
Ok(display) Ok(display)
} }
fn setup() -> Result<DisplayInfo> { fn setup(transparency: bool) -> Result<DisplayInfo> {
unsafe { unsafe {
let lib = xlib::Xlib::open() let lib = xlib::Xlib::open()
.map_err(|e| Error::WindowCreate(format!("failed to load Xlib: {:?}", e)))?; .map_err(|e| Error::WindowCreate(format!("failed to load Xlib: {:?}", e)))?;
@ -124,10 +124,29 @@ impl DisplayInfo {
return Err(Error::WindowCreate("XOpenDisplay failed".to_owned())); return Err(Error::WindowCreate("XOpenDisplay failed".to_owned()));
} }
let screen = (lib.XDefaultScreen)(display); let screen;
let visual = (lib.XDefaultVisual)(display, screen); let visual;
let depth;
let mut vinfo: xlib::XVisualInfo = std::mem::zeroed();
if transparency {
(lib.XMatchVisualInfo)(
display,
(lib.XDefaultScreen)(display),
32,
xlib::TrueColor,
&mut vinfo as *mut _,
);
screen = vinfo.screen;
visual = vinfo.visual;
depth = vinfo.depth;
} else {
screen = (lib.XDefaultScreen)(display);
visual = (lib.XDefaultVisual)(display, screen);
depth = (lib.XDefaultDepth)(display, screen);
}
let gc = (lib.XDefaultGC)(display, screen); let gc = (lib.XDefaultGC)(display, screen);
let depth = (lib.XDefaultDepth)(display, screen);
let screen_width = cast::usize((lib.XDisplayWidth)(display, screen)) let screen_width = cast::usize((lib.XDisplayWidth)(display, screen))
.map_err(|e| Error::WindowCreate(format!("illegal width: {}", e)))?; .map_err(|e| Error::WindowCreate(format!("illegal width: {}", e)))?;
@ -316,7 +335,7 @@ impl Window {
// FIXME: this DisplayInfo should be a singleton, hence this code // FIXME: this DisplayInfo should be a singleton, hence this code
// is probably no good when using multiple windows. // is probably no good when using multiple windows.
let mut d = DisplayInfo::new()?; let mut d = DisplayInfo::new(opts.transparency)?;
let scale = let scale =
Self::get_scale_factor(width, height, d.screen_width, d.screen_height, opts.scale); Self::get_scale_factor(width, height, d.screen_width, d.screen_height, opts.scale);
@ -331,6 +350,10 @@ impl Window {
attributes.border_pixel = (d.lib.XBlackPixel)(d.display, d.screen); attributes.border_pixel = (d.lib.XBlackPixel)(d.display, d.screen);
attributes.background_pixel = attributes.border_pixel; attributes.background_pixel = attributes.border_pixel;
if opts.transparency {
attributes.colormap =
(d.lib.XCreateColormap)(d.display, root, d.visual, xlib::AllocNone);
}
attributes.backing_store = xlib::NotUseful; attributes.backing_store = xlib::NotUseful;
@ -356,10 +379,12 @@ impl Window {
d.depth, d.depth,
xlib::InputOutput as u32, /* class */ xlib::InputOutput as u32, /* class */
d.visual, d.visual,
xlib::CWBackingStore | xlib::CWBackPixel | xlib::CWBorderPixel, xlib::CWColormap | xlib::CWBackingStore | xlib::CWBackPixel | xlib::CWBorderPixel,
&mut attributes, &mut attributes,
); );
d.gc = (d.lib.XCreateGC)(d.display, handle, 0, ptr::null_mut());
if handle == 0 { if handle == 0 {
return Err(Error::WindowCreate("Unable to open Window".to_owned())); return Err(Error::WindowCreate("Unable to open Window".to_owned()));
} }
@ -464,7 +489,6 @@ impl Window {
let bytes_per_line = (width as i32) * 4; let bytes_per_line = (width as i32) * 4;
draw_buffer.resize(width * height, 0); draw_buffer.resize(width * height, 0);
let image = (d.lib.XCreateImage)( let image = (d.lib.XCreateImage)(
d.display, d.display,
d.visual, /* TODO: this was CopyFromParent in the C code */ d.visual, /* TODO: this was CopyFromParent in the C code */

View file

@ -535,6 +535,12 @@ impl Window {
flags &= !winuser::WS_THICKFRAME; flags &= !winuser::WS_THICKFRAME;
} }
//TODO: UpdateLayeredWindow, etc.
//https://gist.github.com/texus/31676aba4ca774b1298e1e15133b8141
if opts.transparency {
flags &= winuser::WS_EX_LAYERED;
}
let handle = winuser::CreateWindowExW( let handle = winuser::CreateWindowExW(
0, 0,
class_name.as_ptr(), class_name.as_ptr(),