Git Product home page Git Product logo

minifb's Introduction

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:

struct mfb_window *window = mfb_open_ex("my display", 800, 600, WF_RESIZABLE);
if (!window)
    return 0;

buffer = (uint32_t *) malloc(800 * 600 * 4);

do {
    int state;

    // TODO: add some fancy rendering to the buffer of size 800 * 600

    state = mfb_update_ex(window, buffer, 800, 600);

    if (state < 0) {
        window = NULL;
        break;
    }
} while(mfb_wait_sync(window));
  1. First the application creates a window calling mfb_open or mfb_open_ex.
  2. Next it's the application responsibility to allocate a buffer to work with.
  3. Next calling mfb_update or mfb_update_ex the buffer will be copied over to the window and displayed. If this function return a value lower than 0 the window will have been destroyed internally and cannot be used anymore.
  4. Last the code waits to synchronize with the monitor calling mfb_wait_sync.

Note that, by default, if ESC key is pressed mfb_update / mfb_update_ex will return -1 (and the window will have been destroyed internally).

See https://github.com/emoon/minifb/blob/master/tests/noise.c for a complete example.

Supported Platforms:

  • Windows
  • MacOS X
  • X11 (FreeBSD, Linux, *nix)
  • Wayland (Linux) [there are some issues]
  • iOS (beta)
  • Android (beta)
  • Web (WASM) (beta)

MiniFB has been tested on Windows, Mac OS X, Linux, iOS, Android and web 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.

Features:

  • Window creation
  • Callbacks to window events
  • Get information from windows
  • Add per window data
  • Timers and target FPS
  • C and C++ interface

Callbacks to window events:

You can add callbacks to the windows:

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);
    // or let mfb caclculate the best fit from your original framebuffer size
    mfb_set_viewport_best_fit(window, old_width, old_height);

}

bool close(struct mfb_window *window) {
    ...
    return true;    // true => confirm close
                    // false => don't close
}

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);
    }
}

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) {
    ...
}


int main(int argc, char argv[]) {

    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_close_callback(window, close);
    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);

    ...
}

C++ event interface:

If you are using C++ you can set the callbacks to a class, or use lambda expressions:

struct Events {
    void active(struct mfb_window *window, bool isActive) {
        ...
    }
    ...
}

int main(int argc, char argv[]) {
    Events e;

    // Using object and pointer to member
    mfb_set_active_callback(window, &e, &Events::active);

    // Using std::bind
    mfb_set_active_callback(std::bind(&Events::active, &e, _1, _2), window);

    // Using a lambda
    mfb_set_active_callback([](struct mfb_window *window, bool isActive) {
        ...
    }, window);

    ...
}

Get information from windows (direct interface)

If you don't want to use callbacks, you can get information about the window events directly:

bool                mfb_is_window_active(struct mfb_window *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
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.

Add per window data

Additionally you can set per window data and recover it:

mfb_set_user_data(window, (void *) myData);
...
myData = (someCast *) mfb_get_user_data(window);

Timers and target FPS

You can create timers for your own purposes.

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 (and get) a target fps for the application. The default is 60 frames per second.

void                mfb_set_target_fps(uint32_t fps);
unsigned            mfb_get_target_fps();

This avoid the problem of update too fast the window collapsing the redrawing in fast processors.

Note: OpenGL and iOS have hardware support for syncing. Other systems will use software syncing. Including MacOS Metal.

In order to be able to use it you need to call the function:

bool                mfb_wait_sync(struct mfb_window *window);

Note that if you have several windows running on the same thread it makes no sense to wait them all...

.

Build instructions

The current build system is CMake.

Initially MiniFB used tundra https://github.com/deplinenoise/tundra as build system and it was required to build the code (but now is not maintained).

In any case, not many changes should be needed if you want to use MiniFB directly in your own code.

MacOS X

Cocoa and clang is assumed to be installed on the system (downloading latest XCode + installing the command line tools should do the trick).

Note that MacOS X Mojave+ does not support Cocoa framework as expected. For that reason you can switch to Metal API. To enable it just compile defining the preprocessor macro USE_METAL_API.

If you use CMake just enable the flag:

mkdir build
cd build
cmake .. -DUSE_METAL_API=ON

or if you don't want to use Metal API:

mkdir build
cd build
cmake .. -DUSE_METAL_API=OFF

Coordinate system

On MacOS, the default mouse coordinate system is (0, 0) -> (left, bottom). But as we want to create a multiplatform library we inverted the coordinates in such a way that now (0, 0) -> (left, top), like in the other platforms.

In any case, if you want to get the default coordinate system you can use the CMake flag: USE_INVERTED_Y_ON_MACOS=ON

mkdir build
cd build
cmake .. -DUSE_INVERTED_Y_ON_MACOS=ON

Note: In the future, we may use a global option so that all platforms behave in the same way. Probably: -DUSE_INVERTED_Y

if you use tundra:

tundra2 macosx-clang-debug

and you should be able to run the noise example (t2-output/macosx-clang-debug-default/noise).

iOS (beta)

It works with and without an UIWindow created. If you want to create the UIWindow through an Story Board, remember to set the UIViewController as iOSViewController and the UIView as iOSView.

Issues:

  • It seems that you have to manually set 'tvOS Deployment Target' to less than 13.
  • It seems that you have to manually set 'Launch Screen File' in project > executable > general to be able to get the real device height.
  • You need to manually set the 'Signing Team' and 'Bundle Identifier'.
  • No multitouch is available yet.
  • As this version uses Metal API it cannot be run in the emulator.

Functions:

Some of the MiniFB functions don't make sense on mobile. The available functions for iOS are:

struct mfb_window * mfb_open(const char *title, unsigned width, unsigned height);
struct mfb_window * mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags);    // flags ignored

