mirror of
https://github.com/italicsjenga/rust_minifb.git
synced 2025-01-27 02:56:33 +11:00
Handle scaling and window close
This commit is contained in:
parent
fa8101b885
commit
264a630c39
2 changed files with 152 additions and 26 deletions
|
@ -10,13 +10,13 @@
|
|||
#define KEY_FUNCTION 0xFF
|
||||
#define KEY_ESC 0x1B
|
||||
|
||||
void mfb_close(void* window_info);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int s_window_count = 0;
|
||||
static Display* s_display;
|
||||
static int s_screen;
|
||||
static int s_width;
|
||||
static int s_height;
|
||||
static GC s_gc;
|
||||
static int s_depth;
|
||||
static int s_setup_done = 0;
|
||||
|
@ -24,6 +24,7 @@ static Visual* s_visual;
|
|||
static int s_screen_width;
|
||||
static int s_screen_height;
|
||||
static XContext s_context;
|
||||
static Atom s_wm_delete_window;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -36,6 +37,7 @@ typedef struct WindowInfo {
|
|||
int scale;
|
||||
int width;
|
||||
int height;
|
||||
int update;
|
||||
} WindowInfo;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -84,6 +86,9 @@ static int setup_display() {
|
|||
s_screen_width = DisplayWidth(s_display, s_screen);
|
||||
s_screen_height = DisplayHeight(s_display, s_screen);
|
||||
|
||||
const char* wmDeleteWindowName = "WM_DELETE_WINDOW";
|
||||
XInternAtoms(s_display, (char**)&wmDeleteWindowName, 1, False, &s_wm_delete_window);
|
||||
|
||||
s_setup_done = 1;
|
||||
|
||||
printf("setup done\n");
|
||||
|
@ -105,6 +110,9 @@ void* mfb_open(const char* title, int width, int height, int scale)
|
|||
return 0;
|
||||
}
|
||||
|
||||
width *= scale;
|
||||
height *= scale;
|
||||
|
||||
Window defaultRootWindow = DefaultRootWindow(s_display);
|
||||
|
||||
windowAttributes.border_pixel = BlackPixel(s_display, s_screen);
|
||||
|
@ -154,6 +162,9 @@ void* mfb_open(const char* title, int width, int height, int scale)
|
|||
window_info->width = width;
|
||||
window_info->height = height;
|
||||
window_info->draw_buffer = malloc(width * height * 4);
|
||||
window_info->update = 1;
|
||||
|
||||
XSetWMProtocols(s_display, window, &s_wm_delete_window, 1);
|
||||
|
||||
XSaveContext(s_display, window, s_context, (XPointer) window_info);
|
||||
|
||||
|
@ -179,13 +190,22 @@ static WindowInfo* find_handle(Window handle)
|
|||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void process_event(XEvent* event) {
|
||||
static int process_event(XEvent* event) {
|
||||
KeySym sym;
|
||||
|
||||
WindowInfo* info = find_handle(event->xany.window);
|
||||
|
||||
if (!info)
|
||||
return;
|
||||
return 1;
|
||||
|
||||
if (event->type == ClientMessage) {
|
||||
if ((Atom)event->xclient.data.l[0] == s_wm_delete_window) {
|
||||
info->update = 0;
|
||||
mfb_close(info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((event->type == KeyPress) || (event->type == KeyRelease) && info->key_callback) {
|
||||
int sym = XLookupKeysym(&event->xkey, 0);
|
||||
|
@ -196,6 +216,8 @@ static void process_event(XEvent* event) {
|
|||
info->key_callback(info->rust_data, sym, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -212,7 +234,10 @@ static int process_events()
|
|||
{
|
||||
XEvent event;
|
||||
XNextEvent(s_display, &event);
|
||||
process_event(&event);
|
||||
|
||||
// Don't process any more messages if event is 0
|
||||
if (process_event(&event) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -220,16 +245,79 @@ static int process_events()
|
|||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void scale_2x(unsigned int* dest, unsigned int* source, int width, int height, int scale) {
|
||||
int x, y;
|
||||
for (y = 0; y < height; y += scale) {
|
||||
for (x = 0; x < width; x += scale) {
|
||||
const unsigned int t = *source++;
|
||||
dest[0] = t;
|
||||
dest[1] = t;
|
||||
dest[width + 0] = t;
|
||||
dest[width + 1] = t;
|
||||
dest += scale;
|
||||
}
|
||||
|
||||
dest += width * (scale - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void scale_4x(unsigned int* dest, unsigned int* source, int width, int height, int scale) {
|
||||
int x, y;
|
||||
for (y = 0; y < height; y += scale) {
|
||||
for (x = 0; x < width; x += scale) {
|
||||
const unsigned int t = *source++;
|
||||
dest[(width * 0) + 0] = t;
|
||||
dest[(width * 0) + 1] = t;
|
||||
dest[(width * 0) + 2] = t;
|
||||
dest[(width * 0) + 3] = t;
|
||||
dest[(width * 1) + 0] = t;
|
||||
dest[(width * 1) + 1] = t;
|
||||
dest[(width * 1) + 2] = t;
|
||||
dest[(width * 1) + 3] = t;
|
||||
dest[(width * 2) + 0] = t;
|
||||
dest[(width * 2) + 1] = t;
|
||||
dest[(width * 2) + 2] = t;
|
||||
dest[(width * 2) + 3] = t;
|
||||
dest[(width * 3) + 0] = t;
|
||||
dest[(width * 3) + 1] = t;
|
||||
dest[(width * 3) + 2] = t;
|
||||
dest[(width * 3) + 3] = t;
|
||||
dest += scale;
|
||||
}
|
||||
|
||||
dest += width * (scale - 1);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void mfb_update(void* window_info, void* buffer)
|
||||
{
|
||||
WindowInfo* info = (WindowInfo*)window_info;
|
||||
int width = info->width;
|
||||
int height = info->height;
|
||||
int scale = info->scale;
|
||||
|
||||
memcpy(info->draw_buffer, buffer, width * height * 4);
|
||||
if (info->update) {
|
||||
switch (scale) {
|
||||
case 1: {
|
||||
memcpy(info->draw_buffer, buffer, width * height * 4);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
scale_2x(info->draw_buffer, buffer, width, height, scale);
|
||||
break;
|
||||
}
|
||||
|
||||
XPutImage(s_display, info->window, s_gc, info->ximage, 0, 0, 0, 0, width, height);
|
||||
XFlush(s_display);
|
||||
case 4: {
|
||||
scale_4x(info->draw_buffer, buffer, width, height, scale);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XPutImage(s_display, info->window, s_gc, info->ximage, 0, 0, 0, 0, width, height);
|
||||
XFlush(s_display);
|
||||
}
|
||||
|
||||
process_events();
|
||||
}
|
||||
|
@ -240,18 +328,18 @@ void mfb_close(void* window_info)
|
|||
{
|
||||
WindowInfo* info = (WindowInfo*)window_info;
|
||||
|
||||
if (!info->draw_buffer)
|
||||
return;
|
||||
|
||||
XSaveContext(s_display, info->window, s_context, (XPointer)0);
|
||||
|
||||
free(info->draw_buffer);
|
||||
|
||||
info->ximage->data = NULL;
|
||||
info->draw_buffer = 0;
|
||||
|
||||
XDestroyImage(info->ximage);
|
||||
XDestroyWindow(s_display, info->window);
|
||||
|
||||
s_window_count--;
|
||||
|
||||
// Only close display when there are no windows left
|
||||
|
||||
if (s_window_count == 0) {
|
||||
XCloseDisplay(s_display);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -263,3 +351,17 @@ void mfb_set_key_callback(void* window, void* rust_data, void (*key_callback)(vo
|
|||
win->rust_data = rust_data;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int mfb_should_close(void* window) {
|
||||
WindowInfo* win = (WindowInfo*)window;
|
||||
return !!win->update;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned int mfb_get_screen_size() {
|
||||
setup_display();
|
||||
return (s_screen_width << 16) | s_screen_height;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@ extern {
|
|||
fn mfb_close(window: *mut c_void);
|
||||
fn mfb_update(window: *mut c_void, buffer: *const c_uchar);
|
||||
fn mfb_set_key_callback(window: *mut c_void, target: *mut c_void, cb: unsafe extern fn(*mut c_void, i32, i32));
|
||||
//fn mfb_should_close(window: *mut c_void) -> i32;
|
||||
//fn mfb_get_screen_size() -> u32;
|
||||
fn mfb_should_close(window: *mut c_void) -> i32;
|
||||
fn mfb_get_screen_size() -> u32;
|
||||
}
|
||||
|
||||
pub struct Window {
|
||||
|
@ -85,6 +85,7 @@ unsafe extern "C" fn key_callback(window: *mut c_void, key: i32, s: i32) {
|
|||
XK_Left => (*win).key_handler.set_key_state(Key::Left, state),
|
||||
XK_Right => (*win).key_handler.set_key_state(Key::Right, state),
|
||||
XK_Up => (*win).key_handler.set_key_state(Key::Up, state),
|
||||
XK_Escape => (*win).key_handler.set_key_state(Key::Escape, state),
|
||||
XK_apostrophe => (*win).key_handler.set_key_state(Key::Apostrophe, state),
|
||||
XK_grave => (*win).key_handler.set_key_state(Key::Backquote, state),
|
||||
XK_backslash => (*win).key_handler.set_key_state(Key::Backslash, state),
|
||||
|
@ -100,7 +101,6 @@ unsafe extern "C" fn key_callback(window: *mut c_void, key: i32, s: i32) {
|
|||
XK_Delete => (*win).key_handler.set_key_state(Key::Delete, state),
|
||||
XK_End => (*win).key_handler.set_key_state(Key::End, state),
|
||||
XK_Return => (*win).key_handler.set_key_state(Key::Enter, state),
|
||||
XK_Escape => (*win).key_handler.set_key_state(Key::Escape, state),
|
||||
XK_Home => (*win).key_handler.set_key_state(Key::Home, state),
|
||||
XK_Insert => (*win).key_handler.set_key_state(Key::Insert, state),
|
||||
XK_Menu => (*win).key_handler.set_key_state(Key::Menu, state),
|
||||
|
@ -203,20 +203,44 @@ impl Window {
|
|||
|
||||
#[inline]
|
||||
pub fn is_open(&self) -> bool {
|
||||
true
|
||||
//unsafe { mfb_should_close(self.window_handle) == 0 }
|
||||
unsafe { mfb_should_close(self.window_handle) == 1 }
|
||||
}
|
||||
|
||||
unsafe fn get_scale_factor(_: usize, _: usize, scale: Scale) -> i32 {
|
||||
unsafe fn get_scale_factor(width: usize, height: usize, scale: Scale) -> i32 {
|
||||
let factor: i32 = match scale {
|
||||
Scale::X1 => 1,
|
||||
Scale::X2 => 2,
|
||||
Scale::X4 => 4,
|
||||
Scale::X8 => 8,
|
||||
Scale::X16 => 16,
|
||||
Scale::X32 => 32,
|
||||
Scale::FitScreen => {
|
||||
1
|
||||
let wh: u32 = mfb_get_screen_size();
|
||||
let screen_x = (wh >> 16) as i32;
|
||||
let screen_y = (wh & 0xffff) as i32;
|
||||
|
||||
println!("{} - {}", screen_x, screen_y);
|
||||
|
||||
let mut scale = 1i32;
|
||||
|
||||
loop {
|
||||
let w = width as i32 * (scale + 1);
|
||||
let h = height as i32 * (scale + 1);
|
||||
|
||||
if w > screen_x || h > screen_y {
|
||||
break;
|
||||
}
|
||||
|
||||
scale *= 2;
|
||||
}
|
||||
|
||||
if scale >= 4 {
|
||||
4
|
||||
} else {
|
||||
scale
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
println!("Scale above 4 not support currently, defaults to 4");
|
||||
4
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue