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:
parent
4175cec89e
commit
35b8439b26
@ -14,6 +14,7 @@ set(SrcLib
|
|||||||
src/MiniFB_cpp.cpp
|
src/MiniFB_cpp.cpp
|
||||||
src/MiniFB_internal.c
|
src/MiniFB_internal.c
|
||||||
src/MiniFB_internal.h
|
src/MiniFB_internal.h
|
||||||
|
src/MiniFB_timer.c
|
||||||
src/WindowData.h
|
src/WindowData.h
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -34,11 +35,13 @@ set(SrcMacOSX
|
|||||||
set(SrcWayland
|
set(SrcWayland
|
||||||
src/wayland/WaylandMiniFB.c
|
src/wayland/WaylandMiniFB.c
|
||||||
src/wayland/WindowData_Way.h
|
src/wayland/WindowData_Way.h
|
||||||
|
src/MiniFB_linux.c
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SrcX11
|
set(SrcX11
|
||||||
src/x11/X11MiniFB.c
|
src/x11/X11MiniFB.c
|
||||||
src/x11/WindowData_X11.h
|
src/x11/WindowData_X11.h
|
||||||
|
src/MiniFB_linux.c
|
||||||
)
|
)
|
||||||
|
|
||||||
# Avoid RelWithDebInfo and MinSizeRel
|
# Avoid RelWithDebInfo and MinSizeRel
|
||||||
@ -52,6 +55,12 @@ if(NOT CMAKE_BUILD_TYPE)
|
|||||||
message(STATUS "Build type not specified: Use Release by default")
|
message(STATUS "Build type not specified: Use Release by default")
|
||||||
endif(NOT CMAKE_BUILD_TYPE)
|
endif(NOT CMAKE_BUILD_TYPE)
|
||||||
|
|
||||||
|
# Set features
|
||||||
|
#--------------------------------------
|
||||||
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
# Set GCC/Clang flags
|
# Set GCC/Clang flags
|
||||||
#--------------------------------------
|
#--------------------------------------
|
||||||
if (NOT MSVC)
|
if (NOT MSVC)
|
||||||
@ -78,7 +87,6 @@ if (NOT MSVC)
|
|||||||
add_compile_options("$<$<CONFIG:Debug>:-g>")
|
add_compile_options("$<$<CONFIG:Debug>:-g>")
|
||||||
add_compile_options("$<IF:$<CONFIG:Debug>,-O0,-O2>")
|
add_compile_options("$<IF:$<CONFIG:Debug>,-O0,-O2>")
|
||||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -pedantic -Wno-switch -Wno-unused-function -Wno-implicit-fallthrough")
|
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -pedantic -Wno-switch -Wno-unused-function -Wno-implicit-fallthrough")
|
||||||
set (CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11")
|
|
||||||
set (CMAKE_OBJC_FLAGS "${CMAKE_C_FLAGS}")
|
set (CMAKE_OBJC_FLAGS "${CMAKE_C_FLAGS}")
|
||||||
set (CMAKE_OBJCXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
set (CMAKE_OBJCXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||||
endif()
|
endif()
|
||||||
|
265
README.md
265
README.md
@ -1,117 +1,173 @@
|
|||||||
MiniFB
|
# MiniFB
|
||||||
======
|
|
||||||
|
|
||||||
MiniFB (Mini FrameBuffer) is a small cross platform library that makes it easy to render (32-bit) pixels in a window. An example is the best way to show how it works:
|
MiniFB (Mini FrameBuffer) is a small cross platform library that makes it easy to render (32-bit) pixels in a window. An example is the best way to show how it works:
|
||||||
|
|
||||||
struct mfb_window *window = mfb_open_ex("my display", 800, 600, WF_RESIZABLE);
|
```c
|
||||||
if (!window)
|
struct mfb_window *window = mfb_open_ex("my display", 800, 600, WF_RESIZABLE);
|
||||||
return 0;
|
if (!window)
|
||||||
|
return 0;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
int state;
|
int state;
|
||||||
|
|
||||||
// TODO: add some fancy rendering to the buffer of size 800 * 600
|
// TODO: add some fancy rendering to the buffer of size 800 * 600
|
||||||
|
|
||||||
state = mfb_update(buffer);
|
state = mfb_update(buffer);
|
||||||
|
|
||||||
if (state < 0)
|
if (state < 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Furthermore, you can add callbacks to the windows:
|
Furthermore, you can _add callbacks to the windows_:
|
||||||
|
|
||||||
void active(struct mfb_window *window, bool isActive) {
|
```c
|
||||||
...
|
void active(struct mfb_window *window, bool isActive) {
|
||||||
}
|
|
||||||
|
|
||||||
void resize(struct mfb_window *window, int width, int height) {
|
|
||||||
...
|
|
||||||
// Optionally you can also change the viewport size
|
|
||||||
mfb_set_viewport(window, x, y, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
void keyboard(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed) {
|
|
||||||
...
|
|
||||||
// Remember to close the window in some way
|
|
||||||
if(key == KB_KEY_ESCAPE) {
|
|
||||||
mfb_close(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stdout, "%s > keyboard: key: %s (pressed: %d) [key_mod: %x]\n", window_title, mfb_get_key_name(key), isPressed, mod);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void char_input(struct mfb_window *window, unsigned int charCode) {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
void mouse_btn(struct mfb_window *window, mfb_mouse_button button, mfb_key_mod mod, bool isPressed) {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use wisely this event. It can be sent too often
|
|
||||||
void mouse_move(struct mfb_window *window, int x, int y) {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mouse wheel
|
|
||||||
void mouse_scroll(struct mfb_window *window, mfb_key_mod mod, float deltaX, float deltaY) {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
struct mfb_window *window = mfb_open_ex("my display", 800, 600, WF_RESIZABLE);
|
|
||||||
if (!window)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
mfb_set_active_callback(window, active);
|
|
||||||
mfb_set_resize_callback(window, resize);
|
|
||||||
mfb_set_keyboard_callback(window, keyboard);
|
|
||||||
mfb_set_char_input_callback(window, char_input);
|
|
||||||
mfb_set_mouse_button_callback(window, mouse_btn);
|
|
||||||
mfb_set_mouse_move_callback(window, mouse_move);
|
|
||||||
mfb_set_mouse_scroll_callback(window, mouse_scroll);
|
|
||||||
|
|
||||||
|
|
||||||
Additionally you can set data per window and recover it
|
|
||||||
|
|
||||||
mfb_set_user_data(window, (void *) myData);
|
|
||||||
...
|
...
|
||||||
myData = (someCast *) mfb_get_user_data(window);
|
}
|
||||||
|
|
||||||
|
void resize(struct mfb_window *window, int width, int height) {
|
||||||
|
...
|
||||||
|
// Optionally you can also change the viewport size
|
||||||
|
mfb_set_viewport(window, x, y, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void keyboard(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed) {
|
||||||
|
...
|
||||||
|
// Remember to close the window in some way
|
||||||
|
if(key == KB_KEY_ESCAPE) {
|
||||||
|
mfb_close(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stdout, "%s > keyboard: key: %s (pressed: %d) [key_mod: %x]\n", window_title, mfb_get_key_name(key), isPressed, mod);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void char_input(struct mfb_window *window, unsigned int charCode) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
void mouse_btn(struct mfb_window *window, mfb_mouse_button button, mfb_key_mod mod, bool isPressed) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use wisely this event. It can be sent too often
|
||||||
|
void mouse_move(struct mfb_window *window, int x, int y) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mouse wheel
|
||||||
|
void mouse_scroll(struct mfb_window *window, mfb_key_mod mod, float deltaX, float deltaY) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mfb_window *window = mfb_open_ex("my display", 800, 600, WF_RESIZABLE);
|
||||||
|
if (!window)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
mfb_set_active_callback(window, active);
|
||||||
|
mfb_set_resize_callback(window, resize);
|
||||||
|
mfb_set_keyboard_callback(window, keyboard);
|
||||||
|
mfb_set_char_input_callback(window, char_input);
|
||||||
|
mfb_set_mouse_button_callback(window, mouse_btn);
|
||||||
|
mfb_set_mouse_move_callback(window, mouse_move);
|
||||||
|
mfb_set_mouse_scroll_callback(window, mouse_scroll);
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Finally, you can get information about the events in the window directly:
|
Additionally you can _set data per window and recover it_:
|
||||||
|
|
||||||
bool mfb_is_window_active(struct mfb_window *window);
|
```c
|
||||||
|
mfb_set_user_data(window, (void *) myData);
|
||||||
|
...
|
||||||
|
myData = (someCast *) mfb_get_user_data(window);
|
||||||
|
```
|
||||||
|
|
||||||
unsigned mfb_get_window_width(struct mfb_window *window);
|
|
||||||
unsigned mfb_get_window_height(struct mfb_window *window);
|
|
||||||
|
|
||||||
int mfb_get_mouse_x(struct mfb_window *window); // Last mouse pos X
|
Finally, you can _get information about the events in the window directly_:
|
||||||
int mfb_get_mouse_y(struct mfb_window *window); // Last mouse pos Y
|
|
||||||
|
|
||||||
float mfb_get_mouse_scroll_x(struct mfb_window *window); // Mouse wheel X as a sum. When you call this function it resets.
|
```c
|
||||||
float mfb_get_mouse_scroll_y(struct mfb_window *window); // Mouse wheel Y as a sum. When you call this function it resets.
|
bool mfb_is_window_active(struct mfb_window *window);
|
||||||
|
|
||||||
const uint8_t * mfb_get_mouse_button_buffer(struct mfb_window *window); // One byte for every button. Press (1), Release 0. (up to 8 buttons)
|
unsigned mfb_get_window_width(struct mfb_window *window);
|
||||||
|
unsigned mfb_get_window_height(struct mfb_window *window);
|
||||||
|
|
||||||
const uint8_t * mfb_get_key_buffer(struct mfb_window *window); // One byte for every key. Press (1), Release 0.
|
int mfb_get_mouse_x(struct mfb_window *window); // Last mouse pos X
|
||||||
|
int mfb_get_mouse_y(struct mfb_window *window); // Last mouse pos Y
|
||||||
|
|
||||||
|
float mfb_get_mouse_scroll_x(struct mfb_window *window); // Mouse wheel X as a sum. When you call this function it resets.
|
||||||
|
float mfb_get_mouse_scroll_y(struct mfb_window *window); // Mouse wheel Y as a sum. When you call this function it resets.
|
||||||
|
|
||||||
|
const uint8_t * mfb_get_mouse_button_buffer(struct mfb_window *window); // One byte for every button. Press (1), Release 0. (up to 8 buttons)
|
||||||
|
|
||||||
|
const uint8_t * mfb_get_key_buffer(struct mfb_window *window); // One byte for every key. Press (1), Release 0.
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
First the code creates window with the mfb_open call that is used to display the data, next it's the applications responsibility to allocate a buffer (which has to be at least the size of the window and in 32-bit) Next when calling mfb_update function the buffer will be copied over to the window and displayed. Currently the mfb_update will return -1 if ESC key is pressed but later on it will support to return a key code for a pressed button. See https://github.com/emoon/minifb/blob/master/tests/noise.c for a complete example
|
First the code creates window with the mfb_open call that is used to display the data, next it's the applications responsibility to allocate a buffer (which has to be at least the size of the window and in 32-bit) Next when calling mfb_update function the buffer will be copied over to the window and displayed. Currently the mfb_update will return -1 if ESC key is pressed but later on it will support to return a key code for a pressed button. See https://github.com/emoon/minifb/blob/master/tests/noise.c for a complete example
|
||||||
|
|
||||||
MiniFB has been tested on Windows, Mac OS X and Linux but may of course have trouble depending on your setup. Currently the code will not do any converting of data if not a proper 32-bit display can be created.
|
MiniFB has been tested on Windows, Mac OS X and Linux but may of course have trouble depending on your setup. Currently the code will not do any converting of data if not a proper 32-bit display can be created.
|
||||||
|
|
||||||
Build instructions
|
|
||||||
------------------
|
**Extra: Timers and target FPS**
|
||||||
|
|
||||||
|
You can create timers for your own purposes.
|
||||||
|
|
||||||
|
```c
|
||||||
|
struct mfb_timer * mfb_timer_create();
|
||||||
|
void mfb_timer_destroy(struct mfb_timer *tmr);
|
||||||
|
|
||||||
|
void mfb_timer_reset(struct mfb_timer *tmr);
|
||||||
|
double mfb_timer_now(struct mfb_timer *tmr);
|
||||||
|
double mfb_timer_delta(struct mfb_timer *tmr);
|
||||||
|
|
||||||
|
double mfb_timer_get_frequency();
|
||||||
|
double mfb_timer_get_resolution();
|
||||||
|
```
|
||||||
|
|
||||||
|
Furthermore you can set a target fps for the application. The default is 60 frames per second.
|
||||||
|
|
||||||
|
```c
|
||||||
|
void mfb_set_target_fps(uint32_t fps);
|
||||||
|
```
|
||||||
|
|
||||||
|
This avoid the problem of update too fast the window collapsing the redrawing in fast processors.
|
||||||
|
|
||||||
|
To use this you need to call the function:
|
||||||
|
|
||||||
|
```c
|
||||||
|
bool mfb_wait_sync(struct mfb_window *window);
|
||||||
|
```
|
||||||
|
|
||||||
|
_Example_:
|
||||||
|
|
||||||
|
```c
|
||||||
|
do {
|
||||||
|
int i;
|
||||||
|
mfb_update_state state;
|
||||||
|
|
||||||
|
// TODO: add some awesome rendering to the buffer
|
||||||
|
|
||||||
|
state = mfb_update(window, g_buffer);
|
||||||
|
if (state != STATE_OK) {
|
||||||
|
window = 0x0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(mfb_wait_sync(window));
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that if you have several windows running on the same thread it makes no sense to wait them all...
|
||||||
|
|
||||||
|
|
||||||
|
## Build instructions
|
||||||
|
|
||||||
MiniFB uses tundra https://github.com/deplinenoise/tundra as build system and is required to build the code as is but not many changes should be needed if you want to use it directly in your own code.
|
MiniFB uses tundra https://github.com/deplinenoise/tundra as build system and is required to build the code as is but not many changes should be needed if you want to use it directly in your own code.
|
||||||
|
|
||||||
You can also use CMake as build system.
|
You can also use CMake as build system.
|
||||||
|
|
||||||
Mac
|
### Mac
|
||||||
---
|
|
||||||
|
|
||||||
Cocoa and clang is assumed to be installed on the system (downloading latest XCode + installing the command line tools should do the trick) then to build run: tundra2 macosx-clang-debug and you should be able to run the noise example (t2-output/macosx-clang-debug-default/noise)
|
Cocoa and clang is assumed to be installed on the system (downloading latest XCode + installing the command line tools should do the trick) then to build run: tundra2 macosx-clang-debug and you should be able to run the noise example (t2-output/macosx-clang-debug-default/noise)
|
||||||
|
|
||||||
@ -120,44 +176,49 @@ To enable it just compile defining the preprocessor macro USE_METAL_API.
|
|||||||
|
|
||||||
If you use CMake just enable the flag:
|
If you use CMake just enable the flag:
|
||||||
|
|
||||||
mkdir build
|
```
|
||||||
cd build
|
mkdir build
|
||||||
cmake .. -DUSE_METAL_API=ON
|
cd build
|
||||||
|
cmake .. -DUSE_METAL_API=ON
|
||||||
|
```
|
||||||
|
|
||||||
or if you don't want to use Metal API:
|
or if you don't want to use Metal API:
|
||||||
|
|
||||||
mkdir build
|
```
|
||||||
cd build
|
mkdir build
|
||||||
cmake .. -DUSE_METAL_API=OFF
|
cd build
|
||||||
|
cmake .. -DUSE_METAL_API=OFF
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Windows
|
### Windows
|
||||||
-------
|
|
||||||
|
|
||||||
Visual Studio (ver 2012 express has been tested) tools needed (using the vcvars32.bat (for 32-bit) will set up the enviroment) to build run: tundra2 win32-msvc-debug and you should be able to run noise in t2-output/win32-msvc-debug-default/noise.exe
|
Visual Studio (ver 2012 express has been tested) tools needed (using the vcvars32.bat (for 32-bit) will set up the enviroment) to build run: tundra2 win32-msvc-debug and you should be able to run noise in t2-output/win32-msvc-debug-default/noise.exe
|
||||||
|
|
||||||
If you use CMake the Visual Studio project will be generated (2015, 2017 and 2019 have been tested).
|
If you use CMake the Visual Studio project will be generated (2015, 2017 and 2019 have been tested).
|
||||||
|
|
||||||
|
|
||||||
x11 (FreeBSD, Linux, *nix)
|
### x11 (FreeBSD, Linux, *nix)
|
||||||
--------------------------
|
|
||||||
|
|
||||||
gcc and x11-dev libs needs to be installed. To build the code run tundra2 x11-gcc-debug and you should be able to run t2-output/x11-gcc-debug-default/noise
|
gcc and x11-dev libs needs to be installed. To build the code run tundra2 x11-gcc-debug and you should be able to run t2-output/x11-gcc-debug-default/noise
|
||||||
|
|
||||||
If you use CMake just disable the flag:
|
If you use CMake just disable the flag:
|
||||||
|
|
||||||
mkdir build
|
```
|
||||||
cd build
|
mkdir build
|
||||||
cmake .. -DUSE_WAYLAND_API=OFF
|
cd build
|
||||||
|
cmake .. -DUSE_WAYLAND_API=OFF
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
wayland (Linux)
|
### Wayland (Linux)
|
||||||
--------------------------
|
|
||||||
|
|
||||||
Depends on gcc and wayland-client and wayland-cursor. Built using the wayland-gcc variants.
|
Depends on gcc and wayland-client and wayland-cursor. Built using the wayland-gcc variants.
|
||||||
|
|
||||||
If you use CMake just enable the flag:
|
If you use CMake just enable the flag:
|
||||||
|
|
||||||
mkdir build
|
```
|
||||||
cd build
|
mkdir build
|
||||||
cmake .. -DUSE_WAYLAND_API=ON
|
cd build
|
||||||
|
cmake .. -DUSE_WAYLAND_API=ON
|
||||||
|
```
|
||||||
|
@ -56,6 +56,17 @@ float mfb_get_mouse_scroll_y(struct mfb_window *window); // M
|
|||||||
const uint8_t * mfb_get_mouse_button_buffer(struct mfb_window *window); // One byte for every button. Press (1), Release 0. (up to 8 buttons)
|
const uint8_t * mfb_get_mouse_button_buffer(struct mfb_window *window); // One byte for every button. Press (1), Release 0. (up to 8 buttons)
|
||||||
const uint8_t * mfb_get_key_buffer(struct mfb_window *window); // One byte for every key. Press (1), Release 0.
|
const uint8_t * mfb_get_key_buffer(struct mfb_window *window); // One byte for every key. Press (1), Release 0.
|
||||||
|
|
||||||
|
void mfb_set_target_fps(uint32_t fps);
|
||||||
|
bool mfb_wait_sync(struct mfb_window *window);
|
||||||
|
|
||||||
|
struct mfb_timer * mfb_timer_create();
|
||||||
|
void mfb_timer_destroy(struct mfb_timer *tmr);
|
||||||
|
void mfb_timer_reset(struct mfb_timer *tmr);
|
||||||
|
double mfb_timer_now(struct mfb_timer *tmr);
|
||||||
|
double mfb_timer_delta(struct mfb_timer *tmr);
|
||||||
|
double mfb_timer_get_frequency();
|
||||||
|
double mfb_timer_get_resolution();
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -172,6 +172,7 @@ typedef enum {
|
|||||||
|
|
||||||
// Opaque pointer
|
// Opaque pointer
|
||||||
struct mfb_window;
|
struct mfb_window;
|
||||||
|
struct mfb_timer;
|
||||||
|
|
||||||
// Event callbacks
|
// Event callbacks
|
||||||
typedef void(*mfb_active_func)(struct mfb_window *window, bool isActive);
|
typedef void(*mfb_active_func)(struct mfb_window *window, bool isActive);
|
||||||
|
@ -6,6 +6,13 @@
|
|||||||
#define kCall(func, ...) if(window_data && window_data->func) window_data->func((struct mfb_window *) window_data, __VA_ARGS__);
|
#define kCall(func, ...) if(window_data && window_data->func) window_data->func((struct mfb_window *) window_data, __VA_ARGS__);
|
||||||
#define kUnused(var) (void) var;
|
#define kUnused(var) (void) var;
|
||||||
|
|
||||||
|
typedef struct mfb_timer {
|
||||||
|
int64_t start_time;
|
||||||
|
int64_t delta_counter;
|
||||||
|
uint64_t time;
|
||||||
|
} mfb_timer;
|
||||||
|
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
32
src/MiniFB_linux.c
Normal file
32
src/MiniFB_linux.c
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include <time.h>
|
||||||
|
#include <MiniFB.h>
|
||||||
|
|
||||||
|
extern double g_timer_frequency;
|
||||||
|
extern double g_timer_resolution;
|
||||||
|
|
||||||
|
#define kClock CLOCK_MONOTONIC
|
||||||
|
//#define kClock CLOCK_REALTIME
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
mfb_timer_tick() {
|
||||||
|
struct timespec time;
|
||||||
|
|
||||||
|
if (clock_gettime(kClock, &time) != 0) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.tv_sec * 1e+9 + time.tv_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mfb_timer_init() {
|
||||||
|
struct timespec res;
|
||||||
|
|
||||||
|
if (clock_getres(kClock, &res) != 0) {
|
||||||
|
g_timer_frequency = 1e+9;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g_timer_frequency = res.tv_sec + res.tv_nsec * 1e+9;
|
||||||
|
}
|
||||||
|
g_timer_resolution = 1.0 / g_timer_frequency;
|
||||||
|
}
|
102
src/MiniFB_timer.c
Normal file
102
src/MiniFB_timer.c
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#include "MiniFB.h"
|
||||||
|
#include "MiniFB_internal.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
double g_timer_frequency;
|
||||||
|
double g_timer_resolution;
|
||||||
|
double g_time_for_frame = 1.0 / 60.0;
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
extern uint64_t mfb_timer_tick();
|
||||||
|
extern void mfb_timer_init();
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
void
|
||||||
|
mfb_set_target_fps(uint32_t fps) {
|
||||||
|
if(fps == 0) {
|
||||||
|
g_time_for_frame = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g_time_for_frame = 1.0 / fps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
struct mfb_timer *
|
||||||
|
mfb_timer_create() {
|
||||||
|
static int once = 1;
|
||||||
|
mfb_timer *tmr;
|
||||||
|
|
||||||
|
if(once) {
|
||||||
|
once = 0;
|
||||||
|
mfb_timer_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
tmr = malloc(sizeof(mfb_timer));
|
||||||
|
mfb_timer_reset(tmr);
|
||||||
|
|
||||||
|
return tmr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
void
|
||||||
|
mfb_timer_destroy(struct mfb_timer *tmr) {
|
||||||
|
if(tmr != 0x0) {
|
||||||
|
free(tmr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
void
|
||||||
|
mfb_timer_reset(struct mfb_timer *tmr) {
|
||||||
|
if(tmr == 0x0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
tmr->start_time = mfb_timer_tick();
|
||||||
|
tmr->delta_counter = tmr->start_time;
|
||||||
|
tmr->time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
double
|
||||||
|
mfb_timer_now(struct mfb_timer *tmr) {
|
||||||
|
uint64_t counter;
|
||||||
|
|
||||||
|
if(tmr == 0x0)
|
||||||
|
return 0.0;
|
||||||
|
|
||||||
|
counter = mfb_timer_tick();
|
||||||
|
tmr->time += (counter - tmr->start_time);
|
||||||
|
tmr->start_time = counter;
|
||||||
|
|
||||||
|
return tmr->time * g_timer_resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
double
|
||||||
|
mfb_timer_delta(struct mfb_timer *tmr) {
|
||||||
|
int64_t counter;
|
||||||
|
uint64_t delta;
|
||||||
|
|
||||||
|
if(tmr == 0x0)
|
||||||
|
return 0.0;
|
||||||
|
|
||||||
|
counter = mfb_timer_tick();
|
||||||
|
delta = (counter - tmr->delta_counter);
|
||||||
|
tmr->delta_counter = counter;
|
||||||
|
|
||||||
|
return delta * g_timer_resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
double
|
||||||
|
mfb_timer_get_frequency() {
|
||||||
|
return g_timer_frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
double
|
||||||
|
mfb_timer_get_resolution() {
|
||||||
|
return g_timer_resolution;
|
||||||
|
}
|
@ -10,6 +10,8 @@
|
|||||||
#include <MetalKit/MetalKit.h>
|
#include <MetalKit/MetalKit.h>
|
||||||
#endif
|
#endif
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <mach/mach_time.h>
|
||||||
|
|
||||||
void init_keycodes();
|
void init_keycodes();
|
||||||
|
|
||||||
@ -250,6 +252,7 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags)
|
|||||||
[window_data_osx->window setAcceptsMouseMovedEvents:YES];
|
[window_data_osx->window setAcceptsMouseMovedEvents:YES];
|
||||||
|
|
||||||
[window_data_osx->window center];
|
[window_data_osx->window center];
|
||||||
|
window_data_osx->timer = mfb_timer_create();
|
||||||
|
|
||||||
[NSApp activateIgnoringOtherApps:YES];
|
[NSApp activateIgnoringOtherApps:YES];
|
||||||
|
|
||||||
@ -286,6 +289,8 @@ destroy_window_data(SWindowData *window_data)
|
|||||||
[window removeWindowData];
|
[window removeWindowData];
|
||||||
[window performClose:nil];
|
[window performClose:nil];
|
||||||
|
|
||||||
|
mfb_timer_destroy(window_data_osx->timer);
|
||||||
|
|
||||||
memset(window_data_osx, 0, sizeof(SWindowData_OSX));
|
memset(window_data_osx, 0, sizeof(SWindowData_OSX));
|
||||||
free(window_data_osx);
|
free(window_data_osx);
|
||||||
}
|
}
|
||||||
@ -303,14 +308,12 @@ update_events(SWindowData *window_data)
|
|||||||
NSEvent* event;
|
NSEvent* event;
|
||||||
|
|
||||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||||
do
|
do {
|
||||||
{
|
|
||||||
event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES];
|
event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES];
|
||||||
if (event) {
|
if (event) {
|
||||||
[NSApp sendEvent:event];
|
[NSApp sendEvent:event];
|
||||||
}
|
}
|
||||||
}
|
} while ((window_data->close == false) && event);
|
||||||
while ((window_data->close == false) && event);
|
|
||||||
|
|
||||||
[pool release];
|
[pool release];
|
||||||
}
|
}
|
||||||
@ -375,6 +378,59 @@ mfb_update_events(struct mfb_window *window)
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
extern double g_time_for_frame;
|
||||||
|
|
||||||
|
bool
|
||||||
|
mfb_wait_sync(struct mfb_window *window)
|
||||||
|
{
|
||||||
|
NSEvent* event;
|
||||||
|
|
||||||
|
if(window == 0x0) {
|
||||||
|
return STATE_INVALID_WINDOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
SWindowData *window_data = (SWindowData *) window;
|
||||||
|
if(window_data->close) {
|
||||||
|
destroy_window_data(window_data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
|
||||||
|
SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific;
|
||||||
|
double current;
|
||||||
|
uint32_t millis = 1;
|
||||||
|
while(1) {
|
||||||
|
event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES];
|
||||||
|
if (event) {
|
||||||
|
[NSApp sendEvent:event];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(window_data->close) {
|
||||||
|
destroy_window_data(window_data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = mfb_timer_now(window_data_osx->timer);
|
||||||
|
if (current >= g_time_for_frame) {
|
||||||
|
mfb_timer_reset(window_data_osx->timer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(current >= g_time_for_frame * 0.8) {
|
||||||
|
millis = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(millis * 1000);
|
||||||
|
//sched_yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
//[pool release];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool
|
bool
|
||||||
mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height)
|
mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height)
|
||||||
{
|
{
|
||||||
@ -540,3 +596,35 @@ init_keycodes()
|
|||||||
g_keycodes[0x43] = KB_KEY_KP_MULTIPLY;
|
g_keycodes[0x43] = KB_KEY_KP_MULTIPLY;
|
||||||
g_keycodes[0x4E] = KB_KEY_KP_SUBTRACT;
|
g_keycodes[0x4E] = KB_KEY_KP_SUBTRACT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
extern double g_timer_frequency;
|
||||||
|
extern double g_timer_resolution;
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
mfb_timer_tick() {
|
||||||
|
static mach_timebase_info_data_t timebase = { 0 };
|
||||||
|
|
||||||
|
if (timebase.denom == 0) {
|
||||||
|
(void) mach_timebase_info(&timebase);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t time = mach_absolute_time();
|
||||||
|
|
||||||
|
//return (time * s_timebase_info.numer) / s_timebase_info.denom;
|
||||||
|
|
||||||
|
// Perform the arithmetic at 128-bit precision to avoid the overflow!
|
||||||
|
uint64_t high = (time >> 32) * timebase.numer;
|
||||||
|
uint64_t highRem = ((high % timebase.denom) << 32) / timebase.denom;
|
||||||
|
uint64_t low = (time & 0xFFFFFFFFull) * timebase.numer / timebase.denom;
|
||||||
|
high /= timebase.denom;
|
||||||
|
|
||||||
|
return (high << 32) + highRem + low;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mfb_timer_init() {
|
||||||
|
g_timer_frequency = 1e+9;
|
||||||
|
g_timer_resolution = 1.0 / g_timer_frequency;
|
||||||
|
}
|
||||||
|
@ -10,7 +10,9 @@
|
|||||||
@class OSXWindow;
|
@class OSXWindow;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
OSXWindow *window;
|
OSXWindow *window;
|
||||||
|
struct mfb_timer *timer;
|
||||||
|
|
||||||
#if defined(USE_METAL_API)
|
#if defined(USE_METAL_API)
|
||||||
struct {
|
struct {
|
||||||
id<MTLCommandQueue> command_queue;
|
id<MTLCommandQueue> command_queue;
|
||||||
|
@ -27,6 +27,7 @@ destroy_window_data(SWindowData *window_data)
|
|||||||
|
|
||||||
SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific;
|
SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific;
|
||||||
if(window_data_way != 0x0) {
|
if(window_data_way != 0x0) {
|
||||||
|
mfb_timer_destroy(window_data_way->timer);
|
||||||
memset(window_data_way, 0, sizeof(SWindowData_Way));
|
memset(window_data_way, 0, sizeof(SWindowData_Way));
|
||||||
free(window_data_way);
|
free(window_data_way);
|
||||||
}
|
}
|
||||||
@ -596,8 +597,8 @@ mfb_open(const char *title, unsigned width, unsigned height)
|
|||||||
|
|
||||||
init_keycodes();
|
init_keycodes();
|
||||||
|
|
||||||
if (wl_display_dispatch(window_data_way->display) == -1 || wl_display_roundtrip(window_data_way->display) == -1)
|
if (wl_display_dispatch(window_data_way->display) == -1 ||
|
||||||
{
|
wl_display_roundtrip(window_data_way->display) == -1) {
|
||||||
return 0x0;
|
return 0x0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -667,6 +668,8 @@ mfb_open(const char *title, unsigned width, unsigned height)
|
|||||||
wl_surface_damage(window_data_way->surface, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height);
|
wl_surface_damage(window_data_way->surface, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height);
|
||||||
wl_surface_commit(window_data_way->surface);
|
wl_surface_commit(window_data_way->surface);
|
||||||
|
|
||||||
|
window_data_way->timer = mfb_timer_create();
|
||||||
|
|
||||||
mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default);
|
mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default);
|
||||||
|
|
||||||
printf("Window created using Wayland API\n");
|
printf("Window created using Wayland API\n");
|
||||||
@ -762,7 +765,7 @@ mfb_update_events(struct mfb_window *window)
|
|||||||
if (!window_data_way->display || wl_display_get_error(window_data_way->display) != 0)
|
if (!window_data_way->display || wl_display_get_error(window_data_way->display) != 0)
|
||||||
return STATE_INTERNAL_ERROR;
|
return STATE_INTERNAL_ERROR;
|
||||||
|
|
||||||
if (wl_display_dispatch(window_data_way->display) == -1 || wl_display_roundtrip(window_data_way->display) == -1) {
|
if (wl_display_dispatch_pending(window_data_way->display) == -1) {
|
||||||
return STATE_INTERNAL_ERROR;
|
return STATE_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -771,6 +774,51 @@ 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 false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SWindowData *window_data = (SWindowData *) window;
|
||||||
|
if(window_data->close) {
|
||||||
|
destroy(window_data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific;
|
||||||
|
double current;
|
||||||
|
uint32_t millis = 1;
|
||||||
|
while(1) {
|
||||||
|
if (wl_display_dispatch_pending(window_data_way->display) == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(window_data->close) {
|
||||||
|
destroy_window_data(window_data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = mfb_timer_now(window_data_way->timer);
|
||||||
|
if (current >= g_time_for_frame) {
|
||||||
|
mfb_timer_reset(window_data_way->timer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(current >= g_time_for_frame * 0.8) {
|
||||||
|
millis = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(millis * 1000);
|
||||||
|
//sched_yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
extern short int g_keycodes[512];
|
extern short int g_keycodes[512];
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -53,5 +53,6 @@ typedef struct
|
|||||||
uint32_t buffer_stride;
|
uint32_t buffer_stride;
|
||||||
|
|
||||||
uint32_t mod_keys;
|
uint32_t mod_keys;
|
||||||
|
struct mfb_timer *timer;
|
||||||
bool close;
|
bool close;
|
||||||
} SWindowData_Way;
|
} SWindowData_Way;
|
||||||
|
@ -48,10 +48,8 @@ WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
|||||||
|
|
||||||
StretchDIBits(window_data_win->hdc, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height, 0, 0, window_data->buffer_width, window_data->buffer_height, window_data->draw_buffer,
|
StretchDIBits(window_data_win->hdc, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height, 0, 0, window_data->buffer_width, window_data->buffer_height, window_data->draw_buffer,
|
||||||
window_data_win->bitmapInfo, DIB_RGB_COLORS, SRCCOPY);
|
window_data_win->bitmapInfo, DIB_RGB_COLORS, SRCCOPY);
|
||||||
|
|
||||||
ValidateRect(hWnd, 0x0);
|
|
||||||
}
|
}
|
||||||
|
ValidateRect(hWnd, 0x0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,6 +357,8 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags)
|
|||||||
|
|
||||||
window_data_win->hdc = GetDC(window_data_win->window);
|
window_data_win->hdc = GetDC(window_data_win->window);
|
||||||
|
|
||||||
|
window_data_win->timer = mfb_timer_create();
|
||||||
|
|
||||||
mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default);
|
mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default);
|
||||||
|
|
||||||
return (struct mfb_window *) window_data;
|
return (struct mfb_window *) window_data;
|
||||||
@ -421,9 +421,8 @@ mfb_update_events(struct mfb_window *window) {
|
|||||||
|
|
||||||
SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific;
|
SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific;
|
||||||
while (window_data->close == false && PeekMessage(&msg, window_data_win->window, 0, 0, PM_REMOVE)) {
|
while (window_data->close == false && PeekMessage(&msg, window_data_win->window, 0, 0, PM_REMOVE)) {
|
||||||
if(msg.message == WM_PAINT)
|
//if(msg.message == WM_PAINT)
|
||||||
return STATE_OK;
|
// return STATE_OK;
|
||||||
|
|
||||||
TranslateMessage(&msg);
|
TranslateMessage(&msg);
|
||||||
DispatchMessage(&msg);
|
DispatchMessage(&msg);
|
||||||
}
|
}
|
||||||
@ -433,6 +432,53 @@ mfb_update_events(struct mfb_window *window) {
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
extern double g_time_for_frame;
|
||||||
|
|
||||||
|
bool
|
||||||
|
mfb_wait_sync(struct mfb_window *window) {
|
||||||
|
MSG msg;
|
||||||
|
|
||||||
|
if (window == 0x0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SWindowData *window_data = (SWindowData *)window;
|
||||||
|
if (window_data->close) {
|
||||||
|
destroy_window_data(window_data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific;
|
||||||
|
double current;
|
||||||
|
uint32_t millis = 1;
|
||||||
|
while (1) {
|
||||||
|
if(PeekMessage(&msg, window_data_win->window, 0, 0, PM_REMOVE)) {
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window_data->close) {
|
||||||
|
destroy_window_data(window_data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = mfb_timer_now(window_data_win->timer);;
|
||||||
|
if (current >= g_time_for_frame) {
|
||||||
|
mfb_timer_reset(window_data_win->timer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(current >= g_time_for_frame * 0.8) {
|
||||||
|
millis = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sleep(millis);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void
|
void
|
||||||
destroy_window_data(SWindowData *window_data) {
|
destroy_window_data(SWindowData *window_data) {
|
||||||
if (window_data == 0x0)
|
if (window_data == 0x0)
|
||||||
@ -453,6 +499,8 @@ destroy_window_data(SWindowData *window_data) {
|
|||||||
window_data_win->window = 0;
|
window_data_win->window = 0;
|
||||||
window_data_win->hdc = 0;
|
window_data_win->hdc = 0;
|
||||||
window_data_win->bitmapInfo = 0x0;
|
window_data_win->bitmapInfo = 0x0;
|
||||||
|
mfb_timer_destroy(window_data_win->timer);
|
||||||
|
window_data_win->timer = 0x0;
|
||||||
window_data->close = true;
|
window_data->close = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -659,3 +707,27 @@ mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
extern double g_timer_frequency;
|
||||||
|
extern double g_timer_resolution;
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
mfb_timer_tick() {
|
||||||
|
int64_t counter;
|
||||||
|
|
||||||
|
QueryPerformanceCounter((LARGE_INTEGER *) &counter);
|
||||||
|
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mfb_timer_init() {
|
||||||
|
uint64_t frequency;
|
||||||
|
|
||||||
|
QueryPerformanceFrequency((LARGE_INTEGER *) &frequency);
|
||||||
|
|
||||||
|
g_timer_frequency = (double) ((int64_t) frequency);
|
||||||
|
g_timer_resolution = 1.0 / g_timer_frequency;
|
||||||
|
}
|
||||||
|
@ -7,9 +7,10 @@
|
|||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
HWND window;
|
HWND window;
|
||||||
WNDCLASS wc;
|
WNDCLASS wc;
|
||||||
HDC hdc;
|
HDC hdc;
|
||||||
BITMAPINFO *bitmapInfo;
|
BITMAPINFO *bitmapInfo;
|
||||||
bool mouse_inside;
|
struct mfb_timer *timer;
|
||||||
|
bool mouse_inside;
|
||||||
} SWindowData_Win;
|
} SWindowData_Win;
|
||||||
|
@ -6,15 +6,16 @@
|
|||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Window window;
|
Window window;
|
||||||
|
|
||||||
Display *display;
|
Display *display;
|
||||||
int screen;
|
int screen;
|
||||||
GC gc;
|
GC gc;
|
||||||
XImage *image;
|
XImage *image;
|
||||||
|
|
||||||
void *image_buffer;
|
void *image_buffer;
|
||||||
XImage *image_scaler;
|
XImage *image_scaler;
|
||||||
uint32_t image_scaler_width;
|
uint32_t image_scaler_width;
|
||||||
uint32_t image_scaler_height;
|
uint32_t image_scaler_height;
|
||||||
|
struct mfb_timer *timer;
|
||||||
} SWindowData_X11;
|
} SWindowData_X11;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <MiniFB.h>
|
#include <MiniFB.h>
|
||||||
#include <MiniFB_internal.h>
|
#include <MiniFB_internal.h>
|
||||||
#include "WindowData.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->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);
|
mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default);
|
||||||
|
|
||||||
printf("Window created using X11 API\n");
|
printf("Window created using X11 API\n");
|
||||||
@ -203,106 +206,111 @@ int translate_key(int scancode);
|
|||||||
int translate_mod(int state);
|
int translate_mod(int state);
|
||||||
int translate_mod_ex(int key, int state, int is_pressed);
|
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
|
static void
|
||||||
processEvents(SWindowData *window_data) {
|
processEvents(SWindowData *window_data) {
|
||||||
XEvent event;
|
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)) {
|
while ((window_data->close == false) && XPending(window_data_x11->display)) {
|
||||||
XNextEvent(window_data_x11->display, &event);
|
XNextEvent(window_data_x11->display, &event);
|
||||||
|
processEvent(window_data, &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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void destroy(SWindowData *window_data);
|
void destroy_window_data(SWindowData *window_data);
|
||||||
|
|
||||||
mfb_update_state
|
mfb_update_state
|
||||||
mfb_update(struct mfb_window *window, void *buffer) {
|
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;
|
SWindowData *window_data = (SWindowData *) window;
|
||||||
if (window_data->close) {
|
if (window_data->close) {
|
||||||
destroy(window_data);
|
destroy_window_data(window_data);
|
||||||
return STATE_EXIT;
|
return STATE_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,7 +376,7 @@ mfb_update_events(struct mfb_window *window) {
|
|||||||
|
|
||||||
SWindowData *window_data = (SWindowData *) window;
|
SWindowData *window_data = (SWindowData *) window;
|
||||||
if (window_data->close) {
|
if (window_data->close) {
|
||||||
destroy(window_data);
|
destroy_window_data(window_data);
|
||||||
return STATE_EXIT;
|
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
|
void
|
||||||
destroy(SWindowData *window_data) {
|
destroy_window_data(SWindowData *window_data) {
|
||||||
if (window_data != 0x0) {
|
if (window_data != 0x0) {
|
||||||
if (window_data->specific != 0x0) {
|
if (window_data->specific != 0x0) {
|
||||||
SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific;
|
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);
|
XDestroyWindow(window_data_x11->display, window_data_x11->window);
|
||||||
XCloseDisplay(window_data_x11->display);
|
XCloseDisplay(window_data_x11->display);
|
||||||
}
|
}
|
||||||
|
mfb_timer_destroy(window_data_x11->timer);
|
||||||
memset(window_data_x11, 0, sizeof(SWindowData_X11));
|
memset(window_data_x11, 0, sizeof(SWindowData_X11));
|
||||||
free(window_data_x11);
|
free(window_data_x11);
|
||||||
}
|
}
|
||||||
|
@ -114,8 +114,7 @@ main()
|
|||||||
|
|
||||||
mfb_set_user_data(window, (void *) "Input Events Test");
|
mfb_set_user_data(window, (void *) "Input Events Test");
|
||||||
|
|
||||||
for (;;)
|
do {
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
mfb_update_state state;
|
mfb_update_state state;
|
||||||
|
|
||||||
@ -143,7 +142,7 @@ main()
|
|||||||
window = 0x0;
|
window = 0x0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} while(mfb_wait_sync(window));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -110,13 +110,11 @@ main()
|
|||||||
|
|
||||||
mfb_set_user_data(window, (void *) "Input Events CPP Test");
|
mfb_set_user_data(window, (void *) "Input Events CPP Test");
|
||||||
|
|
||||||
for (;;)
|
do {
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
mfb_update_state state;
|
mfb_update_state state;
|
||||||
|
|
||||||
for (i = 0; i < WIDTH * HEIGHT; ++i)
|
for (i = 0; i < WIDTH * HEIGHT; ++i) {
|
||||||
{
|
|
||||||
noise = seed;
|
noise = seed;
|
||||||
noise >>= 3;
|
noise >>= 3;
|
||||||
noise ^= seed;
|
noise ^= seed;
|
||||||
@ -133,7 +131,7 @@ main()
|
|||||||
window = 0x0;
|
window = 0x0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} while(mfb_wait_sync(window));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,8 @@ main()
|
|||||||
pallete[64*7 + c] = MFB_RGB(255-col, 0, 0);
|
pallete[64*7 + c] = MFB_RGB(255-col, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mfb_set_target_fps(10);
|
||||||
|
|
||||||
//--
|
//--
|
||||||
float time = 0;
|
float time = 0;
|
||||||
for (;;)
|
for (;;)
|
||||||
@ -191,6 +193,12 @@ main()
|
|||||||
if(window_a == 0x0 && window_b == 0x0) {
|
if(window_a == 0x0 && window_b == 0x0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't need to do this for both windows in the same thread
|
||||||
|
if(window_a != 0x0)
|
||||||
|
mfb_wait_sync(window_a);
|
||||||
|
else if(window_b != 0x0)
|
||||||
|
mfb_wait_sync(window_b);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -17,13 +17,11 @@ main()
|
|||||||
if (!window)
|
if (!window)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (;;)
|
do {
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
mfb_update_state state;
|
mfb_update_state state;
|
||||||
|
|
||||||
for (i = 0; i < WIDTH * HEIGHT; ++i)
|
for (i = 0; i < WIDTH * HEIGHT; ++i) {
|
||||||
{
|
|
||||||
noise = seed;
|
noise = seed;
|
||||||
noise >>= 3;
|
noise >>= 3;
|
||||||
noise ^= seed;
|
noise ^= seed;
|
||||||
@ -40,7 +38,7 @@ main()
|
|||||||
window = 0x0;
|
window = 0x0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} while(mfb_wait_sync(window));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user