mfb_update_state    mfb_update(struct mfb_window *window, void *buffer);

void                mfb_close(struct mfb_window *window);

void                mfb_set_user_data(struct mfb_window *window, void *user_data);
void *              mfb_get_user_data(struct mfb_window *window);

bool                mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height);

bool                mfb_set_viewport_best_fit(struct mfb_window *window, unsigned old_width, unsigned old_height);

void                mfb_set_mouse_button_callback(struct mfb_window *window, mfb_mouse_button_func callback);
void                mfb_set_mouse_move_callback(struct mfb_window *window, mfb_mouse_move_func callback);
void                mfb_set_resize_callback(struct mfb_window *window, mfb_resize_func callback);
void                mfb_set_close_callback(struct mfb_window *window, mfb_close_func callback);

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
int                 mfb_get_mouse_y(struct mfb_window *window);             // Last mouse pos Y
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)

void                mfb_get_monitor_scale(struct mfb_window *window, float *scale_x, float *scale_y)
// [Deprecated] Use mfb_get_monitor_scale instead
void                mfb_get_monitor_dpi(struct mfb_window *window, float *dpi_x, float *dpi_y)

Timers are also available.

struct mfb_timer *  mfb_timer_create(void);
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(void);
double              mfb_timer_get_resolution(void);

For now, no multitouch is available.

Example:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    if(g_window == 0x0) {
        g_width  = [UIScreen mainScreen].bounds.size.width;
        g_height = [UIScreen mainScreen].bounds.size.height;
        g_window = mfb_open("noise", g_width, g_height);
        if(g_window != 0x0) {
            g_buffer = malloc(g_width * g_height * 4);
        }
    }

    return YES;
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    mDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(OnUpdateFrame)];
    [mDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}

- (void)applicationWillTerminate:(UIApplication *)application {
    [mDisplayLink invalidate];
    mfb_close(g_window);
}

- (void) OnUpdateFrame {
    if(g_buffer != 0x0) {
        // Do your wonderful rendering stuff
    }

    mfb_update_state state = mfb_update(g_window, g_buffer);
    if (state != STATE_OK) {
        free(g_buffer);
        g_buffer  = 0x0;
        g_width   = 0;
        g_height  = 0;
    }
}

CMake

mkdir build
cd build
cmake -G Xcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 ..

Android (beta)

Take a look at the example in tests/android. You need Android Studio to build and run it.

Functions:

Some of the MiniFB functions don't make sense on mobile. The available functions for Android are:

struct mfb_window * mfb_open(const char *title, unsigned width, unsigned height);
struct mfb_window * mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags);    // flags ignored

mfb_update_state    mfb_update(struct mfb_window *window, void *buffer);

void                mfb_close(struct mfb_window *window);

void                mfb_set_user_data(struct mfb_window *window, void *user_data);
void *              mfb_get_user_data(struct mfb_window *window);

bool                mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height);

bool                mfb_set_viewport_best_fit(struct mfb_window *window, unsigned old_width, unsigned old_height);

void                mfb_set_active_callback(struct mfb_window *window, mfb_active_func callback);
void                mfb_set_mouse_button_callback(struct mfb_window *window, mfb_mouse_button_func callback);
void                mfb_set_mouse_move_callback(struct mfb_window *window, mfb_mouse_move_func callback);
void                mfb_set_resize_callback(struct mfb_window *window, mfb_resize_func callback);
void                mfb_set_close_callback(struct mfb_window *window, mfb_close_func callback);

bool                mfb_is_window_active(struct mfb_window *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
int                 mfb_get_mouse_y(struct mfb_window *window);             // Last mouse pos Y
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)

Timers are also available.

struct mfb_timer *  mfb_timer_create(void);
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(void);
double              mfb_timer_get_resolution(void);

Windows

If you use CMake the Visual Studio project will be generated (2015, 2017 and 2019 have been tested).

Furthermore you can also use MinGW instead of Visual Studio.

if you use tundra:

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

OpenGL API backend

Now, by default, OpenGL backend is used, instead of Windows GDI, because it is faster. To maintain compatibility with old computers an OpenGL 1.5 context is created (no shaders needed).

