Merged window-opts to master

commit 53e9cd45567a1308fdbd2e46763e15b2a3fa3d4c
Author: Daniel Collin <daniel@collin.com>
Date:   Sun Jan 31 18:31:38 2016 +0100

    Correct header for v0.4.0

commit fcf64d5dfad0796fee16ce8985e66d1b3e82c5a4
Author: Daniel Collin <daniel@collin.com>
Date:   Sun Jan 31 18:30:12 2016 +0100

    More cleanup

commit b7f4b187569a753656f19a74b78d8ada3fd95b70
Author: Daniel Collin <daniel@collin.com>
Date:   Sun Jan 31 18:29:23 2016 +0100

    Minor cleanup

commit 7392cd4a5aaad7f0d8332082c75d6cbc41d50ca6
Author: Daniel Collin <daniel@collin.com>
Date:   Sun Jan 31 18:28:06 2016 +0100

    Updated example added Changelog link

commit 236a82883a68e576ceb1e38a54b0a18fdc2e4465
Author: Daniel Collin <daniel@collin.com>
Date:   Sun Jan 31 18:24:58 2016 +0100

    Updated readme

commit e6bc68721513ca66c5566a19e6bfad33875b3280
Author: Daniel Collin <daniel@collin.com>
Date:   Sun Jan 31 18:20:42 2016 +0100

    Doc fixes

commit edfd688f045764b66c944d4aa616c6d48246816d
Author: Daniel Collin <daniel@collin.com>
Date:   Sun Jan 31 18:20:35 2016 +0100

    Updated with 0.4.0 release info

commit 784628fa9a1de93280592e634b522fd916a7588a
Author: Daniel Collin <daniel@collin.com>
Date:   Sun Jan 31 15:45:37 2016 +0100

    Fixed bad comment

commit 2c6d8730b566193b573afb5dc95a82987d1c4ce4
Author: Daniel Collin <daniel@collin.com>
Date:   Sun Jan 31 15:37:52 2016 +0100

    Linux support for WindowOptions

commit cbf7c17c3a92d676f5707095781071016e8b90e1
Author: Daniel Collin <daniel@collin.com>
Date:   Sun Jan 31 15:05:10 2016 +0100

    Updated Windows version with WindowOptions

commit ed1254245384e3e64c082a8368cbbe4a9f679efa
Author: Daniel Collin <daniel@collin.com>
Date:   Sun Jan 31 14:32:04 2016 +0100

    Added get_window_handle

commit e4a15f98c70facda7e7b2f30ba95a42091fa078c
Author: Daniel Collin <daniel@collin.com>
Date:   Sun Jan 31 14:30:34 2016 +0100

    Cleanup + links

commit 7dadb090d1037eade525093e2a541c99940e6a3a
Author: Daniel Collin <daniel@collin.com>
Date:   Sun Jan 31 14:25:41 2016 +0100

    And again

commit 70bdb0f88812e12bf9ca9adc55c1e52cc36c3ef9
Author: Daniel Collin <daniel@collin.com>
Date:   Sun Jan 31 14:24:44 2016 +0100

    Try link again

commit b4b7b3c4cda1d958e8f9cf6a2418db68ac32bcc5
Author: Daniel Collin <daniel@collin.com>
Date:   Sun Jan 31 14:21:54 2016 +0100

    Some cleanup

commit fb9845bae37f6ce9ba309b8a57128ce8c426fbca
Author: Daniel Collin <daniel@collin.com>
Date:   Sun Jan 31 13:16:23 2016 +0100

    Renamed resizeable to resize

commit 89c5af826612dbd887855dca3937e99856c9fcf2
Author: Daniel Collin <daniel@collin.com>
Date:   Sun Jan 31 12:59:57 2016 +0100

    Working on making Windows a bit more generic

    * Added WindowOptions that can configure how the Window should look and behave better (resize, title, borderless)
    * Renamed update -> update_with_buffer
    * Added update which doesn't take a buffer (used to updated the window without buffers)
This commit is contained in:
Daniel Collin 2016-01-31 18:34:05 +01:00
parent 1eb052fa27
commit 73813b63f4
12 changed files with 366 additions and 91 deletions

View file

