├── nim.cfg ├── .gitignore ├── src ├── macosx │ ├── OSXWindowFrameView.h │ ├── OSXWindow.h │ ├── OSXWindowFrameView.m │ ├── MacMiniFB.m │ └── OSXWindow.m ├── windows │ ├── WindowData_Win.h │ └── WinMiniFB.c ├── MiniFB_linux.c ├── MiniFB_internal.h ├── minifb.nim ├── WindowData.h ├── MiniFB_timer.c ├── x11 │ └── X11MiniFB.c ├── MiniFB_internal.c ├── include │ ├── MiniFB.h │ ├── MiniFB_enums.h │ └── MiniFB_cpp.h └── MiniFB_common.c ├── test ├── sine.nim ├── framebuf.nim └── noise.nim └── README.md /nim.cfg: -------------------------------------------------------------------------------- 1 | path=src 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | nimcache 2 | .DS_Store 3 | *~ 4 | *.swp 5 | *.exe 6 | -------------------------------------------------------------------------------- /src/macosx/OSXWindowFrameView.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface OSXWindowFrameView : NSView 4 | { 5 | } 6 | 7 | @end 8 | 9 | -------------------------------------------------------------------------------- /src/macosx/OSXWindow.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | // @class OSXWindowFrameView; 4 | 5 | @interface OSXWindow : NSWindow 6 | { 7 | NSView* childContentView; 8 | @public bool closed; 9 | } 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /src/windows/WindowData_Win.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | // #define WIN32_LEAN_AND_MEAN 5 | #include 6 | 7 | typedef struct 8 | { 9 | HWND window; 10 | WNDCLASS wc; 11 | HDC hdc; 12 | #if defined(USE_OPENGL_API) 13 | HGLRC hGLRC; 14 | uint32_t text_id; 15 | #else 16 | BITMAPINFO *bitmapInfo; 17 | #endif 18 | struct mfb_timer *timer; 19 | bool mouse_inside; 20 | } SWindowData_Win; 21 | -------------------------------------------------------------------------------- /test/sine.nim: -------------------------------------------------------------------------------- 1 | import math, os, times 2 | import framebuf, minifb 3 | 4 | 5 | proc main() = 6 | let 7 | width = 640 8 | height = 480 9 | 10 | var fb = newFrameBuf(width, height) 11 | 12 | if not mfbOpen("Sine Test", width, height): 13 | quit(0) 14 | 15 | while true: 16 | let t = epochTime() 17 | fb.clear(0x303030) 18 | 19 | for x in 0.. 4 | #include 5 | 6 | extern double g_timer_frequency; 7 | extern double g_timer_resolution; 8 | 9 | #define kClock CLOCK_MONOTONIC 10 | //#define kClock CLOCK_REALTIME 11 | 12 | uint64_t 13 | mfb_timer_tick() { 14 | struct timespec time; 15 | 16 | if (clock_gettime(kClock, &time) != 0) { 17 | return 0.0; 18 | } 19 | 20 | return time.tv_sec * 1e+9 + time.tv_nsec; 21 | } 22 | 23 | void 24 | mfb_timer_init() { 25 | struct timespec res; 26 | 27 | if (clock_getres(kClock, &res) != 0) { 28 | g_timer_frequency = 1e+9; 29 | } 30 | else { 31 | g_timer_frequency = res.tv_sec + res.tv_nsec * 1e+9; 32 | } 33 | g_timer_resolution = 1.0 / g_timer_frequency; 34 | } 35 | 36 | #endif 37 | 38 | -------------------------------------------------------------------------------- /test/noise.nim: -------------------------------------------------------------------------------- 1 | import minifb 2 | 3 | 4 | proc main() = 5 | let 6 | width = 800 7 | height = 600 8 | 9 | var 10 | noise = 0 11 | carry = 0 12 | seed = 0xbeef 13 | buffer: seq[int32] 14 | 15 | if not mfbOpen("Noise Test", width, height): 16 | quit(1) 17 | 18 | buffer = newSeq[int32](width * height) 19 | 20 | while true: 21 | for i in 0..<(width * height): 22 | noise = seed 23 | noise = noise shr 3 24 | noise = noise xor seed 25 | carry = noise and 1 26 | noise = noise shr 1 27 | seed = seed shr 1 28 | seed = seed or (carry shl 30) 29 | noise = noise and 0xff 30 | buffer[i] = int32((noise shl 16) or (noise shl 8) or noise) 31 | 32 | if mfbUpdate(cast[pointer](buffer[0].addr)): 33 | break 34 | 35 | mfbClose() 36 | 37 | 38 | main() 39 | -------------------------------------------------------------------------------- /src/MiniFB_internal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "WindowData.h" 5 | 6 | #define kCall(func, ...) if(window_data && window_data->func) window_data->func((struct mfb_window *) window_data, __VA_ARGS__); 7 | #define kUnused(var) (void) var; 8 | 9 | typedef struct mfb_timer { 10 | int64_t start_time; 11 | int64_t delta_counter; 12 | uint64_t time; 13 | } mfb_timer; 14 | 15 | #if defined(__cplusplus) 16 | extern "C" { 17 | #endif 18 | extern short int g_keycodes[512]; 19 | void keyboard_default(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed); 20 | 21 | void calc_dst_factor(SWindowData *window_data, uint32_t width, uint32_t height); 22 | void resize_dst(SWindowData *window_data, uint32_t width, uint32_t height); 23 | void set_target_fps_aux(); 24 | 25 | #if defined(__cplusplus) 26 | } 27 | #endif 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nim-MiniFB 2 | 3 | Nim wrapper/port of the cute [MiniFB](https://github.com/emoon/minifb) (Mini 4 | FrameBuffer) library originally written by [Daniel 5 | Collin](https://github.com/emoon). 6 | 7 | The usage in a nutshell: 8 | 9 | * `mfbOpen` opens a non-resizable window of the specified size. 10 | 11 | * `mfbUpdate` copies a buffer of 32-bit pixels (in XRGB 12 | format) into the window area and displays it. It returns `true` if ESC was 13 | pressed, `false` otherwise. The buffer must be at least 14 | `WIDTH * HEIGHT * 4` bytes in size and must be managed by the application. 15 | 16 | * `mfbClose` closes the window (duh). 17 | 18 | See the original documentation 19 | [here](https://github.com/emoon/minifb/blob/master/README.md) and the 20 | [test](test/) directory for examples. 21 | 22 | Works on Windows, Mac OS X and X11 (FreeBSD, Linux, *nix). Most likely fails 23 | on platforms where it cannot allocate a 32-bit pixel buffer and probably only 24 | supports little-endian architectures (can't test either, sorry). 25 | 26 | -------------------------------------------------------------------------------- /src/minifb.nim: -------------------------------------------------------------------------------- 1 | 2 | {.passC: "-Isrc", 3 | compile: "src/MiniFB_common.c", 4 | compile:"src/MiniFB_internal.c", 5 | compile:"src/MiniFB_timer.c" .} 6 | 7 | when defined(windows): 8 | {.passC: "-Isrc/include", 9 | passL: "-lgdi32 -lwinmm", 10 | compile: "src/windows/WinMiniFB.c".} 11 | 12 | elif defined(macosx): 13 | {.passL: "-framework Cocoa", 14 | passC: "-Isrc/include", 15 | compile: "src/macosx/OSXWindowFrameView.m", 16 | compile: "src/macosx/MacMiniFB.m", 17 | compile: "src/macosx/OSXWindow.m".} 18 | 19 | else: 20 | {.passL: "-lX11", 21 | passC: "-Isrc/include", 22 | compile: "src/x11/X11MiniFB.c".} 23 | 24 | proc native_mfbOpen(title: string, width, height: int): int 25 | {.cdecl, importc: "mfb_open".} 26 | 27 | proc mfbOpen*(title: string, width, height: int): bool = 28 | native_mfbOpen(title, width, height) == 1 29 | 30 | proc native_mfbUpdate(buffer: pointer): int {.cdecl, importc: "mfb_update".} 31 | 32 | proc mfbUpdate*(buffer: pointer): bool = 33 | native_mfbUpdate(buffer) != 0 34 | 35 | proc mfbClose*() {.cdecl, importc: "mfb_close".} 36 | 37 | -------------------------------------------------------------------------------- /src/macosx/OSXWindowFrameView.m: -------------------------------------------------------------------------------- 1 | #import "OSXWindowFrameView.h" 2 | 3 | @implementation OSXWindowFrameView 4 | 5 | extern void* g_updateBuffer; 6 | extern int g_width; 7 | extern int g_height; 8 | 9 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 10 | 11 | - (NSRect)resizeRect 12 | { 13 | const CGFloat resizeBoxSize = 16.0; 14 | const CGFloat contentViewPadding = 5.5; 15 | 16 | NSRect contentViewRect = [[self window] contentRectForFrameRect:[[self window] frame]]; 17 | NSRect resizeRect = NSMakeRect( 18 | NSMaxX(contentViewRect) + contentViewPadding, 19 | NSMinY(contentViewRect) - resizeBoxSize - contentViewPadding, 20 | resizeBoxSize, 21 | resizeBoxSize); 22 | 23 | return resizeRect; 24 | } 25 | 26 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 27 | 28 | - (void)drawRect:(NSRect)rect 29 | { 30 | (void)rect; 31 | 32 | if (!g_updateBuffer) 33 | return; 34 | 35 | CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; 36 | 37 | CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); 38 | CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, g_updateBuffer, g_width * g_height * 4, NULL); 39 | 40 | CGImageRef img = CGImageCreate(g_width, g_height, 8, 32, g_width * 4, space, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little, 41 | provider, NULL, false, kCGRenderingIntentDefault); 42 | 43 | CGColorSpaceRelease(space); 44 | CGDataProviderRelease(provider); 45 | 46 | CGContextDrawImage(context, CGRectMake(0, 0, g_width, g_height), img); 47 | 48 | CGImageRelease(img); 49 | } 50 | 51 | @end 52 | 53 | -------------------------------------------------------------------------------- /src/WindowData.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | //------------------------------------- 8 | typedef struct { 9 | void *specific; 10 | void *user_data; 11 | 12 | mfb_active_func active_func; 13 | mfb_resize_func resize_func; 14 | mfb_close_func close_func; 15 | mfb_keyboard_func keyboard_func; 16 | mfb_char_input_func char_input_func; 17 | mfb_mouse_button_func mouse_btn_func; 18 | mfb_mouse_move_func mouse_move_func; 19 | mfb_mouse_scroll_func mouse_wheel_func; 20 | 21 | uint32_t window_width; 22 | uint32_t window_height; 23 | 24 | uint32_t dst_offset_x; 25 | uint32_t dst_offset_y; 26 | uint32_t dst_width; 27 | uint32_t dst_height; 28 | float factor_x; 29 | float factor_y; 30 | float factor_width; 31 | float factor_height; 32 | 33 | void *draw_buffer; 34 | uint32_t buffer_width; 35 | uint32_t buffer_height; 36 | uint32_t buffer_stride; 37 | 38 | int32_t mouse_pos_x; 39 | int32_t mouse_pos_y; 40 | float mouse_wheel_x; 41 | float mouse_wheel_y; 42 | uint8_t mouse_button_status[8]; 43 | uint8_t key_status[512]; 44 | uint32_t mod_keys; 45 | 46 | bool is_active; 47 | bool is_initialized; 48 | 49 | bool close; 50 | } SWindowData; 51 | -------------------------------------------------------------------------------- /src/macosx/MacMiniFB.m: -------------------------------------------------------------------------------- 1 | 2 | #include "OSXWindow.h" 3 | #include 4 | #include 5 | #include "MiniFB.h" 6 | 7 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 8 | 9 | void* g_updateBuffer = 0; 10 | int g_width = 0; 11 | int g_height = 0; 12 | static OSXWindow* window_; 13 | 14 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 15 | 16 | int mfb_open(const char* name, int width, int height) 17 | { 18 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 19 | 20 | g_width = width; 21 | g_height = height; 22 | 23 | [NSApplication sharedApplication]; 24 | [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; 25 | 26 | unsigned int styles = NSResizableWindowMask | NSClosableWindowMask | NSTitledWindowMask; 27 | 28 | NSRect rectangle = NSMakeRect(0, 0, width, height); 29 | window_ = [[OSXWindow alloc] initWithContentRect:rectangle styleMask:styles backing:NSBackingStoreBuffered defer:NO]; 30 | 31 | if (!window_) 32 | return 0; 33 | 34 | [window_ setTitle:[NSString stringWithUTF8String:name]]; 35 | [window_ setReleasedWhenClosed:NO]; 36 | [window_ performSelectorOnMainThread:@selector(makeKeyAndOrderFront:) withObject:nil waitUntilDone:YES]; 37 | 38 | [window_ center]; 39 | 40 | [NSApp activateIgnoringOtherApps:YES]; 41 | 42 | [pool drain]; 43 | 44 | return 1; 45 | } 46 | 47 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 48 | 49 | void mfb_close() 50 | { 51 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 52 | 53 | if (window_) 54 | [window_ close]; 55 | 56 | [pool drain]; 57 | } 58 | 59 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 60 | 61 | static int updateEvents() 62 | { 63 | int state = 0; 64 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 65 | NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; 66 | if (event) 67 | { 68 | switch ([event type]) 69 | { 70 | case NSKeyDown: 71 | case NSKeyUp: 72 | { 73 | state = -1; 74 | break; 75 | } 76 | 77 | default : 78 | { 79 | [NSApp sendEvent:event]; 80 | break; 81 | } 82 | } 83 | } 84 | [pool release]; 85 | 86 | if (window_->closed) 87 | state = -1; 88 | 89 | return state; 90 | } 91 | 92 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 93 | 94 | int mfb_update(void* buffer) 95 | { 96 | g_updateBuffer = buffer; 97 | int state = updateEvents(); 98 | [[window_ contentView] setNeedsDisplay:YES]; 99 | return state; 100 | } 101 | -------------------------------------------------------------------------------- /src/MiniFB_timer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "MiniFB_internal.h" 3 | #include 4 | 5 | //------------------------------------- 6 | double g_timer_frequency; 7 | double g_timer_resolution; 8 | double g_time_for_frame = 1.0 / 60.0; 9 | bool g_use_hardware_sync = false; 10 | 11 | //------------------------------------- 12 | extern uint64_t mfb_timer_tick(void); 13 | extern void mfb_timer_init(void); 14 | 15 | //------------------------------------- 16 | void 17 | mfb_set_target_fps(uint32_t fps) { 18 | if(fps == 0) { 19 | g_time_for_frame = 0; 20 | } 21 | else { 22 | g_time_for_frame = 1.0 / fps; 23 | } 24 | set_target_fps_aux(); 25 | } 26 | 27 | //------------------------------------- 28 | unsigned 29 | mfb_get_target_fps() { 30 | if (g_time_for_frame == 0) { 31 | return 0; 32 | } 33 | else { 34 | return (unsigned) (1.0 / g_time_for_frame); 35 | } 36 | } 37 | 38 | //------------------------------------- 39 | struct mfb_timer * 40 | mfb_timer_create() { 41 | static int once = 1; 42 | mfb_timer *tmr; 43 | 44 | if(once) { 45 | once = 0; 46 | mfb_timer_init(); 47 | } 48 | 49 | tmr = malloc(sizeof(mfb_timer)); 50 | mfb_timer_reset(tmr); 51 | 52 | return tmr; 53 | } 54 | 55 | //------------------------------------- 56 | void 57 | mfb_timer_destroy(struct mfb_timer *tmr) { 58 | if(tmr != 0x0) { 59 | free(tmr); 60 | } 61 | } 62 | 63 | //------------------------------------- 64 | void 65 | mfb_timer_reset(struct mfb_timer *tmr) { 66 | if(tmr == 0x0) 67 | return; 68 | 69 | tmr->start_time = mfb_timer_tick(); 70 | tmr->delta_counter = tmr->start_time; 71 | tmr->time = 0; 72 | } 73 | 74 | //------------------------------------- 75 | double 76 | mfb_timer_now(struct mfb_timer *tmr) { 77 | uint64_t counter; 78 | 79 | if(tmr == 0x0) 80 | return 0.0; 81 | 82 | counter = mfb_timer_tick(); 83 | tmr->time += (counter - tmr->start_time); 84 | tmr->start_time = counter; 85 | 86 | return tmr->time * g_timer_resolution; 87 | } 88 | 89 | //------------------------------------- 90 | double 91 | mfb_timer_delta(struct mfb_timer *tmr) { 92 | int64_t counter; 93 | uint64_t delta; 94 | 95 | if(tmr == 0x0) 96 | return 0.0; 97 | 98 | counter = mfb_timer_tick(); 99 | delta = (counter - tmr->delta_counter); 100 | tmr->delta_counter = counter; 101 | 102 | return delta * g_timer_resolution; 103 | } 104 | 105 | //------------------------------------- 106 | double 107 | mfb_timer_get_frequency() { 108 | return g_timer_frequency; 109 | } 110 | 111 | //------------------------------------- 112 | double 113 | mfb_timer_get_resolution() { 114 | return g_timer_resolution; 115 | } 116 | -------------------------------------------------------------------------------- /src/x11/X11MiniFB.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 6 | 7 | #define KEY_FUNCTION 0xFF 8 | #define KEY_ESC 0x1B 9 | 10 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 11 | 12 | static Display* s_display; 13 | static int s_screen; 14 | static int s_width; 15 | static int s_height; 16 | static Window s_window; 17 | static GC s_gc; 18 | static XImage *s_ximage; 19 | 20 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 21 | 22 | int mfb_open(const char* title, int width, int height) 23 | { 24 | int depth, i, formatCount, convDepth = -1; 25 | XPixmapFormatValues* formats; 26 | XSetWindowAttributes windowAttributes; 27 | XSizeHints sizeHints; 28 | Visual* visual; 29 | 30 | s_display = XOpenDisplay(0); 31 | 32 | if (!s_display) 33 | return -1; 34 | 35 | s_screen = DefaultScreen(s_display); 36 | visual = DefaultVisual(s_display, s_screen); 37 | formats = XListPixmapFormats(s_display, &formatCount); 38 | depth = DefaultDepth(s_display, s_screen); 39 | Window defaultRootWindow = DefaultRootWindow(s_display); 40 | 41 | for (i = 0; i < formatCount; ++i) 42 | { 43 | if (depth == formats[i].depth) 44 | { 45 | convDepth = formats[i].bits_per_pixel; 46 | break; 47 | } 48 | } 49 | 50 | XFree(formats); 51 | 52 | // We only support 32-bit right now 53 | if (convDepth != 32) 54 | { 55 | XCloseDisplay(s_display); 56 | return -1; 57 | } 58 | 59 | int screenWidth = DisplayWidth(s_display, s_screen); 60 | int screenHeight = DisplayHeight(s_display, s_screen); 61 | 62 | windowAttributes.border_pixel = BlackPixel(s_display, s_screen); 63 | windowAttributes.background_pixel = BlackPixel(s_display, s_screen); 64 | windowAttributes.backing_store = NotUseful; 65 | 66 | s_window = XCreateWindow(s_display, defaultRootWindow, (screenWidth - width) / 2, 67 | (screenHeight - height) / 2, width, height, 0, depth, InputOutput, 68 | visual, CWBackPixel | CWBorderPixel | CWBackingStore, 69 | &windowAttributes); 70 | if (!s_window) 71 | return 0; 72 | 73 | XSelectInput(s_display, s_window, KeyPressMask | KeyReleaseMask); 74 | XStoreName(s_display, s_window, title); 75 | 76 | sizeHints.flags = PPosition | PMinSize | PMaxSize; 77 | sizeHints.x = 0; 78 | sizeHints.y = 0; 79 | sizeHints.min_width = width; 80 | sizeHints.max_width = width; 81 | sizeHints.min_height = height; 82 | sizeHints.max_height = height; 83 | 84 | XSetWMNormalHints(s_display, s_window, &sizeHints); 85 | XClearWindow(s_display, s_window); 86 | XMapRaised(s_display, s_window); 87 | XFlush(s_display); 88 | 89 | s_gc = DefaultGC(s_display, s_screen); 90 | 91 | s_ximage = XCreateImage(s_display, CopyFromParent, depth, ZPixmap, 0, NULL, width, height, 32, width * 4); 92 | 93 | s_width = width; 94 | s_height = height; 95 | 96 | return 1; 97 | } 98 | 99 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 100 | 101 | static int processEvents() 102 | { 103 | XEvent event; 104 | KeySym sym; 105 | 106 | if (!XPending(s_display)) 107 | return 0; 108 | 109 | XNextEvent(s_display, &event); 110 | 111 | if (event.type != KeyPress) 112 | return 0; 113 | 114 | sym = XLookupKeysym(&event.xkey, 0); 115 | 116 | if ((sym >> 8) != KEY_FUNCTION) 117 | return 0; 118 | 119 | if ((sym & 0xFF) == KEY_ESC) 120 | return -1; 121 | 122 | return 0; 123 | } 124 | 125 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 126 | 127 | int mfb_update(void* buffer) 128 | { 129 | s_ximage->data = (char*)buffer; 130 | 131 | XPutImage(s_display, s_window, s_gc, s_ximage, 0, 0, 0, 0, s_width, s_height); 132 | XFlush(s_display); 133 | 134 | if (processEvents() < 0) 135 | return -1; 136 | 137 | return 0; 138 | } 139 | 140 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 141 | 142 | void mfb_close (void) 143 | { 144 | s_ximage->data = NULL; 145 | XDestroyImage(s_ximage); 146 | XDestroyWindow(s_display, s_window); 147 | XCloseDisplay(s_display); 148 | } 149 | -------------------------------------------------------------------------------- /src/macosx/OSXWindow.m: -------------------------------------------------------------------------------- 1 | #import "OSXWindow.h" 2 | #import "OSXWindowFrameView.h" 3 | 4 | @implementation OSXWindow 5 | 6 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 7 | 8 | - (id)initWithContentRect:(NSRect)contentRect 9 | styleMask:(NSUInteger)windowStyle 10 | backing:(NSBackingStoreType)bufferingType 11 | defer:(BOOL)deferCreation 12 | { 13 | self = [super 14 | initWithContentRect:contentRect 15 | styleMask:windowStyle 16 | backing:bufferingType 17 | defer:deferCreation]; 18 | if (self) 19 | { 20 | [self setOpaque:YES]; 21 | [self setBackgroundColor:[NSColor clearColor]]; 22 | 23 | [[NSNotificationCenter defaultCenter] 24 | addObserver:self 25 | selector:@selector(mainWindowChanged:) 26 | name:NSWindowDidBecomeMainNotification 27 | object:self]; 28 | 29 | [[NSNotificationCenter defaultCenter] 30 | addObserver:self 31 | selector:@selector(mainWindowChanged:) 32 | name:NSWindowDidResignMainNotification 33 | object:self]; 34 | 35 | [[NSNotificationCenter defaultCenter] 36 | addObserver:self 37 | selector:@selector(willClose) 38 | name:NSWindowWillCloseNotification 39 | object:self]; 40 | 41 | closed = false; 42 | } 43 | return self; 44 | } 45 | 46 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 47 | 48 | - (void)dealloc 49 | { 50 | [[NSNotificationCenter defaultCenter] 51 | removeObserver:self]; 52 | [super dealloc]; 53 | } 54 | 55 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 56 | 57 | - (void)setContentSize:(NSSize)newSize 58 | { 59 | NSSize sizeDelta = newSize; 60 | NSSize childBoundsSize = [childContentView bounds].size; 61 | sizeDelta.width -= childBoundsSize.width; 62 | sizeDelta.height -= childBoundsSize.height; 63 | 64 | OSXWindowFrameView *frameView = [super contentView]; 65 | NSSize newFrameSize = [frameView bounds].size; 66 | newFrameSize.width += sizeDelta.width; 67 | newFrameSize.height += sizeDelta.height; 68 | 69 | [super setContentSize:newFrameSize]; 70 | } 71 | 72 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 73 | 74 | - (void)mainWindowChanged:(NSNotification *)aNotification 75 | { 76 | (void)aNotification; 77 | } 78 | 79 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 80 | 81 | - (void)setContentView:(NSView *)aView 82 | { 83 | if ([childContentView isEqualTo:aView]) 84 | { 85 | return; 86 | } 87 | 88 | NSRect bounds = [self frame]; 89 | bounds.origin = NSZeroPoint; 90 | 91 | OSXWindowFrameView *frameView = [super contentView]; 92 | if (!frameView) 93 | { 94 | frameView = [[[OSXWindowFrameView alloc] initWithFrame:bounds] autorelease]; 95 | 96 | [super setContentView:frameView]; 97 | } 98 | 99 | if (childContentView) 100 | { 101 | [childContentView removeFromSuperview]; 102 | } 103 | childContentView = aView; 104 | [childContentView setFrame:[self contentRectForFrameRect:bounds]]; 105 | [childContentView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; 106 | [frameView addSubview:childContentView]; 107 | } 108 | 109 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 110 | 111 | - (NSView *)contentView 112 | { 113 | return childContentView; 114 | } 115 | 116 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 117 | 118 | - (BOOL)canBecomeKeyWindow 119 | { 120 | return YES; 121 | } 122 | 123 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 124 | 125 | - (BOOL)canBecomeMainWindow 126 | { 127 | return YES; 128 | } 129 | 130 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 131 | 132 | - (NSRect)contentRectForFrameRect:(NSRect)windowFrame 133 | { 134 | windowFrame.origin = NSZeroPoint; 135 | return NSInsetRect(windowFrame, 0, 0); 136 | } 137 | 138 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 139 | 140 | + (NSRect)frameRectForContentRect:(NSRect)windowContentRect styleMask:(NSUInteger)windowStyle 141 | { 142 | (void)windowStyle; 143 | return NSInsetRect(windowContentRect, 0, 0); 144 | } 145 | 146 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 147 | 148 | - (void)willClose 149 | { 150 | closed = true; 151 | } 152 | 153 | @end 154 | -------------------------------------------------------------------------------- /src/MiniFB_internal.c: -------------------------------------------------------------------------------- 1 | #include "MiniFB_internal.h" 2 | #include 3 | 4 | //#define kUseBilinearInterpolation 5 | 6 | #if defined(kUseBilinearInterpolation) 7 | //------------------------------------- 8 | static uint32_t 9 | interpolate(uint32_t *srcImage, uint32_t x, uint32_t y, uint32_t srcOffsetX, uint32_t srcOffsetY, uint32_t srcWidth, uint32_t srcHeight, uint32_t srcPitch) { 10 | uint32_t incX = x + 1 < srcWidth ? 1 : 0; 11 | uint32_t incY = y + 1 < srcHeight ? srcPitch : 0; 12 | uint8_t *p00 = (uint8_t *) &srcImage[(srcOffsetX >> 16)]; 13 | uint8_t *p01 = (uint8_t *) &srcImage[(srcOffsetX >> 16) + incX]; 14 | uint8_t *p10 = (uint8_t *) &srcImage[(srcOffsetX >> 16) + incY]; 15 | uint8_t *p11 = (uint8_t *) &srcImage[(srcOffsetX >> 16) + incY + incX]; 16 | 17 | uint32_t wx2 = srcOffsetX & 0xffff; 18 | uint32_t wy2 = srcOffsetY & 0xffff; 19 | uint32_t wx1 = 0x10000 - wx2; 20 | uint32_t wy1 = 0x10000 - wy2; 21 | 22 | uint32_t w1 = ((uint64_t) wx1 * wy1) >> 16; 23 | uint32_t w2 = ((uint64_t) wx2 * wy1) >> 16; 24 | uint32_t w3 = ((uint64_t) wx1 * wy2) >> 16; 25 | uint32_t w4 = ((uint64_t) wx2 * wy2) >> 16; 26 | 27 | // If you don't have uint64_t 28 | //uint32_t b = (((p00[0] * wx1 + p01[0] * wx2) >> 16) * wy1 + ((p10[0] * wx1 + p11[0] * wx2) >> 16) * wy2) >> 16; 29 | //uint32_t g = (((p00[1] * wx1 + p01[1] * wx2) >> 16) * wy1 + ((p10[1] * wx1 + p11[1] * wx2) >> 16) * wy2) >> 16; 30 | //uint32_t r = (((p00[2] * wx1 + p01[2] * wx2) >> 16) * wy1 + ((p10[2] * wx1 + p11[2] * wx2) >> 16) * wy2) >> 16; 31 | //uint32_t a = (((p00[3] * wx1 + p01[3] * wx2) >> 16) * wy1 + ((p10[3] * wx1 + p11[3] * wx2) >> 16) * wy2) >> 16; 32 | 33 | uint32_t b = ((p00[0] * w1 + p01[0] * w2) + (p10[0] * w3 + p11[0] * w4)) >> 16; 34 | uint32_t g = ((p00[1] * w1 + p01[1] * w2) + (p10[1] * w3 + p11[1] * w4)) >> 16; 35 | uint32_t r = ((p00[2] * w1 + p01[2] * w2) + (p10[2] * w3 + p11[2] * w4)) >> 16; 36 | uint32_t a = ((p00[3] * w1 + p01[3] * w2) + (p10[3] * w3 + p11[3] * w4)) >> 16; 37 | 38 | return (a << 24) + (r << 16) + (g << 8) + b; 39 | } 40 | #endif 41 | 42 | // Only for 32 bits images 43 | //------------------------------------- 44 | void 45 | stretch_image(uint32_t *srcImage, uint32_t srcX, uint32_t srcY, uint32_t srcWidth, uint32_t srcHeight, uint32_t srcPitch, 46 | uint32_t *dstImage, uint32_t dstX, uint32_t dstY, uint32_t dstWidth, uint32_t dstHeight, uint32_t dstPitch) { 47 | 48 | uint32_t x, y; 49 | uint32_t srcOffsetX, srcOffsetY; 50 | 51 | if(srcImage == 0x0 || dstImage == 0x0) 52 | return; 53 | 54 | srcImage += srcX + srcY * srcPitch; 55 | dstImage += dstX + dstY * dstPitch; 56 | 57 | const uint32_t deltaX = (srcWidth << 16) / dstWidth; 58 | const uint32_t deltaY = (srcHeight << 16) / dstHeight; 59 | 60 | srcOffsetY = 0; 61 | for(y=0; y> 16]; 68 | #endif 69 | srcOffsetX += deltaX; 70 | } 71 | 72 | srcOffsetY += deltaY; 73 | if(srcOffsetY >= 0x10000) { 74 | srcImage += (srcOffsetY >> 16) * srcPitch; 75 | srcOffsetY &= 0xffff; 76 | } 77 | dstImage += dstPitch; 78 | } 79 | } 80 | 81 | //------------------------------------- 82 | void 83 | calc_dst_factor(SWindowData *window_data, uint32_t width, uint32_t height) { 84 | if (window_data->dst_width == 0) { 85 | window_data->dst_width = width; 86 | } 87 | window_data->factor_x = (float) window_data->dst_offset_x / (float) width; 88 | window_data->factor_width = (float) window_data->dst_width / (float) width; 89 | 90 | if (window_data->dst_height == 0) { 91 | window_data->dst_height = height; 92 | } 93 | window_data->factor_y = (float) window_data->dst_offset_y / (float) height; 94 | window_data->factor_height = (float) window_data->dst_height / (float) height; 95 | } 96 | 97 | //------------------------------------- 98 | void 99 | resize_dst(SWindowData *window_data, uint32_t width, uint32_t height) { 100 | window_data->dst_offset_x = (uint32_t) (width * window_data->factor_x); 101 | window_data->dst_offset_y = (uint32_t) (height * window_data->factor_y); 102 | window_data->dst_width = (uint32_t) (width * window_data->factor_width); 103 | window_data->dst_height = (uint32_t) (height * window_data->factor_height); 104 | } 105 | 106 | #if !defined(USE_OPENGL_API) && !defined(USE_METAL_API) 107 | 108 | //------------------------------------- 109 | void 110 | set_target_fps_aux() { 111 | } 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /src/include/MiniFB.h: -------------------------------------------------------------------------------- 1 | #ifndef _MINIFB_H_ 2 | #define _MINIFB_H_ 3 | 4 | #include "MiniFB_enums.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" 8 | { 9 | #endif 10 | 11 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 12 | #ifndef __ANDROID__ 13 | #define MFB_RGB(r, g, b) (((uint32_t)r) << 16) | (((uint32_t)g) << 8) | ((uint32_t)b) 14 | #define MFB_ARGB(a, r, g, b) (((uint32_t)a) << 24) | (((uint32_t)r) << 16) | (((uint32_t)g) << 8) | ((uint32_t)b) 15 | #else 16 | #ifdef HOST_WORDS_BIGENDIAN 17 | #define MFB_RGB(r, g, b) (((uint32_t)r) << 16) | (((uint32_t)g) << 8) | ((uint32_t)b) 18 | #define MFB_ARGB(a, r, g, b) (((uint32_t)a) << 24) | (((uint32_t)r) << 16) | (((uint32_t)g) << 8) | ((uint32_t)b) 19 | #else 20 | #define MFB_ARGB(r, g, b) (((uint32_t)a) << 24) | (((uint32_t)b) << 16) | (((uint32_t)g) << 8) | ((uint32_t)r) 21 | #define MFB_RGB(r, g, b) (((uint32_t)b) << 16) | (((uint32_t)g) << 8) | ((uint32_t)r) 22 | #endif 23 | #endif 24 | 25 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 26 | 27 | // Create a window that is used to display the buffer sent into the mfb_update function, returns 0 if fails 28 | struct mfb_window *mfb_open(const char *title, unsigned width, unsigned height); 29 | struct mfb_window *mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags); 30 | 31 | // Update the display 32 | // Input buffer is assumed to be a 32-bit buffer of the size given in the open call 33 | // Will return a negative status if something went wrong or the user want to exit 34 | // Also updates the window events 35 | mfb_update_state mfb_update(struct mfb_window *window, void *buffer); 36 | 37 | mfb_update_state mfb_update_ex(struct mfb_window *window, void *buffer, unsigned width, unsigned height); 38 | 39 | // Only updates the window events 40 | mfb_update_state mfb_update_events(struct mfb_window *window); 41 | 42 | // Close the window 43 | void mfb_close(struct mfb_window *window); 44 | 45 | // Set user data 46 | void mfb_set_user_data(struct mfb_window *window, void *user_data); 47 | void *mfb_get_user_data(struct mfb_window *window); 48 | 49 | // Set viewport (useful when resize) 50 | bool mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height); 51 | // Let mfb to calculate the best fit from your framebuffer original size 52 | bool mfb_set_viewport_best_fit(struct mfb_window *window, unsigned old_width, unsigned old_height); 53 | 54 | // DPI 55 | // [Deprecated]: Probably a better name will be mfb_get_monitor_scale 56 | void mfb_get_monitor_dpi(struct mfb_window *window, float *dpi_x, float *dpi_y); 57 | // Use this instead 58 | void mfb_get_monitor_scale(struct mfb_window *window, float *scale_x, float *scale_y); 59 | 60 | // Callbacks 61 | void mfb_set_active_callback(struct mfb_window *window, mfb_active_func callback); 62 | void mfb_set_resize_callback(struct mfb_window *window, mfb_resize_func callback); 63 | void mfb_set_close_callback(struct mfb_window *window, mfb_close_func callback); 64 | void mfb_set_keyboard_callback(struct mfb_window *window, mfb_keyboard_func callback); 65 | void mfb_set_char_input_callback(struct mfb_window *window, mfb_char_input_func callback); 66 | void mfb_set_mouse_button_callback(struct mfb_window *window, mfb_mouse_button_func callback); 67 | void mfb_set_mouse_move_callback(struct mfb_window *window, mfb_mouse_move_func callback); 68 | void mfb_set_mouse_scroll_callback(struct mfb_window *window, mfb_mouse_scroll_func callback); 69 | 70 | // Getters 71 | const char *mfb_get_key_name(mfb_key key); 72 | 73 | bool mfb_is_window_active(struct mfb_window *window); 74 | unsigned mfb_get_window_width(struct mfb_window *window); 75 | unsigned mfb_get_window_height(struct mfb_window *window); 76 | int mfb_get_mouse_x(struct mfb_window *window); // Last mouse pos X 77 | int mfb_get_mouse_y(struct mfb_window *window); // Last mouse pos Y 78 | float mfb_get_mouse_scroll_x(struct mfb_window *window); // Mouse wheel X as a sum. When you call this function it resets. 79 | float mfb_get_mouse_scroll_y(struct mfb_window *window); // Mouse wheel Y as a sum. When you call this function it resets. 80 | 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) 81 | const uint8_t *mfb_get_key_buffer(struct mfb_window *window); // One byte for every key. Press (1), Release 0. 82 | 83 | // FPS 84 | void mfb_set_target_fps(uint32_t fps); 85 | unsigned mfb_get_target_fps(void); 86 | bool mfb_wait_sync(struct mfb_window *window); 87 | 88 | // Timer 89 | struct mfb_timer *mfb_timer_create(void); 90 | void mfb_timer_destroy(struct mfb_timer *tmr); 91 | void mfb_timer_reset(struct mfb_timer *tmr); 92 | double mfb_timer_now(struct mfb_timer *tmr); 93 | double mfb_timer_delta(struct mfb_timer *tmr); 94 | double mfb_timer_get_frequency(void); 95 | double mfb_timer_get_resolution(void); 96 | 97 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 98 | 99 | #ifdef __cplusplus 100 | } 101 | 102 | #if !defined(MINIFB_AVOID_CPP_HEADERS) 103 | #include "MiniFB_cpp.h" 104 | #endif 105 | 106 | #endif 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /src/include/MiniFB_enums.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | // Enums 7 | typedef enum { 8 | STATE_OK = 0, 9 | STATE_EXIT = -1, 10 | STATE_INVALID_WINDOW = -2, 11 | STATE_INVALID_BUFFER = -3, 12 | STATE_INTERNAL_ERROR = -4, 13 | } mfb_update_state; 14 | 15 | typedef enum { 16 | MOUSE_BTN_0, // No mouse button 17 | MOUSE_BTN_1, 18 | MOUSE_BTN_2, 19 | MOUSE_BTN_3, 20 | MOUSE_BTN_4, 21 | MOUSE_BTN_5, 22 | MOUSE_BTN_6, 23 | MOUSE_BTN_7, 24 | } mfb_mouse_button; 25 | #define MOUSE_LEFT MOUSE_BTN_1 26 | #define MOUSE_RIGHT MOUSE_BTN_2 27 | #define MOUSE_MIDDLE MOUSE_BTN_3 28 | 29 | typedef enum { 30 | KB_KEY_UNKNOWN = -1, 31 | 32 | KB_KEY_SPACE = 32, 33 | KB_KEY_APOSTROPHE = 39, 34 | KB_KEY_COMMA = 44, 35 | KB_KEY_MINUS = 45, 36 | KB_KEY_PERIOD = 46, 37 | KB_KEY_SLASH = 47, 38 | KB_KEY_0 = 48, 39 | KB_KEY_1 = 49, 40 | KB_KEY_2 = 50, 41 | KB_KEY_3 = 51, 42 | KB_KEY_4 = 52, 43 | KB_KEY_5 = 53, 44 | KB_KEY_6 = 54, 45 | KB_KEY_7 = 55, 46 | KB_KEY_8 = 56, 47 | KB_KEY_9 = 57, 48 | KB_KEY_SEMICOLON = 59, 49 | KB_KEY_EQUAL = 61, 50 | KB_KEY_A = 65, 51 | KB_KEY_B = 66, 52 | KB_KEY_C = 67, 53 | KB_KEY_D = 68, 54 | KB_KEY_E = 69, 55 | KB_KEY_F = 70, 56 | KB_KEY_G = 71, 57 | KB_KEY_H = 72, 58 | KB_KEY_I = 73, 59 | KB_KEY_J = 74, 60 | KB_KEY_K = 75, 61 | KB_KEY_L = 76, 62 | KB_KEY_M = 77, 63 | KB_KEY_N = 78, 64 | KB_KEY_O = 79, 65 | KB_KEY_P = 80, 66 | KB_KEY_Q = 81, 67 | KB_KEY_R = 82, 68 | KB_KEY_S = 83, 69 | KB_KEY_T = 84, 70 | KB_KEY_U = 85, 71 | KB_KEY_V = 86, 72 | KB_KEY_W = 87, 73 | KB_KEY_X = 88, 74 | KB_KEY_Y = 89, 75 | KB_KEY_Z = 90, 76 | KB_KEY_LEFT_BRACKET = 91, 77 | KB_KEY_BACKSLASH = 92, 78 | KB_KEY_RIGHT_BRACKET = 93, 79 | KB_KEY_GRAVE_ACCENT = 96, 80 | KB_KEY_WORLD_1 = 161, 81 | KB_KEY_WORLD_2 = 162, 82 | 83 | KB_KEY_ESCAPE = 256, 84 | KB_KEY_ENTER = 257, 85 | KB_KEY_TAB = 258, 86 | KB_KEY_BACKSPACE = 259, 87 | KB_KEY_INSERT = 260, 88 | KB_KEY_DELETE = 261, 89 | KB_KEY_RIGHT = 262, 90 | KB_KEY_LEFT = 263, 91 | KB_KEY_DOWN = 264, 92 | KB_KEY_UP = 265, 93 | KB_KEY_PAGE_UP = 266, 94 | KB_KEY_PAGE_DOWN = 267, 95 | KB_KEY_HOME = 268, 96 | KB_KEY_END = 269, 97 | KB_KEY_CAPS_LOCK = 280, 98 | KB_KEY_SCROLL_LOCK = 281, 99 | KB_KEY_NUM_LOCK = 282, 100 | KB_KEY_PRINT_SCREEN = 283, 101 | KB_KEY_PAUSE = 284, 102 | KB_KEY_F1 = 290, 103 | KB_KEY_F2 = 291, 104 | KB_KEY_F3 = 292, 105 | KB_KEY_F4 = 293, 106 | KB_KEY_F5 = 294, 107 | KB_KEY_F6 = 295, 108 | KB_KEY_F7 = 296, 109 | KB_KEY_F8 = 297, 110 | KB_KEY_F9 = 298, 111 | KB_KEY_F10 = 299, 112 | KB_KEY_F11 = 300, 113 | KB_KEY_F12 = 301, 114 | KB_KEY_F13 = 302, 115 | KB_KEY_F14 = 303, 116 | KB_KEY_F15 = 304, 117 | KB_KEY_F16 = 305, 118 | KB_KEY_F17 = 306, 119 | KB_KEY_F18 = 307, 120 | KB_KEY_F19 = 308, 121 | KB_KEY_F20 = 309, 122 | KB_KEY_F21 = 310, 123 | KB_KEY_F22 = 311, 124 | KB_KEY_F23 = 312, 125 | KB_KEY_F24 = 313, 126 | KB_KEY_F25 = 314, 127 | KB_KEY_KP_0 = 320, 128 | KB_KEY_KP_1 = 321, 129 | KB_KEY_KP_2 = 322, 130 | KB_KEY_KP_3 = 323, 131 | KB_KEY_KP_4 = 324, 132 | KB_KEY_KP_5 = 325, 133 | KB_KEY_KP_6 = 326, 134 | KB_KEY_KP_7 = 327, 135 | KB_KEY_KP_8 = 328, 136 | KB_KEY_KP_9 = 329, 137 | KB_KEY_KP_DECIMAL = 330, 138 | KB_KEY_KP_DIVIDE = 331, 139 | KB_KEY_KP_MULTIPLY = 332, 140 | KB_KEY_KP_SUBTRACT = 333, 141 | KB_KEY_KP_ADD = 334, 142 | KB_KEY_KP_ENTER = 335, 143 | KB_KEY_KP_EQUAL = 336, 144 | KB_KEY_LEFT_SHIFT = 340, 145 | KB_KEY_LEFT_CONTROL = 341, 146 | KB_KEY_LEFT_ALT = 342, 147 | KB_KEY_LEFT_SUPER = 343, 148 | KB_KEY_RIGHT_SHIFT = 344, 149 | KB_KEY_RIGHT_CONTROL = 345, 150 | KB_KEY_RIGHT_ALT = 346, 151 | KB_KEY_RIGHT_SUPER = 347, 152 | KB_KEY_MENU = 348 153 | } mfb_key; 154 | #define KB_KEY_LAST KB_KEY_MENU 155 | 156 | typedef enum { 157 | KB_MOD_SHIFT = 0x0001, 158 | KB_MOD_CONTROL = 0x0002, 159 | KB_MOD_ALT = 0x0004, 160 | KB_MOD_SUPER = 0x0008, 161 | KB_MOD_CAPS_LOCK = 0x0010, 162 | KB_MOD_NUM_LOCK = 0x0020 163 | } mfb_key_mod; 164 | 165 | typedef enum { 166 | WF_RESIZABLE = 0x01, 167 | WF_FULLSCREEN = 0x02, 168 | WF_FULLSCREEN_DESKTOP = 0x04, 169 | WF_BORDERLESS = 0x08, 170 | WF_ALWAYS_ON_TOP = 0x10, 171 | } mfb_window_flags; 172 | 173 | // Opaque pointer 174 | struct mfb_window; 175 | struct mfb_timer; 176 | 177 | // Event callbacks 178 | typedef void(*mfb_active_func)(struct mfb_window *window, bool isActive); 179 | typedef void(*mfb_resize_func)(struct mfb_window *window, int width, int height); 180 | typedef bool(*mfb_close_func)(struct mfb_window* window); 181 | typedef void(*mfb_keyboard_func)(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed); 182 | typedef void(*mfb_char_input_func)(struct mfb_window *window, unsigned int code); 183 | typedef void(*mfb_mouse_button_func)(struct mfb_window *window, mfb_mouse_button button, mfb_key_mod mod, bool isPressed); 184 | typedef void(*mfb_mouse_move_func)(struct mfb_window *window, int x, int y); 185 | typedef void(*mfb_mouse_scroll_func)(struct mfb_window *window, mfb_key_mod mod, float deltaX, float deltaY); 186 | 187 | -------------------------------------------------------------------------------- /src/include/MiniFB_cpp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(__cplusplus) 4 | 5 | #include 6 | #include "MiniFB.h" 7 | 8 | //------------------------------------- 9 | // To be able to distinguish these C++ functions, using std::function, from C functions, using raw function pointers, we need to reverse params order. 10 | // 11 | // Note that FROM the compiler point of view 12 | // mfb_set_XXX_callback(window, &my_c_func) 13 | // and 14 | // mfb_set_XXX_callback(window, [](...) {}) 15 | // have the same parameters. 16 | //------------------------------------- 17 | void mfb_set_active_callback (std::function func, struct mfb_window *window); 18 | void mfb_set_resize_callback (std::function func, struct mfb_window *window); 19 | void mfb_set_close_callback (std::function func, struct mfb_window *window); 20 | void mfb_set_keyboard_callback (std::function func, struct mfb_window *window); 21 | void mfb_set_char_input_callback (std::function func, struct mfb_window *window); 22 | void mfb_set_mouse_button_callback(std::function func, struct mfb_window *window); 23 | void mfb_set_mouse_move_callback (std::function func, struct mfb_window *window); 24 | void mfb_set_mouse_scroll_callback(std::function func, struct mfb_window *window); 25 | //------------------------------------- 26 | 27 | //------------------------------------- 28 | template 29 | void mfb_set_active_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, bool)); 30 | 31 | template 32 | void mfb_set_resize_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, int, int)); 33 | 34 | template 35 | void mfb_set_keyboard_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_key, mfb_key_mod, bool)); 36 | 37 | template 38 | void mfb_set_char_input_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, unsigned int)); 39 | 40 | template 41 | void mfb_set_mouse_button_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_mouse_button, mfb_key_mod, bool)); 42 | 43 | template 44 | void mfb_set_mouse_move_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, int, int)); 45 | 46 | template 47 | void mfb_set_mouse_scroll_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_key_mod, float, float)); 48 | //------------------------------------- 49 | 50 | //------------------------------------- 51 | // To avoid clumsy hands 52 | //------------------------------------- 53 | class mfb_stub { 54 | mfb_stub() : m_window(0x0) {} 55 | 56 | friend void mfb_set_active_callback (std::function func, struct mfb_window *window); 57 | friend void mfb_set_resize_callback (std::function func, struct mfb_window *window); 58 | friend void mfb_set_close_callback (std::function func, struct mfb_window *window); 59 | friend void mfb_set_keyboard_callback (std::function func, struct mfb_window *window); 60 | friend void mfb_set_char_input_callback (std::function func, struct mfb_window *window); 61 | friend void mfb_set_mouse_button_callback(std::function func, struct mfb_window *window); 62 | friend void mfb_set_mouse_move_callback (std::function func, struct mfb_window *window); 63 | friend void mfb_set_mouse_scroll_callback(std::function func, struct mfb_window *window); 64 | 65 | template 66 | friend void mfb_set_active_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, bool)); 67 | template 68 | friend void mfb_set_resize_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, int, int)); 69 | template 70 | friend void mfb_set_close_callback(struct mfb_window *window, T *obj, bool (T::*method)(struct mfb_window *)); 71 | template 72 | friend void mfb_set_mouse_button_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_mouse_button, mfb_key_mod, bool)); 73 | template 74 | friend void mfb_set_keyboard_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_key, mfb_key_mod, bool)); 75 | template 76 | friend void mfb_set_char_input_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, unsigned int)); 77 | template 78 | friend void mfb_set_mouse_button_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_mouse_button, mfb_key_mod, bool)); 79 | template 80 | friend void mfb_set_mouse_move_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, int, int)); 81 | template 82 | friend void mfb_set_mouse_scroll_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_key_mod, float, float)); 83 | 84 | static mfb_stub *GetInstance(struct mfb_window *window); 85 | 86 | static void active_stub(struct mfb_window *window, bool isActive); 87 | static void resize_stub(struct mfb_window *window, int width, int height); 88 | static bool close_stub(struct mfb_window *window); 89 | static void keyboard_stub(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed); 90 | static void char_input_stub(struct mfb_window *window, unsigned int); 91 | static void mouse_btn_stub(struct mfb_window *window, mfb_mouse_button button, mfb_key_mod mod, bool isPressed); 92 | static void mouse_move_stub(struct mfb_window *window, int x, int y); 93 | static void scroll_stub(struct mfb_window *window, mfb_key_mod mod, float deltaX, float deltaY); 94 | 95 | struct mfb_window *m_window; 96 | std::function m_active; 97 | std::function m_resize; 98 | std::function m_close; 99 | std::function m_keyboard; 100 | std::function m_char_input; 101 | std::function m_mouse_btn; 102 | std::function m_mouse_move; 103 | std::function m_scroll; 104 | }; 105 | 106 | //------------------------------------- 107 | template 108 | inline void mfb_set_active_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, bool)) { 109 | using namespace std::placeholders; 110 | 111 | mfb_stub *stub = mfb_stub::GetInstance(window); 112 | stub->m_active = std::bind(method, obj, _1, _2); 113 | mfb_set_active_callback(window, mfb_stub::active_stub); 114 | } 115 | 116 | //------------------------------------- 117 | template 118 | inline void mfb_set_resize_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, int, int)) { 119 | using namespace std::placeholders; 120 | 121 | mfb_stub *stub = mfb_stub::GetInstance(window); 122 | stub->m_resize = std::bind(method, obj, _1, _2, _3); 123 | mfb_set_resize_callback(window, mfb_stub::resize_stub); 124 | } 125 | 126 | //------------------------------------- 127 | template 128 | inline void mfb_set_close_callback(struct mfb_window *window, T *obj, bool (T::*method)(struct mfb_window *window)) { 129 | using namespace std::placeholders; 130 | 131 | mfb_stub *stub = mfb_stub::GetInstance(window); 132 | stub->m_close = std::bind(method, obj, _1); 133 | mfb_set_close_callback(window, mfb_stub::close_stub); 134 | } 135 | 136 | //------------------------------------- 137 | template 138 | inline void mfb_set_keyboard_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, mfb_key, mfb_key_mod, bool)) { 139 | using namespace std::placeholders; 140 | 141 | mfb_stub *stub = mfb_stub::GetInstance(window); 142 | stub->m_keyboard = std::bind(method, obj, _1, _2, _3, _4); 143 | mfb_set_keyboard_callback(window, mfb_stub::keyboard_stub); 144 | } 145 | 146 | //------------------------------------- 147 | template 148 | inline void mfb_set_char_input_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, unsigned int)) { 149 | using namespace std::placeholders; 150 | 151 | mfb_stub *stub = mfb_stub::GetInstance(window); 152 | stub->m_char_input = std::bind(method, obj, _1, _2); 153 | mfb_set_char_input_callback(window, mfb_stub::char_input_stub); 154 | } 155 | 156 | //------------------------------------- 157 | template 158 | inline void mfb_set_mouse_button_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, mfb_mouse_button, mfb_key_mod, bool)) { 159 | using namespace std::placeholders; 160 | 161 | mfb_stub *stub = mfb_stub::GetInstance(window); 162 | stub->m_mouse_btn = std::bind(method, obj, _1, _2, _3, _4); 163 | mfb_set_mouse_button_callback(window, mfb_stub::mouse_btn_stub); 164 | } 165 | 166 | //------------------------------------- 167 | template 168 | inline void mfb_set_mouse_move_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, int, int)) { 169 | using namespace std::placeholders; 170 | 171 | mfb_stub *stub = mfb_stub::GetInstance(window); 172 | stub->m_mouse_move = std::bind(method, obj, _1, _2, _3); 173 | mfb_set_mouse_move_callback(window, mfb_stub::mouse_move_stub); 174 | } 175 | 176 | //------------------------------------- 177 | template 178 | inline void mfb_set_mouse_scroll_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, mfb_key_mod, float, float)) { 179 | using namespace std::placeholders; 180 | 181 | mfb_stub *stub = mfb_stub::GetInstance(window); 182 | stub->m_scroll = std::bind(method, obj, _1, _2, _3, _4); 183 | mfb_set_mouse_scroll_callback(window, mfb_stub::scroll_stub); 184 | } 185 | 186 | #endif 187 | -------------------------------------------------------------------------------- /src/MiniFB_common.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "WindowData.h" 3 | #include "MiniFB_internal.h" 4 | 5 | //------------------------------------- 6 | short int g_keycodes[512] = {0}; 7 | //------------------------------------- 8 | 9 | //------------------------------------- 10 | struct mfb_window * 11 | mfb_open(const char *title, unsigned width, unsigned height) 12 | { 13 | return mfb_open_ex(title, width, height, 0); 14 | } 15 | 16 | //------------------------------------- 17 | mfb_update_state 18 | mfb_update(struct mfb_window *window, void *buffer) 19 | { 20 | if (window == 0x0) 21 | { 22 | return STATE_INVALID_WINDOW; 23 | } 24 | 25 | SWindowData *window_data = (SWindowData *)window; 26 | 27 | return mfb_update_ex(window, buffer, window_data->buffer_width, window_data->buffer_height); 28 | } 29 | 30 | //------------------------------------- 31 | void mfb_set_active_callback(struct mfb_window *window, mfb_active_func callback) 32 | { 33 | if (window != 0x0) 34 | { 35 | SWindowData *window_data = (SWindowData *)window; 36 | window_data->active_func = callback; 37 | } 38 | } 39 | 40 | //------------------------------------- 41 | void mfb_set_resize_callback(struct mfb_window *window, mfb_resize_func callback) 42 | { 43 | if (window != 0x0) 44 | { 45 | SWindowData *window_data = (SWindowData *)window; 46 | window_data->resize_func = callback; 47 | } 48 | } 49 | 50 | //------------------------------------- 51 | void mfb_set_close_callback(struct mfb_window *window, mfb_close_func callback) 52 | { 53 | if (window != 0x0) 54 | { 55 | SWindowData *window_data = (SWindowData *)window; 56 | window_data->close_func = callback; 57 | } 58 | } 59 | 60 | //------------------------------------- 61 | void mfb_set_keyboard_callback(struct mfb_window *window, mfb_keyboard_func callback) 62 | { 63 | if (window != 0x0) 64 | { 65 | SWindowData *window_data = (SWindowData *)window; 66 | window_data->keyboard_func = callback; 67 | } 68 | } 69 | 70 | //------------------------------------- 71 | void mfb_set_char_input_callback(struct mfb_window *window, mfb_char_input_func callback) 72 | { 73 | if (window != 0x0) 74 | { 75 | SWindowData *window_data = (SWindowData *)window; 76 | window_data->char_input_func = callback; 77 | } 78 | } 79 | 80 | //------------------------------------- 81 | void mfb_set_mouse_button_callback(struct mfb_window *window, mfb_mouse_button_func callback) 82 | { 83 | if (window != 0x0) 84 | { 85 | SWindowData *window_data = (SWindowData *)window; 86 | window_data->mouse_btn_func = callback; 87 | } 88 | } 89 | 90 | //------------------------------------- 91 | void mfb_set_mouse_move_callback(struct mfb_window *window, mfb_mouse_move_func callback) 92 | { 93 | if (window != 0x0) 94 | { 95 | SWindowData *window_data = (SWindowData *)window; 96 | window_data->mouse_move_func = callback; 97 | } 98 | } 99 | 100 | //------------------------------------- 101 | void mfb_set_mouse_scroll_callback(struct mfb_window *window, mfb_mouse_scroll_func callback) 102 | { 103 | if (window != 0x0) 104 | { 105 | SWindowData *window_data = (SWindowData *)window; 106 | window_data->mouse_wheel_func = callback; 107 | } 108 | } 109 | 110 | //------------------------------------- 111 | void mfb_set_user_data(struct mfb_window *window, void *user_data) 112 | { 113 | if (window != 0x0) 114 | { 115 | SWindowData *window_data = (SWindowData *)window; 116 | window_data->user_data = user_data; 117 | } 118 | } 119 | 120 | //------------------------------------- 121 | void * 122 | mfb_get_user_data(struct mfb_window *window) 123 | { 124 | if (window != 0x0) 125 | { 126 | SWindowData *window_data = (SWindowData *)window; 127 | return window_data->user_data; 128 | } 129 | 130 | return 0x0; 131 | } 132 | 133 | // [Deprecated] 134 | //------------------------------------- 135 | void mfb_get_monitor_dpi(struct mfb_window *window, float *dpi_x, float *dpi_y) 136 | { 137 | mfb_get_monitor_scale(window, dpi_x, dpi_y); 138 | } 139 | 140 | //------------------------------------- 141 | void mfb_close(struct mfb_window *window) 142 | { 143 | if (window != 0x0) 144 | { 145 | SWindowData *window_data = (SWindowData *)window; 146 | window_data->close = true; 147 | } 148 | } 149 | 150 | //------------------------------------- 151 | void keyboard_default(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed) 152 | { 153 | kUnused(mod); 154 | kUnused(isPressed); 155 | if (key == KB_KEY_ESCAPE) 156 | { 157 | SWindowData *window_data = (SWindowData *)window; 158 | if (!window_data->close_func || window_data->close_func((struct mfb_window *)window_data)) 159 | { 160 | window_data->close = true; 161 | } 162 | } 163 | } 164 | 165 | //------------------------------------- 166 | bool mfb_set_viewport_best_fit(struct mfb_window *window, unsigned old_width, unsigned old_height) 167 | { 168 | if (window != 0x0) 169 | { 170 | SWindowData *window_data = (SWindowData *)window; 171 | 172 | unsigned new_width = window_data->window_width; 173 | unsigned new_height = window_data->window_height; 174 | 175 | float scale_x = new_width / (float)old_width; 176 | float scale_y = new_height / (float)old_height; 177 | if (scale_x >= scale_y) 178 | scale_x = scale_y; 179 | else 180 | scale_y = scale_x; 181 | 182 | unsigned finalWidth = (old_width * scale_x) + 0.5f; 183 | unsigned finalHeight = (old_height * scale_y) + 0.5f; 184 | 185 | unsigned offset_x = (new_width - finalWidth) >> 1; 186 | unsigned offset_y = (new_height - finalHeight) >> 1; 187 | 188 | mfb_get_monitor_scale(window, &scale_x, &scale_y); 189 | return mfb_set_viewport(window, offset_x / scale_x, offset_y / scale_y, finalWidth / scale_x, finalHeight / scale_y); 190 | } 191 | 192 | return false; 193 | } 194 | 195 | //------------------------------------- 196 | bool mfb_is_window_active(struct mfb_window *window) 197 | { 198 | if (window != 0x0) 199 | { 200 | SWindowData *window_data = (SWindowData *)window; 201 | return window_data->is_active; 202 | } 203 | return false; 204 | } 205 | 206 | //------------------------------------- 207 | unsigned 208 | mfb_get_window_width(struct mfb_window *window) 209 | { 210 | if (window != 0x0) 211 | { 212 | SWindowData *window_data = (SWindowData *)window; 213 | return window_data->window_width; 214 | } 215 | return 0; 216 | } 217 | 218 | //------------------------------------- 219 | unsigned 220 | mfb_get_window_height(struct mfb_window *window) 221 | { 222 | if (window != 0x0) 223 | { 224 | SWindowData *window_data = (SWindowData *)window; 225 | return window_data->window_height; 226 | } 227 | return 0; 228 | } 229 | 230 | //------------------------------------- 231 | int mfb_get_mouse_x(struct mfb_window *window) 232 | { 233 | if (window != 0x0) 234 | { 235 | SWindowData *window_data = (SWindowData *)window; 236 | return window_data->mouse_pos_x; 237 | } 238 | return 0; 239 | } 240 | 241 | //------------------------------------- 242 | int mfb_get_mouse_y(struct mfb_window *window) 243 | { 244 | if (window != 0x0) 245 | { 246 | SWindowData *window_data = (SWindowData *)window; 247 | return window_data->mouse_pos_y; 248 | } 249 | return 0; 250 | } 251 | 252 | //------------------------------------- 253 | float mfb_get_mouse_scroll_x(struct mfb_window *window) 254 | { 255 | if (window != 0x0) 256 | { 257 | SWindowData *window_data = (SWindowData *)window; 258 | return window_data->mouse_wheel_x; 259 | } 260 | return 0; 261 | } 262 | 263 | //------------------------------------- 264 | float mfb_get_mouse_scroll_y(struct mfb_window *window) 265 | { 266 | if (window != 0x0) 267 | { 268 | SWindowData *window_data = (SWindowData *)window; 269 | return window_data->mouse_wheel_y; 270 | } 271 | return 0; 272 | } 273 | 274 | //------------------------------------- 275 | const uint8_t * 276 | mfb_get_mouse_button_buffer(struct mfb_window *window) 277 | { 278 | if (window != 0x0) 279 | { 280 | SWindowData *window_data = (SWindowData *)window; 281 | return window_data->mouse_button_status; 282 | } 283 | return 0; 284 | } 285 | 286 | //------------------------------------- 287 | const uint8_t * 288 | mfb_get_key_buffer(struct mfb_window *window) 289 | { 290 | if (window != 0x0) 291 | { 292 | SWindowData *window_data = (SWindowData *)window; 293 | return window_data->key_status; 294 | } 295 | return 0; 296 | } 297 | 298 | //------------------------------------- 299 | const char * 300 | mfb_get_key_name(mfb_key key) 301 | { 302 | 303 | switch (key) 304 | { 305 | case KB_KEY_SPACE: 306 | return "Space"; 307 | 308 | case KB_KEY_APOSTROPHE: 309 | return "Apostrophe"; 310 | 311 | case KB_KEY_COMMA: 312 | return "Comma"; 313 | 314 | case KB_KEY_MINUS: 315 | return "Minus"; 316 | 317 | case KB_KEY_PERIOD: 318 | return "Period"; 319 | 320 | case KB_KEY_SLASH: 321 | return "Slash"; 322 | 323 | case KB_KEY_0: 324 | return "0"; 325 | 326 | case KB_KEY_1: 327 | return "1"; 328 | 329 | case KB_KEY_2: 330 | return "2"; 331 | 332 | case KB_KEY_3: 333 | return "3"; 334 | 335 | case KB_KEY_4: 336 | return "4"; 337 | 338 | case KB_KEY_5: 339 | return "5"; 340 | 341 | case KB_KEY_6: 342 | return "6"; 343 | 344 | case KB_KEY_7: 345 | return "7"; 346 | 347 | case KB_KEY_8: 348 | return "8"; 349 | 350 | case KB_KEY_9: 351 | return "9"; 352 | 353 | case KB_KEY_SEMICOLON: 354 | return "Semicolon"; 355 | 356 | case KB_KEY_EQUAL: 357 | return "Equal"; 358 | 359 | case KB_KEY_A: 360 | return "A"; 361 | 362 | case KB_KEY_B: 363 | return "B"; 364 | 365 | case KB_KEY_C: 366 | return "C"; 367 | 368 | case KB_KEY_D: 369 | return "D"; 370 | 371 | case KB_KEY_E: 372 | return "E"; 373 | 374 | case KB_KEY_F: 375 | return "F"; 376 | 377 | case KB_KEY_G: 378 | return "G"; 379 | 380 | case KB_KEY_H: 381 | return "H"; 382 | 383 | case KB_KEY_I: 384 | return "I"; 385 | 386 | case KB_KEY_J: 387 | return "J"; 388 | 389 | case KB_KEY_K: 390 | return "K"; 391 | 392 | case KB_KEY_L: 393 | return "L"; 394 | 395 | case KB_KEY_M: 396 | return "M"; 397 | 398 | case KB_KEY_N: 399 | return "N"; 400 | 401 | case KB_KEY_O: 402 | return "O"; 403 | 404 | case KB_KEY_P: 405 | return "P"; 406 | 407 | case KB_KEY_Q: 408 | return "Q"; 409 | 410 | case KB_KEY_R: 411 | return "R"; 412 | 413 | case KB_KEY_S: 414 | return "S"; 415 | 416 | case KB_KEY_T: 417 | return "T"; 418 | 419 | case KB_KEY_U: 420 | return "U"; 421 | 422 | case KB_KEY_V: 423 | return "V"; 424 | 425 | case KB_KEY_W: 426 | return "W"; 427 | 428 | case KB_KEY_X: 429 | return "X"; 430 | 431 | case KB_KEY_Y: 432 | return "Y"; 433 | 434 | case KB_KEY_Z: 435 | return "Z"; 436 | 437 | case KB_KEY_LEFT_BRACKET: 438 | return "Left_Bracket"; 439 | 440 | case KB_KEY_BACKSLASH: 441 | return "Backslash"; 442 | 443 | case KB_KEY_RIGHT_BRACKET: 444 | return "Right_Bracket"; 445 | 446 | case KB_KEY_GRAVE_ACCENT: 447 | return "Grave_Accent"; 448 | 449 | case KB_KEY_WORLD_1: 450 | return "World_1"; 451 | 452 | case KB_KEY_WORLD_2: 453 | return "World_2"; 454 | 455 | case KB_KEY_ESCAPE: 456 | return "Escape"; 457 | 458 | case KB_KEY_ENTER: 459 | return "Enter"; 460 | 461 | case KB_KEY_TAB: 462 | return "Tab"; 463 | 464 | case KB_KEY_BACKSPACE: 465 | return "Backspace"; 466 | 467 | case KB_KEY_INSERT: 468 | return "Insert"; 469 | 470 | case KB_KEY_DELETE: 471 | return "Delete"; 472 | 473 | case KB_KEY_RIGHT: 474 | return "Right"; 475 | 476 | case KB_KEY_LEFT: 477 | return "Left"; 478 | 479 | case KB_KEY_DOWN: 480 | return "Down"; 481 | 482 | case KB_KEY_UP: 483 | return "Up"; 484 | 485 | case KB_KEY_PAGE_UP: 486 | return "Page_Up"; 487 | 488 | case KB_KEY_PAGE_DOWN: 489 | return "Page_Down"; 490 | 491 | case KB_KEY_HOME: 492 | return "Home"; 493 | 494 | case KB_KEY_END: 495 | return "End"; 496 | 497 | case KB_KEY_CAPS_LOCK: 498 | return "Caps_Lock"; 499 | 500 | case KB_KEY_SCROLL_LOCK: 501 | return "Scroll_Lock"; 502 | 503 | case KB_KEY_NUM_LOCK: 504 | return "Num_Lock"; 505 | 506 | case KB_KEY_PRINT_SCREEN: 507 | return "Print_Screen"; 508 | 509 | case KB_KEY_PAUSE: 510 | return "Pause"; 511 | 512 | case KB_KEY_F1: 513 | return "F1"; 514 | 515 | case KB_KEY_F2: 516 | return "F2"; 517 | 518 | case KB_KEY_F3: 519 | return "F3"; 520 | 521 | case KB_KEY_F4: 522 | return "F4"; 523 | 524 | case KB_KEY_F5: 525 | return "F5"; 526 | 527 | case KB_KEY_F6: 528 | return "F6"; 529 | 530 | case KB_KEY_F7: 531 | return "F7"; 532 | 533 | case KB_KEY_F8: 534 | return "F8"; 535 | 536 | case KB_KEY_F9: 537 | return "F9"; 538 | 539 | case KB_KEY_F10: 540 | return "F10"; 541 | 542 | case KB_KEY_F11: 543 | return "F11"; 544 | 545 | case KB_KEY_F12: 546 | return "F12"; 547 | 548 | case KB_KEY_F13: 549 | return "F13"; 550 | 551 | case KB_KEY_F14: 552 | return "F14"; 553 | 554 | case KB_KEY_F15: 555 | return "F15"; 556 | 557 | case KB_KEY_F16: 558 | return "F16"; 559 | 560 | case KB_KEY_F17: 561 | return "F17"; 562 | 563 | case KB_KEY_F18: 564 | return "F18"; 565 | 566 | case KB_KEY_F19: 567 | return "F19"; 568 | 569 | case KB_KEY_F20: 570 | return "F20"; 571 | 572 | case KB_KEY_F21: 573 | return "F21"; 574 | 575 | case KB_KEY_F22: 576 | return "F22"; 577 | 578 | case KB_KEY_F23: 579 | return "F23"; 580 | 581 | case KB_KEY_F24: 582 | return "F24"; 583 | 584 | case KB_KEY_F25: 585 | return "F25"; 586 | 587 | case KB_KEY_KP_0: 588 | return "KP_0"; 589 | 590 | case KB_KEY_KP_1: 591 | return "KP_1"; 592 | 593 | case KB_KEY_KP_2: 594 | return "KP_2"; 595 | 596 | case KB_KEY_KP_3: 597 | return "KP_3"; 598 | 599 | case KB_KEY_KP_4: 600 | return "KP_4"; 601 | 602 | case KB_KEY_KP_5: 603 | return "KP_5"; 604 | 605 | case KB_KEY_KP_6: 606 | return "KP_6"; 607 | 608 | case KB_KEY_KP_7: 609 | return "KP_7"; 610 | 611 | case KB_KEY_KP_8: 612 | return "KP_8"; 613 | 614 | case KB_KEY_KP_9: 615 | return "KP_9"; 616 | 617 | case KB_KEY_KP_DECIMAL: 618 | return "KP_Decimal"; 619 | 620 | case KB_KEY_KP_DIVIDE: 621 | return "KP_Divide"; 622 | 623 | case KB_KEY_KP_MULTIPLY: 624 | return "KP_Multiply"; 625 | 626 | case KB_KEY_KP_SUBTRACT: 627 | return "KP_Subtract"; 628 | 629 | case KB_KEY_KP_ADD: 630 | return "KP_Add"; 631 | 632 | case KB_KEY_KP_ENTER: 633 | return "KP_Enter"; 634 | 635 | case KB_KEY_KP_EQUAL: 636 | return "KP_Equal"; 637 | 638 | case KB_KEY_LEFT_SHIFT: 639 | return "Left_Shift"; 640 | 641 | case KB_KEY_LEFT_CONTROL: 642 | return "Left_Control"; 643 | 644 | case KB_KEY_LEFT_ALT: 645 | return "Left_Alt"; 646 | 647 | case KB_KEY_LEFT_SUPER: 648 | return "Left_Super"; 649 | 650 | case KB_KEY_RIGHT_SHIFT: 651 | return "Right_Shift"; 652 | 653 | case KB_KEY_RIGHT_CONTROL: 654 | return "Right_Control"; 655 | 656 | case KB_KEY_RIGHT_ALT: 657 | return "Right_Alt"; 658 | 659 | case KB_KEY_RIGHT_SUPER: 660 | return "Right_Super"; 661 | 662 | case KB_KEY_MENU: 663 | return "Menu"; 664 | 665 | case KB_KEY_UNKNOWN: 666 | return "Unknown"; 667 | } 668 | 669 | return "Unknown"; 670 | } 671 | -------------------------------------------------------------------------------- /src/windows/WinMiniFB.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "WindowData_Win.h" 5 | #if defined(USE_OPENGL_API) 6 | #include "gl/MiniFB_GL.h" 7 | #endif 8 | #include 9 | #include 10 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 11 | 12 | // Added by FC 13 | #define USER_DEFAULT_SCREEN_DPI 96 14 | #define WM_MOUSEHWHEEL 0x020E 15 | // #define USE_OPENGL_API false 16 | ///// 17 | 18 | // Copied (and modified) from Windows Kit 10 to avoid setting _WIN32_WINNT to a higher version 19 | typedef enum mfb_PROCESS_DPI_AWARENESS 20 | { 21 | mfb_PROCESS_DPI_UNAWARE = 0, 22 | mfb_PROCESS_SYSTEM_DPI_AWARE = 1, 23 | mfb_PROCESS_PER_MONITOR_DPI_AWARE = 2 24 | } mfb_PROCESS_DPI_AWARENESS; 25 | 26 | typedef enum mfb_MONITOR_DPI_TYPE 27 | { 28 | mfb_MDT_EFFECTIVE_DPI = 0, 29 | mfb_MDT_ANGULAR_DPI = 1, 30 | mfb_MDT_RAW_DPI = 2, 31 | mfb_MDT_DEFAULT = mfb_MDT_EFFECTIVE_DPI 32 | } mfb_MONITOR_DPI_TYPE; 33 | 34 | #define mfb_DPI_AWARENESS_CONTEXT_UNAWARE ((HANDLE) - 1) 35 | #define mfb_DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ((HANDLE) - 2) 36 | #define mfb_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ((HANDLE) - 3) 37 | #define mfb_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE) - 4) 38 | #define mfb_DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED ((HANDLE) - 5) 39 | 40 | // user32.dll 41 | typedef BOOL(WINAPI *PFN_SetProcessDPIAware)(void); 42 | typedef BOOL(WINAPI *PFN_SetProcessDpiAwarenessContext)(HANDLE); 43 | typedef UINT(WINAPI *PFN_GetDpiForWindow)(HWND); 44 | typedef BOOL(WINAPI *PFN_EnableNonClientDpiScaling)(HWND); 45 | 46 | HMODULE mfb_user32_dll = 0x0; 47 | PFN_SetProcessDPIAware mfb_SetProcessDPIAware = 0x0; 48 | PFN_SetProcessDpiAwarenessContext mfb_SetProcessDpiAwarenessContext = 0x0; 49 | PFN_GetDpiForWindow mfb_GetDpiForWindow = 0x0; 50 | PFN_EnableNonClientDpiScaling mfb_EnableNonClientDpiScaling = 0x0; 51 | 52 | // shcore.dll 53 | typedef HRESULT(WINAPI *PFN_SetProcessDpiAwareness)(mfb_PROCESS_DPI_AWARENESS); 54 | typedef HRESULT(WINAPI *PFN_GetDpiForMonitor)(HMONITOR, mfb_MONITOR_DPI_TYPE, UINT *, UINT *); 55 | 56 | HMODULE mfb_shcore_dll = 0x0; 57 | PFN_SetProcessDpiAwareness mfb_SetProcessDpiAwareness = 0x0; 58 | PFN_GetDpiForMonitor mfb_GetDpiForMonitor = 0x0; 59 | 60 | //-- 61 | void load_functions() 62 | { 63 | if (mfb_user32_dll == 0x0) 64 | { 65 | mfb_user32_dll = LoadLibraryA("user32.dll"); 66 | if (mfb_user32_dll != 0x0) 67 | { 68 | mfb_SetProcessDPIAware = (PFN_SetProcessDPIAware)GetProcAddress(mfb_user32_dll, "SetProcessDPIAware"); 69 | mfb_SetProcessDpiAwarenessContext = (PFN_SetProcessDpiAwarenessContext)GetProcAddress(mfb_user32_dll, "SetProcessDpiAwarenessContext"); 70 | mfb_GetDpiForWindow = (PFN_GetDpiForWindow)GetProcAddress(mfb_user32_dll, "GetDpiForWindow"); 71 | mfb_EnableNonClientDpiScaling = (PFN_EnableNonClientDpiScaling)GetProcAddress(mfb_user32_dll, "EnableNonClientDpiScaling"); 72 | } 73 | } 74 | 75 | if (mfb_shcore_dll == 0x0) 76 | { 77 | mfb_shcore_dll = LoadLibraryA("shcore.dll"); 78 | if (mfb_shcore_dll != 0x0) 79 | { 80 | mfb_SetProcessDpiAwareness = (PFN_SetProcessDpiAwareness)GetProcAddress(mfb_shcore_dll, "SetProcessDpiAwareness"); 81 | mfb_GetDpiForMonitor = (PFN_GetDpiForMonitor)GetProcAddress(mfb_shcore_dll, "GetDpiForMonitor"); 82 | } 83 | } 84 | } 85 | 86 | //-- 87 | // NOT Thread safe. Just convenient (Don't do this at home guys) 88 | char * 89 | GetErrorMessage() 90 | { 91 | static char buffer[256]; 92 | 93 | buffer[0] = 0; 94 | FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 95 | NULL, // Not used with FORMAT_MESSAGE_FROM_SYSTEM 96 | GetLastError(), 97 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 98 | buffer, 99 | sizeof(buffer), 100 | NULL); 101 | 102 | return buffer; 103 | } 104 | 105 | //-- 106 | void dpi_aware() 107 | { 108 | if (mfb_SetProcessDpiAwarenessContext != 0x0) 109 | { 110 | if (mfb_SetProcessDpiAwarenessContext(mfb_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) == false) 111 | { 112 | uint32_t error = GetLastError(); 113 | if (error == ERROR_INVALID_PARAMETER) 114 | { 115 | error = NO_ERROR; 116 | if (mfb_SetProcessDpiAwarenessContext(mfb_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE) == false) 117 | { 118 | error = GetLastError(); 119 | } 120 | } 121 | if (error != NO_ERROR) 122 | { 123 | fprintf(stderr, "Error (SetProcessDpiAwarenessContext): %s\n", GetErrorMessage()); 124 | } 125 | } 126 | } 127 | else if (mfb_SetProcessDpiAwareness != 0x0) 128 | { 129 | if (mfb_SetProcessDpiAwareness(mfb_PROCESS_PER_MONITOR_DPI_AWARE) != S_OK) 130 | { 131 | fprintf(stderr, "Error (SetProcessDpiAwareness): %s\n", GetErrorMessage()); 132 | } 133 | } 134 | else if (mfb_SetProcessDPIAware != 0x0) 135 | { 136 | if (mfb_SetProcessDPIAware() == false) 137 | { 138 | fprintf(stderr, "Error (SetProcessDPIAware): %s\n", GetErrorMessage()); 139 | } 140 | } 141 | } 142 | 143 | //-- 144 | void get_monitor_scale(HWND hWnd, float *scale_x, float *scale_y) 145 | { 146 | UINT x, y; 147 | 148 | if (mfb_GetDpiForMonitor != 0x0) 149 | { 150 | HMONITOR monitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST); 151 | mfb_GetDpiForMonitor(monitor, mfb_MDT_EFFECTIVE_DPI, &x, &y); 152 | } 153 | else 154 | { 155 | const HDC dc = GetDC(hWnd); 156 | x = GetDeviceCaps(dc, LOGPIXELSX); 157 | y = GetDeviceCaps(dc, LOGPIXELSY); 158 | ReleaseDC(NULL, dc); 159 | } 160 | 161 | if (scale_x) 162 | { 163 | *scale_x = x / (float)USER_DEFAULT_SCREEN_DPI; 164 | if (*scale_x == 0) 165 | { 166 | *scale_x = 1; 167 | } 168 | } 169 | 170 | if (scale_y) 171 | { 172 | *scale_y = y / (float)USER_DEFAULT_SCREEN_DPI; 173 | if (*scale_y == 0) 174 | { 175 | *scale_y = 1; 176 | } 177 | } 178 | } 179 | 180 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 181 | 182 | void mfb_get_monitor_scale(struct mfb_window *window, float *scale_x, float *scale_y) 183 | { 184 | HWND hWnd = 0x0; 185 | 186 | if (window != 0x0) 187 | { 188 | SWindowData *window_data = (SWindowData *)window; 189 | SWindowData_Win *window_data_win = (SWindowData_Win *)window_data->specific; 190 | hWnd = window_data_win->window; 191 | } 192 | get_monitor_scale(hWnd, scale_x, scale_y); 193 | } 194 | 195 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 196 | 197 | long s_window_style = WS_POPUP | WS_SYSMENU | WS_CAPTION; 198 | 199 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 200 | 201 | void init_keycodes(); 202 | 203 | uint32_t translate_mod(); 204 | mfb_key translate_key(unsigned int wParam, unsigned long lParam); 205 | void destroy_window_data(SWindowData *window_data); 206 | 207 | LRESULT CALLBACK 208 | WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 209 | { 210 | LRESULT res = 0; 211 | 212 | SWindowData *window_data = (SWindowData *)GetWindowLongPtr(hWnd, GWLP_USERDATA); 213 | SWindowData_Win *window_data_win = 0x0; 214 | if (window_data != 0x0) 215 | { 216 | window_data_win = (SWindowData_Win *)window_data->specific; 217 | } 218 | 219 | switch (message) 220 | { 221 | case WM_NCCREATE: 222 | { 223 | if (mfb_EnableNonClientDpiScaling) 224 | mfb_EnableNonClientDpiScaling(hWnd); 225 | 226 | return DefWindowProc(hWnd, message, wParam, lParam); 227 | } 228 | 229 | // TODO 230 | // case 0x02E4://WM_GETDPISCALEDSIZE: 231 | //{ 232 | // SIZE* size = (SIZE*) lParam; 233 | // WORD dpi = LOWORD(wParam); 234 | // return true; 235 | // break; 236 | //} 237 | 238 | // TODO 239 | // case WM_DPICHANGED: 240 | //{ 241 | // const float xscale = HIWORD(wParam); 242 | // const float yscale = LOWORD(wParam); 243 | // break; 244 | //} 245 | 246 | #if !defined(USE_OPENGL_API) 247 | case WM_PAINT: 248 | { 249 | if (window_data && window_data->draw_buffer && window_data_win) 250 | { 251 | 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, 252 | window_data_win->bitmapInfo, DIB_RGB_COLORS, SRCCOPY); 253 | } 254 | ValidateRect(hWnd, 0x0); 255 | break; 256 | } 257 | #endif 258 | case WM_CLOSE: 259 | { 260 | if (window_data) 261 | { 262 | bool destroy = false; 263 | 264 | // Obtain a confirmation of close 265 | if (!window_data->close_func || window_data->close_func((struct mfb_window *)window_data)) 266 | { 267 | destroy = true; 268 | } 269 | 270 | if (destroy) 271 | { 272 | window_data->close = true; 273 | if (window_data_win) 274 | { 275 | DestroyWindow(window_data_win->window); 276 | } 277 | } 278 | } 279 | break; 280 | } 281 | 282 | case WM_DESTROY: 283 | if (window_data) 284 | { 285 | window_data->close = true; 286 | } 287 | break; 288 | 289 | case WM_KEYDOWN: 290 | case WM_SYSKEYDOWN: 291 | case WM_KEYUP: 292 | case WM_SYSKEYUP: 293 | { 294 | if (window_data) 295 | { 296 | mfb_key key_code = translate_key((unsigned int)wParam, (unsigned long)lParam); 297 | int is_pressed = !((lParam >> 31) & 1); 298 | window_data->mod_keys = translate_mod(); 299 | 300 | if (key_code == KB_KEY_UNKNOWN) 301 | return FALSE; 302 | 303 | window_data->key_status[key_code] = (uint8_t)is_pressed; 304 | kCall(keyboard_func, key_code, window_data->mod_keys, is_pressed); 305 | } 306 | break; 307 | } 308 | 309 | case WM_CHAR: 310 | case WM_SYSCHAR: 311 | { 312 | static WCHAR highSurrogate = 0; 313 | if (window_data) 314 | { 315 | if (wParam >= 0xd800 && wParam <= 0xdbff) 316 | { 317 | highSurrogate = (WCHAR)wParam; 318 | } 319 | else 320 | { 321 | unsigned int codepoint = 0; 322 | if (wParam >= 0xdc00 && wParam <= 0xdfff) 323 | { 324 | if (highSurrogate != 0) 325 | { 326 | codepoint += (highSurrogate - 0xd800) << 10; 327 | codepoint += (WCHAR)wParam - 0xdc00; 328 | codepoint += 0x10000; 329 | } 330 | } 331 | else 332 | { 333 | codepoint = (WCHAR)wParam; 334 | } 335 | highSurrogate = 0; 336 | kCall(char_input_func, codepoint); 337 | } 338 | } 339 | } 340 | break; 341 | 342 | case WM_UNICHAR: 343 | { 344 | if (window_data) 345 | { 346 | if (wParam == UNICODE_NOCHAR) 347 | { 348 | // WM_UNICHAR is not sent by Windows, but is sent by some third-party input method engine 349 | // Returning TRUE here announces support for this message 350 | return TRUE; 351 | } 352 | 353 | kCall(char_input_func, (unsigned int)wParam); 354 | } 355 | break; 356 | } 357 | 358 | case WM_LBUTTONUP: 359 | case WM_RBUTTONUP: 360 | case WM_MBUTTONUP: 361 | case WM_XBUTTONUP: 362 | case WM_LBUTTONDOWN: 363 | case WM_LBUTTONDBLCLK: 364 | case WM_RBUTTONDOWN: 365 | case WM_RBUTTONDBLCLK: 366 | case WM_MBUTTONDOWN: 367 | case WM_MBUTTONDBLCLK: 368 | case WM_XBUTTONDOWN: 369 | case WM_XBUTTONDBLCLK: 370 | { 371 | if (window_data) 372 | { 373 | mfb_mouse_button button = MOUSE_BTN_0; 374 | window_data->mod_keys = translate_mod(); 375 | int is_pressed = 0; 376 | switch (message) 377 | { 378 | case WM_LBUTTONDOWN: 379 | is_pressed = 1; 380 | case WM_LBUTTONUP: 381 | button = MOUSE_BTN_1; 382 | break; 383 | case WM_RBUTTONDOWN: 384 | is_pressed = 1; 385 | case WM_RBUTTONUP: 386 | button = MOUSE_BTN_2; 387 | break; 388 | case WM_MBUTTONDOWN: 389 | is_pressed = 1; 390 | case WM_MBUTTONUP: 391 | button = MOUSE_BTN_3; 392 | break; 393 | 394 | default: 395 | button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? MOUSE_BTN_5 : MOUSE_BTN_6); 396 | if (message == WM_XBUTTONDOWN) 397 | { 398 | is_pressed = 1; 399 | } 400 | } 401 | window_data->mouse_button_status[button & 0x07] = is_pressed; 402 | kCall(mouse_btn_func, button, window_data->mod_keys, is_pressed); 403 | } 404 | break; 405 | } 406 | 407 | case WM_MOUSEWHEEL: 408 | if (window_data) 409 | { 410 | window_data->mouse_wheel_y = (SHORT)HIWORD(wParam) / (float)WHEEL_DELTA; 411 | kCall(mouse_wheel_func, translate_mod(), 0.0f, window_data->mouse_wheel_y); 412 | } 413 | break; 414 | 415 | case WM_MOUSEHWHEEL: 416 | // This message is only sent on Windows Vista and later 417 | // NOTE: The X-axis is inverted for consistency with macOS and X11 418 | if (window_data) 419 | { 420 | window_data->mouse_wheel_x = -((SHORT)HIWORD(wParam) / (float)WHEEL_DELTA); 421 | kCall(mouse_wheel_func, translate_mod(), window_data->mouse_wheel_x, 0.0f); 422 | } 423 | break; 424 | 425 | case WM_MOUSEMOVE: 426 | if (window_data) 427 | { 428 | if (window_data_win->mouse_inside == false) 429 | { 430 | window_data_win->mouse_inside = true; 431 | TRACKMOUSEEVENT tme; 432 | ZeroMemory(&tme, sizeof(tme)); 433 | tme.cbSize = sizeof(tme); 434 | tme.dwFlags = TME_LEAVE; 435 | tme.hwndTrack = hWnd; 436 | TrackMouseEvent(&tme); 437 | } 438 | window_data->mouse_pos_x = (int)(short)LOWORD(lParam); 439 | window_data->mouse_pos_y = (int)(short)HIWORD(lParam); 440 | kCall(mouse_move_func, window_data->mouse_pos_x, window_data->mouse_pos_y); 441 | } 442 | break; 443 | 444 | case WM_MOUSELEAVE: 445 | if (window_data) 446 | { 447 | window_data_win->mouse_inside = false; 448 | } 449 | break; 450 | 451 | case WM_SIZE: 452 | if (window_data) 453 | { 454 | float scale_x, scale_y; 455 | uint32_t width, height; 456 | 457 | if (wParam == SIZE_MINIMIZED) 458 | { 459 | return res; 460 | } 461 | 462 | get_monitor_scale(hWnd, &scale_x, &scale_y); 463 | window_data->window_width = LOWORD(lParam); 464 | window_data->window_height = HIWORD(lParam); 465 | resize_dst(window_data, window_data->window_width, window_data->window_height); 466 | 467 | #if !defined(USE_OPENGL_API) 468 | BitBlt(window_data_win->hdc, 0, 0, window_data->window_width, window_data->window_height, 0, 0, 0, BLACKNESS); 469 | #else 470 | resize_GL(window_data); 471 | #endif 472 | if (window_data->window_width != 0 && window_data->window_height != 0) 473 | { 474 | width = (uint32_t)(window_data->window_width / scale_x); 475 | height = (uint32_t)(window_data->window_height / scale_y); 476 | kCall(resize_func, width, height); 477 | } 478 | } 479 | break; 480 | 481 | case WM_SETFOCUS: 482 | if (window_data) 483 | { 484 | window_data->is_active = true; 485 | kCall(active_func, true); 486 | } 487 | break; 488 | 489 | case WM_KILLFOCUS: 490 | if (window_data) 491 | { 492 | window_data->is_active = false; 493 | kCall(active_func, false); 494 | } 495 | break; 496 | 497 | default: 498 | { 499 | res = DefWindowProc(hWnd, message, wParam, lParam); 500 | } 501 | } 502 | 503 | return res; 504 | } 505 | 506 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 507 | 508 | struct mfb_window * 509 | mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) 510 | { 511 | RECT rect = {0}; 512 | int x = 0, y = 0; 513 | 514 | load_functions(); 515 | dpi_aware(); 516 | init_keycodes(); 517 | 518 | SWindowData *window_data = malloc(sizeof(SWindowData)); 519 | if (window_data == 0x0) 520 | { 521 | return 0x0; 522 | } 523 | memset(window_data, 0, sizeof(SWindowData)); 524 | 525 | SWindowData_Win *window_data_win = malloc(sizeof(SWindowData_Win)); 526 | if (window_data_win == 0x0) 527 | { 528 | free(window_data); 529 | return 0x0; 530 | } 531 | memset(window_data_win, 0, sizeof(SWindowData_Win)); 532 | window_data->specific = window_data_win; 533 | 534 | window_data->buffer_width = width; 535 | window_data->buffer_height = height; 536 | window_data->buffer_stride = width * 4; 537 | 538 | s_window_style = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME; 539 | if (flags & WF_FULLSCREEN) 540 | { 541 | flags = WF_FULLSCREEN; // Remove all other flags 542 | rect.right = GetSystemMetrics(SM_CXSCREEN); 543 | rect.bottom = GetSystemMetrics(SM_CYSCREEN); 544 | s_window_style = WS_POPUP & ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU); 545 | 546 | DEVMODE settings = {0}; 547 | EnumDisplaySettings(0, 0, &settings); 548 | settings.dmPelsWidth = GetSystemMetrics(SM_CXSCREEN); 549 | settings.dmPelsHeight = GetSystemMetrics(SM_CYSCREEN); 550 | settings.dmBitsPerPel = 32; 551 | settings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; 552 | 553 | if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) 554 | { 555 | flags = WF_FULLSCREEN_DESKTOP; 556 | } 557 | } 558 | 559 | if (flags & WF_BORDERLESS) 560 | { 561 | s_window_style = WS_POPUP; 562 | } 563 | 564 | if (flags & WF_RESIZABLE) 565 | { 566 | s_window_style |= WS_MAXIMIZEBOX | WS_SIZEBOX; 567 | } 568 | 569 | if (flags & WF_FULLSCREEN_DESKTOP) 570 | { 571 | s_window_style = WS_OVERLAPPEDWINDOW; 572 | 573 | width = GetSystemMetrics(SM_CXFULLSCREEN); 574 | height = GetSystemMetrics(SM_CYFULLSCREEN); 575 | 576 | rect.right = width; 577 | rect.bottom = height; 578 | AdjustWindowRect(&rect, s_window_style, 0); 579 | if (rect.left < 0) 580 | { 581 | width += rect.left * 2; 582 | rect.right += rect.left; 583 | rect.left = 0; 584 | } 585 | if (rect.bottom > (LONG)height) 586 | { 587 | height -= (rect.bottom - height); 588 | rect.bottom += (rect.bottom - height); 589 | rect.top = 0; 590 | } 591 | } 592 | else if (!(flags & WF_FULLSCREEN)) 593 | { 594 | float scale_x, scale_y; 595 | 596 | get_monitor_scale(0, &scale_x, &scale_y); 597 | 598 | rect.right = (LONG)(width * scale_x); 599 | rect.bottom = (LONG)(height * scale_y); 600 | 601 | AdjustWindowRect(&rect, s_window_style, 0); 602 | 603 | rect.right -= rect.left; 604 | rect.bottom -= rect.top; 605 | 606 | x = (GetSystemMetrics(SM_CXSCREEN) - rect.right) / 2; 607 | y = (GetSystemMetrics(SM_CYSCREEN) - rect.bottom + rect.top) / 2; 608 | } 609 | 610 | window_data_win->wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW; 611 | window_data_win->wc.lpfnWndProc = WndProc; 612 | window_data_win->wc.hCursor = LoadCursor(0, IDC_ARROW); 613 | window_data_win->wc.lpszClassName = title; 614 | RegisterClass(&window_data_win->wc); 615 | 616 | calc_dst_factor(window_data, width, height); 617 | 618 | window_data->window_width = rect.right; 619 | window_data->window_height = rect.bottom; 620 | 621 | window_data_win->window = CreateWindowEx( 622 | 0, 623 | title, title, 624 | s_window_style, 625 | x, y, 626 | window_data->window_width, window_data->window_height, 627 | 0, 0, 0, 0); 628 | 629 | if (!window_data_win->window) 630 | { 631 | free(window_data); 632 | free(window_data_win); 633 | return 0x0; 634 | } 635 | 636 | SetWindowLongPtr(window_data_win->window, GWLP_USERDATA, (LONG_PTR)window_data); 637 | 638 | if (flags & WF_ALWAYS_ON_TOP) 639 | SetWindowPos(window_data_win->window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); 640 | 641 | ShowWindow(window_data_win->window, SW_NORMAL); 642 | 643 | window_data_win->hdc = GetDC(window_data_win->window); 644 | 645 | #if !defined(USE_OPENGL_API) 646 | 647 | window_data_win->bitmapInfo = (BITMAPINFO *)calloc(1, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 3); 648 | if (window_data_win->bitmapInfo == 0x0) 649 | { 650 | free(window_data); 651 | free(window_data_win); 652 | return 0x0; 653 | } 654 | 655 | window_data_win->bitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 656 | window_data_win->bitmapInfo->bmiHeader.biPlanes = 1; 657 | window_data_win->bitmapInfo->bmiHeader.biBitCount = 32; 658 | window_data_win->bitmapInfo->bmiHeader.biCompression = BI_BITFIELDS; 659 | window_data_win->bitmapInfo->bmiHeader.biWidth = window_data->buffer_width; 660 | window_data_win->bitmapInfo->bmiHeader.biHeight = -(LONG)window_data->buffer_height; 661 | window_data_win->bitmapInfo->bmiColors[0].rgbRed = 0xff; 662 | window_data_win->bitmapInfo->bmiColors[1].rgbGreen = 0xff; 663 | window_data_win->bitmapInfo->bmiColors[2].rgbBlue = 0xff; 664 | 665 | #else 666 | 667 | create_GL_context(window_data); 668 | 669 | #endif 670 | 671 | window_data_win->timer = mfb_timer_create(); 672 | 673 | mfb_set_keyboard_callback((struct mfb_window *)window_data, keyboard_default); 674 | 675 | #if defined(_DEBUG) || defined(DEBUG) 676 | #if defined(USE_OPENGL_API) 677 | printf("Window created using OpenGL API\n"); 678 | #else 679 | printf("Window created using GDI API\n"); 680 | #endif 681 | #endif 682 | 683 | window_data->is_initialized = true; 684 | return (struct mfb_window *)window_data; 685 | } 686 | 687 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 688 | 689 | mfb_update_state 690 | mfb_update_ex(struct mfb_window *window, void *buffer, unsigned width, unsigned height) 691 | { 692 | MSG msg; 693 | 694 | if (window == 0x0) 695 | { 696 | return STATE_INVALID_WINDOW; 697 | } 698 | 699 | SWindowData *window_data = (SWindowData *)window; 700 | if (window_data->close) 701 | { 702 | destroy_window_data(window_data); 703 | return STATE_EXIT; 704 | } 705 | 706 | if (buffer == 0x0) 707 | { 708 | return STATE_INVALID_BUFFER; 709 | } 710 | 711 | window_data->draw_buffer = buffer; 712 | window_data->buffer_width = width; 713 | window_data->buffer_stride = width * 4; 714 | window_data->buffer_height = height; 715 | 716 | SWindowData_Win *window_data_win = (SWindowData_Win *)window_data->specific; 717 | 718 | #if !defined(USE_OPENGL_API) 719 | 720 | window_data_win->bitmapInfo->bmiHeader.biWidth = window_data->buffer_width; 721 | window_data_win->bitmapInfo->bmiHeader.biHeight = -(LONG)window_data->buffer_height; 722 | InvalidateRect(window_data_win->window, 0x0, TRUE); 723 | SendMessage(window_data_win->window, WM_PAINT, 0, 0); 724 | 725 | #else 726 | 727 | redraw_GL(window_data, buffer); 728 | 729 | #endif 730 | 731 | while (window_data->close == false && PeekMessage(&msg, window_data_win->window, 0, 0, PM_REMOVE)) 732 | { 733 | TranslateMessage(&msg); 734 | DispatchMessage(&msg); 735 | } 736 | 737 | return STATE_OK; 738 | } 739 | 740 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 741 | 742 | mfb_update_state 743 | mfb_update_events(struct mfb_window *window) 744 | { 745 | MSG msg; 746 | 747 | if (window == 0x0) 748 | { 749 | return STATE_INVALID_WINDOW; 750 | } 751 | 752 | SWindowData *window_data = (SWindowData *)window; 753 | if (window_data->close) 754 | { 755 | destroy_window_data(window_data); 756 | return STATE_EXIT; 757 | } 758 | 759 | SWindowData_Win *window_data_win = (SWindowData_Win *)window_data->specific; 760 | while (window_data->close == false && PeekMessage(&msg, window_data_win->window, 0, 0, PM_REMOVE)) 761 | { 762 | // if(msg.message == WM_PAINT) 763 | // return STATE_OK; 764 | TranslateMessage(&msg); 765 | DispatchMessage(&msg); 766 | } 767 | 768 | return STATE_OK; 769 | } 770 | 771 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 772 | 773 | extern double g_time_for_frame; 774 | extern bool g_use_hardware_sync; 775 | 776 | bool mfb_wait_sync(struct mfb_window *window) 777 | { 778 | if (window == 0x0) 779 | { 780 | return false; 781 | } 782 | 783 | SWindowData *window_data = (SWindowData *)window; 784 | if (window_data->close) 785 | { 786 | destroy_window_data(window_data); 787 | return false; 788 | } 789 | 790 | if (g_use_hardware_sync) 791 | { 792 | return true; 793 | } 794 | 795 | MSG msg; 796 | SWindowData_Win *window_data_win = (SWindowData_Win *)window_data->specific; 797 | double current; 798 | 799 | while (1) 800 | { 801 | current = mfb_timer_now(window_data_win->timer); 802 | if (current >= g_time_for_frame) 803 | { 804 | mfb_timer_reset(window_data_win->timer); 805 | return true; 806 | } 807 | else if (g_time_for_frame - current > 2.0 / 1000.0) 808 | { 809 | timeBeginPeriod(1); 810 | Sleep(1); 811 | timeEndPeriod(1); 812 | 813 | if (PeekMessage(&msg, window_data_win->window, 0, 0, PM_REMOVE)) 814 | { 815 | TranslateMessage(&msg); 816 | DispatchMessage(&msg); 817 | 818 | if (window_data->close) 819 | { 820 | destroy_window_data(window_data); 821 | return false; 822 | } 823 | } 824 | } 825 | } 826 | 827 | return true; 828 | } 829 | 830 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 831 | 832 | void destroy_window_data(SWindowData *window_data) 833 | { 834 | if (window_data == 0x0) 835 | return; 836 | 837 | SWindowData_Win *window_data_win = (SWindowData_Win *)window_data->specific; 838 | 839 | #if !defined(USE_OPENGL_API) 840 | if (window_data_win->bitmapInfo != 0x0) 841 | { 842 | free(window_data_win->bitmapInfo); 843 | window_data_win->bitmapInfo = 0x0; 844 | } 845 | #else 846 | destroy_GL_context(window_data); 847 | #endif 848 | 849 | if (window_data_win->window != 0 && window_data_win->hdc != 0) 850 | { 851 | ReleaseDC(window_data_win->window, window_data_win->hdc); 852 | DestroyWindow(window_data_win->window); 853 | } 854 | 855 | window_data_win->window = 0; 856 | window_data_win->hdc = 0; 857 | 858 | mfb_timer_destroy(window_data_win->timer); 859 | window_data_win->timer = 0x0; 860 | 861 | window_data->draw_buffer = 0x0; 862 | window_data->close = true; 863 | } 864 | 865 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 866 | 867 | uint32_t 868 | translate_mod() 869 | { 870 | uint32_t mods = 0; 871 | 872 | if (GetKeyState(VK_SHIFT) & 0x8000) 873 | mods |= KB_MOD_SHIFT; 874 | if (GetKeyState(VK_CONTROL) & 0x8000) 875 | mods |= KB_MOD_CONTROL; 876 | if (GetKeyState(VK_MENU) & 0x8000) 877 | mods |= KB_MOD_ALT; 878 | if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & 0x8000) 879 | mods |= KB_MOD_SUPER; 880 | if (GetKeyState(VK_CAPITAL) & 1) 881 | mods |= KB_MOD_CAPS_LOCK; 882 | if (GetKeyState(VK_NUMLOCK) & 1) 883 | mods |= KB_MOD_NUM_LOCK; 884 | 885 | return mods; 886 | } 887 | 888 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 889 | 890 | extern short int g_keycodes[512]; 891 | 892 | void init_keycodes() 893 | { 894 | if (g_keycodes[0x00B] != KB_KEY_0) 895 | { 896 | g_keycodes[0x00B] = KB_KEY_0; 897 | g_keycodes[0x002] = KB_KEY_1; 898 | g_keycodes[0x003] = KB_KEY_2; 899 | g_keycodes[0x004] = KB_KEY_3; 900 | g_keycodes[0x005] = KB_KEY_4; 901 | g_keycodes[0x006] = KB_KEY_5; 902 | g_keycodes[0x007] = KB_KEY_6; 903 | g_keycodes[0x008] = KB_KEY_7; 904 | g_keycodes[0x009] = KB_KEY_8; 905 | g_keycodes[0x00A] = KB_KEY_9; 906 | g_keycodes[0x01E] = KB_KEY_A; 907 | g_keycodes[0x030] = KB_KEY_B; 908 | g_keycodes[0x02E] = KB_KEY_C; 909 | g_keycodes[0x020] = KB_KEY_D; 910 | g_keycodes[0x012] = KB_KEY_E; 911 | g_keycodes[0x021] = KB_KEY_F; 912 | g_keycodes[0x022] = KB_KEY_G; 913 | g_keycodes[0x023] = KB_KEY_H; 914 | g_keycodes[0x017] = KB_KEY_I; 915 | g_keycodes[0x024] = KB_KEY_J; 916 | g_keycodes[0x025] = KB_KEY_K; 917 | g_keycodes[0x026] = KB_KEY_L; 918 | g_keycodes[0x032] = KB_KEY_M; 919 | g_keycodes[0x031] = KB_KEY_N; 920 | g_keycodes[0x018] = KB_KEY_O; 921 | g_keycodes[0x019] = KB_KEY_P; 922 | g_keycodes[0x010] = KB_KEY_Q; 923 | g_keycodes[0x013] = KB_KEY_R; 924 | g_keycodes[0x01F] = KB_KEY_S; 925 | g_keycodes[0x014] = KB_KEY_T; 926 | g_keycodes[0x016] = KB_KEY_U; 927 | g_keycodes[0x02F] = KB_KEY_V; 928 | g_keycodes[0x011] = KB_KEY_W; 929 | g_keycodes[0x02D] = KB_KEY_X; 930 | g_keycodes[0x015] = KB_KEY_Y; 931 | g_keycodes[0x02C] = KB_KEY_Z; 932 | 933 | g_keycodes[0x028] = KB_KEY_APOSTROPHE; 934 | g_keycodes[0x02B] = KB_KEY_BACKSLASH; 935 | g_keycodes[0x033] = KB_KEY_COMMA; 936 | g_keycodes[0x00D] = KB_KEY_EQUAL; 937 | g_keycodes[0x029] = KB_KEY_GRAVE_ACCENT; 938 | g_keycodes[0x01A] = KB_KEY_LEFT_BRACKET; 939 | g_keycodes[0x00C] = KB_KEY_MINUS; 940 | g_keycodes[0x034] = KB_KEY_PERIOD; 941 | g_keycodes[0x01B] = KB_KEY_RIGHT_BRACKET; 942 | g_keycodes[0x027] = KB_KEY_SEMICOLON; 943 | g_keycodes[0x035] = KB_KEY_SLASH; 944 | g_keycodes[0x056] = KB_KEY_WORLD_2; 945 | 946 | g_keycodes[0x00E] = KB_KEY_BACKSPACE; 947 | g_keycodes[0x153] = KB_KEY_DELETE; 948 | g_keycodes[0x14F] = KB_KEY_END; 949 | g_keycodes[0x01C] = KB_KEY_ENTER; 950 | g_keycodes[0x001] = KB_KEY_ESCAPE; 951 | g_keycodes[0x147] = KB_KEY_HOME; 952 | g_keycodes[0x152] = KB_KEY_INSERT; 953 | g_keycodes[0x15D] = KB_KEY_MENU; 954 | g_keycodes[0x151] = KB_KEY_PAGE_DOWN; 955 | g_keycodes[0x149] = KB_KEY_PAGE_UP; 956 | g_keycodes[0x045] = KB_KEY_PAUSE; 957 | g_keycodes[0x146] = KB_KEY_PAUSE; 958 | g_keycodes[0x039] = KB_KEY_SPACE; 959 | g_keycodes[0x00F] = KB_KEY_TAB; 960 | g_keycodes[0x03A] = KB_KEY_CAPS_LOCK; 961 | g_keycodes[0x145] = KB_KEY_NUM_LOCK; 962 | g_keycodes[0x046] = KB_KEY_SCROLL_LOCK; 963 | g_keycodes[0x03B] = KB_KEY_F1; 964 | g_keycodes[0x03C] = KB_KEY_F2; 965 | g_keycodes[0x03D] = KB_KEY_F3; 966 | g_keycodes[0x03E] = KB_KEY_F4; 967 | g_keycodes[0x03F] = KB_KEY_F5; 968 | g_keycodes[0x040] = KB_KEY_F6; 969 | g_keycodes[0x041] = KB_KEY_F7; 970 | g_keycodes[0x042] = KB_KEY_F8; 971 | g_keycodes[0x043] = KB_KEY_F9; 972 | g_keycodes[0x044] = KB_KEY_F10; 973 | g_keycodes[0x057] = KB_KEY_F11; 974 | g_keycodes[0x058] = KB_KEY_F12; 975 | g_keycodes[0x064] = KB_KEY_F13; 976 | g_keycodes[0x065] = KB_KEY_F14; 977 | g_keycodes[0x066] = KB_KEY_F15; 978 | g_keycodes[0x067] = KB_KEY_F16; 979 | g_keycodes[0x068] = KB_KEY_F17; 980 | g_keycodes[0x069] = KB_KEY_F18; 981 | g_keycodes[0x06A] = KB_KEY_F19; 982 | g_keycodes[0x06B] = KB_KEY_F20; 983 | g_keycodes[0x06C] = KB_KEY_F21; 984 | g_keycodes[0x06D] = KB_KEY_F22; 985 | g_keycodes[0x06E] = KB_KEY_F23; 986 | g_keycodes[0x076] = KB_KEY_F24; 987 | g_keycodes[0x038] = KB_KEY_LEFT_ALT; 988 | g_keycodes[0x01D] = KB_KEY_LEFT_CONTROL; 989 | g_keycodes[0x02A] = KB_KEY_LEFT_SHIFT; 990 | g_keycodes[0x15B] = KB_KEY_LEFT_SUPER; 991 | g_keycodes[0x137] = KB_KEY_PRINT_SCREEN; 992 | g_keycodes[0x138] = KB_KEY_RIGHT_ALT; 993 | g_keycodes[0x11D] = KB_KEY_RIGHT_CONTROL; 994 | g_keycodes[0x036] = KB_KEY_RIGHT_SHIFT; 995 | g_keycodes[0x15C] = KB_KEY_RIGHT_SUPER; 996 | g_keycodes[0x150] = KB_KEY_DOWN; 997 | g_keycodes[0x14B] = KB_KEY_LEFT; 998 | g_keycodes[0x14D] = KB_KEY_RIGHT; 999 | g_keycodes[0x148] = KB_KEY_UP; 1000 | 1001 | g_keycodes[0x052] = KB_KEY_KP_0; 1002 | g_keycodes[0x04F] = KB_KEY_KP_1; 1003 | g_keycodes[0x050] = KB_KEY_KP_2; 1004 | g_keycodes[0x051] = KB_KEY_KP_3; 1005 | g_keycodes[0x04B] = KB_KEY_KP_4; 1006 | g_keycodes[0x04C] = KB_KEY_KP_5; 1007 | g_keycodes[0x04D] = KB_KEY_KP_6; 1008 | g_keycodes[0x047] = KB_KEY_KP_7; 1009 | g_keycodes[0x048] = KB_KEY_KP_8; 1010 | g_keycodes[0x049] = KB_KEY_KP_9; 1011 | g_keycodes[0x04E] = KB_KEY_KP_ADD; 1012 | g_keycodes[0x053] = KB_KEY_KP_DECIMAL; 1013 | g_keycodes[0x135] = KB_KEY_KP_DIVIDE; 1014 | g_keycodes[0x11C] = KB_KEY_KP_ENTER; 1015 | g_keycodes[0x037] = KB_KEY_KP_MULTIPLY; 1016 | g_keycodes[0x04A] = KB_KEY_KP_SUBTRACT; 1017 | } 1018 | } 1019 | 1020 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1021 | 1022 | mfb_key 1023 | translate_key(unsigned int wParam, unsigned long lParam) 1024 | { 1025 | if (wParam == VK_CONTROL) 1026 | { 1027 | MSG next; 1028 | DWORD time; 1029 | 1030 | if (lParam & 0x01000000) 1031 | return KB_KEY_RIGHT_CONTROL; 1032 | 1033 | time = GetMessageTime(); 1034 | if (PeekMessageW(&next, 0x0, 0, 0, PM_NOREMOVE)) 1035 | if (next.message == WM_KEYDOWN || next.message == WM_SYSKEYDOWN || next.message == WM_KEYUP || next.message == WM_SYSKEYUP) 1036 | if (next.wParam == VK_MENU && (next.lParam & 0x01000000) && next.time == time) 1037 | return KB_KEY_UNKNOWN; 1038 | 1039 | return KB_KEY_LEFT_CONTROL; 1040 | } 1041 | 1042 | if (wParam == VK_PROCESSKEY) 1043 | return KB_KEY_UNKNOWN; 1044 | 1045 | return (mfb_key)g_keycodes[HIWORD(lParam) & 0x1FF]; 1046 | } 1047 | 1048 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1049 | 1050 | bool mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) 1051 | { 1052 | SWindowData *window_data = (SWindowData *)window; 1053 | SWindowData_Win *window_data_win = 0x0; 1054 | float scale_x, scale_y; 1055 | 1056 | if (window_data == 0x0) 1057 | { 1058 | return false; 1059 | } 1060 | 1061 | if (offset_x + width > window_data->window_width) 1062 | { 1063 | return false; 1064 | } 1065 | if (offset_y + height > window_data->window_height) 1066 | { 1067 | return false; 1068 | } 1069 | 1070 | window_data_win = (SWindowData_Win *)window_data->specific; 1071 | 1072 | get_monitor_scale(window_data_win->window, &scale_x, &scale_y); 1073 | window_data->dst_offset_x = (uint32_t)(offset_x * scale_x); 1074 | window_data->dst_offset_y = (uint32_t)(offset_y * scale_y); 1075 | 1076 | window_data->dst_width = (uint32_t)(width * scale_x); 1077 | window_data->dst_height = (uint32_t)(height * scale_y); 1078 | 1079 | calc_dst_factor(window_data, window_data->window_width, window_data->window_height); 1080 | 1081 | #if !defined(USE_OPENGL_API) 1082 | window_data_win = (SWindowData_Win *)window_data->specific; 1083 | BitBlt(window_data_win->hdc, 0, 0, window_data->window_width, window_data->window_height, 0, 0, 0, BLACKNESS); 1084 | #endif 1085 | 1086 | return true; 1087 | } 1088 | 1089 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1090 | 1091 | extern double g_timer_frequency; 1092 | extern double g_timer_resolution; 1093 | 1094 | uint64_t 1095 | mfb_timer_tick() 1096 | { 1097 | int64_t counter; 1098 | 1099 | QueryPerformanceCounter((LARGE_INTEGER *)&counter); 1100 | 1101 | return counter; 1102 | } 1103 | 1104 | void mfb_timer_init() 1105 | { 1106 | uint64_t frequency; 1107 | 1108 | QueryPerformanceFrequency((LARGE_INTEGER *)&frequency); 1109 | 1110 | g_timer_frequency = (double)((int64_t)frequency); 1111 | g_timer_resolution = 1.0 / g_timer_frequency; 1112 | } 1113 | --------------------------------------------------------------------------------