To enable or disable OpenGL just use a CMake flag:

cmake .. -DUSE_OPENGL_API=ON
# or
cmake .. -DUSE_OPENGL_API=OFF

X11 (FreeBSD, Linux, *nix)

gcc and x11-dev libs needs to be installed.

If you use CMake just disable the flag:

mkdir build
cd build
cmake .. -DUSE_WAYLAND_API=OFF

If you use tundra:

To build the code run:

tundra2 x11-gcc-debug

and you should be able to run t2-output/x11-gcc-debug-default/noise

OpenGL API backend

Now, by default, OpenGL backend is used instead of X11 XImages because it is faster. To maintain compatibility with old computers an OpenGL 1.5 context is created (no shaders needed).

To enable or disable OpenGL just use a CMake flag:

cmake .. -DUSE_OPENGL_API=ON -DUSE_WAYLAND_API=OFF
# or
cmake .. -DUSE_OPENGL_API=OFF -DUSE_WAYLAND_API=OFF

Wayland (Linux)

Depends on gcc and wayland-client and wayland-cursor. Built using the wayland-gcc variants.

If you use CMake just enable the flag:

mkdir build
cd build
cmake .. -DUSE_WAYLAND_API=ON

Web (WASM)

Download and install Emscripten. When configuring your CMake build, specify the Emscripten toolchain file. Then proceed to build as usual.

Building and running the examples

cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/emsdk/<version>/emscripten/cmake/Modules/Platform/Emscripten.cmake -S . -B build
cmake --build build

Note: On Windows, you will need a build tool other than Visual Studio. Ninja is the best and easiest option. Simply download it, put the ninja.exe executable somewhere, and make it available on the command line via your PATH environment variable. Then invoke the first command above with the addition of -G Ninja at the end.

Then open the file build/index.html in your browser to view the example index.

The examples are build using the Emscripten flag -sSINGLE_FILE, which will coalesce the .js and .wasm files into a single .js file. If you build your own apps without the -sSINGLE_FILE flag, you can not simply open the .html file in the browser from disk. Instead, you need an HTTP server to serve the build output. The simplest solution for that is Python's http.server module:

python3 -m http.server build/

You can then open the index at http://localhost:8000 in your browser.

Integrating a MiniFB app in a website

To build an executable target for the web, you need to add a linker option specifying its module name, e.g.:

target_link_options(my_app PRIVATE "-sEXPORT_NAME=my_app")

The Emscripten toolchain will then build a my_app.wasm and my_app.js file containing your app's WASM code and JavaScript glue code to load the WASM file and run it. To load and run your app, you need to:

  1. Create a <canvas> element with an id attribute matching the title you specify when calling mfb_open_window() or mfb_open_window_ex().
  2. Call the <my_module_name>() in JavaScript.

Example app:

int main() {
    struct mfb_window *window = mfb_open_ex("my_app", 320, 240);
    if (!window)
        return 0;
    uint32_t *buffer = (uint32_t *) malloc(g_width * g_height * 4);
    mfb_update_state state;
    do {
        state = mfb_update_ex(window, buffer, 320, 200);
        if (state != STATE_OK) {
            break;
        }
    } while(mfb_wait_sync(window));
    return 0;
}

Assuming the build will generate my_app.wasm and my_app.js, the simplest .html file to load and run the app would look like this:

<html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset='utf-8'>
    <meta http-equiv='X-UA-Compatible' content='IE=edge'>
    <meta name='viewport' content='width=device-width, initial-scale=1'>
    <!-- Load the app's .js file -->
    <script src="./my_app.js"></script>
</head>
<body>
<div>
    <canvas id="Noise Test" style="background: #000;"></canvas>
</div>
<script>
    // Call the app's main() function
    noise();
</script>
</body>
</html>

Limitations & caveats

The web backend currently does not support the following MiniFB features:

  • The flags to mfb_open_ex() are ignored
  • mfb_set_viewport() (no-op)
  • mfb_set_viewport_best_fit() (no-op)
  • mfb_get_monitor_dpi() (reports a fixed value)
  • mfb_get_monitor_scale() (reports a fixed value)
  • mfb_set_target_fps() (no-op)
  • mfb_get_target_fps() (no-op)

Everything else is supported.

When calling mfb_open() or mfb_open_ex(), the specified title must match the id attribute of a <canvas> element in the DOM. The functions will modify the width and height attribute of the <canvas> element. If not already set, then the functions will also modify the CSS style width and height attributes of the canvas.

Setting the CSS width and height of the canvas allows you to up-scale the framebuffer arbitrarily:

// Request a 320x240 window
mfb_open("my_app", 320, 240);

// Up-scale 2x via CSS
<canvas id="my_app" style="width: 640px; height: 480px">

If not already set, the backend will also set a handfull of CSS styles on the canvas that are good defaults for pixel graphics.

  • image-rendering: pixelated
  • user-select: none
  • border: none
  • outline-style: none;

How to add it to your project