@ -2,14 +2,24 @@
This project follows semantic versioning. This project follows semantic versioning.
### v0.4.0 (2016-01-31)
This release breaks some of the API by changing names and parameters to some functions.
- [changed] ```Window::new(...)``` now takes WindowOptions struct to configure the creation of the Window. [doc](http://prodbg.com/minifb/minifb/struct.Window.html#method.new)
- [changed] ```window.update()``` Doesn't take a buffer anymore. See ```window.update_with_buffer``` [doc](http://prodbg.com/minifb/minifb/struct.Window.html#method.update)
- [added] ```window.update_with_buffer()``` Old update version that takes buffer as input parameter [doc](http://prodbg.com/minifb/minifb/struct.Window.html#method.update_with_buffer)
- [added] ```window.get_window_handle()``` Returns the native handle (os dependant) [doc](http://prodbg.com/minifb/minifb/struct.Window.html#method.get_window_handle)
### v0.3.1 (2016-01-29) ### v0.3.1 (2016-01-29)
- [fixed] ```get_mouse_pos(MouseMode::Clamp)``` now is in the region [(0, 0) - (width - 1, height - 1)] instead of (width, height) - [fixed] ```get_mouse_pos(Clamp)``` clamps to ```[(0, 0) - (width - 1, height - 1)]``` instead of ```(width, height)```
### v0.3.0 (2016-01-29) ### v0.3.0 (2016-01-29)
- [added] ```get_mouse_pos``` This release adds support for mouse input. See the documentation and the examples for usage
- [added] ```get_mouse_down```
- [added] ```get_scroll_wheel``` - [added] [get_mouse_pos](http://prodbg.com/minifb/minifb/struct.Window.html#method.get_mouse_pos)
- [added] [get_mouse_down](http://prodbg.com/minifb/minifb/struct.Window.html#method.get_mouse_down)
- [added] [get_scroll_wheel](http://prodbg.com/minifb/minifb/struct.Window.html#method.get_scroll_wheel)
This relase adds support for mouse input. See the documentation and the examples for usage

View file

@ -1,10 +1,10 @@
[package] [package]
name = "minifb" name = "minifb"
version = "0.3.1" version = "0.4.0"
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
authors = ["Daniel Collin <daniel@collin.com>"] authors = ["Daniel Collin <daniel@collin.com>"]
description = "Cross-platform window setup for bitmap rendering" description = "Cross-platform window setup with optional bitmap rendering"
keywords = ["windowing", "framebuffer"] keywords = ["windowing", "window", "framebuffer"]
repository = "https://github.com/emoon/rust_minifb" repository = "https://github.com/emoon/rust_minifb"
homepage = "https://github.com/emoon/rust_minifb" homepage = "https://github.com/emoon/rust_minifb"
documentation = "http://prodbg.com/minifb/minifb/index.html" documentation = "http://prodbg.com/minifb/minifb/index.html"

View file

@ -2,9 +2,11 @@
[![Build Status](https://travis-ci.org/emoon/rust_minifb.svg)](https://travis-ci.org/emoon/rust_minifb) [![Build Status](https://travis-ci.org/emoon/rust_minifb.svg)](https://travis-ci.org/emoon/rust_minifb)
[![Build Status](https://ci.appveyor.com/api/projects/status/sfvgqq4d4sjulkbx?svg=true)](https://ci.appveyor.com/project/emoon/rust-minifb) [![Build Status](https://ci.appveyor.com/api/projects/status/sfvgqq4d4sjulkbx?svg=true)](https://ci.appveyor.com/project/emoon/rust-minifb)
minifb (Mini FrameBuffer) is a small cross platform library written in [Rust](https://www.rust-lang.org) and that makes it easy to render (32-bit) pixels in a window. An example is the best way to show how it works: minifb is a cross platform library written in [Rust](https://www.rust-lang.org) and that makes it easy to setup a window and to (optional) display 32-bit a pixel buffer. It also makes it easy to get input from keyboard and mouse.
An example is the best way to show how it works:
[Documentation](http://prodbg.com/minifb/minifb/index.html) [Documentation](http://prodbg.com/minifb/minifb/index.html)
[Changelog](https://github.com/emoon/rust_minifb/blob/window-opts/CHANGELOG.md)
Usage Usage
----- -----
@ -12,7 +14,7 @@ Usage
```toml ```toml
# Cargo.toml # Cargo.toml
[dependencies] [dependencies]
minifb = "0.3.1" minifb = "0.4.0"
``` ```
Example Example
@ -21,7 +23,7 @@ Example
```rust ```rust
extern crate minifb; extern crate minifb;
use minifb::{Key, Scale}; use minifb::{Key, Scale, WindowOptions};
const WIDTH: usize = 640; const WIDTH: usize = 640;
const HEIGHT: usize = 360; const HEIGHT: usize = 360;
@ -29,7 +31,8 @@ const HEIGHT: usize = 360;
fn main() { fn main() {
let mut buffer: Vec<u32> = vec![0; WIDTH * HEIGHT]; let mut buffer: Vec<u32> = vec![0; WIDTH * HEIGHT];
let mut window = match minifb::Window::new("Test - ESC to exit", WIDTH, HEIGHT, Scale::X1) { let mut window = match minifb::Window::new("Test - ESC to exit", WIDTH, HEIGHT,
WindowOptions::default()) {
Ok(win) => win, Ok(win) => win,
Err(err) => { Err(err) => {
println!("Unable to create window {}", err); println!("Unable to create window {}", err);
@ -42,7 +45,7 @@ fn main() {
*i = 0; // write something more funny here! *i = 0; // write something more funny here!
} }
window.update(&buffer); window.update_with_buffer(&buffer);
} }
} }
``` ```

View file

@ -1,6 +1,6 @@
extern crate minifb; extern crate minifb;
use minifb::{MouseButton, MouseMode, Window, Key, Scale}; use minifb::{MouseButton, MouseMode, Window, Key, Scale, WindowOptions};
const WIDTH: usize = 640; const WIDTH: usize = 640;
const HEIGHT: usize = 360; const HEIGHT: usize = 360;
@ -8,7 +8,11 @@ const HEIGHT: usize = 360;
fn main() { fn main() {
let mut buffer: Vec<u32> = vec![0; WIDTH * HEIGHT]; let mut buffer: Vec<u32> = vec![0; WIDTH * HEIGHT];
let mut window = match Window::new("Mouse Draw - Press ESC to exit", WIDTH, HEIGHT, Scale::X2) { let mut window = match Window::new("Mouse Draw - Press ESC to exit", WIDTH, HEIGHT,
WindowOptions {
scale: Scale::X2,
..WindowOptions::default()
}) {
Ok(win) => win, Ok(win) => win,
Err(err) => { Err(err) => {
println!("Unable to create window {}", err); println!("Unable to create window {}", err);
@ -33,6 +37,6 @@ fn main() {
println!("Scrolling {} - {}", scroll.0, scroll.1); println!("Scrolling {} - {}", scroll.0, scroll.1);
}); });
window.update(&buffer); window.update_with_buffer(&buffer);
} }
} }

View file

@ -1,6 +1,6 @@
extern crate minifb; extern crate minifb;
use minifb::{Window, Key, Scale}; use minifb::{Window, Key, Scale, WindowOptions};
const WIDTH: usize = 640; const WIDTH: usize = 640;
const HEIGHT: usize = 360; const HEIGHT: usize = 360;
@ -12,7 +12,12 @@ fn main() {
let mut buffer: Vec<u32> = vec![0; WIDTH * HEIGHT]; let mut buffer: Vec<u32> = vec![0; WIDTH * HEIGHT];
let mut window = match Window::new("Noise Test - Press ESC to exit", WIDTH, HEIGHT, Scale::X2) { let mut window = match Window::new("Noise Test - Press ESC to exit", WIDTH, HEIGHT,
WindowOptions {
resize: true,
scale: Scale::X2,
..WindowOptions::default()
}) {
Ok(win) => win, Ok(win) => win,
Err(err) => { Err(err) => {
println!("Unable to create window {}", err); println!("Unable to create window {}", err);
@ -43,6 +48,6 @@ fn main() {
} }
}); });
window.update(&buffer); window.update_with_buffer(&buffer);
} }
} }

View file

@ -183,10 +183,13 @@ pub enum MouseMode {
extern crate libc; extern crate libc;
use std::os::raw;
#[doc(hidden)] #[doc(hidden)]
pub mod os; pub mod os;
mod mouse_handler; mod mouse_handler;
mod key_handler; mod key_handler;
mod window_flags;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
use self::os::macos as imp; use self::os::macos as imp;
@ -199,36 +202,58 @@ use self::os::windows as imp;
target_os="openbsd"))] target_os="openbsd"))]
use self::os::unix as imp; use self::os::unix as imp;
pub struct Window(imp::Window);
/// ///
/// Window used for displaying a 32-bit RGB buffer. Here is a small example on how to use it: /// WindowOptions is creation settings for the window. By default the settings are defined for
/// (without error checking /// displayng a 32-bit buffer (no scaling of window is possible)
///
pub struct WindowOptions {
/// If the window should be borderless (default: false)
pub borderless: bool,
/// If the window should have a title (default: true)
pub title: bool,
/// If it should be possible to resize the window (default: false)
pub resize: bool,
/// Scale of the window that used in conjunction with update_with_buffer (default: X1)
pub scale: Scale
}
///
/// Window is used to open up a window. It's possible to optionally display a 32-bit buffer when
/// the widow is set as non-resizable.
///
/// # Examples
///
/// Open up a window and display a 32-bit RGB buffer (without error checking)
/// ///
/// ```ignore /// ```ignore
///
/// const WIDTH: usize = 640; /// const WIDTH: usize = 640;
/// const HEIGHT: usize = 360; /// const HEIGHT: usize = 360;
/// ///
/// let mut buffer: Vec<u32> = vec![0; WIDTH * HEIGHT]; /// let mut buffer: Vec<u32> = vec![0; WIDTH * HEIGHT];
/// ///
/// let mut window = match Window::new("Test - Press ESC to exit", WIDTH, HEIGHT, Scale::X1).unwrap() /// let mut window = match Window::new("Test - Press ESC to exit", WIDTH, HEIGHT,
/// WindowOptions::default()).unwrap()
/// ///
/// while window.is_open() && !window.is_key_down(Key::Escape) { /// while window.is_open() && !window.is_key_down(Key::Escape) {
/// for i in buffer.iter_mut() { /// for i in buffer.iter_mut() {
/// *i = 0; // write something interesting here /// *i = 0; // write something interesting here
/// } /// }
/// window.update(&buffer); /// window.update_with_buffer(&buffer);
/// } /// }
/// ``` /// ```
/// ///
pub struct Window(imp::Window);
impl Window { impl Window {
/// ///
/// Opens up a new window /// Opens up a new window
/// ///
/// # Examples
///
/// Open up a window with default settings
///
/// ```ignore /// ```ignore
/// let mut window = match Window::new("Test", 640, 400, Scale::X1) { /// let mut window = match Window::new("Test", 640, 400, WindowOptions::default()) {
/// Ok(win) => win, /// Ok(win) => win,
/// Err(err) => { /// Err(err) => {
/// println!("Unable to create window {}", err); /// println!("Unable to create window {}", err);
@ -236,8 +261,39 @@ impl Window {
/// } /// }
///}; ///};
/// ``` /// ```
pub fn new(name: &str, width: usize, height: usize, scale: Scale) -> Result<Window, &str> { ///
imp::Window::new(name, width, height, scale).map(Window) /// Open up a window that is resizeable
///
/// ```ignore
/// let mut window = match Window::new("Test", 640, 400,
/// WindowOptions {
/// resize: true,
/// ..WindowOptions::default()
/// }) {
/// Ok(win) => win,
/// Err(err) => {
/// println!("Unable to create window {}", err);
/// return;
/// }
///};
/// ```
pub fn new(name: &str, width: usize, height: usize, opts: WindowOptions) -> Result<Window, &str> {
imp::Window::new(name, width, height, opts).map(Window)
}
///
/// Returns the native handle for a window which is an opaque pointer/handle which
/// dependens on the current operating system:
///
/// ```ignore
/// Windows HWND
/// MacOS NSWindow
/// X11 XWindow
/// ```
///
#[inline]
pub fn get_window_handle(&self) -> *mut raw::c_void {
self.0.get_window_handle()
} }
/// ///
@ -249,12 +305,30 @@ impl Window {
/// ```ignore /// ```ignore
/// let mut buffer: Vec<u32> = vec![0; 640 * 400]; /// let mut buffer: Vec<u32> = vec![0; 640 * 400];
/// ///
/// let mut window = match Window::new("Test", 640, 400, Scale::X1).unwrap(); /// let mut window = match Window::new("Test", 640, 400, WindowOptions::default()).unwrap();
/// ///
/// window.update(&buffer); /// window.update_with_buffer(&buffer);
/// ``` /// ```
pub fn update(&mut self, buffer: &[u32]) { #[inline]
self.0.update(buffer) pub fn update_with_buffer(&mut self, buffer: &[u32]) {
self.0.update_with_buffer(buffer)
}
///
/// Updates the window (this is required to call in order to get keyboard/mouse input, etc)
///
/// # Examples
///
/// ```ignore
/// let mut buffer: Vec<u32> = vec![0; 640 * 400];
///
/// let mut window = match Window::new("Test", 640, 400, WindowOptions::default()).unwrap();
///
/// window.update();
/// ```
#[inline]
pub fn update(&mut self) {
self.0.update()
} }
/// ///
@ -281,7 +355,7 @@ impl Window {
/// # Examples /// # Examples
/// ///
/// ```ignore /// ```ignore
/// // Moves the window to pixel postion 20, 20 on the screen /// // Moves the window to pixel position 20, 20 on the screen
/// window.set_position(20, 20); /// window.set_position(20, 20);
/// ``` /// ```
/// ///
@ -435,7 +509,7 @@ impl Window {
} }
/// ///
/// Sets the rate in between when the keys has passed the intital repeat_delay. The default /// Sets the rate in between when the keys has passed the initial repeat_delay. The default
/// value is 0.05 sec /// value is 0.05 sec
/// ///
/// # Examples /// # Examples
@ -449,3 +523,19 @@ impl Window {
self.0.set_key_repeat_rate(rate) self.0.set_key_repeat_rate(rate)
} }
} }
// Impl for WindowOptions
#[doc(hidden)]
impl Default for WindowOptions {
fn default() -> WindowOptions {
WindowOptions {
borderless: false,
title: true,
resize: false,
scale: Scale::X1,
}
}
}

View file

@ -6,6 +6,11 @@
static bool s_init = false; static bool s_init = false;
// window_handler.rs
const uint32_t WINDOW_BORDERLESS = 1 << 1;
const uint32_t WINDOW_RESIZE = 1 << 2;
const uint32_t WINDOW_TITLE = 1 << 3;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef __clang__ #ifdef __clang__
@ -14,7 +19,7 @@ static bool s_init = false;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void* mfb_open(const char* name, int width, int height, int scale) void* mfb_open(const char* name, int width, int height, uint32_t flags, int scale)
{ {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
@ -24,7 +29,17 @@ void* mfb_open(const char* name, int width, int height, int scale)
s_init = true; s_init = true;
} }
unsigned int styles = NSClosableWindowMask | NSTitledWindowMask; uint32_t styles = NSClosableWindowMask | NSMiniaturizableWindowMask;
if (flags & WINDOW_BORDERLESS)
styles |= NSBorderlessWindowMask;
if (flags & WINDOW_RESIZE)
styles |= NSResizableWindowMask;
if (flags & WINDOW_TITLE)
styles |= NSTitledWindowMask;
NSRect rectangle = NSMakeRect(0, 0, width * scale, (height * scale)); NSRect rectangle = NSMakeRect(0, 0, width * scale, (height * scale));
OSXWindow* window = [[OSXWindow alloc] initWithContentRect:rectangle styleMask:styles backing:NSBackingStoreBuffered defer:NO]; OSXWindow* window = [[OSXWindow alloc] initWithContentRect:rectangle styleMask:styles backing:NSBackingStoreBuffered defer:NO];
@ -88,11 +103,7 @@ static int update_events()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int mfb_update(void* window, void* buffer) static int generic_update(OSXWindow* win) {
{
OSXWindow* win = (OSXWindow*)window;
memcpy(win->draw_buffer, buffer, win->width * win->height * 4);
int state = update_events(); int state = update_events();
if (win->shared_data) { if (win->shared_data) {
@ -103,6 +114,26 @@ int mfb_update(void* window, void* buffer)
win->shared_data->mouse_y = contentRect.size.height - p.y; win->shared_data->mouse_y = contentRect.size.height - p.y;
} }
return state;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int mfb_update(void* window, void* buffer)
{
OSXWindow* win = (OSXWindow*)window;
return generic_update(win);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int mfb_update_with_buffer(void* window, void* buffer)
{
OSXWindow* win = (OSXWindow*)window;
memcpy(win->draw_buffer, buffer, win->width * win->height * 4);
int state = generic_update(win);
[[win contentView] setNeedsDisplay:YES]; [[win contentView] setNeedsDisplay:YES];
return state; return state;
} }

View file

@ -13,6 +13,11 @@
#define Button6 6 #define Button6 6
#define Button7 7 #define Button7 7
// window_handler.rs
const uint32_t WINDOW_BORDERLESS = 1 << 1;
const uint32_t WINDOW_RESIZE = 1 << 2;
const uint32_t WINDOW_TITLE = 1 << 3;
void mfb_close(void* window_info); void mfb_close(void* window_info);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -113,7 +118,7 @@ static int setup_display() {
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void* mfb_open(const char* title, int width, int height, int scale) void* mfb_open(const char* title, int width, int height, unsigned int flags, int scale)
{ {
XSetWindowAttributes windowAttributes; XSetWindowAttributes windowAttributes;
XSizeHints sizeHints; XSizeHints sizeHints;
@ -125,6 +130,9 @@ void* mfb_open(const char* title, int width, int height, int scale)
return 0; return 0;
} }
//TODO: Handle no title/borderless
(void)flags;
width *= scale; width *= scale;
height *= scale; height *= scale;
@ -146,6 +154,9 @@ void* mfb_open(const char* title, int width, int height, int scale)
//XSelectInput(s_display, s_window, KeyPressMask | KeyReleaseMask); //XSelectInput(s_display, s_window, KeyPressMask | KeyReleaseMask);
XStoreName(s_display, window, title); XStoreName(s_display, window, title);
XSelectInput(s_display, window, ButtonPressMask | KeyPressMask | KeyReleaseMask | ButtonReleaseMask);
if (!(flags & WINDOW_RESIZE)) {
sizeHints.flags = PPosition | PMinSize | PMaxSize; sizeHints.flags = PPosition | PMinSize | PMaxSize;
sizeHints.x = 0; sizeHints.x = 0;
sizeHints.y = 0; sizeHints.y = 0;
@ -153,9 +164,9 @@ void* mfb_open(const char* title, int width, int height, int scale)
sizeHints.max_width = width; sizeHints.max_width = width;
sizeHints.min_height = height; sizeHints.min_height = height;
sizeHints.max_height = height; sizeHints.max_height = height;
XSelectInput(s_display, window, ButtonPressMask | KeyPressMask | KeyReleaseMask | ButtonReleaseMask);
XSetWMNormalHints(s_display, window, &sizeHints); XSetWMNormalHints(s_display, window, &sizeHints);
}
XClearWindow(s_display, window); XClearWindow(s_display, window);
XMapRaised(s_display, window); XMapRaised(s_display, window);
XFlush(s_display); XFlush(s_display);
@ -376,14 +387,14 @@ static void scale_4x(unsigned int* dest, unsigned int* source, int width, int he
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void mfb_update(void* window_info, void* buffer) void mfb_update_with_buffer(void* window_info, void* buffer)
{ {
WindowInfo* info = (WindowInfo*)window_info; WindowInfo* info = (WindowInfo*)window_info;
int width = info->width; int width = info->width;
int height = info->height; int height = info->height;
int scale = info->scale; int scale = info->scale;
if (info->update) { if (info->update && buffer) {
switch (scale) { switch (scale) {
case 1: { case 1: {
memcpy(info->draw_buffer, buffer, width * height * 4); memcpy(info->draw_buffer, buffer, width * height * 4);
@ -417,6 +428,13 @@ void mfb_update(void* window_info, void* buffer)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void mfb_update(void* window_info, void* buffer)
{
mfb_update_with_buffer(window_info, 0);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void mfb_set_position(void* window, int x, int y) void mfb_set_position(void* window, int x, int y)
{ {
WindowInfo* info = (WindowInfo*)window; WindowInfo* info = (WindowInfo*)window;

View file

@ -1,13 +1,15 @@
#![cfg(target_os = "macos")] #![cfg(target_os = "macos")]
use {MouseButton, MouseMode, Scale, Key, KeyRepeat}; use {MouseButton, MouseMode, Scale, Key, KeyRepeat, WindowOptions};
use key_handler::KeyHandler; use key_handler::KeyHandler;
use mouse_handler; use mouse_handler;
use window_flags;
use libc::{c_void, c_char, c_uchar}; use libc::{c_void, c_char, c_uchar};
use std::ffi::{CString}; use std::ffi::{CString};
use std::ptr; use std::ptr;
use std::mem; use std::mem;
use std::os::raw;
// Table taken from GLFW and slightly modified // Table taken from GLFW and slightly modified
@ -144,9 +146,10 @@ static KEY_MAPPINGS: [Key; 128] = [
#[link(name = "Cocoa", kind = "framework")] #[link(name = "Cocoa", kind = "framework")]
extern { extern {
fn mfb_open(name: *const c_char, width: u32, height: u32, scale: i32) -> *mut c_void; fn mfb_open(name: *const c_char, width: u32, height: u32, flags: u32, scale: i32) -> *mut c_void;
fn mfb_close(window: *mut c_void); fn mfb_close(window: *mut c_void);
fn mfb_update(window: *mut c_void, buffer: *const c_uchar); fn mfb_update(window: *mut c_void);
fn mfb_update_with_buffer(window: *mut c_void, buffer: *const c_uchar);
fn mfb_set_position(window: *mut c_void, x: i32, y: i32); fn mfb_set_position(window: *mut c_void, x: i32, y: i32);
fn mfb_set_key_callback(window: *mut c_void, target: *mut c_void, cb: unsafe extern fn(*mut c_void, i32, i32)); fn mfb_set_key_callback(window: *mut c_void, target: *mut c_void, cb: unsafe extern fn(*mut c_void, i32, i32));
fn mfb_set_mouse_data(window_handle: *mut c_void, shared_data: *mut SharedData); fn mfb_set_mouse_data(window_handle: *mut c_void, shared_data: *mut SharedData);
@ -187,7 +190,7 @@ unsafe extern "C" fn key_callback(window: *mut c_void, key: i32, state: i32) {
} }
impl Window { impl Window {
pub fn new(name: &str, width: usize, height: usize, scale: Scale) -> Result<Window, &str> { pub fn new(name: &str, width: usize, height: usize, opts: WindowOptions) -> Result<Window, &str> {
let n = match CString::new(name) { let n = match CString::new(name) {
Err(_) => { Err(_) => {
println!("Unable to convert {} to c_string", name); println!("Unable to convert {} to c_string", name);
@ -197,8 +200,8 @@ impl Window {
}; };
unsafe { unsafe {
let scale_factor = Self::get_scale_factor(width, height, scale) as usize; let scale_factor = Self::get_scale_factor(width, height, opts.scale) as usize;
let handle = mfb_open(n.as_ptr(), width as u32, height as u32, scale_factor as i32); let handle = mfb_open(n.as_ptr(), width as u32, height as u32, window_flags::get_flags(opts), scale_factor as i32);
if handle == ptr::null_mut() { if handle == ptr::null_mut() {
return Err("Unable to open Window"); return Err("Unable to open Window");
@ -218,15 +221,31 @@ impl Window {
} }
} }
#[inline]
pub fn get_window_handle(&self) -> *mut raw::c_void {
self.window_handle as *mut raw::c_void
}
#[inline]
unsafe fn set_mouse_data(&mut self) { unsafe fn set_mouse_data(&mut self) {
mfb_set_mouse_data(self.window_handle, &mut self.shared_data); mfb_set_mouse_data(self.window_handle, &mut self.shared_data);
} }
pub fn update(&mut self, buffer: &[u32]) { pub fn update_with_buffer(&mut self, buffer: &[u32]) {
self.key_handler.update(); self.key_handler.update();
unsafe { unsafe {
mfb_update(self.window_handle, buffer.as_ptr() as *const u8); mfb_update_with_buffer(self.window_handle, buffer.as_ptr() as *const u8);
Self::set_mouse_data(self);
mfb_set_key_callback(self.window_handle, mem::transmute(self), key_callback);
}
}
pub fn update(&mut self) {
self.key_handler.update();
unsafe {
mfb_update(self.window_handle);
Self::set_mouse_data(self); Self::set_mouse_data(self);
mfb_set_key_callback(self.window_handle, mem::transmute(self), key_callback); mfb_set_key_callback(self.window_handle, mem::transmute(self), key_callback);
} }

View file

@ -6,7 +6,7 @@
extern crate x11_dl; extern crate x11_dl;
use {MouseMode, MouseButton, Scale, Key, KeyRepeat}; use {MouseMode, MouseButton, Scale, Key, KeyRepeat, WindowOptions};
use key_handler::KeyHandler; use key_handler::KeyHandler;
use self::x11_dl::keysym::*; use self::x11_dl::keysym::*;
@ -14,13 +14,16 @@ use libc::{c_void, c_char, c_uchar};
use std::ffi::{CString}; use std::ffi::{CString};
use std::ptr; use std::ptr;
use std::mem; use std::mem;
use std::os::raw;
use mouse_handler; use mouse_handler;
use window_flags;
#[link(name = "X11")] #[link(name = "X11")]
extern { extern {
fn mfb_open(name: *const c_char, width: u32, height: u32, scale: i32) -> *mut c_void; fn mfb_open(name: *const c_char, width: u32, height: u32, flags: u32, scale: i32) -> *mut c_void;
fn mfb_close(window: *mut c_void); fn mfb_close(window: *mut c_void);
fn mfb_update(window: *mut c_void, buffer: *const c_uchar); fn mfb_update(window: *mut c_void);
fn mfb_update_with_buffer(window: *mut c_void, buffer: *const c_uchar);
fn mfb_set_position(window: *mut c_void, x: i32, y: i32); fn mfb_set_position(window: *mut c_void, x: i32, y: i32);
fn mfb_set_key_callback(window: *mut c_void, target: *mut c_void, cb: unsafe extern fn(*mut c_void, i32, i32)); fn mfb_set_key_callback(window: *mut c_void, target: *mut c_void, cb: unsafe extern fn(*mut c_void, i32, i32));
fn mfb_set_shared_data(window: *mut c_void, target: *mut SharedData); fn mfb_set_shared_data(window: *mut c_void, target: *mut SharedData);
@ -160,7 +163,7 @@ unsafe extern "C" fn key_callback(window: *mut c_void, key: i32, s: i32) {
} }
impl Window { impl Window {
pub fn new(name: &str, width: usize, height: usize, scale: Scale) -> Result<Window, &str> { pub fn new(name: &str, width: usize, height: usize, opts: WindowOptions) -> Result<Window, &str> {
let n = match CString::new(name) { let n = match CString::new(name) {
Err(_) => { Err(_) => {
println!("Unable to convert {} to c_string", name); println!("Unable to convert {} to c_string", name);
@ -170,8 +173,12 @@ impl Window {
}; };
unsafe { unsafe {
let scale = Self::get_scale_factor(width, height, scale); let scale = Self::get_scale_factor(width, height, opts.scale);
let handle = mfb_open(n.as_ptr(), width as u32, height as u32, scale); let handle = mfb_open(n.as_ptr(),
width as u32,
height as u32,
window_flags::get_flags(opts),
scale);
if handle == ptr::null_mut() { if handle == ptr::null_mut() {
return Err("Unable to open Window"); return Err("Unable to open Window");
@ -192,16 +199,31 @@ impl Window {
mfb_set_shared_data(self.window_handle, &mut self.shared_data); mfb_set_shared_data(self.window_handle, &mut self.shared_data);
} }
pub fn update(&mut self, buffer: &[u32]) { pub fn update_with_buffer(&mut self, buffer: &[u32]) {
self.key_handler.update(); self.key_handler.update();
unsafe { unsafe {
Self::set_shared_data(self); Self::set_shared_data(self);
mfb_update(self.window_handle, buffer.as_ptr() as *const u8); mfb_update_with_buffer(self.window_handle, buffer.as_ptr() as *const u8);
mfb_set_key_callback(self.window_handle, mem::transmute(self), key_callback); mfb_set_key_callback(self.window_handle, mem::transmute(self), key_callback);
} }
} }
pub fn update(&mut self) {
self.key_handler.update();
unsafe {
Self::set_shared_data(self);
mfb_update(self.window_handle);
mfb_set_key_callback(self.window_handle, mem::transmute(self), key_callback);
}
}
#[inline]
pub fn get_window_handle(&self) -> *mut raw::c_void {
self.window_handle as *mut raw::c_void
}
#[inline] #[inline]
pub fn set_position(&mut self, x: isize, y: isize) { pub fn set_position(&mut self, x: isize, y: isize) {
unsafe { mfb_set_position(self.window_handle, x as i32, y as i32) } unsafe { mfb_set_position(self.window_handle, x as i32, y as i32) }

View file

@ -6,7 +6,7 @@ extern crate winapi;
extern crate gdi32; extern crate gdi32;
extern crate time; extern crate time;
use {Scale, Key, KeyRepeat, MouseButton, MouseMode}; use {Scale, Key, KeyRepeat, MouseButton, MouseMode, WindowOptions};
use key_handler::KeyHandler; use key_handler::KeyHandler;
@ -14,6 +14,7 @@ use std::ptr;
use std::os::windows::ffi::OsStrExt; use std::os::windows::ffi::OsStrExt;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::mem; use std::mem;
use std::os::raw;
use mouse_handler; use mouse_handler;
use self::winapi::windef::HWND; use self::winapi::windef::HWND;
@ -226,6 +227,12 @@ unsafe extern "system" fn wnd_proc(window: winapi::HWND,
} }
winapi::winuser::WM_PAINT => { winapi::winuser::WM_PAINT => {
// if we have nothing to draw here we return the default function
if wnd.buffer.len() == 0 {
return user32::DefWindowProcW(window, msg, wparam, lparam);
}
let mut bitmap_info: BitmapInfo = mem::zeroed(); let mut bitmap_info: BitmapInfo = mem::zeroed();
bitmap_info.bmi_header.biSize = mem::size_of::<BITMAPINFOHEADER>() as u32; bitmap_info.bmi_header.biSize = mem::size_of::<BITMAPINFOHEADER>() as u32;
@ -294,7 +301,7 @@ pub struct Window {
} }
impl Window { impl Window {
fn open_window(name: &str, width: usize, height: usize, scale_factor: i32) -> Option<HWND> { fn open_window(name: &str, width: usize, height: usize, opts: WindowOptions, scale_factor: i32) -> Option<HWND> {
unsafe { unsafe {
let class_name = to_wstring("minifb_window"); let class_name = to_wstring("minifb_window");
let class = WNDCLASSW { let class = WNDCLASSW {
@ -337,12 +344,28 @@ impl Window {
let window_name = to_wstring(name); let window_name = to_wstring(name);
let mut flags = 0;
if opts.title {
flags |= winapi::WS_OVERLAPPEDWINDOW as u32;
}
if opts.resize {
flags |= winapi::WS_THICKFRAME as u32 | winapi::WS_MAXIMIZEBOX as u32 ;
} else {
flags &= !winapi::WS_MAXIMIZEBOX;
flags &= !winapi::WS_THICKFRAME;
}
if opts.borderless {
flags &= !winapi::WS_THICKFRAME;
}
let handle = user32::CreateWindowExW(0, let handle = user32::CreateWindowExW(0,
class_name.as_ptr(), class_name.as_ptr(),
window_name.as_ptr(), window_name.as_ptr(),
winapi::WS_OVERLAPPEDWINDOW & flags,
!winapi::WS_MAXIMIZEBOX &
!winapi::WS_THICKFRAME,
winapi::CW_USEDEFAULT, winapi::CW_USEDEFAULT,
winapi::CW_USEDEFAULT, winapi::CW_USEDEFAULT,
rect.right, rect.right,
@ -365,12 +388,12 @@ impl Window {
pub fn new(name: &str, pub fn new(name: &str,
width: usize, width: usize,
height: usize, height: usize,
scale: Scale) opts: WindowOptions)
-> Result<Window, &str> { -> Result<Window, &str> {
unsafe { unsafe {
let scale_factor = Self::get_scale_factor(width, height, scale); let scale_factor = Self::get_scale_factor(width, height, opts.scale);
let handle = Self::open_window(name, width, height, scale_factor); let handle = Self::open_window(name, width, height, opts, scale_factor);
if handle.is_none() { if handle.is_none() {
return Err("Unable to create Window"); return Err("Unable to create Window");
@ -392,6 +415,11 @@ impl Window {
} }
} }
#[inline]
pub fn get_window_handle(&self) -> *mut raw::c_void {
self.window.unwrap() as *mut raw::c_void
}
#[inline] #[inline]
pub fn set_position(&mut self, x: isize, y: isize) { pub fn set_position(&mut self, x: isize, y: isize) {
unsafe { unsafe {
@ -461,10 +489,8 @@ impl Window {
return self.is_open return self.is_open
} }
pub fn update(&mut self, buffer: &[u32]) { fn generic_update(&mut self, window: HWND) {
unsafe { unsafe {
let mut msg = mem::uninitialized();
let window = self.window.unwrap();
let mut point: winapi::POINT = mem::uninitialized(); let mut point: winapi::POINT = mem::uninitialized();
user32::GetCursorPos(&mut point); user32::GetCursorPos(&mut point);
@ -474,18 +500,15 @@ impl Window {
self.mouse.y = point.y as f32; self.mouse.y = point.y as f32;
self.mouse.scroll = 0.0; self.mouse.scroll = 0.0;
//self.mouse_data.x
//println!("{} {}", point.x, point.y);
self.key_handler.update(); self.key_handler.update();
// TODO: Optimize
self.buffer = buffer.iter().cloned().collect();
set_window_long(window, mem::transmute(self)); set_window_long(window, mem::transmute(self));
user32::InvalidateRect(window, ptr::null_mut(), winapi::TRUE); }
}
fn message_loop(&mut self, window: HWND) {
unsafe {
let mut msg = mem::uninitialized();
while user32::PeekMessageW(&mut msg, window, 0, 0, winapi::winuser::PM_REMOVE) != 0 { while user32::PeekMessageW(&mut msg, window, 0, 0, winapi::winuser::PM_REMOVE) != 0 {
user32::TranslateMessage(&mut msg); user32::TranslateMessage(&mut msg);
@ -494,6 +517,26 @@ impl Window {
} }
} }
pub fn update_with_buffer(&mut self, buffer: &[u32]) {
let window = self.window.unwrap();
Self::generic_update(self, window);
self.buffer = buffer.iter().cloned().collect();
unsafe {
user32::InvalidateRect(window, ptr::null_mut(), winapi::TRUE);
}
Self::message_loop(self, window);
}
pub fn update(&mut self) {
let window = self.window.unwrap();
Self::generic_update(self, window);
Self::message_loop(self, window);
}
unsafe fn get_scale_factor(width: usize, height: usize, scale: Scale) -> i32 { unsafe fn get_scale_factor(width: usize, height: usize, scale: Scale) -> i32 {
let factor: i32 = match scale { let factor: i32 = match scale {
Scale::X1 => 1, Scale::X1 => 1,

30
src/window_flags.rs Normal file
View file

@ -0,0 +1,30 @@
#[allow(dead_code)]
const WINDOW_BORDERLESS: u32 = 1 << 1;
#[allow(dead_code)]
const WINDOW_RESIZE: u32 = 1 << 2;
#[allow(dead_code)]
const WINDOW_TITLE: u32 = 1 << 3;
use WindowOptions;
//
// Construct a bitmask of flags (sent to backends) from WindowOpts
//
#[allow(dead_code)]
pub fn get_flags(opts: WindowOptions) -> u32 {
let mut flags = 0u32;
if opts.borderless {
flags |= WINDOW_BORDERLESS;
}
if opts.title {
flags |= WINDOW_TITLE;
}
if opts.resize {
flags |= WINDOW_RESIZE;
}
flags
}