Add timers and ability to set a target fps for the application (#36)

* working on windows

* minor fix

* working on macosx

* Oops! I reversed resolution and frequency on macos

* working on X11

* working on wayland

* update the readme

* format the readme

Co-authored-by: Carlos Aragones <>
This commit is contained in:
Carlos Aragonés
2020-04-22 13:00:15 +02:00
committed by GitHub
parent 4175cec89e
commit 35b8439b26
19 changed files with 734 additions and 239 deletions

View File

@ -6,15 +6,16 @@
typedef struct {
Window window;
Display *display;
int screen;
GC gc;
XImage *image;
void *image_buffer;
XImage *image_scaler;
uint32_t image_scaler_width;
uint32_t image_scaler_height;
Window window;
Display *display;
int screen;
GC gc;
XImage *image;
void *image_buffer;
XImage *image_scaler;
uint32_t image_scaler_width;
uint32_t image_scaler_height;
struct mfb_timer *timer;
} SWindowData_X11;

View File

@ -7,6 +7,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <MiniFB.h>
#include <MiniFB_internal.h>
#include "WindowData.h"
@ -185,6 +186,8 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags)
window_data_x11->image = XCreateImage(window_data_x11->display, CopyFromParent, depth, ZPixmap, 0, 0x0, width, height, 32, width * 4);
window_data_x11->timer = mfb_timer_create();
mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default);
printf("Window created using X11 API\n");
@ -203,106 +206,111 @@ int translate_key(int scancode);
int translate_mod(int state);
int translate_mod_ex(int key, int state, int is_pressed);
static void
processEvent(SWindowData *window_data, XEvent *event) {
switch (event->type) {
case KeyPress:
case KeyRelease:
{
mfb_key key_code = (mfb_key) translate_key(event->xkey.keycode);
int is_pressed = (event->type == KeyPress);
window_data->mod_keys = translate_mod_ex(key_code, event->xkey.state, is_pressed);
window_data->key_status[key_code] = is_pressed;
kCall(keyboard_func, key_code, (mfb_key_mod) window_data->mod_keys, is_pressed);
}
break;
case ButtonPress:
case ButtonRelease:
{
mfb_mouse_button button = (mfb_mouse_button) event->xbutton.button;
int is_pressed = (event->type == ButtonPress);
window_data->mod_keys = translate_mod(event->xkey.state);
switch (button) {
case Button1:
case Button2:
case Button3:
kCall(mouse_btn_func, button, (mfb_key_mod) window_data->mod_keys, is_pressed);
break;
case Button4:
kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 0.0f, 1.0f);
break;
case Button5:
kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 0.0f, -1.0f);
break;
case 6:
kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 1.0f, 0.0f);
break;
case 7:
kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, -1.0f, 0.0f);
break;
default:
kCall(mouse_btn_func, (mfb_mouse_button) (button - 4), (mfb_key_mod) window_data->mod_keys, is_pressed);
break;
}
}
break;
case MotionNotify:
window_data->mouse_pos_x = event->xmotion.x;
window_data->mouse_pos_y = event->xmotion.y;
kCall(mouse_move_func, event->xmotion.x, event->xmotion.y);
break;
case ConfigureNotify:
{
window_data->window_width = event->xconfigure.width;
window_data->window_height = event->xconfigure.height;
window_data->dst_offset_x = 0;
window_data->dst_offset_y = 0;
window_data->dst_width = window_data->window_width;
window_data->dst_height = window_data->window_height;
SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific;
XClearWindow(window_data_x11->display, window_data_x11->window);
kCall(resize_func, window_data->window_width, window_data->window_height);
}
break;
case EnterNotify:
case LeaveNotify:
break;
case FocusIn:
window_data->is_active = true;
kCall(active_func, true);
break;
case FocusOut:
window_data->is_active = false;
kCall(active_func, false);
break;
case DestroyNotify:
window_data->close = true;
return;
break;
}
}
static void
processEvents(SWindowData *window_data) {
XEvent event;
SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific;
SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific;
while ((window_data->close == false) && XPending(window_data_x11->display)) {
XNextEvent(window_data_x11->display, &event);
switch (event.type) {
case KeyPress:
case KeyRelease:
{
mfb_key key_code = (mfb_key) translate_key(event.xkey.keycode);
int is_pressed = (event.type == KeyPress);
window_data->mod_keys = translate_mod_ex(key_code, event.xkey.state, is_pressed);
window_data->key_status[key_code] = is_pressed;
kCall(keyboard_func, key_code, (mfb_key_mod) window_data->mod_keys, is_pressed);
}
break;
case ButtonPress:
case ButtonRelease:
{
mfb_mouse_button button = (mfb_mouse_button) event.xbutton.button;
int is_pressed = (event.type == ButtonPress);
window_data->mod_keys = translate_mod(event.xkey.state);
switch (button) {
case Button1:
case Button2:
case Button3:
kCall(mouse_btn_func, button, (mfb_key_mod) window_data->mod_keys, is_pressed);
break;
case Button4:
kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 0.0f, 1.0f);
break;
case Button5:
kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 0.0f, -1.0f);
break;
case 6:
kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 1.0f, 0.0f);
break;
case 7:
kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, -1.0f, 0.0f);
break;
default:
kCall(mouse_btn_func, (mfb_mouse_button) (button - 4), (mfb_key_mod) window_data->mod_keys, is_pressed);
break;
}
}
break;
case MotionNotify:
window_data->mouse_pos_x = event.xmotion.x;
window_data->mouse_pos_y = event.xmotion.y;
kCall(mouse_move_func, event.xmotion.x, event.xmotion.y);
break;
case ConfigureNotify:
{
window_data->window_width = event.xconfigure.width;
window_data->window_height = event.xconfigure.height;
window_data->dst_offset_x = 0;
window_data->dst_offset_y = 0;
window_data->dst_width = window_data->window_width;
window_data->dst_height = window_data->window_height;
XClearWindow(window_data_x11->display, window_data_x11->window);
kCall(resize_func, window_data->window_width, window_data->window_height);
}
break;
case EnterNotify:
case LeaveNotify:
break;
case FocusIn:
window_data->is_active = true;
kCall(active_func, true);
break;
case FocusOut:
window_data->is_active = false;
kCall(active_func, false);
break;
case DestroyNotify:
window_data->close = true;
return;
break;
}
processEvent(window_data, &event);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void destroy(SWindowData *window_data);
void destroy_window_data(SWindowData *window_data);
mfb_update_state
mfb_update(struct mfb_window *window, void *buffer) {
@ -312,7 +320,7 @@ mfb_update(struct mfb_window *window, void *buffer) {
SWindowData *window_data = (SWindowData *) window;
if (window_data->close) {
destroy(window_data);
destroy_window_data(window_data);
return STATE_EXIT;
}
@ -368,7 +376,7 @@ mfb_update_events(struct mfb_window *window) {
SWindowData *window_data = (SWindowData *) window;
if (window_data->close) {
destroy(window_data);
destroy_window_data(window_data);
return STATE_EXIT;
}
@ -381,8 +389,56 @@ mfb_update_events(struct mfb_window *window) {
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
extern double g_time_for_frame;
bool
mfb_wait_sync(struct mfb_window *window) {
if (window == 0x0) {
return STATE_INVALID_WINDOW;
}
SWindowData *window_data = (SWindowData *) window;
if (window_data->close) {
destroy_window_data(window_data);
return false;
}
SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific;
XFlush(window_data_x11->display);
XEvent event;
double current;
uint32_t millis = 1;
while(1) {
if(XEventsQueued(window_data_x11->display, QueuedAlready) > 0) {
XNextEvent(window_data_x11->display, &event);
processEvent(window_data, &event);
}
if(window_data->close) {
destroy_window_data(window_data);
return false;
}
current = mfb_timer_now(window_data_x11->timer);
if (current >= g_time_for_frame) {
mfb_timer_reset(window_data_x11->timer);
return true;
}
else if(current >= g_time_for_frame * 0.8) {
millis = 0;
}
usleep(millis * 1000);
//sched_yield();
}
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void
destroy(SWindowData *window_data) {
destroy_window_data(SWindowData *window_data) {
if (window_data != 0x0) {
if (window_data->specific != 0x0) {
SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific;
@ -392,6 +448,7 @@ destroy(SWindowData *window_data) {
XDestroyWindow(window_data_x11->display, window_data_x11->window);
XCloseDisplay(window_data_x11->display);
}
mfb_timer_destroy(window_data_x11->timer);
memset(window_data_x11, 0, sizeof(SWindowData_X11));
free(window_data_x11);
}