First add this repository as a submodule in your dependencies folder. Something like dependencies/:

git submodule add https://github.com/emoon/minifb.git dependencies/minifb

Then in your CMakeLists.txt file, include the following:

add_subdirectory(dependencies/minifb)

# Link MiniFB to your project:
target_link_libraries(${PROJECT_NAME}
    minifb
)

Fill out the rest of your CMakeLists.txt file with your source files and dependencies.

minifb's People

Contributors

aduros avatar badlogic avatar bradgrantham avatar clems71 avatar darky-lucera avatar emoon avatar enjector avatar fantomjac avatar fritschy avatar kippesp avatar lkesteloot avatar maximumspatium avatar nlguillemot avatar onbjerg avatar rayworks avatar ricop avatar skiars avatar superdump avatar thedavesims avatar xiaozhuai avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

minifb's Issues

Clarification of a paragraph in the README

Hi!

The README has a paragraph which I don't really understand 100%, and that I believe should be clarified. This one:

Note that MacOS X Mojave+ does not support Cocoa framework as expected. For that reason you can switch to Metal API. To enable it just compile defining the preprocessor macro USE_METAL_API.

Does this apply to building code, or to running old executables? I mean: will old applications run incorrectly in Mojave? Or maybe you meant that you'll face problems if you build Cocoa code with the Mojave SDK?

Basically, what I'd like to know is if there's any possibility of building without Metal in a way that will run correctly in Mojave and later.

Thanks!

disable "Window created" message?

It would be nice to remove (or at least have a way to disable) the printed message on each window creation. It is generally not good behavior for libraries to print messages unnecessarily.

Wrong window size on MacOS

On MacOS the window is not tall enough, because the passed-in rectangle (the size of the image) is used for the entire window, including the title bar. I don't know why, since the API for NSWindow calls the parameter contentRect. You have to convert from contentRect to frameRect yourself in mfb_open():

        NSRect rectangle = NSMakeRect(0, 0, width, height);
-       window_ = [[OSXWindow alloc] initWithContentRect:rectangle styleMask:styles backing:NSBackingStoreBuffered defer:NO];
+        NSRect frameRect = [NSWindow frameRectForContentRect:rectangle styleMask:styles];
+       window_ = [[OSXWindow alloc] initWithContentRect:frameRect styleMask:styles backing:NSBackingStoreBuffered defer:NO];

Ability to change app cursor

Hi, just found out about minifb. Looks great!

I was wondering if you have any plans to allow changing the app's cursor (eg. pointer, resize, dragging, etc) or even setting a custom one. Or would this go against the "mini" part of the library?

On a sidenote, drag and drop support would also be nice to have. :)

[Julia] Window does not close in Mac

I am writing a wrapper for minifb in the Julia Programming Language. Julia is a dynamic language with its own REPL. It has an easy C ffi, so function calls in Julia forward directly to C API calls in minifb.

So I'm using code like this

function noise()
    WIDTH = 800
    HEIGHT = 600
    g_buffer = zeros(UInt32, WIDTH * HEIGHT)
    window = mfb_open_ex("Noise Test", WIDTH, HEIGHT, MiniFB.WF_RESIZABLE);
    while mfb_wait_sync(window)
       for i in 1:WIDTH * HEIGHT
             # populate g_buffer
        end
        state = mfb_update(window, g_buffer);
        if state != MiniFB.STATE_OK
            break;
        end
    end
    mfb_close(window)
end

And this works well. However, on the Mac, I find that the window does not close. It stays on screen, even when the function has returned. (Note that due to the REPL, the Julia process is still in memory, but the function above has returned). If I exit the process, the windows does close. And if i run another mfb_open_ex in the same process, the old window dissapears, and the new one comes on.

On Windows 10, the window is closed when the function returns.

Any ideas why this could be?

PS: code here: https://github.com/aviks/MiniFB.jl

Type prefixes

Although the library uses prefixes on its functions to avoid name collisions, the same isn't done for the types. Is adding the prefix to the types (eg. Window => mfb_Window) a change you would consider making or accepting as a pull request?

Blank window in release mode only?

I really don't understand why, but I only get a blank white window when I build this library in release mode. This is on Windows 10, 64 bit build, Visual Studio 2015.

WM_PAINT messages are coming, the code is not hanging anywhere, the data I pass in looks ok...

I really don't understand what could be going wrong.

Mouse Y is inverted on Mac

The Y values of the mouse (using mfb_get_mouse_y) seem to be inverted. It looks like 0 = the bottom of the window, where 0 should = the top of the window.

Window title incorrect on Windows

On Windows 10, when calling mfb_open_ex with a title of "Hello World!", the title for the resulting window is completely messed up. I THINK windows expects some UTF-16 encoding. If so, this might be the culprit
if minifb doesn't perform this conversion, however I'm not familiar with winapi stuff so I could be wrong.

Here's what "Hello World!" becomes:
image

Continuous input disabled after "input_events" run

