mirror of
https://github.com/italicsjenga/rust_minifb.git
synced 2024-12-23 19:31:30 +11:00
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:
parent
29a4c5d9df
commit
d2fe8c0469
|
@ -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() {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
extern crate minifb;
|
|
||||||
|
|
||||||
use minifb::{Key, Scale, Window, WindowOptions};
|
use minifb::{Key, Scale, Window, WindowOptions};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
24
examples/transparent.rs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
10
src/lib.rs
10
src/lib.rs
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
Loading…
Reference in a new issue