Hello, after executing and closing the sample input_events.c on a Linux system, it seems to disable the continuous keyboard events, resulting in helding a keyboard key produce only a single input, not repeated.

compiler flags forced in CMakeLists.txt are GCC-specific, warned and ignored in clang

On my Mac I get warning: unknown warning option '-Wno-cast-function-type'; did you mean '-Wno-bad-function-cast'? [-Wunknown-warning-option]. I'm not certain but it looks like "cast-function-type" is GCC-specific.

I don't know if "bad-function-cast" is the right option for clang (as suggested) and my CMake-fu isn't strong enough to recommend a change to emit a different option on clang, I apologize.

Performance oddities on OS X 10.15.5

I stated with the rust version and then switched to the C version to debug this issue. In short, I cannot reliably get any frame rates faster than 30 FPS ( ~33 ms per frame ). I dug into the code and the only explicit timing code I see is in mfb_wait_sync in MacMiniFB.m. I figured before I started looking up OSX API calls (not as familiar with them as I want to be) I would see if this is a known issue of some sort.

This is with the latest version of the rust and C APIs using Metal.

In short, if I set a framerate in the C version or set the limit_update_rate in the Rust version, once I go below 30 FPS the majority of the frames still take ~33ms. Sample output from the code below fro fps set to 60:

 33.24
 33.27
 33.40
 33.28
 33.37
 33.22
 33.30
 33.26
 33.52
 33.42
 33.27
 33.29
 33.49
 33.05
 33.44
 33.42
 49.86
 33.45
 49.46
 33.67
 33.27
 33.36
 33.32
 33.32
 33.48

And fps set to 10 (somehow I think the code in drawInMTKView in OSXViewDelegate.m comes into play because of the ~.96 number but I do not know how it gets there:

 95.95
 96.02
 95.97
 96.12
 96.04
 95.97
 96.06
 96.14
 95.98
 96.05
 95.85

My barebones code is below. This is drastically reduced from the original to try and isolate the issue.:

#include <MiniFB.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

static uint32_t  g_width  = 400;
static uint32_t  g_height = 400;
static uint32_t *g_buffer = 0x0;

int main( int argc, char *argv[] ) {
  struct mfb_window *window = mfb_open_ex("Foo display", 800, 600, WF_RESIZABLE);
  if (!window)
    return 0;

  g_buffer = (uint32_t *) malloc(g_width * g_height * 4);

  mfb_set_target_fps(60);

  struct mfb_timer *t = mfb_timer_create();

  long count = 1;
  double total = 0;

  do {
    int state;

    double start = mfb_timer_now( t );
      
    state = mfb_update_ex(window, g_buffer, g_width, g_height);

    if (state < 0) {
      window = NULL;
      break;
    }
  
    double end = mfb_timer_delta( t );
    total += end;

    // Print out the time for the last cycle and the average time (average seems
    // to suffer from high times for early frames
    printf( "%6.2f\n", end * 1000.0 );
    
    count++;
  } while(mfb_wait_sync(window));

  /* Cleanup code conveniently omitted (i.e. I didn't write it */
}

OSX: macOS 10.12 deprecation warnings

When compiling on OSX, I get a bunch of warnings like:

warning: 'NSKeyDown' is deprecated: first deprecated in macOS 10.12 [-Wdeprecated-declarations]

I don't know enough about OSX/Cocoa dev to easily fix this. It's just a warning, so not a show stopper.

If used as child CMake directory, parent CXXFLAGS_DEBUG etc are forcibly cleared in parent CMakeCache.txt on MacOS (and probably any platform but MSVC)

MiniFB is great, and I'm happy to have it! I'm using minifb as a submodule in my project using add_subdirectory() in my CMakeLists.txt.

I think that the lines in CMakeLists.txt in f66e92c between 121 and 135 of the form set(CMAKE_... "" CACHE STRING "" FORCE) are forcing the system CMAKE_... variables to be overwritten in CMakeCache.txt. E.g. A line CMAKE_CXX_FLAGS_DEBUG:STRING= is emitted into my CMakeCache.txt. These variables are therefore overwritten for my project, and, if I understand CMake correctly, for every other subdirectory which doesn't explicitly set them.

But I expect CMAKE_CXX_FLAGS_DEBUG:STRING=-g. If I compile my project with -DCMAKE_BUILD_TYPE=Debug, none of my project code is compiled debug, and I have no symbols in my executable and can't do any symbolic debugging with lldb. Additionally my environment CXX_FLAGS is ignored (in which I have "-Wall")

If I remove CACHE STRING "" FORCE from those lines, my code compiles Debug just fine (and my environment CXX_FLAGS are honored, which had been missing up to this point) and MiniFB still clears the system compile flags and gets its custom build flags specified at 139 and 140.

Is it possible you don't want to set those variables in the cache at all?

a meet by chance bug.

whn i us minifb finish code a example. some magic things happened. lol...
i can us the mouse check window and nothing apear.
but if i us keyboard anyone key,the window will stuck.
i can't even turn it off.
last, i have to kill explorer and reboot.

compiling on macosx 11.2

Hi there!
I'm trying to compile minifb on Mac OS X 11.2 and I haven't had any luck. So far, I have tried the process outlined in the readme (cmake with option metal), but my tundra command fails, because it can't find WindowData.h (although I can). Compiling directly in an XCode project doesn't work either: XCode doesn't find files, can't include files etc. I'm sure, I'm doing something stupid, but I can't quite figure out what. Just to be sure: has anyone successfully used minifb on 11.2? Since updating, I'm having trouble with some other libraries as well.

Compile failure on MacOSX

I'm using xcode 10.12 on x86_64, and getting the following error. This code was seemingly introduced in 8fc7dd9

[11:39:08] /workspace/srcdir/minifb/src/macosx/OSXView.m:357:20: error: unknown class name 'NSAttributedStringKey'; did you mean 'NSAttributedString'?
[11:39:08] - (nonnull NSArray<NSAttributedStringKey> *)validAttributesForMarkedText {
[11:39:08]                    ^~~~~~~~~~~~~~~~~~~~~
[11:39:08]                    NSAttributedString
[11:39:08] /opt/x86_64-apple-darwin14/x86_64-apple-darwin14/sys-root/System/Library/Frameworks/AppKit.framework/Headers/NSStatusItem.h:13:8: note: 'NSAttributedString' declared here
[11:39:08] @class NSAttributedString;
[11:39:08]        ^
[11:39:08] /workspace/srcdir/minifb/src/macosx/OSXView.m:357:20: error: type argument 'NSAttributedString' must be a pointer (requires a '*')
[11:39:08] - (nonnull NSArray<NSAttributedStringKey> *)validAttributesForMarkedText {
[11:39:08]                    ^
[11:39:08]                                          *
[11:39:08] 2 errors generated.

Check if the next frame is due

Unlike with mfb_wait_sync, I do not want the thread to stall until the next frame is due but I want to execute code in between, if there is still time to do so. I would appreciate a way do to so, maybe even with an argument to check the future (like mfb_frame_is_due_in(nanoseconds)

If there already is a way to due so, please tell me. If there isnt, this is a feature suggestion (:

Mouse right and middle buttons are swapped in X11

It looks like in X11 (and maybe also Wayland?) mouse button 2 is middle and 3 is right.

We could fix either by swapping the button codes to be consistent with the other platforms, or making the MOUSE_RIGHT and MOUSE_MIDDLE values vary depending on the platform.

Let me know if you have a favored approach and I can open a PR 😃

Linker dependencies

I love this little thing, but as I can see in CMakeLists.txt, libraries such as X11 or Metal Framework have to be linked in your executable, so...
Why do you decide to do in that way rather than link them directly to minifb library?, I mean, why doesn't exist something like:
target_link_libraries (minifb X11)
in CMakeLists.txt.
Also would be interesting, to include
target_include_directories(minifb ${CMAKE_CURRENT_SOURCE_DIR}/include)
so you can use it directly like a sub-directory into your cmake based project with all of its benefits.
Also I notice in de README.md example code that in the call to mfb_update() function the pointer window parameter is missing.

Problem compiling on arm with 1.6

Due to this breakage the crate doesn't compile on arm.

Compiling minifb v0.1.0 (https://github.com/emoon/rust_minifb.git#858b07f5)
/home/odroid/.cargo/git/checkouts/rust_minifb-65b6a7c68ef60bd2/master/src/lib.rs:38:24: 38:34 error: mismatched types:
 expected `*const i8`,
    found `*const u8`
(expected i8,
    found u8) [E0308]
/home/odroid/.cargo/git/checkouts/rust_minifb-65b6a7c68ef60bd2/master/src/lib.rs:38         ret = mfb_open(s.as_ptr(), width as c_int, height as c_int);
                                                                                                           ^~~~~~~~~~
/home/odroid/.cargo/git/checkouts/rust_minifb-65b6a7c68ef60bd2/master/src/lib.rs:38:24: 38:34 help: run `rustc --explain E0308` to see a detailed explanation
error: aborting due to previous error

I tried to fix it with a simple hack s.as_ptr() as *const _ but it ends in a segfault.
Using std::mem:transmute seems to segfault as well so you'll have to look into it yourself :)

(I think I had it working from within rust64 a few months ago using 1.5)

Scaling for WF_FULLSCREEN window (on Windows)

If I create a window with WF_FULLSCREEN, the pixel buffer seems to be sized according to the desktop resolution, not the width and height arguments. So the content is small and in the top left corner, instead of filling the screen. It is proportional though.

If I create a window with WF_FULLSCREEN_DESKTOP, the pixel buffer seems to be correctly sized and fills the window, but the window size isn't proportional to the frame buffer, so the content is stretched.

It would be nice to be able to programmatically resize a window, and/or create a full-screen window with the content scaled (preferably proportionally, with black bars if necessary).

Failed to compile on Windows

It seems that the macro GWL_USERDATA in src\windows\WinMiniFB.c(22) is not defined.
And It can compiles if I change it to GWLP_USERDATA.

My environment:

  • Windows 10 (1903)
  • CMake 3.14.5
  • Visual Studio 2017 with Windows 10 SDK (10.0.17763.0).

Thank you!

As you know, this library has now been wrapped for the Julia programming language. I wanted to thank you for creating and maintaining this library. The Julia community has shown a lot of interest in this library -- many developers have already integrated their packages with MiniFB. You can see the discussion here: https://discourse.julialang.org/t/build-simple-guis-with-minifb/46195. You will certainly see more of us here.

Also worth mentioning, we build and distribute binaries of MiniFB for 13 different platforms: Win/Linux/Mac/FreeBSD, x86/x64/armv7/aarch64/power. This ensures our users do not have to have C compliers on their machines to use the library. The build recipes are here: https://github.com/JuliaPackaging/Yggdrasil/blob/master/M/MiniFB/build_tarballs.jl . The resulting binaries (dll/dylib/so) can be downloaded from https://github.com/JuliaBinaryWrappers/MiniFB_jll.jl/releases/tag/MiniFB-v0.1.1%2B1

Finally, the source of the Julia package is here: https://github.com/aviks/MiniFB.jl and the documentation: https://juliahub.com/docs/MiniFB/

Please close this issue at your convinience, I just wanted to let you know what we have been up to.

Tests on Windows so far

Hi.
I just compiled it with MinGW to test it out and see what is it about.

These were my steps if anyone else is interested.

cmake -S . -G "MinGW Makefiles" -DUSE_OPENGL_API=OFF --fresh

To remove the cmd.exe, adding -DCMAKE_C_FLAGS="-mwindows" didn't worked. It was required to edit the CMakeLists.txt to add WIN32 flag to add_executable

add_executable(noise WIN32
    tests/noise.c
)

I really like the portability shown here and that it abstracts the handling of the window creation.
For example, on Windows I am able to choose to link to GDI or to WGL (which also links to GDI).

However, from the readme, I keep wondering what libraries can be used on top of it in order to see real world applications. Are there real world examples? A list of Could it work as backend for ImGUI libraries ? Is there any 'mini' ImGUI library that would match well with it?

Kind regards

Compile on Linux

Hello, tried to compile on Linux (Ubuntu) and had difficulties as I didn't know whether compile with Wayland or not (I don't know what this is). So tried both without success - different failures. Finally checked without Wayland und gat an X11 error not finding an #include <X11/Xlib.h>.
Maybe simply add that the interested user should install the headers. I used the following line (but is probably less to be needed to install, but this works on Ubuntu 20 LTS version from scratch).

sudo apt-get install -y libx11-dev libgl1-mesa-dev libgtk-3-dev pkg-config

Eliminate warnings with explicit casts

Hello,

with VisualStudio 2019 I encounter the following warning package:

2>MiniFB_common.c
2>D:\git\minifb\src\MiniFB_common.c(171,59): warning C4244: "Funktion": Konvertierung von "float" in "unsigned int", möglicher Datenverlust
2>D:\git\minifb\src\MiniFB_common.c(171,79): warning C4244: "Funktion": Konvertierung von "float" in "unsigned int", möglicher Datenverlust
2>D:\git\minifb\src\MiniFB_common.c(171,101): warning C4244: "Funktion": Konvertierung von "float" in "unsigned int", möglicher Datenverlust
2>D:\git\minifb\src\MiniFB_common.c(171,124): warning C4244: "Funktion": Konvertierung von "float" in "unsigned int", möglicher Datenverlust
2>D:\git\minifb\src\MiniFB_common.c(164,1): warning C4244: "Initialisierung": Konvertierung von "float" in "unsigned int", möglicher Datenverlust
2>D:\git\minifb\src\MiniFB_common.c(165,1): warning C4244: "Initialisierung": Konvertierung von "float" in "unsigned int", möglicher Datenverlust

Would be nice to compile without warnings after fresh pull ;-) This increases overall project healthyness ... thanks!

real width and height with no dpi correction

Hey there,

very nice little library! Thanks for your work.

The width & height do not match the pixels on screen.

I'm experimenting a bit and was curious to know, if there is a straight forward way to let the width and height one initializes the mfb with, correspond to the actual pixels that the display is displaying. As I could see in the code, it gets corrected with the specific display dpi. In theory thats really nice, so the window is more or less the same size on all displays.
Is there a flag or function to disable this? Or maybe mention in the readme that this scaling is gonna happen?

Just as a suggestion.

For my experiments on windows I've rewritten lines 432 & 432 of mfb_open_ex() to be:

        rect.right  = (LONG) width;
        rect.bottom = (LONG) height;

But I'm not sure if this breaks some other things down the line.

Have a great day!
Nik

Colors in Windows 7 wrong

It appears that the colors are wrong in the current release. If I set 0x00ff0000 as a color I get red (correct), but 0x00ffff00 is not yellow (it's still red).
Bugfix: change s_bitmapInfo entry from BITFIELDS to BI_RGB:

s_bitmapInfo.bmiHeader.biCompression = BI_RGB;

VisualStudio

Hello,

building for Windows with VisualStudio it would be fine to set the "Noise-Example" as the default startup-project (so that it can be immediately started and debugged after building).
CMAKE offers a property for that (to be applied in master-"CMakeLists.txt" ?):

set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT <... EXECUTABLE-NAME ...> )
I haven't seen this interfering with other options, so this should be a non-brainer ...

Feature request: on expose callback

Hi! I love this little library, fast and easy. <3

I was wondering if you would be interested in adding an "on expose" callback, which gets called when the window needs to be redrawn for any reason?

This would be useful for me because with the way I'm using the library, I'm not redrawing the window continuously for continuous animation. Rather, I'm redrawing only when something changes, or perhaps I'm only drawing a single static frame for the lifetime of the window.

Currently, without an "on expose" callback, this leads to an issue, because without redrawing the frame constantly, the window collects artifacts as other items on the screen cover up the contents of the window. It would also be very useful to know when the window has been created and is ready to be drawn for the first time.

cygwin - worksfine!

  • copy include / src / windows to root
  • create a makefile or simply run
  • cygwin+win7+

cat Makefile

all:
gcc -std=c99 -I. MiniFB_common.c MiniFB_internal.c MiniFB_timer.c WinMiniFB.c noise.c -lgdi32

is_open function

While the segfault in #48 should probably be fixed, a possible mitigation might have been the existence of an is_open(window) function. That will prevent calling mfb_update on closed windows.

It looks like the minifb_rust has an is_open function, so it may be useful to have it here as well?

Segfault on updating closed window [Linux/X11]

On calling mfb_update once after closing a window, STATE_EXIT is returned. On calling mfb_update a second time, a segfault is thrown, which looks possibly like a double free.

Replication using Julia is below. C code looks very similar.

julia> using MiniFB

julia> window = mfb_open("Noise Test", 300, 400);
Window created using X11 API

julia> g_buffer = zeros(UInt32, 300 * 400);

julia> mfb_update(window, g_buffer)
STATE_OK::mfb_update_state = 0

julia> mfb_close(window)

julia> mfb_update(window, g_buffer)
STATE_EXIT::mfb_update_state = -1

julia> mfb_update(window, g_buffer)
signal (11): Segmentation fault
in expression starting at REPL[10]:1
__libc_free at /build/glibc-2ORdQG/glibc-2.27/malloc/malloc.c:3098
destroy_window_data at /home/aviks/.julia/artifacts/94a1e8c638cfe92322b13b5657c82978c19230b4/lib/libminifb.so (unknown line)
mfb_update at /home/aviks/.julia/artifacts/94a1e8c638cfe92322b13b5657c82978c19230b4/lib/libminifb.so

This is with the X11 backend on Linux. On Windows, multiple mfb_updates on a closed window returns STATE_EXIT correctly.

Suggestion: #include "MiniFB.h" instead of <MiniFB.h>

At least with Visual Studio, including <MiniFB.h> inside WinMiniFB.c requires MiniFB's path to be put in the include directory list, even if MiniFB.h is in the same directory as WinMiniFB.c.

I was lazy and dropped all the files into the same directory, so I had to switch to include "MiniFB.h", note the with double quotes instead of angle braces.

I think using double quotes still looks at the include directory list if it can't find a local file with the name, so I guess that approach is more compatible. Therefore, I suggest replacing all includes of <MiniFB.h> with "MiniFB.h".

Segmentation fault error running multiple multiple_windows

I got Segmentation fault runniig the multiple_windows on head of master (7a2aa56).

Image with more infos:
image

stack-trace
image

My system infos:

OS: Manjaro 20.0.2 Lysia
Kernel: x86_64 Linux 5.6.15-1-MANJARO
Uptime: 4h 0m
Packages: 1369
Shell: bash 5.0.17
Resolution: 2560x1440
DE: GNOME 3.36.2
WM: Mutter
WM Theme: 
GTK Theme: Adwaita-dark [GTK2/3]
Icon Theme: Adwaita
Font: Noto Sans 11
Disk: 756G / 1,5T (52%)
CPU: AMD FX-8320E Eight-Core @ 8x 3.2GHz
GPU: GeForce RTX 2060
RAM: 8700MiB / 15965MiB

ios/android ?

Hi
is it possible to support android & ios without using opengles ?

Full-resolution on Retina displays (Mac and iOS)

For MacOS with a hi-dpi Retina display, and all iOS, is there a way to tell mfb_update that the buffer contains 4 times as many pixels that can be directly displayed? There seems to be some code in iOSMiniFB.m that deals with [UIScreen mainScreen].scale but it's not clear that it suffices; and there's no similar code in MacMiniFB.m. Thanks, and apologies if this is already addressed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.