From d6a52459eff31bde1d66836dc6a5f20ec7b0c364 Mon Sep 17 00:00:00 2001 From: Darky-Lucera Date: Sun, 3 Mar 2019 23:34:38 +0100 Subject: [PATCH 01/14] added metal support for macosx version (based on rust_minifb) (#17) --- src/macosx/MacMiniFB.m | 201 +++++++++++++++++++++++++++++--- src/macosx/OSXWindow.h | 5 + src/macosx/OSXWindow.m | 2 + src/macosx/OSXWindowFrameView.h | 27 +++++ src/macosx/OSXWindowFrameView.m | 103 ++++++++++++++++ 5 files changed, 324 insertions(+), 14 deletions(-) diff --git a/src/macosx/MacMiniFB.m b/src/macosx/MacMiniFB.m index 076d2bc..4947d08 100644 --- a/src/macosx/MacMiniFB.m +++ b/src/macosx/MacMiniFB.m @@ -1,15 +1,121 @@ - #include "OSXWindow.h" +#include "OSXWindowFrameView.h" #include +#if defined(USE_METAL_API) +#include +#include +#endif #include #include "MiniFB.h" +#if defined(USE_METAL_API) +extern id g_metal_device; +extern id g_command_queue; +extern id g_library; +extern id g_pipeline_state; + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +NSString* g_shadersSrc = @ +" #include \n" + "using namespace metal;\n" + + "struct VertexOutput {\n" + "float4 pos [[position]];\n" + "float2 texcoord;\n" + "};\n" + + "vertex VertexOutput vertFunc(\n" + "unsigned int vID[[vertex_id]])\n" + "{\n" + "VertexOutput out;\n" + + "out.pos.x = (float)(vID / 2) * 4.0 - 1.0;\n" + "out.pos.y = (float)(vID % 2) * 4.0 - 1.0;\n" + "out.pos.z = 0.0;\n" + "out.pos.w = 1.0;\n" + + "out.texcoord.x = (float)(vID / 2) * 2.0;\n" + "out.texcoord.y = 1.0 - (float)(vID % 2) * 2.0;\n" + + "return out;\n" + "}\n" + + "fragment float4 fragFunc(VertexOutput input [[stage_in]],\n" + "texture2d colorTexture [[ texture(0) ]])\n" + "{\n" + "constexpr sampler textureSampler(mag_filter::nearest, min_filter::nearest);\n" + + // Sample the texture to obtain a color + "const half4 colorSample = colorTexture.sample(textureSampler, input.texcoord);\n" + + // We return the color of the texture + "return float4(colorSample);\n" + //"return half4(input.texcoord.x, input.texcoord.y, 0.0, 1.0);\n" + "}\n"; + +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if !defined(USE_METAL_API) void* g_updateBuffer = 0; int g_width = 0; int g_height = 0; -static OSXWindow* window_; +#endif +static OSXWindow *s_window; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if defined(USE_METAL_API) +static bool create_shaders() { + // Error + NSError* nsError = NULL; + NSError** nsErrorPtr = &nsError; + + id library = [g_metal_device newLibraryWithSource:g_shadersSrc + options:[[MTLCompileOptions alloc] init] + error:nsErrorPtr]; + + // Error update + if (nsError || !library) { + NSLog(@"Unable to create shaders %@", nsError); + return false; + } + + g_library = library; + NSLog(@"Names %@", [g_library functionNames]); + + id vertex_shader_func = [g_library newFunctionWithName:@"vertFunc"]; + id fragment_shader_func = [g_library newFunctionWithName:@"fragFunc"]; + + if (!vertex_shader_func) { + printf("Unable to get vertFunc!\n"); + return false; + } + + if (!fragment_shader_func) { + printf("Unable to get fragFunc!\n"); + return false; + } + + // Create a reusable pipeline state + MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; + pipelineStateDescriptor.label = @"MyPipeline"; + pipelineStateDescriptor.vertexFunction = vertex_shader_func; + pipelineStateDescriptor.fragmentFunction = fragment_shader_func; + pipelineStateDescriptor.colorAttachments[0].pixelFormat = 80; //bgra8Unorm; + + NSError *error = NULL; + g_pipeline_state = [g_metal_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error]; + if (!g_pipeline_state) + { + NSLog(@"Failed to created pipeline state, error %@", error); + } + + return true; +} +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -17,28 +123,91 @@ int mfb_open(const char* name, int width, int height) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; +#if !defined(USE_METAL_API) g_width = width; g_height = height; - +#endif [NSApplication sharedApplication]; [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; +#if defined(USE_METAL_API) + g_metal_device = MTLCreateSystemDefaultDevice(); + + if (!g_metal_device) { + printf("Your device/OS doesn't support Metal."); + return -1; + } + + if (!create_shaders()) { + return -2; + } +#endif + NSWindowStyleMask styles = NSWindowStyleMaskResizable | NSWindowStyleMaskClosable | NSWindowStyleMaskTitled; NSRect rectangle = NSMakeRect(0, 0, width, height); - window_ = [[OSXWindow alloc] initWithContentRect:rectangle styleMask:styles backing:NSBackingStoreBuffered defer:NO]; + s_window = [[OSXWindow alloc] initWithContentRect:rectangle styleMask:styles backing:NSBackingStoreBuffered defer:NO]; - if (!window_) - return 0; + if (!s_window) + return -3; - [window_ setTitle:[NSString stringWithUTF8String:name]]; - [window_ setReleasedWhenClosed:NO]; - [window_ performSelectorOnMainThread:@selector(makeKeyAndOrderFront:) withObject:nil waitUntilDone:YES]; +#if defined(USE_METAL_API) + s_window->draw_buffer = malloc(width * height * 4); - [window_ center]; + if (!s_window->draw_buffer) + return -4; + + // Setup command queue + g_command_queue = [g_metal_device newCommandQueue]; + + WindowViewController* viewController = [WindowViewController new]; + + MTLTextureDescriptor* textureDescriptor = [[MTLTextureDescriptor alloc] init]; + + // Indicate that each pixel has a blue, green, red, and alpha channel, where each channel is + // an 8-bit unsigned normalized value (i.e. 0 maps to 0.0 and 255 maps to 1.0) + textureDescriptor.pixelFormat = MTLPixelFormatBGRA8Unorm; + + // Set the pixel dimensions of the texture + textureDescriptor.width = width; + textureDescriptor.height = height; + + // Create the texture from the device by using the descriptor + + for (int i = 0; i < MaxBuffersInFlight; ++i) { + viewController->m_texture_buffers[i] = [g_metal_device newTextureWithDescriptor:textureDescriptor]; + } + + // Used for syncing the CPU and GPU + viewController->m_semaphore = dispatch_semaphore_create(MaxBuffersInFlight); + viewController->m_draw_buffer = s_window->draw_buffer; + viewController->m_width = width; + viewController->m_height = height; + + MTKView* view = [[MTKView alloc] initWithFrame:rectangle]; + view.device = g_metal_device; + view.delegate = viewController; + view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; + [s_window.contentView addSubview:view]; + + s_window->width = width; + s_window->height = height; + + //[s_window updateSize]; +#endif + + [s_window setTitle:[NSString stringWithUTF8String:name]]; + [s_window setReleasedWhenClosed:NO]; + [s_window performSelectorOnMainThread:@selector(makeKeyAndOrderFront:) withObject:nil waitUntilDone:YES]; + + [s_window center]; [NSApp activateIgnoringOtherApps:YES]; +#if defined(USE_METAL_API) + [NSApp finishLaunching]; +#endif + [pool drain]; return 1; @@ -50,8 +219,8 @@ void mfb_close() { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - if (window_) - [window_ close]; + if (s_window) + [s_window close]; [pool drain]; } @@ -83,7 +252,7 @@ static int updateEvents() } [pool release]; - if (window_->closed) + if (s_window->closed) state = -1; return state; @@ -93,8 +262,12 @@ static int updateEvents() int mfb_update(void* buffer) { +#if defined(USE_METAL_API) + memcpy(s_window->draw_buffer, buffer, s_window->width * s_window->height * 4); +#else g_updateBuffer = buffer; +#endif int state = updateEvents(); - [[window_ contentView] setNeedsDisplay:YES]; + [[s_window contentView] setNeedsDisplay:YES]; return state; } diff --git a/src/macosx/OSXWindow.h b/src/macosx/OSXWindow.h index 05eb51e..28bf33f 100644 --- a/src/macosx/OSXWindow.h +++ b/src/macosx/OSXWindow.h @@ -6,6 +6,11 @@ { NSView* childContentView; @public bool closed; +#if defined(USE_METAL_API) + @public int width; + @public int height; + @public void* draw_buffer; +#endif } @end diff --git a/src/macosx/OSXWindow.m b/src/macosx/OSXWindow.m index e1107d1..cd3d63c 100644 --- a/src/macosx/OSXWindow.m +++ b/src/macosx/OSXWindow.m @@ -5,6 +5,7 @@ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#if !defined(USE_METAL_API) - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)windowStyle backing:(NSBackingStoreType)bufferingType @@ -42,6 +43,7 @@ } return self; } +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/macosx/OSXWindowFrameView.h b/src/macosx/OSXWindowFrameView.h index 96408e9..92bb70f 100644 --- a/src/macosx/OSXWindowFrameView.h +++ b/src/macosx/OSXWindowFrameView.h @@ -1,7 +1,34 @@ #import +#if defined(USE_METAL_API) +#import + +// Number of textures in flight (tripple buffered) +static const int MaxBuffersInFlight = 3; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface WindowViewController : NSViewController +{ + @public id m_texture_buffers[MaxBuffersInFlight]; + @public int m_current_buffer; + @public void* m_draw_buffer; + @public int m_width; + @public int m_height; + // Used for syncing with CPU/GPU + @public dispatch_semaphore_t m_semaphore; +} + +@end +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + @interface OSXWindowFrameView : NSView { +#if defined(USE_METAL_API) + @private NSTrackingArea* trackingArea; +#endif } @end diff --git a/src/macosx/OSXWindowFrameView.m b/src/macosx/OSXWindowFrameView.m index 0961d41..2ff218e 100644 --- a/src/macosx/OSXWindowFrameView.m +++ b/src/macosx/OSXWindowFrameView.m @@ -1,7 +1,109 @@ #import "OSXWindowFrameView.h" +#if defined(USE_METAL_API) +#import + +id g_metal_device; +id g_command_queue; +id g_library; +id g_pipeline_state; + +@implementation WindowViewController + +-(void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size +{ + (void)view; + (void)size; + // resize +} + +-(void)drawInMTKView:(nonnull MTKView *)view +{ + // Wait to ensure only MaxBuffersInFlight number of frames are getting proccessed + // by any stage in the Metal pipeline (App, Metal, Drivers, GPU, etc) + dispatch_semaphore_wait(m_semaphore, DISPATCH_TIME_FOREVER); + + // Iterate through our Metal buffers, and cycle back to the first when we've written to MaxBuffersInFlight + m_current_buffer = (m_current_buffer + 1) % MaxBuffersInFlight; + + // Calculate the number of bytes per row of our image. + NSUInteger bytesPerRow = 4 * m_width; + MTLRegion region = { { 0, 0, 0 }, { m_width, m_height, 1 } }; + + // Copy the bytes from our data object into the texture + [m_texture_buffers[m_current_buffer] replaceRegion:region + mipmapLevel:0 withBytes:m_draw_buffer bytesPerRow:bytesPerRow]; + + // Create a new command buffer for each render pass to the current drawable + id commandBuffer = [g_command_queue commandBuffer]; + commandBuffer.label = @"minifb_command_buffer"; + + // Add completion hander which signals _inFlightSemaphore when Metal and the GPU has fully + // finished processing the commands we're encoding this frame. This indicates when the + // dynamic buffers filled with our vertices, that we're writing to this frame, will no longer + // be needed by Metal and the GPU, meaning we can overwrite the buffer contents without + // corrupting the rendering. + __block dispatch_semaphore_t block_sema = m_semaphore; + [commandBuffer addCompletedHandler:^(id buffer) + { + (void)buffer; + dispatch_semaphore_signal(block_sema); + }]; + + MTLRenderPassDescriptor* renderPassDescriptor = view.currentRenderPassDescriptor; + + if (renderPassDescriptor != nil) + { + renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(1.0, 0.0, 0.0, 1.0); + + // Create a render command encoder so we can render into something + id renderEncoder = + [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; + renderEncoder.label = @"minifb_command_encoder"; + + // Set render command encoder state + [renderEncoder setRenderPipelineState:g_pipeline_state]; + + [renderEncoder setFragmentTexture:m_texture_buffers[m_current_buffer] atIndex:0]; + + // Draw the vertices of our quads + [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle + vertexStart:0 + vertexCount:3]; + + // We're done encoding commands + [renderEncoder endEncoding]; + + // Schedule a present once the framebuffer is complete using the current drawable + [commandBuffer presentDrawable:view.currentDrawable]; + } + + // Finalize rendering here & push the command buffer to the GPU + [commandBuffer commit]; +} +@end +#endif + @implementation OSXWindowFrameView +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if defined(USE_METAL_API) +-(void)updateTrackingAreas +{ + if(trackingArea != nil) { + [self removeTrackingArea:trackingArea]; + [trackingArea release]; + } + + int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways); + trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds] + options:opts + owner:self + userInfo:nil]; + [self addTrackingArea:trackingArea]; +} +#else extern void* g_updateBuffer; extern int g_width; extern int g_height; @@ -47,6 +149,7 @@ extern int g_height; CGImageRelease(img); } +#endif @end From 8b6148cf97de3df22060144f64e812f64e4dc71d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Aragon=C3=A9s?= <9335325+Darky-Lucera@users.noreply.github.com> Date: Sat, 8 Jun 2019 20:11:02 +0200 Subject: [PATCH 02/14] Add input events (#18) * MacOSX with input events and mfb_set_viewport * Windows with input events and mfb_set_viewport * Minor changes in macosx and windows * X11 with input and mfb_set_viewport * Minor changes on X11 * Fix bug in X11 resize event * Fix bug in windows resize * added scale image to X11 * Added stretch_image with & without bilinear interpolation * moved MiniFB_internal.h * Added wayland events * minor changes * unify a bit the window structs * More work on wayland * Added cmake file * minor fix on windows * modified test * Fix on wayland. Unset wayland as default for linux * Use stdbool instead of our own macro eBool Remove prefix e from all enums * Remove _ex sufix in common files * merge X11MiniFB_ex.c into X11MiniFB.c * Merge WaylandMiniFB_ex.c into WaylandMiniFB.c * Add user_data to callbacks * Merge WinMiniFB_ex.c into WinMiniFB.c * Some minor changes on Windows * Fix bug on Wayland * Added mfb_get_key_name * keyboard_default on all platforms --- .gitignore | 6 + CMakeLists.txt | 75 +++ include/MiniFB.h | 90 ++- include/MiniFB_cpp.h | 124 ++++ include/MiniFB_enums.h | 163 ++++++ src/MiniFB_common.c | 421 ++++++++++++++ src/MiniFB_cpp.cpp | 38 ++ src/MiniFB_internal.c | 75 +++ src/MiniFB_internal.h | 28 + src/macosx/MacMiniFB.m | 769 ++++++++++++++++--------- src/macosx/OSXWindow.h | 26 +- src/macosx/OSXWindow.m | 431 +++++++++----- src/macosx/OSXWindowData.h | 22 + src/macosx/OSXWindowFrameView.h | 74 +-- src/macosx/OSXWindowFrameView.m | 474 +++++++++++----- src/wayland/WaylandMiniFB.c | 972 ++++++++++++++++++++++++-------- src/wayland/WaylandWindowData.h | 57 ++ src/windows/WinMiniFB.c | 617 ++++++++++++++++---- src/windows/WinWindowData.h | 30 + src/x11/X11MiniFB.c | 780 ++++++++++++++++++++----- src/x11/X11WindowData.h | 34 ++ tests/noise.c | 169 +++++- 22 files changed, 4322 insertions(+), 1153 deletions(-) create mode 100644 CMakeLists.txt create mode 100755 include/MiniFB_cpp.h create mode 100755 include/MiniFB_enums.h create mode 100755 src/MiniFB_common.c create mode 100755 src/MiniFB_cpp.cpp create mode 100644 src/MiniFB_internal.c create mode 100755 src/MiniFB_internal.h create mode 100644 src/macosx/OSXWindowData.h create mode 100644 src/wayland/WaylandWindowData.h create mode 100644 src/windows/WinWindowData.h create mode 100644 src/x11/X11WindowData.h diff --git a/.gitignore b/.gitignore index 9379cf7..0836cf7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,8 @@ .tundra2.* t2-output +/.vscode +/win +/macosx +/linux +/build +/.history diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b286d7a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,75 @@ +cmake_minimum_required(VERSION 2.8.9) +project (noise) + +include_directories(include src) + +file(GLOB SrcLib "src/*.c" + "src/*.cpp" + "include/*.h") +file(GLOB SrcWindows "src/windows/*.c" + "src/windows/*.h") +file(GLOB SrcMacOSX "src/macosx/*.c" + "src/macosx/*.cpp" + "src/macosx/*.m" + "src/macosx/*.mm" + "src/macosx/*.h") +file(GLOB SrcWayland "src/wayland/*.c") +file(GLOB SrcX11 "src/x11/*.c") + +if (NOT MSVC) + set (CMAKE_C_FLAGS "-g -Wall -Wextra -Wno-switch -Wno-unused-function") + set (CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11") + set (CMAKE_OBJC_FLAGS "${CMAKE_C_FLAGS}") + set (CMAKE_OBJCXX_FLAGS "${CMAKE_CXX_FLAGS}") +endif() + +if (APPLE) + OPTION(USE_METAL_API "Build the project using metal API code" ON) +elseif (UNIX) + OPTION(USE_WAYLAND_API "Build the project using wayland API code" OFF) +endif() + +if (MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + add_definitions(-D_WIN32_WINNT=0x0600) + list (APPEND SrcLib ${SrcWindows}) +elseif (MINGW) + add_definitions(-D_WIN32_WINNT=0x0600) + list(APPEND SrcLib ${SrcWindows}) +elseif (APPLE) + if(USE_METAL_API) + add_definitions(-DUSE_METAL_API) + endif() + list(APPEND SrcLib ${SrcMacOSX}) +elseif (UNIX) + if(USE_WAYLAND_API) + list(APPEND SrcLib ${SrcWayland}) + else() + list(APPEND SrcLib ${SrcX11}) + endif() +endif() + +add_library(minifb STATIC + ${SrcLib} +) + +add_executable(noise + tests/noise.c +) + +target_link_libraries(noise minifb) + +if (MSVC) +elseif (MINGW) +elseif (APPLE) + target_link_libraries(noise "-framework Cocoa") + target_link_libraries(noise "-framework QuartzCore") + target_link_libraries(noise "-framework Metal") + target_link_libraries(noise "-framework MetalKit") +elseif (UNIX) + if(USE_WAYLAND_API) + target_link_libraries(noise -lwayland-client -lwayland-cursor) + else() + target_link_libraries(noise -lX11) + endif() +endif() diff --git a/include/MiniFB.h b/include/MiniFB.h index eb1a34e..6f302b0 100644 --- a/include/MiniFB.h +++ b/include/MiniFB.h @@ -1,30 +1,60 @@ -#ifndef _MINIFB_H_ -#define _MINIFB_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#define MFB_RGB(r, g, b) (((unsigned int)r) << 16) | (((unsigned int)g) << 8) | b - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// Create a window that is used to display the buffer sent into the mfb_update function, returns 0 if fails -int mfb_open(const char* name, int width, int height); - -// Update the display. Input buffer is assumed to be a 32-bit buffer of the size given in the open call -// Will return -1 when ESC key is pressed (later on will return keycode and -1 on other close signal) -int mfb_update(void* buffer); - -// Close the window -void mfb_close(); - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef _MINIFB_H_ +#define _MINIFB_H_ + +#include "MiniFB_enums.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define MFB_RGB(r, g, b) (((unsigned int)r) << 16) | (((unsigned int)g) << 8) | b + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Create a window that is used to display the buffer sent into the mfb_update function, returns 0 if fails +int mfb_open(const char* name, int width, int height); +int mfb_open_ex(const char* name, int width, int height, int flags); + +// Update the display. Input buffer is assumed to be a 32-bit buffer of the size given in the open call +// Will return -1 when ESC key is pressed (later on will return keycode and -1 on other close signal) +int mfb_update(void* buffer); + +// Close the window +void mfb_close(); + +// Set user data +void mfb_set_user_data(void *user_data); + +// Set viewport (useful when resize) +bool mfb_set_viewport(unsigned offset_x, unsigned offset_y, unsigned width, unsigned height); + +// Event callbacks +typedef void(*mfb_active_func)(void *user_data, bool isActive); +typedef void(*mfb_resize_func)(void *user_data, int width, int height); +typedef void(*mfb_keyboard_func)(void *user_data, Key key, KeyMod mod, bool isPressed); +typedef void(*mfb_char_input_func)(void *user_data, unsigned int code); +typedef void(*mfb_mouse_btn_func)(void *user_data, MouseButton button, KeyMod mod, bool isPressed); +typedef void(*mfb_mouse_move_func)(void *user_data, int x, int y); +typedef void(*mfb_mouse_scroll_func)(void *user_data, KeyMod mod, float deltaX, float deltaY); + +void mfb_active_callback(mfb_active_func callback); +void mfb_resize_callback(mfb_resize_func callback); +void mfb_keyboard_callback(mfb_keyboard_func callback); +void mfb_char_input_callback(mfb_char_input_func callback); +void mfb_mouse_button_callback(mfb_mouse_btn_func callback); +void mfb_mouse_move_callback(mfb_mouse_move_func callback); +void mfb_mouse_scroll_callback(mfb_mouse_scroll_func callback); + +const char *mfb_get_key_name(Key key); + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +} + +#include "MiniFB_cpp.h" +#endif + +#endif diff --git a/include/MiniFB_cpp.h b/include/MiniFB_cpp.h new file mode 100755 index 0000000..f665a0b --- /dev/null +++ b/include/MiniFB_cpp.h @@ -0,0 +1,124 @@ +#pragma once + +#if defined(__cplusplus) + +#include +#include "MiniFB.h" + +template +void mfb_active_callback(T *obj, void (T::*method)(void *, bool)); + +template +void mfb_resize_callback(T *obj, void (T::*method)(void *, int, int)); + +template +void mfb_keyboard_callback(T *obj, void (T::*method)(void *, Key, KeyMod, bool)); + +template +void mfb_char_input_callback(T *obj, void (T::*method)(void *, unsigned int)); + +template +void mfb_mouse_button_callback(T *obj, void (T::*method)(void *, MouseButton, KeyMod, bool)); + +template +void mfb_mouse_move_callback(T *obj, void (T::*method)(void *, int, int)); + +template +void mfb_mouse_scroll_callback(T *obj, void (T::*method)(void *, KeyMod, float, float)); + +//------------------------------------- +// To avoid clumsy hands +//------------------------------------- +class Stub { + template + friend void mfb_active_callback(T *obj, void (T::*method)(void *, bool)); + template + friend void mfb_resize_callback(T *obj, void (T::*method)(void *, int, int)); + template + friend void mfb_mouse_button_callback(T *obj, void (T::*method)(void *, MouseButton, KeyMod, bool)); + template + friend void mfb_keyboard_callback(T *obj, void (T::*method)(void *, Key, KeyMod, bool)); + template + friend void mfb_char_input_callback(T *obj, void (T::*method)(void *, unsigned int)); + template + friend void mfb_mouse_button_callback(T *obj, void (T::*method)(void *, MouseButton, KeyMod, bool)); + template + friend void mfb_mouse_move_callback(T *obj, void (T::*method)(void *, int, int)); + template + friend void mfb_mouse_scroll_callback(T *obj, void (T::*method)(void *, KeyMod, float, float)); + + static void active_stub(void *user_data, bool isActive); + static void resize_stub(void *user_data, int width, int height); + static void keyboard_stub(void *user_data, Key key, KeyMod mod, bool isPressed); + static void char_input_stub(void *user_data, unsigned int); + static void mouse_btn_stub(void *user_data, MouseButton button, KeyMod mod, bool isPressed); + static void mouse_move_stub(void *user_data, int x, int y); + static void scroll_stub(void *user_data, KeyMod mod, float deltaX, float deltaY); + + static std::function m_active; + static std::function m_resize; + static std::function m_keyboard; + static std::function m_char_input; + static std::function m_mouse_btn; + static std::function m_mouse_move; + static std::function m_scroll; +}; + +//------------------------------------- +template +inline void mfb_active_callback(T *obj, void (T::*method)(void *user_data, bool)) { + using namespace std::placeholders; + + Stub::m_active = std::bind(method, obj, _1, _2); + mfb_active_callback(Stub::active_stub); +} + +template +inline void mfb_resize_callback(T *obj, void (T::*method)(void *user_data, int, int)) { + using namespace std::placeholders; + + Stub::m_resize = std::bind(method, obj, _1, _2, _3); + mfb_resize_callback(Stub::resize_stub); +} + +template +inline void mfb_keyboard_callback(T *obj, void (T::*method)(void *user_data, Key, KeyMod, bool)) { + using namespace std::placeholders; + + Stub::m_keyboard = std::bind(method, obj, _1, _2, _3, _4); + mfb_keyboard_callback(Stub::keyboard_stub); +} + +template +inline void mfb_char_input_callback(T *obj, void (T::*method)(void *user_data, unsigned int)) { + using namespace std::placeholders; + + Stub::m_char_input = std::bind(method, obj, _1, _2); + mfb_char_input_callback(Stub::char_input_stub); +} + +template +inline void mfb_mouse_button_callback(T *obj, void (T::*method)(void *user_data, MouseButton, KeyMod, bool)) { + using namespace std::placeholders; + + Stub::m_mouse_btn = std::bind(method, obj, _1, _2, _3, _4); + mfb_mouse_button_callback(Stub::mouse_btn_stub); +} + +template +inline void mfb_mouse_move_callback(T *obj, void (T::*method)(void *user_data, int, int)) { + using namespace std::placeholders; + + Stub::m_mouse_move = std::bind(method, obj, _1, _2, _3); + mfb_mouse_move_callback(Stub::mouse_move_stub); +} + +template +inline void mfb_mouse_scroll_callback(T *obj, void (T::*method)(void *user_data, KeyMod, float, float)) { + using namespace std::placeholders; + + Stub::m_scroll = std::bind(method, obj, _1, _2, _3, _4); + mfb_mouse_scroll_callback(Stub::scroll_stub); +} + +#endif diff --git a/include/MiniFB_enums.h b/include/MiniFB_enums.h new file mode 100755 index 0000000..cc7b6fd --- /dev/null +++ b/include/MiniFB_enums.h @@ -0,0 +1,163 @@ +#pragma once + +#include + +typedef enum { + MOUSE_BTN_0, // No mouse button + MOUSE_BTN_1, + MOUSE_BTN_2, + MOUSE_BTN_3, + MOUSE_BTN_4, + MOUSE_BTN_5, + MOUSE_BTN_6, + MOUSE_BTN_7, + MOUSE_BTN_8 +} MouseButton; +#define MOUSE_LAST MOUSE_BTN_8 +#define MOUSE_LEFT MOUSE_BTN_0 +#define MOUSE_RIGHT MOUSE_BTN_1 +#define MOUSE_MIDDLE MOUSE_BTN_2 + +typedef enum { + KB_KEY_UNKNOWN = -1, + + KB_KEY_SPACE = 32, + KB_KEY_APOSTROPHE = 39, + KB_KEY_COMMA = 44, + KB_KEY_MINUS = 45, + KB_KEY_PERIOD = 46, + KB_KEY_SLASH = 47, + KB_KEY_0 = 48, + KB_KEY_1 = 49, + KB_KEY_2 = 50, + KB_KEY_3 = 51, + KB_KEY_4 = 52, + KB_KEY_5 = 53, + KB_KEY_6 = 54, + KB_KEY_7 = 55, + KB_KEY_8 = 56, + KB_KEY_9 = 57, + KB_KEY_SEMICOLON = 59, + KB_KEY_EQUAL = 61, + KB_KEY_A = 65, + KB_KEY_B = 66, + KB_KEY_C = 67, + KB_KEY_D = 68, + KB_KEY_E = 69, + KB_KEY_F = 70, + KB_KEY_G = 71, + KB_KEY_H = 72, + KB_KEY_I = 73, + KB_KEY_J = 74, + KB_KEY_K = 75, + KB_KEY_L = 76, + KB_KEY_M = 77, + KB_KEY_N = 78, + KB_KEY_O = 79, + KB_KEY_P = 80, + KB_KEY_Q = 81, + KB_KEY_R = 82, + KB_KEY_S = 83, + KB_KEY_T = 84, + KB_KEY_U = 85, + KB_KEY_V = 86, + KB_KEY_W = 87, + KB_KEY_X = 88, + KB_KEY_Y = 89, + KB_KEY_Z = 90, + KB_KEY_LEFT_BRACKET = 91, + KB_KEY_BACKSLASH = 92, + KB_KEY_RIGHT_BRACKET = 93, + KB_KEY_GRAVE_ACCENT = 96, + KB_KEY_WORLD_1 = 161, + KB_KEY_WORLD_2 = 162, + + KB_KEY_ESCAPE = 256, + KB_KEY_ENTER = 257, + KB_KEY_TAB = 258, + KB_KEY_BACKSPACE = 259, + KB_KEY_INSERT = 260, + KB_KEY_DELETE = 261, + KB_KEY_RIGHT = 262, + KB_KEY_LEFT = 263, + KB_KEY_DOWN = 264, + KB_KEY_UP = 265, + KB_KEY_PAGE_UP = 266, + KB_KEY_PAGE_DOWN = 267, + KB_KEY_HOME = 268, + KB_KEY_END = 269, + KB_KEY_CAPS_LOCK = 280, + KB_KEY_SCROLL_LOCK = 281, + KB_KEY_NUM_LOCK = 282, + KB_KEY_PRINT_SCREEN = 283, + KB_KEY_PAUSE = 284, + KB_KEY_F1 = 290, + KB_KEY_F2 = 291, + KB_KEY_F3 = 292, + KB_KEY_F4 = 293, + KB_KEY_F5 = 294, + KB_KEY_F6 = 295, + KB_KEY_F7 = 296, + KB_KEY_F8 = 297, + KB_KEY_F9 = 298, + KB_KEY_F10 = 299, + KB_KEY_F11 = 300, + KB_KEY_F12 = 301, + KB_KEY_F13 = 302, + KB_KEY_F14 = 303, + KB_KEY_F15 = 304, + KB_KEY_F16 = 305, + KB_KEY_F17 = 306, + KB_KEY_F18 = 307, + KB_KEY_F19 = 308, + KB_KEY_F20 = 309, + KB_KEY_F21 = 310, + KB_KEY_F22 = 311, + KB_KEY_F23 = 312, + KB_KEY_F24 = 313, + KB_KEY_F25 = 314, + KB_KEY_KP_0 = 320, + KB_KEY_KP_1 = 321, + KB_KEY_KP_2 = 322, + KB_KEY_KP_3 = 323, + KB_KEY_KP_4 = 324, + KB_KEY_KP_5 = 325, + KB_KEY_KP_6 = 326, + KB_KEY_KP_7 = 327, + KB_KEY_KP_8 = 328, + KB_KEY_KP_9 = 329, + KB_KEY_KP_DECIMAL = 330, + KB_KEY_KP_DIVIDE = 331, + KB_KEY_KP_MULTIPLY = 332, + KB_KEY_KP_SUBTRACT = 333, + KB_KEY_KP_ADD = 334, + KB_KEY_KP_ENTER = 335, + KB_KEY_KP_EQUAL = 336, + KB_KEY_LEFT_SHIFT = 340, + KB_KEY_LEFT_CONTROL = 341, + KB_KEY_LEFT_ALT = 342, + KB_KEY_LEFT_SUPER = 343, + KB_KEY_RIGHT_SHIFT = 344, + KB_KEY_RIGHT_CONTROL = 345, + KB_KEY_RIGHT_ALT = 346, + KB_KEY_RIGHT_SUPER = 347, + KB_KEY_MENU = 348 +} Key; +#define KB_KEY_LAST KB_KEY_MENU + +typedef enum { + KB_MOD_SHIFT = 0x0001, + KB_MOD_CONTROL = 0x0002, + KB_MOD_ALT = 0x0004, + KB_MOD_SUPER = 0x0008, + KB_MOD_CAPS_LOCK = 0x0010, + KB_MOD_NUM_LOCK = 0x0020 +} KeyMod; + +typedef enum { + WF_RESIZABLE = 0x01, + WF_FULLSCREEN = 0x02, + WF_FULLSCREEN_DESKTOP = 0x04, + WF_BORDERLESS = 0x08, + WF_ALWAYS_ON_TOP = 0x10, +} WindowFlags; diff --git a/src/MiniFB_common.c b/src/MiniFB_common.c new file mode 100755 index 0000000..3e24254 --- /dev/null +++ b/src/MiniFB_common.c @@ -0,0 +1,421 @@ +#include "MiniFB.h" + +//------------------------------------- +mfb_active_func g_active_func = 0x0; +mfb_resize_func g_resize_func = 0x0; +mfb_keyboard_func g_keyboard_func = 0x0; +mfb_char_input_func g_char_input_func = 0x0; +mfb_mouse_btn_func g_mouse_btn_func = 0x0; +mfb_mouse_move_func g_mouse_move_func = 0x0; +mfb_mouse_scroll_func g_mouse_wheel_func = 0x0; + +void *g_user_data = 0x0; + +//------------------------------------- +void mfb_active_callback(mfb_active_func callback) { + g_active_func = callback; +} + +//------------------------------------- +void mfb_resize_callback(mfb_resize_func callback) { + g_resize_func = callback; +} + +//------------------------------------- +void mfb_keyboard_callback(mfb_keyboard_func callback) { + g_keyboard_func = callback; +} + +//------------------------------------- +void mfb_char_input_callback(mfb_char_input_func callback) { + g_char_input_func = callback; +} + +//------------------------------------- +void mfb_mouse_button_callback(mfb_mouse_btn_func callback) { + g_mouse_btn_func = callback; +} + +//------------------------------------- +void mfb_mouse_move_callback(mfb_mouse_move_func callback) { + g_mouse_move_func = callback; +} + +//------------------------------------- +void mfb_mouse_scroll_callback(mfb_mouse_scroll_func callback) { + g_mouse_wheel_func = callback; +} + +//------------------------------------- +void mfb_set_user_data(void *user_data) { + g_user_data = user_data; +} + +//------------------------------------- +const char *mfb_get_key_name(Key key) { + + switch (key) + { + case KB_KEY_SPACE: + return "Space"; + + case KB_KEY_APOSTROPHE: + return "Apostrophe"; + + case KB_KEY_COMMA: + return "Comma"; + + case KB_KEY_MINUS: + return "Minus"; + + case KB_KEY_PERIOD: + return "Period"; + + case KB_KEY_SLASH: + return "Slash"; + + case KB_KEY_0: + return "0"; + + case KB_KEY_1: + return "1"; + + case KB_KEY_2: + return "2"; + + case KB_KEY_3: + return "3"; + + case KB_KEY_4: + return "4"; + + case KB_KEY_5: + return "5"; + + case KB_KEY_6: + return "6"; + + case KB_KEY_7: + return "7"; + + case KB_KEY_8: + return "8"; + + case KB_KEY_9: + return "9"; + + case KB_KEY_SEMICOLON: + return "Semicolon"; + + case KB_KEY_EQUAL: + return "Equal"; + + case KB_KEY_A: + return "A"; + + case KB_KEY_B: + return "B"; + + case KB_KEY_C: + return "C"; + + case KB_KEY_D: + return "D"; + + case KB_KEY_E: + return "E"; + + case KB_KEY_F: + return "F"; + + case KB_KEY_G: + return "G"; + + case KB_KEY_H: + return "H"; + + case KB_KEY_I: + return "I"; + + case KB_KEY_J: + return "J"; + + case KB_KEY_K: + return "K"; + + case KB_KEY_L: + return "L"; + + case KB_KEY_M: + return "M"; + + case KB_KEY_N: + return "N"; + + case KB_KEY_O: + return "O"; + + case KB_KEY_P: + return "P"; + + case KB_KEY_Q: + return "Q"; + + case KB_KEY_R: + return "R"; + + case KB_KEY_S: + return "S"; + + case KB_KEY_T: + return "T"; + + case KB_KEY_U: + return "U"; + + case KB_KEY_V: + return "V"; + + case KB_KEY_W: + return "W"; + + case KB_KEY_X: + return "X"; + + case KB_KEY_Y: + return "Y"; + + case KB_KEY_Z: + return "Z"; + + case KB_KEY_LEFT_BRACKET: + return "Left_Bracket"; + + case KB_KEY_BACKSLASH: + return "Backslash"; + + case KB_KEY_RIGHT_BRACKET: + return "Right_Bracket"; + + case KB_KEY_GRAVE_ACCENT: + return "Grave_Accent"; + + case KB_KEY_WORLD_1: + return "World_1"; + + case KB_KEY_WORLD_2: + return "World_2"; + + case KB_KEY_ESCAPE: + return "Escape"; + + case KB_KEY_ENTER: + return "Enter"; + + case KB_KEY_TAB: + return "Tab"; + + case KB_KEY_BACKSPACE: + return "Backspace"; + + case KB_KEY_INSERT: + return "Insert"; + + case KB_KEY_DELETE: + return "Delete"; + + case KB_KEY_RIGHT: + return "Right"; + + case KB_KEY_LEFT: + return "Left"; + + case KB_KEY_DOWN: + return "Down"; + + case KB_KEY_UP: + return "Up"; + + case KB_KEY_PAGE_UP: + return "Page_Up"; + + case KB_KEY_PAGE_DOWN: + return "Page_Down"; + + case KB_KEY_HOME: + return "Home"; + + case KB_KEY_END: + return "End"; + + case KB_KEY_CAPS_LOCK: + return "Caps_Lock"; + + case KB_KEY_SCROLL_LOCK: + return "Scroll_Lock"; + + case KB_KEY_NUM_LOCK: + return "Num_Lock"; + + case KB_KEY_PRINT_SCREEN: + return "Print_Screen"; + + case KB_KEY_PAUSE: + return "Pause"; + + case KB_KEY_F1: + return "F1"; + + case KB_KEY_F2: + return "F2"; + + case KB_KEY_F3: + return "F3"; + + case KB_KEY_F4: + return "F4"; + + case KB_KEY_F5: + return "F5"; + + case KB_KEY_F6: + return "F6"; + + case KB_KEY_F7: + return "F7"; + + case KB_KEY_F8: + return "F8"; + + case KB_KEY_F9: + return "F9"; + + case KB_KEY_F10: + return "F10"; + + case KB_KEY_F11: + return "F11"; + + case KB_KEY_F12: + return "F12"; + + case KB_KEY_F13: + return "F13"; + + case KB_KEY_F14: + return "F14"; + + case KB_KEY_F15: + return "F15"; + + case KB_KEY_F16: + return "F16"; + + case KB_KEY_F17: + return "F17"; + + case KB_KEY_F18: + return "F18"; + + case KB_KEY_F19: + return "F19"; + + case KB_KEY_F20: + return "F20"; + + case KB_KEY_F21: + return "F21"; + + case KB_KEY_F22: + return "F22"; + + case KB_KEY_F23: + return "F23"; + + case KB_KEY_F24: + return "F24"; + + case KB_KEY_F25: + return "F25"; + + case KB_KEY_KP_0: + return "KP_0"; + + case KB_KEY_KP_1: + return "KP_1"; + + case KB_KEY_KP_2: + return "KP_2"; + + case KB_KEY_KP_3: + return "KP_3"; + + case KB_KEY_KP_4: + return "KP_4"; + + case KB_KEY_KP_5: + return "KP_5"; + + case KB_KEY_KP_6: + return "KP_6"; + + case KB_KEY_KP_7: + return "KP_7"; + + case KB_KEY_KP_8: + return "KP_8"; + + case KB_KEY_KP_9: + return "KP_9"; + + case KB_KEY_KP_DECIMAL: + return "KP_Decimal"; + + case KB_KEY_KP_DIVIDE: + return "KP_Divide"; + + case KB_KEY_KP_MULTIPLY: + return "KP_Multiply"; + + case KB_KEY_KP_SUBTRACT: + return "KP_Subtract"; + + case KB_KEY_KP_ADD: + return "KP_Add"; + + case KB_KEY_KP_ENTER: + return "KP_Enter"; + + case KB_KEY_KP_EQUAL: + return "KP_Equal"; + + case KB_KEY_LEFT_SHIFT: + return "Left_Shift"; + + case KB_KEY_LEFT_CONTROL: + return "Left_Control"; + + case KB_KEY_LEFT_ALT: + return "Left_Alt"; + + case KB_KEY_LEFT_SUPER: + return "Left_Super"; + + case KB_KEY_RIGHT_SHIFT: + return "Right_Shift"; + + case KB_KEY_RIGHT_CONTROL: + return "Right_Control"; + + case KB_KEY_RIGHT_ALT: + return "Right_Alt"; + + case KB_KEY_RIGHT_SUPER: + return "Right_Super"; + + case KB_KEY_MENU: + return "Menu"; + + } + return "Unknown"; +} \ No newline at end of file diff --git a/src/MiniFB_cpp.cpp b/src/MiniFB_cpp.cpp new file mode 100755 index 0000000..eb38303 --- /dev/null +++ b/src/MiniFB_cpp.cpp @@ -0,0 +1,38 @@ +#include +#include + +std::function Stub::m_active; +std::function Stub::m_resize; +std::function Stub::m_keyboard; +std::function Stub::m_char_input; +std::function Stub::m_mouse_btn; +std::function Stub::m_mouse_move; +std::function Stub::m_scroll; + +void Stub::active_stub(void *user_data, bool isActive) { + m_active(user_data, isActive); +} + +void Stub::resize_stub(void *user_data, int width, int height) { + m_resize(user_data, width, height); +} + +void Stub::keyboard_stub(void *user_data, Key key, KeyMod mod, bool isPressed) { + m_keyboard(user_data, key, mod, isPressed); +} + +void Stub::char_input_stub(void *user_data, unsigned int code) { + m_char_input(user_data, code); +} + +void Stub::mouse_btn_stub(void *user_data, MouseButton button, KeyMod mod, bool isPressed) { + m_mouse_btn(user_data, button, mod, isPressed); +} + +void Stub::mouse_move_stub(void *user_data, int x, int y) { + m_mouse_move(user_data, x, y); +} + +void Stub::scroll_stub(void *user_data, KeyMod mod, float deltaX, float deltaY) { + m_scroll(user_data, mod, deltaX, deltaY); +} diff --git a/src/MiniFB_internal.c b/src/MiniFB_internal.c new file mode 100644 index 0000000..5b74a3b --- /dev/null +++ b/src/MiniFB_internal.c @@ -0,0 +1,75 @@ +#include "MiniFB_internal.h" +#include + +//#define kUseBilinearInterpolation + +#if defined(kUseBilinearInterpolation) +static uint32_t 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) { + uint32_t incX = x + 1 < srcWidth ? 1 : 0; + uint32_t incY = y + 1 < srcHeight ? srcPitch : 0; + uint8_t *p00 = (uint8_t *) &srcImage[(srcOffsetX >> 16)]; + uint8_t *p01 = (uint8_t *) &srcImage[(srcOffsetX >> 16) + incX]; + uint8_t *p10 = (uint8_t *) &srcImage[(srcOffsetX >> 16) + incY]; + uint8_t *p11 = (uint8_t *) &srcImage[(srcOffsetX >> 16) + incY + incX]; + + uint32_t wx2 = srcOffsetX & 0xffff; + uint32_t wy2 = srcOffsetY & 0xffff; + uint32_t wx1 = 0x10000 - wx2; + uint32_t wy1 = 0x10000 - wy2; + + uint32_t w1 = ((uint64_t) wx1 * wy1) >> 16; + uint32_t w2 = ((uint64_t) wx2 * wy1) >> 16; + uint32_t w3 = ((uint64_t) wx1 * wy2) >> 16; + uint32_t w4 = ((uint64_t) wx2 * wy2) >> 16; + + // If you don't have uint64_t + //uint32_t b = (((p00[0] * wx1 + p01[0] * wx2) >> 16) * wy1 + ((p10[0] * wx1 + p11[0] * wx2) >> 16) * wy2) >> 16; + //uint32_t g = (((p00[1] * wx1 + p01[1] * wx2) >> 16) * wy1 + ((p10[1] * wx1 + p11[1] * wx2) >> 16) * wy2) >> 16; + //uint32_t r = (((p00[2] * wx1 + p01[2] * wx2) >> 16) * wy1 + ((p10[2] * wx1 + p11[2] * wx2) >> 16) * wy2) >> 16; + //uint32_t a = (((p00[3] * wx1 + p01[3] * wx2) >> 16) * wy1 + ((p10[3] * wx1 + p11[3] * wx2) >> 16) * wy2) >> 16; + + uint32_t b = ((p00[0] * w1 + p01[0] * w2) + (p10[0] * w3 + p11[0] * w4)) >> 16; + uint32_t g = ((p00[1] * w1 + p01[1] * w2) + (p10[1] * w3 + p11[1] * w4)) >> 16; + uint32_t r = ((p00[2] * w1 + p01[2] * w2) + (p10[2] * w3 + p11[2] * w4)) >> 16; + uint32_t a = ((p00[3] * w1 + p01[3] * w2) + (p10[3] * w3 + p11[3] * w4)) >> 16; + + return (a << 24) + (r << 16) + (g << 8) + b; +} +#endif + +// Only for 32 bits images +void stretch_image(uint32_t *srcImage, uint32_t srcX, uint32_t srcY, uint32_t srcWidth, uint32_t srcHeight, uint32_t srcPitch, + uint32_t *dstImage, uint32_t dstX, uint32_t dstY, uint32_t dstWidth, uint32_t dstHeight, uint32_t dstPitch) { + + uint32_t x, y; + uint32_t srcOffsetX, srcOffsetY; + + if(srcImage == 0x0 || dstImage == 0x0) + return; + + srcImage += srcX + srcY * srcPitch; + dstImage += dstX + dstY * dstPitch; + + const uint32_t deltaX = (srcWidth << 16) / dstWidth; + const uint32_t deltaY = (srcHeight << 16) / dstHeight; + + srcOffsetY = 0; + for(y=0; y> 16]; +#endif + srcOffsetX += deltaX; + } + + srcOffsetY += deltaY; + if(srcOffsetY >= 0x10000) { + srcImage += (srcOffsetY >> 16) * srcPitch; + srcOffsetY &= 0xffff; + } + dstImage += dstPitch; + } +} \ No newline at end of file diff --git a/src/MiniFB_internal.h b/src/MiniFB_internal.h new file mode 100755 index 0000000..f7b2010 --- /dev/null +++ b/src/MiniFB_internal.h @@ -0,0 +1,28 @@ +#pragma once + +#include "MiniFB.h" + +extern void *g_user_data; + +#define kCall(f, ...) if((f)) (f)(g_user_data, __VA_ARGS__); +#define kUnused(var) (void) var; + +#if defined(__cplusplus) +extern "C" { +#endif + + short int keycodes[512]; + void init_keycodes(); + void keyboard_default(void *user_data, Key key, KeyMod mod, bool isPressed); + + extern mfb_active_func g_active_func; + extern mfb_resize_func g_resize_func; + extern mfb_keyboard_func g_keyboard_func; + extern mfb_char_input_func g_char_input_func; + extern mfb_mouse_btn_func g_mouse_btn_func; + extern mfb_mouse_move_func g_mouse_move_func; + extern mfb_mouse_scroll_func g_mouse_wheel_func; + +#if defined(__cplusplus) +} +#endif diff --git a/src/macosx/MacMiniFB.m b/src/macosx/MacMiniFB.m index 4947d08..a990b70 100644 --- a/src/macosx/MacMiniFB.m +++ b/src/macosx/MacMiniFB.m @@ -1,273 +1,496 @@ -#include "OSXWindow.h" -#include "OSXWindowFrameView.h" -#include -#if defined(USE_METAL_API) -#include -#include -#endif -#include -#include "MiniFB.h" - -#if defined(USE_METAL_API) -extern id g_metal_device; -extern id g_command_queue; -extern id g_library; -extern id g_pipeline_state; - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -NSString* g_shadersSrc = @ -" #include \n" - "using namespace metal;\n" - - "struct VertexOutput {\n" - "float4 pos [[position]];\n" - "float2 texcoord;\n" - "};\n" - - "vertex VertexOutput vertFunc(\n" - "unsigned int vID[[vertex_id]])\n" - "{\n" - "VertexOutput out;\n" - - "out.pos.x = (float)(vID / 2) * 4.0 - 1.0;\n" - "out.pos.y = (float)(vID % 2) * 4.0 - 1.0;\n" - "out.pos.z = 0.0;\n" - "out.pos.w = 1.0;\n" - - "out.texcoord.x = (float)(vID / 2) * 2.0;\n" - "out.texcoord.y = 1.0 - (float)(vID % 2) * 2.0;\n" - - "return out;\n" - "}\n" - - "fragment float4 fragFunc(VertexOutput input [[stage_in]],\n" - "texture2d colorTexture [[ texture(0) ]])\n" - "{\n" - "constexpr sampler textureSampler(mag_filter::nearest, min_filter::nearest);\n" - - // Sample the texture to obtain a color - "const half4 colorSample = colorTexture.sample(textureSampler, input.texcoord);\n" - - // We return the color of the texture - "return float4(colorSample);\n" - //"return half4(input.texcoord.x, input.texcoord.y, 0.0, 1.0);\n" - "}\n"; - -#endif - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#if !defined(USE_METAL_API) -void* g_updateBuffer = 0; -int g_width = 0; -int g_height = 0; -#endif -static OSXWindow *s_window; - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#if defined(USE_METAL_API) -static bool create_shaders() { - // Error - NSError* nsError = NULL; - NSError** nsErrorPtr = &nsError; - - id library = [g_metal_device newLibraryWithSource:g_shadersSrc - options:[[MTLCompileOptions alloc] init] - error:nsErrorPtr]; - - // Error update - if (nsError || !library) { - NSLog(@"Unable to create shaders %@", nsError); - return false; - } - - g_library = library; - NSLog(@"Names %@", [g_library functionNames]); - - id vertex_shader_func = [g_library newFunctionWithName:@"vertFunc"]; - id fragment_shader_func = [g_library newFunctionWithName:@"fragFunc"]; - - if (!vertex_shader_func) { - printf("Unable to get vertFunc!\n"); - return false; - } - - if (!fragment_shader_func) { - printf("Unable to get fragFunc!\n"); - return false; - } - - // Create a reusable pipeline state - MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; - pipelineStateDescriptor.label = @"MyPipeline"; - pipelineStateDescriptor.vertexFunction = vertex_shader_func; - pipelineStateDescriptor.fragmentFunction = fragment_shader_func; - pipelineStateDescriptor.colorAttachments[0].pixelFormat = 80; //bgra8Unorm; - - NSError *error = NULL; - g_pipeline_state = [g_metal_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error]; - if (!g_pipeline_state) - { - NSLog(@"Failed to created pipeline state, error %@", error); - } - - return true; -} -#endif - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int mfb_open(const char* name, int width, int height) -{ - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - -#if !defined(USE_METAL_API) - g_width = width; - g_height = height; -#endif - [NSApplication sharedApplication]; - [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; - -#if defined(USE_METAL_API) - g_metal_device = MTLCreateSystemDefaultDevice(); - - if (!g_metal_device) { - printf("Your device/OS doesn't support Metal."); - return -1; - } - - if (!create_shaders()) { - return -2; - } -#endif - - NSWindowStyleMask styles = NSWindowStyleMaskResizable | NSWindowStyleMaskClosable | NSWindowStyleMaskTitled; - - NSRect rectangle = NSMakeRect(0, 0, width, height); - s_window = [[OSXWindow alloc] initWithContentRect:rectangle styleMask:styles backing:NSBackingStoreBuffered defer:NO]; - - if (!s_window) - return -3; - -#if defined(USE_METAL_API) - s_window->draw_buffer = malloc(width * height * 4); - - if (!s_window->draw_buffer) - return -4; - - // Setup command queue - g_command_queue = [g_metal_device newCommandQueue]; - - WindowViewController* viewController = [WindowViewController new]; - - MTLTextureDescriptor* textureDescriptor = [[MTLTextureDescriptor alloc] init]; - - // Indicate that each pixel has a blue, green, red, and alpha channel, where each channel is - // an 8-bit unsigned normalized value (i.e. 0 maps to 0.0 and 255 maps to 1.0) - textureDescriptor.pixelFormat = MTLPixelFormatBGRA8Unorm; - - // Set the pixel dimensions of the texture - textureDescriptor.width = width; - textureDescriptor.height = height; - - // Create the texture from the device by using the descriptor - - for (int i = 0; i < MaxBuffersInFlight; ++i) { - viewController->m_texture_buffers[i] = [g_metal_device newTextureWithDescriptor:textureDescriptor]; - } - - // Used for syncing the CPU and GPU - viewController->m_semaphore = dispatch_semaphore_create(MaxBuffersInFlight); - viewController->m_draw_buffer = s_window->draw_buffer; - viewController->m_width = width; - viewController->m_height = height; - - MTKView* view = [[MTKView alloc] initWithFrame:rectangle]; - view.device = g_metal_device; - view.delegate = viewController; - view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; - [s_window.contentView addSubview:view]; - - s_window->width = width; - s_window->height = height; - - //[s_window updateSize]; -#endif - - [s_window setTitle:[NSString stringWithUTF8String:name]]; - [s_window setReleasedWhenClosed:NO]; - [s_window performSelectorOnMainThread:@selector(makeKeyAndOrderFront:) withObject:nil waitUntilDone:YES]; - - [s_window center]; - - [NSApp activateIgnoringOtherApps:YES]; - -#if defined(USE_METAL_API) - [NSApp finishLaunching]; -#endif - - [pool drain]; - - return 1; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void mfb_close() -{ - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - - if (s_window) - [s_window close]; - - [pool drain]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -static int updateEvents() -{ - int state = 0; - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; - if (event) - { - switch ([event type]) - { - case NSEventTypeKeyDown: - case NSEventTypeKeyUp: - { - state = -1; - break; - } - - default : - { - [NSApp sendEvent:event]; - break; - } - } - } - [pool release]; - - if (s_window->closed) - state = -1; - - return state; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int mfb_update(void* buffer) -{ -#if defined(USE_METAL_API) - memcpy(s_window->draw_buffer, buffer, s_window->width * s_window->height * 4); -#else - g_updateBuffer = buffer; -#endif - int state = updateEvents(); - [[s_window contentView] setNeedsDisplay:YES]; - return state; -} +#include "OSXWindow.h" +#include "OSXWindowFrameView.h" +#include "OSXWindowData.h" +#include +#include +#include +#include +#if defined(USE_METAL_API) +#include +#include +#endif +#include + +SWindowData g_window_data = { 0 }; + +void init_keycodes(); + +#if defined(USE_METAL_API) +extern id g_metal_device; +extern id g_command_queue; +extern id g_library; +extern id g_pipeline_state; + +Vertex gVertices[4] = { + {-1.0, -1.0, 0, 1}, + {-1.0, 1.0, 0, 1}, + { 1.0, -1.0, 0, 1}, + { 1.0, 1.0, 0, 1}, +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +NSString* g_shadersSrc = @ +" #include \n" + "using namespace metal;\n" + + "struct VertexOutput {\n" + "float4 pos [[position]];\n" + "float2 texcoord;\n" + "};\n" + + "vertex VertexOutput vertFunc(unsigned int vID[[vertex_id]])\n" + "{\n" + "VertexOutput out;\n" + + "out.pos.x = (float)(vID / 2) * 4.0 - 1.0;\n" + "out.pos.y = (float)(vID % 2) * 4.0 - 1.0;\n" + "out.pos.z = 0.0;\n" + "out.pos.w = 1.0;\n" + + "out.texcoord.x = (float)(vID / 2) * 2.0;\n" + "out.texcoord.y = 1.0 - (float)(vID % 2) * 2.0;\n" + + "return out;\n" + "}\n" + + "struct Vertex\n" + "{\n" + "float4 position [[position]];\n" + "};\n" + + "vertex VertexOutput vertFunc2(unsigned int vID[[vertex_id]], device Vertex *pos [[buffer(0)]])\n" + "{\n" + "VertexOutput out;\n" + + "out.pos = pos[vID].position;\n" + + "out.texcoord.x = (float)(vID / 2);\n" + "out.texcoord.y = 1.0 - (float)(vID % 2);\n" + + "return out;\n" + "}\n" + + "fragment float4 fragFunc(VertexOutput input [[stage_in]],\n" + "texture2d colorTexture [[ texture(0) ]])\n" + "{\n" + "constexpr sampler textureSampler(mag_filter::nearest, min_filter::nearest);\n" + + // Sample the texture to obtain a color + "const half4 colorSample = colorTexture.sample(textureSampler, input.texcoord);\n" + + // We return the color of the texture + "return float4(colorSample);\n" + //"return float4(input.texcoord.x, input.texcoord.y, 0.0, 1.0);\n" + "}\n"; + +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if defined(USE_METAL_API) +static bool create_shaders() { + // Error + NSError* nsError = NULL; + NSError** nsErrorPtr = &nsError; + + id library = [g_metal_device newLibraryWithSource:g_shadersSrc + options:[[MTLCompileOptions alloc] init] + error:nsErrorPtr]; + + // Error update + if (nsError || !library) { + NSLog(@"Unable to create shaders %@", nsError); + return false; + } + + g_library = library; + NSLog(@"Names %@", [g_library functionNames]); + + id vertex_shader_func = [g_library newFunctionWithName:@"vertFunc2"]; + id fragment_shader_func = [g_library newFunctionWithName:@"fragFunc"]; + + if (!vertex_shader_func) { + printf("Unable to get vertFunc!\n"); + return false; + } + + if (!fragment_shader_func) { + printf("Unable to get fragFunc!\n"); + return false; + } + + // Create a reusable pipeline state + MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; + pipelineStateDescriptor.label = @"MyPipeline"; + pipelineStateDescriptor.vertexFunction = vertex_shader_func; + pipelineStateDescriptor.fragmentFunction = fragment_shader_func; + pipelineStateDescriptor.colorAttachments[0].pixelFormat = 80; //bgra8Unorm; + + NSError *error = NULL; + g_pipeline_state = [g_metal_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error]; + if (!g_pipeline_state) + { + NSLog(@"Failed to created pipeline state, error %@", error); + } + + return true; +} +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int mfb_open(const char* name, int width, int height) +{ + return mfb_open_ex(name, width, height, 0); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int mfb_open_ex(const char* name, int width, int height, int flags) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + init_keycodes(); + + g_window_data.window_width = width; + g_window_data.window_height = height; + + g_window_data.dst_width = width; + g_window_data.dst_height = height; + + g_window_data.buffer_width = width; + g_window_data.buffer_height = height; + + [NSApplication sharedApplication]; + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + +#if defined(USE_METAL_API) + g_metal_device = MTLCreateSystemDefaultDevice(); + + if (!g_metal_device) { + printf("Your device/OS doesn't support Metal."); + return -1; + } + + if (!create_shaders()) { + return -2; + } +#endif + + NSWindowStyleMask styles = NSWindowStyleMaskClosable | NSWindowStyleMaskTitled; + + if (flags & WF_BORDERLESS) + styles |= NSWindowStyleMaskBorderless; + + if (flags & WF_RESIZABLE) + styles |= NSWindowStyleMaskResizable; + + NSRect rectangle = NSMakeRect(0, 0, width, height); + g_window_data.window = [[OSXWindow alloc] initWithContentRect:rectangle styleMask:styles backing:NSBackingStoreBuffered defer:NO]; + if (!g_window_data.window) + return -3; + +#if defined(USE_METAL_API) + g_window_data.draw_buffer = malloc(width * height * 4); + + if (!g_window_data.draw_buffer) + return -4; + + // Setup command queue + g_command_queue = [g_metal_device newCommandQueue]; + + WindowViewController* viewController = [WindowViewController new]; + + MTLTextureDescriptor* textureDescriptor = [[MTLTextureDescriptor alloc] init]; + + // Indicate that each pixel has a blue, green, red, and alpha channel, where each channel is + // an 8-bit unsigned normalized value (i.e. 0 maps to 0.0 and 255 maps to 1.0) + textureDescriptor.pixelFormat = MTLPixelFormatBGRA8Unorm; + + // Set the pixel dimensions of the texture + textureDescriptor.width = width; + textureDescriptor.height = height; + + // Create the texture from the device by using the descriptor + + for (int i = 0; i < MaxBuffersInFlight; ++i) { + viewController->m_texture_buffers[i] = [g_metal_device newTextureWithDescriptor:textureDescriptor]; + } + + // Used for syncing the CPU and GPU + viewController->m_semaphore = dispatch_semaphore_create(MaxBuffersInFlight); + viewController->m_draw_buffer = g_window_data.draw_buffer; + viewController->m_width = width; + viewController->m_height = height; + + MTKView* view = [[MTKView alloc] initWithFrame:rectangle]; + view.device = g_metal_device; + view.delegate = viewController; + view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; + [g_window_data.window.contentView addSubview:view]; + + g_window_data.buffer_width = width; + g_window_data.buffer_height = height; + + //[g_window_data.window updateSize]; +#endif + + [g_window_data.window setTitle:[NSString stringWithUTF8String:name]]; + [g_window_data.window setReleasedWhenClosed:NO]; + [g_window_data.window performSelectorOnMainThread:@selector(makeKeyAndOrderFront:) withObject:nil waitUntilDone:YES]; + [g_window_data.window setAcceptsMouseMovedEvents:YES]; + + [g_window_data.window center]; + + [NSApp activateIgnoringOtherApps:YES]; + +#if defined(USE_METAL_API) + [NSApp finishLaunching]; +#endif + + if (g_keyboard_func == 0x0) { + mfb_keyboard_callback(keyboard_default); + } + +#if defined(USE_METAL_API) + NSLog(@"Window created using Metal API"); +#else + NSLog(@"Window created using Cocoa API"); +#endif + + [pool drain]; + + return 1; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void keyboard_default(void *user_data, Key key, KeyMod mod, bool isPressed) { + kUnused(user_data); + kUnused(mod); + kUnused(isPressed); + if (key == KB_KEY_ESCAPE) + g_window_data.close = true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void mfb_close() +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + g_window_data.close = true; + if (g_window_data.window) + [g_window_data.window close]; + + [pool drain]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static int update_events() +{ + NSEvent* event; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + do + { + event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; + if (event) { + [NSApp sendEvent:event]; + } + } + while ((g_window_data.close == false) && event); + + [pool release]; + + if(g_window_data.close == true) + return -1; + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int mfb_update(void* buffer) +{ + if(buffer == 0x0) + return -2; + +#if defined(USE_METAL_API) + memcpy(g_window_data.draw_buffer, buffer, g_window_data.buffer_width * g_window_data.buffer_height * 4); +#else + g_window_data.draw_buffer = buffer; +#endif + + int state = update_events(); + if(g_window_data.close == false) + [[g_window_data.window contentView] setNeedsDisplay:YES]; + + return state; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +bool mfb_set_viewport(unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) +{ + if(offset_x + width > g_window_data.window_width) { + return false; + } + if(offset_y + height > g_window_data.window_height) { + return false; + } + + g_window_data.dst_offset_x = offset_x; + g_window_data.dst_offset_y = offset_y; + g_window_data.dst_width = width; + g_window_data.dst_height = height; + +#if defined(USE_METAL_API) + float x1 = ((float) offset_x / g_window_data.window_width) * 2.0f - 1.0f; + float x2 = (((float) offset_x + width) / g_window_data.window_width) * 2.0f - 1.0f; + float y1 = ((float) offset_y / g_window_data.window_height) * 2.0f - 1.0f; + float y2 = (((float) offset_y + height) / g_window_data.window_height) * 2.0f - 1.0f; + + gVertices[0].x = x1; + gVertices[0].y = y1; + + gVertices[1].x = x1; + gVertices[1].y = y2; + + gVertices[2].x = x2; + gVertices[2].y = y1; + + gVertices[3].x = x2; + gVertices[3].y = y2; +#endif + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +extern short int keycodes[512]; + +void init_keycodes() +{ + // Clear keys + for (unsigned int i = 0; i < sizeof(keycodes) / sizeof(keycodes[0]); ++i) + keycodes[i] = 0; + + keycodes[0x1D] = KB_KEY_0; + keycodes[0x12] = KB_KEY_1; + keycodes[0x13] = KB_KEY_2; + keycodes[0x14] = KB_KEY_3; + keycodes[0x15] = KB_KEY_4; + keycodes[0x17] = KB_KEY_5; + keycodes[0x16] = KB_KEY_6; + keycodes[0x1A] = KB_KEY_7; + keycodes[0x1C] = KB_KEY_8; + keycodes[0x19] = KB_KEY_9; + keycodes[0x00] = KB_KEY_A; + keycodes[0x0B] = KB_KEY_B; + keycodes[0x08] = KB_KEY_C; + keycodes[0x02] = KB_KEY_D; + keycodes[0x0E] = KB_KEY_E; + keycodes[0x03] = KB_KEY_F; + keycodes[0x05] = KB_KEY_G; + keycodes[0x04] = KB_KEY_H; + keycodes[0x22] = KB_KEY_I; + keycodes[0x26] = KB_KEY_J; + keycodes[0x28] = KB_KEY_K; + keycodes[0x25] = KB_KEY_L; + keycodes[0x2E] = KB_KEY_M; + keycodes[0x2D] = KB_KEY_N; + keycodes[0x1F] = KB_KEY_O; + keycodes[0x23] = KB_KEY_P; + keycodes[0x0C] = KB_KEY_Q; + keycodes[0x0F] = KB_KEY_R; + keycodes[0x01] = KB_KEY_S; + keycodes[0x11] = KB_KEY_T; + keycodes[0x20] = KB_KEY_U; + keycodes[0x09] = KB_KEY_V; + keycodes[0x0D] = KB_KEY_W; + keycodes[0x07] = KB_KEY_X; + keycodes[0x10] = KB_KEY_Y; + keycodes[0x06] = KB_KEY_Z; + + keycodes[0x27] = KB_KEY_APOSTROPHE; + keycodes[0x2A] = KB_KEY_BACKSLASH; + keycodes[0x2B] = KB_KEY_COMMA; + keycodes[0x18] = KB_KEY_EQUAL; + keycodes[0x32] = KB_KEY_GRAVE_ACCENT; + keycodes[0x21] = KB_KEY_LEFT_BRACKET; + keycodes[0x1B] = KB_KEY_MINUS; + keycodes[0x2F] = KB_KEY_PERIOD; + keycodes[0x1E] = KB_KEY_RIGHT_BRACKET; + keycodes[0x29] = KB_KEY_SEMICOLON; + keycodes[0x2C] = KB_KEY_SLASH; + keycodes[0x0A] = KB_KEY_WORLD_1; + + keycodes[0x33] = KB_KEY_BACKSPACE; + keycodes[0x39] = KB_KEY_CAPS_LOCK; + keycodes[0x75] = KB_KEY_DELETE; + keycodes[0x7D] = KB_KEY_DOWN; + keycodes[0x77] = KB_KEY_END; + keycodes[0x24] = KB_KEY_ENTER; + keycodes[0x35] = KB_KEY_ESCAPE; + keycodes[0x7A] = KB_KEY_F1; + keycodes[0x78] = KB_KEY_F2; + keycodes[0x63] = KB_KEY_F3; + keycodes[0x76] = KB_KEY_F4; + keycodes[0x60] = KB_KEY_F5; + keycodes[0x61] = KB_KEY_F6; + keycodes[0x62] = KB_KEY_F7; + keycodes[0x64] = KB_KEY_F8; + keycodes[0x65] = KB_KEY_F9; + keycodes[0x6D] = KB_KEY_F10; + keycodes[0x67] = KB_KEY_F11; + keycodes[0x6F] = KB_KEY_F12; + keycodes[0x69] = KB_KEY_F13; + keycodes[0x6B] = KB_KEY_F14; + keycodes[0x71] = KB_KEY_F15; + keycodes[0x6A] = KB_KEY_F16; + keycodes[0x40] = KB_KEY_F17; + keycodes[0x4F] = KB_KEY_F18; + keycodes[0x50] = KB_KEY_F19; + keycodes[0x5A] = KB_KEY_F20; + keycodes[0x73] = KB_KEY_HOME; + keycodes[0x72] = KB_KEY_INSERT; + keycodes[0x7B] = KB_KEY_LEFT; + keycodes[0x3A] = KB_KEY_LEFT_ALT; + keycodes[0x3B] = KB_KEY_LEFT_CONTROL; + keycodes[0x38] = KB_KEY_LEFT_SHIFT; + keycodes[0x37] = KB_KEY_LEFT_SUPER; + keycodes[0x6E] = KB_KEY_MENU; + keycodes[0x47] = KB_KEY_NUM_LOCK; + keycodes[0x79] = KB_KEY_PAGE_DOWN; + keycodes[0x74] = KB_KEY_PAGE_UP; + keycodes[0x7C] = KB_KEY_RIGHT; + keycodes[0x3D] = KB_KEY_RIGHT_ALT; + keycodes[0x3E] = KB_KEY_RIGHT_CONTROL; + keycodes[0x3C] = KB_KEY_RIGHT_SHIFT; + keycodes[0x36] = KB_KEY_RIGHT_SUPER; + keycodes[0x31] = KB_KEY_SPACE; + keycodes[0x30] = KB_KEY_TAB; + keycodes[0x7E] = KB_KEY_UP; + + keycodes[0x52] = KB_KEY_KP_0; + keycodes[0x53] = KB_KEY_KP_1; + keycodes[0x54] = KB_KEY_KP_2; + keycodes[0x55] = KB_KEY_KP_3; + keycodes[0x56] = KB_KEY_KP_4; + keycodes[0x57] = KB_KEY_KP_5; + keycodes[0x58] = KB_KEY_KP_6; + keycodes[0x59] = KB_KEY_KP_7; + keycodes[0x5B] = KB_KEY_KP_8; + keycodes[0x5C] = KB_KEY_KP_9; + keycodes[0x45] = KB_KEY_KP_ADD; + keycodes[0x41] = KB_KEY_KP_DECIMAL; + keycodes[0x4B] = KB_KEY_KP_DIVIDE; + keycodes[0x4C] = KB_KEY_KP_ENTER; + keycodes[0x51] = KB_KEY_KP_EQUAL; + keycodes[0x43] = KB_KEY_KP_MULTIPLY; + keycodes[0x4E] = KB_KEY_KP_SUBTRACT; +} diff --git a/src/macosx/OSXWindow.h b/src/macosx/OSXWindow.h index 28bf33f..61a92e7 100644 --- a/src/macosx/OSXWindow.h +++ b/src/macosx/OSXWindow.h @@ -1,16 +1,10 @@ -#import - -// @class OSXWindowFrameView; - -@interface OSXWindow : NSWindow -{ - NSView* childContentView; - @public bool closed; -#if defined(USE_METAL_API) - @public int width; - @public int height; - @public void* draw_buffer; -#endif -} - -@end +#import + +// @class OSXWindowFrameView; + +@interface OSXWindow : NSWindow +{ + NSView *childContentView; +} + +@end diff --git a/src/macosx/OSXWindow.m b/src/macosx/OSXWindow.m index cd3d63c..9b1a4ab 100644 --- a/src/macosx/OSXWindow.m +++ b/src/macosx/OSXWindow.m @@ -1,155 +1,276 @@ -#import "OSXWindow.h" -#import "OSXWindowFrameView.h" - -@implementation OSXWindow - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#if !defined(USE_METAL_API) -- (id)initWithContentRect:(NSRect)contentRect - styleMask:(NSWindowStyleMask)windowStyle - backing:(NSBackingStoreType)bufferingType - defer:(BOOL)deferCreation -{ - self = [super - initWithContentRect:contentRect - styleMask:windowStyle - backing:bufferingType - defer:deferCreation]; - if (self) - { - [self setOpaque:YES]; - [self setBackgroundColor:[NSColor clearColor]]; - - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(mainWindowChanged:) - name:NSWindowDidBecomeMainNotification - object:self]; - - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(mainWindowChanged:) - name:NSWindowDidResignMainNotification - object:self]; - - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(willClose) - name:NSWindowWillCloseNotification - object:self]; - - closed = false; - } - return self; -} -#endif - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] - removeObserver:self]; - [super dealloc]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (void)setContentSize:(NSSize)newSize -{ - NSSize sizeDelta = newSize; - NSSize childBoundsSize = [childContentView bounds].size; - sizeDelta.width -= childBoundsSize.width; - sizeDelta.height -= childBoundsSize.height; - - OSXWindowFrameView *frameView = [super contentView]; - NSSize newFrameSize = [frameView bounds].size; - newFrameSize.width += sizeDelta.width; - newFrameSize.height += sizeDelta.height; - - [super setContentSize:newFrameSize]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (void)mainWindowChanged:(NSNotification *)aNotification -{ - (void)aNotification; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (void)setContentView:(NSView *)aView -{ - if ([childContentView isEqualTo:aView]) - { - return; - } - - NSRect bounds = [self frame]; - bounds.origin = NSZeroPoint; - - OSXWindowFrameView *frameView = [super contentView]; - if (!frameView) - { - frameView = [[[OSXWindowFrameView alloc] initWithFrame:bounds] autorelease]; - - [super setContentView:frameView]; - } - - if (childContentView) - { - [childContentView removeFromSuperview]; - } - childContentView = aView; - [childContentView setFrame:[self contentRectForFrameRect:bounds]]; - [childContentView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - [frameView addSubview:childContentView]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (NSView *)contentView -{ - return childContentView; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (BOOL)canBecomeKeyWindow -{ - return YES; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (BOOL)canBecomeMainWindow -{ - return YES; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (NSRect)contentRectForFrameRect:(NSRect)windowFrame -{ - windowFrame.origin = NSZeroPoint; - return NSInsetRect(windowFrame, 0, 0); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -+ (NSRect)frameRectForContentRect:(NSRect)windowContentRect styleMask:(NSWindowStyleMask)windowStyle -{ - (void)windowStyle; - return NSInsetRect(windowContentRect, 0, 0); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (void)willClose -{ - closed = true; -} - -@end +#import "OSXWindow.h" +#import "OSXWindowFrameView.h" +#include "OSXWindowData.h" +#include +#include + +extern SWindowData g_window_data; +extern short int g_keycodes[512]; + +bool gActive = false; + +@implementation OSXWindow + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (id)initWithContentRect:(NSRect)contentRect + styleMask:(NSWindowStyleMask)windowStyle + backing:(NSBackingStoreType)bufferingType + defer:(BOOL)deferCreation +{ + self = [super + initWithContentRect:contentRect + styleMask:windowStyle + backing:bufferingType + defer:deferCreation]; + + if (self) + { + [self setOpaque:YES]; + [self setBackgroundColor:[NSColor clearColor]]; + + self.delegate = self; + } + return self; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] + removeObserver:self]; + [super dealloc]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)setContentSize:(NSSize)newSize +{ + NSSize sizeDelta = newSize; + NSSize childBoundsSize = [childContentView bounds].size; + sizeDelta.width -= childBoundsSize.width; + sizeDelta.height -= childBoundsSize.height; + + OSXWindowFrameView *frameView = [super contentView]; + NSSize newFrameSize = [frameView bounds].size; + newFrameSize.width += sizeDelta.width; + newFrameSize.height += sizeDelta.height; + + [super setContentSize:newFrameSize]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +-(void)flagsChanged:(NSEvent *)event +{ + const uint32_t flags = [event modifierFlags]; + uint32_t mod_keys = 0, mod_keys_aux = 0; + + //NSEventModifierFlagHelp = 1 << 22, + //NSEventModifierFlagFunction = 1 << 23, + if(flags & NSEventModifierFlagCapsLock) { + mod_keys |= KB_MOD_CAPS_LOCK; + } + if(flags & NSEventModifierFlagShift) { + mod_keys |= KB_MOD_SHIFT; + } + if(flags & NSEventModifierFlagControl) { + mod_keys |= KB_MOD_CONTROL; + } + if(flags & NSEventModifierFlagOption) { + mod_keys |= KB_MOD_ALT; + } + if(flags & NSEventModifierFlagCommand) { + mod_keys |= KB_MOD_SUPER; + } + if(flags & NSEventModifierFlagNumericPad) { + mod_keys |= KB_MOD_NUM_LOCK; + } + + if(mod_keys != g_window_data.mod_keys) { + short int keyCode = keycodes[[event keyCode] & 0x1ff]; + if(keyCode != KB_KEY_UNKNOWN) { + mod_keys_aux = mod_keys ^ g_window_data.mod_keys; + if(mod_keys_aux & KB_MOD_CAPS_LOCK) { + kCall(g_keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_CAPS_LOCK) != 0); + } + if(mod_keys_aux & KB_MOD_SHIFT) { + kCall(g_keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_SHIFT) != 0); + } + if(mod_keys_aux & KB_MOD_CONTROL) { + kCall(g_keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_CONTROL) != 0); + } + if(mod_keys_aux & KB_MOD_ALT) { + kCall(g_keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_ALT) != 0); + } + if(mod_keys_aux & KB_MOD_SUPER) { + kCall(g_keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_SUPER) != 0); + } + if(mod_keys_aux & KB_MOD_NUM_LOCK) { + kCall(g_keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_NUM_LOCK) != 0); + } + } + } + g_window_data.mod_keys = mod_keys; + //NSLog(@"KeyCode: %d (%x) - %x", [event keyCode], [event keyCode], flags); + + [super flagsChanged:event]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)keyDown:(NSEvent *)event +{ + short int keyCode = keycodes[[event keyCode] & 0x1ff]; + kCall(g_keyboard_func, keyCode, g_window_data.mod_keys, true); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)keyUp:(NSEvent *)event +{ + short int keyCode = keycodes[[event keyCode] & 0x1ff]; + kCall(g_keyboard_func, keyCode, g_window_data.mod_keys, false); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)insertText:(id)string replacementRange:(NSRange)replacementRange +{ + NSString *characters; + NSUInteger length; + + kUnused(replacementRange); + + if ([string isKindOfClass:[NSAttributedString class]]) + characters = [string string]; + else + characters = (NSString*) string; + + length = [characters length]; + for (NSUInteger i = 0; i < length; i++) + { + const unichar code = [characters characterAtIndex:i]; + if ((code & 0xff00) == 0xf700) + continue; + + kCall(g_char_input_func, code); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)mainWindowChanged:(NSNotification *)notification +{ + kUnused(notification); + + if(gActive == true) { + gActive = false; + kCall(g_active_func, false); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)setContentView:(NSView *)aView +{ + if ([childContentView isEqualTo:aView]) + { + return; + } + NSRect bounds = [self frame]; + bounds.origin = NSZeroPoint; + + OSXWindowFrameView *frameView = [super contentView]; + if (!frameView) + { + frameView = [[[OSXWindowFrameView alloc] initWithFrame:bounds] autorelease]; + + [super setContentView:frameView]; + } + + if (childContentView) + { + [childContentView removeFromSuperview]; + } + childContentView = aView; + [childContentView setFrame:[self contentRectForFrameRect:bounds]]; + [childContentView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + [frameView addSubview:childContentView]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (NSView *)contentView +{ + return childContentView; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)canBecomeKeyWindow +{ + return YES; +} + +- (void)windowDidBecomeKey:(NSNotification *)notification +{ + kUnused(notification); + kCall(g_active_func, true); +} + +- (void)windowDidResignKey:(NSNotification *)notification +{ + kUnused(notification); + kCall(g_active_func, false); +} + +- (void)windowWillClose:(NSNotification *)notification { + kUnused(notification); + g_window_data.close = true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)canBecomeMainWindow +{ + return YES; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (NSRect)contentRectForFrameRect:(NSRect)windowFrame +{ + windowFrame.origin = NSZeroPoint; + return NSInsetRect(windowFrame, 0, 0); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ++ (NSRect)frameRectForContentRect:(NSRect)windowContentRect styleMask:(NSWindowStyleMask)windowStyle +{ + kUnused(windowStyle); + return NSInsetRect(windowContentRect, 0, 0); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)willClose +{ + g_window_data.close = true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)windowDidResize:(NSNotification *)notification { + kUnused(notification); + CGSize size = [self contentRectForFrameRect:[self frame]].size; + + g_window_data.window_width = size.width; + g_window_data.window_height = size.height; + + kCall(g_resize_func, size.width, size.height); +} + +@end diff --git a/src/macosx/OSXWindowData.h b/src/macosx/OSXWindowData.h new file mode 100644 index 0000000..b0ebc0b --- /dev/null +++ b/src/macosx/OSXWindowData.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +@class OSXWindow; + +typedef struct { + OSXWindow *window; + uint32_t window_width; + uint32_t window_height; + + uint32_t dst_offset_x; + uint32_t dst_offset_y; + uint32_t dst_width; + uint32_t dst_height; + + void *draw_buffer; + uint32_t buffer_width; + uint32_t buffer_height; + uint32_t mod_keys; + bool close; +} SWindowData; diff --git a/src/macosx/OSXWindowFrameView.h b/src/macosx/OSXWindowFrameView.h index 92bb70f..93e6173 100644 --- a/src/macosx/OSXWindowFrameView.h +++ b/src/macosx/OSXWindowFrameView.h @@ -1,35 +1,39 @@ -#import - -#if defined(USE_METAL_API) -#import - -// Number of textures in flight (tripple buffered) -static const int MaxBuffersInFlight = 3; - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@interface WindowViewController : NSViewController -{ - @public id m_texture_buffers[MaxBuffersInFlight]; - @public int m_current_buffer; - @public void* m_draw_buffer; - @public int m_width; - @public int m_height; - // Used for syncing with CPU/GPU - @public dispatch_semaphore_t m_semaphore; -} - -@end -#endif - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@interface OSXWindowFrameView : NSView -{ -#if defined(USE_METAL_API) - @private NSTrackingArea* trackingArea; -#endif -} - -@end - +#import + +#if defined(USE_METAL_API) +#import + +typedef struct Vertex { + float x, y, z, w; +} Vertex; + +// Number of textures in flight (tripple buffered) +static const int MaxBuffersInFlight = 3; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface WindowViewController : NSViewController +{ + @public id m_texture_buffers[MaxBuffersInFlight]; + @public int m_current_buffer; + @public void* m_draw_buffer; + @public int m_width; + @public int m_height; + // Used for syncing with CPU/GPU + @public dispatch_semaphore_t m_semaphore; +} + +@end +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface OSXWindowFrameView : NSView +{ +#if defined(USE_METAL_API) + @private NSTrackingArea* trackingArea; +#endif +} + +@end + diff --git a/src/macosx/OSXWindowFrameView.m b/src/macosx/OSXWindowFrameView.m index 2ff218e..fc278ec 100644 --- a/src/macosx/OSXWindowFrameView.m +++ b/src/macosx/OSXWindowFrameView.m @@ -1,155 +1,319 @@ -#import "OSXWindowFrameView.h" - -#if defined(USE_METAL_API) -#import - -id g_metal_device; -id g_command_queue; -id g_library; -id g_pipeline_state; - -@implementation WindowViewController - --(void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size -{ - (void)view; - (void)size; - // resize -} - --(void)drawInMTKView:(nonnull MTKView *)view -{ - // Wait to ensure only MaxBuffersInFlight number of frames are getting proccessed - // by any stage in the Metal pipeline (App, Metal, Drivers, GPU, etc) - dispatch_semaphore_wait(m_semaphore, DISPATCH_TIME_FOREVER); - - // Iterate through our Metal buffers, and cycle back to the first when we've written to MaxBuffersInFlight - m_current_buffer = (m_current_buffer + 1) % MaxBuffersInFlight; - - // Calculate the number of bytes per row of our image. - NSUInteger bytesPerRow = 4 * m_width; - MTLRegion region = { { 0, 0, 0 }, { m_width, m_height, 1 } }; - - // Copy the bytes from our data object into the texture - [m_texture_buffers[m_current_buffer] replaceRegion:region - mipmapLevel:0 withBytes:m_draw_buffer bytesPerRow:bytesPerRow]; - - // Create a new command buffer for each render pass to the current drawable - id commandBuffer = [g_command_queue commandBuffer]; - commandBuffer.label = @"minifb_command_buffer"; - - // Add completion hander which signals _inFlightSemaphore when Metal and the GPU has fully - // finished processing the commands we're encoding this frame. This indicates when the - // dynamic buffers filled with our vertices, that we're writing to this frame, will no longer - // be needed by Metal and the GPU, meaning we can overwrite the buffer contents without - // corrupting the rendering. - __block dispatch_semaphore_t block_sema = m_semaphore; - [commandBuffer addCompletedHandler:^(id buffer) - { - (void)buffer; - dispatch_semaphore_signal(block_sema); - }]; - - MTLRenderPassDescriptor* renderPassDescriptor = view.currentRenderPassDescriptor; - - if (renderPassDescriptor != nil) - { - renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(1.0, 0.0, 0.0, 1.0); - - // Create a render command encoder so we can render into something - id renderEncoder = - [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; - renderEncoder.label = @"minifb_command_encoder"; - - // Set render command encoder state - [renderEncoder setRenderPipelineState:g_pipeline_state]; - - [renderEncoder setFragmentTexture:m_texture_buffers[m_current_buffer] atIndex:0]; - - // Draw the vertices of our quads - [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle - vertexStart:0 - vertexCount:3]; - - // We're done encoding commands - [renderEncoder endEncoding]; - - // Schedule a present once the framebuffer is complete using the current drawable - [commandBuffer presentDrawable:view.currentDrawable]; - } - - // Finalize rendering here & push the command buffer to the GPU - [commandBuffer commit]; -} -@end -#endif - -@implementation OSXWindowFrameView - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#if defined(USE_METAL_API) --(void)updateTrackingAreas -{ - if(trackingArea != nil) { - [self removeTrackingArea:trackingArea]; - [trackingArea release]; - } - - int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways); - trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds] - options:opts - owner:self - userInfo:nil]; - [self addTrackingArea:trackingArea]; -} -#else -extern void* g_updateBuffer; -extern int g_width; -extern int g_height; - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (NSRect)resizeRect -{ - const CGFloat resizeBoxSize = 16.0; - const CGFloat contentViewPadding = 5.5; - - NSRect contentViewRect = [[self window] contentRectForFrameRect:[[self window] frame]]; - NSRect resizeRect = NSMakeRect( - NSMaxX(contentViewRect) + contentViewPadding, - NSMinY(contentViewRect) - resizeBoxSize - contentViewPadding, - resizeBoxSize, - resizeBoxSize); - - return resizeRect; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (void)drawRect:(NSRect)rect -{ - (void)rect; - - if (!g_updateBuffer) - return; - - CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; - - CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); - CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, g_updateBuffer, g_width * g_height * 4, NULL); - - CGImageRef img = CGImageCreate(g_width, g_height, 8, 32, g_width * 4, space, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little, - provider, NULL, false, kCGRenderingIntentDefault); - - CGColorSpaceRelease(space); - CGDataProviderRelease(provider); - - CGContextDrawImage(context, CGRectMake(0, 0, g_width, g_height), img); - - CGImageRelease(img); -} -#endif - -@end - +#import "OSXWindowFrameView.h" +#import "OSXWindow.h" +#include "OSXWindowData.h" +#include + +extern SWindowData g_window_data; + +#if defined(USE_METAL_API) +#import + +id g_metal_device; +id g_command_queue; +id g_library; +id g_pipeline_state; + +extern Vertex gVertices[4]; + +@implementation WindowViewController + +-(void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size +{ + (void)view; + (void)size; + // resize +} + +-(void)drawInMTKView:(nonnull MTKView *)view +{ + // Wait to ensure only MaxBuffersInFlight number of frames are getting proccessed + // by any stage in the Metal pipeline (App, Metal, Drivers, GPU, etc) + dispatch_semaphore_wait(m_semaphore, DISPATCH_TIME_FOREVER); + + // Iterate through our Metal buffers, and cycle back to the first when we've written to MaxBuffersInFlight + m_current_buffer = (m_current_buffer + 1) % MaxBuffersInFlight; + + // Calculate the number of bytes per row of our image. + NSUInteger bytesPerRow = 4 * m_width; + MTLRegion region = { { 0, 0, 0 }, { m_width, m_height, 1 } }; + + // Copy the bytes from our data object into the texture + [m_texture_buffers[m_current_buffer] replaceRegion:region + mipmapLevel:0 withBytes:m_draw_buffer bytesPerRow:bytesPerRow]; + + // Create a new command buffer for each render pass to the current drawable + id commandBuffer = [g_command_queue commandBuffer]; + commandBuffer.label = @"minifb_command_buffer"; + + // Add completion hander which signals _inFlightSemaphore when Metal and the GPU has fully + // finished processing the commands we're encoding this frame. This indicates when the + // dynamic buffers filled with our vertices, that we're writing to this frame, will no longer + // be needed by Metal and the GPU, meaning we can overwrite the buffer contents without + // corrupting the rendering. + __block dispatch_semaphore_t block_sema = m_semaphore; + [commandBuffer addCompletedHandler:^(id buffer) + { + (void)buffer; + dispatch_semaphore_signal(block_sema); + }]; + + MTLRenderPassDescriptor* renderPassDescriptor = view.currentRenderPassDescriptor; + + if (renderPassDescriptor != nil) + { + renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0); + + // Create a render command encoder so we can render into something + id renderEncoder = + [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; + renderEncoder.label = @"minifb_command_encoder"; + + // Set render command encoder state + [renderEncoder setRenderPipelineState:g_pipeline_state]; + + [renderEncoder setVertexBytes:gVertices + length:sizeof(gVertices) + atIndex:0]; + + [renderEncoder setFragmentTexture:m_texture_buffers[m_current_buffer] atIndex:0]; + + // Draw the vertices of our quads + // [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle + // vertexStart:0 + // vertexCount:3]; + [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip + vertexStart:0 + vertexCount:4]; + + // We're done encoding commands + [renderEncoder endEncoding]; + + // Schedule a present once the framebuffer is complete using the current drawable + [commandBuffer presentDrawable:view.currentDrawable]; + } + + // Finalize rendering here & push the command buffer to the GPU + [commandBuffer commit]; +} +@end +#endif + +@implementation OSXWindowFrameView + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if defined(USE_METAL_API) +-(void)updateTrackingAreas +{ + if(trackingArea != nil) { + [self removeTrackingArea:trackingArea]; + [trackingArea release]; + } + + int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways); + trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds] + options:opts + owner:self + userInfo:nil]; + [self addTrackingArea:trackingArea]; +} +#else + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (NSRect)resizeRect +{ + const CGFloat resizeBoxSize = 16.0; + const CGFloat contentViewPadding = 5.5; + + NSRect contentViewRect = [[self window] contentRectForFrameRect:[[self window] frame]]; + NSRect resizeRect = NSMakeRect( + NSMaxX(contentViewRect) + contentViewPadding, + NSMinY(contentViewRect) - resizeBoxSize - contentViewPadding, + resizeBoxSize, + resizeBoxSize); + + return resizeRect; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)drawRect:(NSRect)rect +{ + (void)rect; + + if (!g_window_data.window || !g_window_data.draw_buffer) + return; + + CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; + + CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); + CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, g_window_data.draw_buffer, g_window_data.buffer_width * g_window_data.buffer_height * 4, NULL); + + CGImageRef img = CGImageCreate(g_window_data.buffer_width, g_window_data.buffer_height, 8, 32, g_window_data.buffer_width * 4, space, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little, + provider, NULL, false, kCGRenderingIntentDefault); + + const CGFloat components[] = {0.0f, 0.0f, 0.0f, 1.0f}; + const CGColorRef black = CGColorCreate(space, components); + + CGColorSpaceRelease(space); + CGDataProviderRelease(provider); + + if(g_window_data.dst_offset_x != 0 || g_window_data.dst_offset_y != 0 || g_window_data.dst_width != g_window_data.window_width || g_window_data.dst_height != g_window_data.window_height) { + CGContextSetFillColorWithColor(context, black); + CGContextFillRect(context, CGRectMake(0, 0, g_window_data.window_width, g_window_data.window_height)); + } + + CGContextDrawImage(context, CGRectMake(g_window_data.dst_offset_x, g_window_data.dst_offset_y, g_window_data.dst_width, g_window_data.dst_height), img); + + CGImageRelease(img); +} +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)acceptsFirstMouse:(NSEvent *)event +{ + (void)event; + return YES; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)mouseDown:(NSEvent*)event +{ + (void)event; + kCall(g_mouse_btn_func, MOUSE_BTN_1, g_window_data.mod_keys, true); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)mouseUp:(NSEvent*)event +{ + (void)event; + kCall(g_mouse_btn_func, MOUSE_BTN_1, g_window_data.mod_keys, false); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)rightMouseDown:(NSEvent*)event +{ + (void)event; + kCall(g_mouse_btn_func, MOUSE_BTN_2, g_window_data.mod_keys, true); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)rightMouseUp:(NSEvent*)event +{ + (void)event; + kCall(g_mouse_btn_func, MOUSE_BTN_1, g_window_data.mod_keys, false); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)otherMouseDown:(NSEvent *)event +{ + (void)event; + kCall(g_mouse_btn_func, [event buttonNumber], g_window_data.mod_keys, true); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)otherMouseUp:(NSEvent *)event +{ + (void)event; + kCall(g_mouse_btn_func, [event buttonNumber], g_window_data.mod_keys, false); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)scrollWheel:(NSEvent *)event +{ + kCall(g_mouse_wheel_func, g_window_data.mod_keys, [event deltaX], [event deltaY]); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)mouseDragged:(NSEvent *)event +{ + [self mouseMoved:event]; +} + +- (void)rightMouseDragged:(NSEvent *)event +{ + [self mouseMoved:event]; +} + +- (void)otherMouseDragged:(NSEvent *)event +{ + [self mouseMoved:event]; +} + +- (void)mouseMoved:(NSEvent *)event +{ + NSPoint point = [event locationInWindow]; + //NSPoint localPoint = [self convertPoint:point fromView:nil]; + kCall(g_mouse_move_func, point.x, point.y); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)mouseExited:(NSEvent *)event +{ + (void)event; + //printf("mouse exit\n"); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)mouseEntered:(NSEvent *)event +{ + (void)event; + //printf("mouse enter\n"); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)canBecomeKeyView +{ + return YES; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (NSView *)nextValidKeyView +{ + return self; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (NSView *)previousValidKeyView +{ + return self; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)viewDidMoveToWindow +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [super dealloc]; +} + +@end + diff --git a/src/wayland/WaylandMiniFB.c b/src/wayland/WaylandMiniFB.c index cbd7bf4..73db7b5 100644 --- a/src/wayland/WaylandMiniFB.c +++ b/src/wayland/WaylandMiniFB.c @@ -1,6 +1,10 @@ #include +#include "MiniFB_internal.h" +#include "MiniFB_enums.h" +#include "WaylandWindowData.h" #include +#include #include #include @@ -10,276 +14,802 @@ #include #include +#include #include -static struct wl +SWindowData g_window_data = { 0 }; + +static void +destroy(void) { - struct wl_display *display; - struct wl_registry *registry; - struct wl_compositor *compositor; - struct wl_shell *shell; - struct wl_seat *seat; - struct wl_keyboard *keyboard; - struct wl_shm *shm; - struct wl_shm_pool *shm_pool; - struct wl_surface *surface; - struct wl_shell_surface *shell_surface; + if (! g_window_data.display) + return; - uint32_t seat_version; - uint32_t shm_format; - uint32_t width; - uint32_t height; - uint32_t stride; - uint32_t *shm_ptr; - struct wl_buffer *buffer; - int should_close; -} wl; +#define KILL(NAME) \ + do \ + { \ + if (g_window_data.NAME) \ + wl_##NAME##_destroy(g_window_data.NAME); \ + } while (0); \ + g_window_data.NAME = 0x0; -static void destroy(void) -{ - if (! wl.display) - return; - -#define KILL(NAME) \ - do \ - { \ - if (wl.NAME) \ - wl_##NAME##_destroy(wl.NAME); \ - } while (0) - KILL(shell_surface); - KILL(shell); - KILL(surface); - KILL(buffer); - KILL(shm_pool); - KILL(shm); - KILL(compositor); - KILL(keyboard); - KILL(seat); - KILL(registry); + KILL(shell_surface); + KILL(shell); + KILL(surface); + //KILL(buffer); + if(g_window_data.draw_buffer) { + wl_buffer_destroy(g_window_data.draw_buffer); + g_window_data.draw_buffer = 0x0; + } + KILL(shm_pool); + KILL(shm); + KILL(compositor); + KILL(keyboard); + KILL(seat); + KILL(registry); #undef KILL - wl_display_disconnect(wl.display); - memset(&wl, 0, sizeof(wl)); + wl_display_disconnect(g_window_data.display); + memset(&g_window_data, 0, sizeof(SWindowData)); } -static void nop() {} - -#define NO_FUNC (void (*)()) nop - -static void keyboard_key(void *data, struct wl_keyboard *wl_keyboard, - uint32_t serial, uint32_t time, uint32_t key, - uint32_t state) +// This event provides a file descriptor to the client which can be memory-mapped +// to provide a keyboard mapping description. +// format: keymap format +// fd: keymap file descriptor +// size: keymap size, in bytes +static void +keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size) { - if (state == WL_KEYBOARD_KEY_STATE_RELEASED && key == KEY_ESC) - { - wl.should_close = 1; - } + kUnused(data); + kUnused(keyboard); + kUnused(format); + kUnused(fd); + kUnused(size); +} + +// Notification that this seat's keyboard focus is on a certain surface. +// serial: serial number of the enter event +// surface: surface gaining keyboard focus +// keys: the currently pressed keys +static void +keyboard_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) +{ + kUnused(data); + kUnused(keyboard); + kUnused(serial); + kUnused(surface); + kUnused(keys); + kCall(g_active_func, true); +} + +// The leave notification is sent before the enter notification for the new focus. +// serial: serial number of the leave event +// surface: surface that lost keyboard focus +static void +keyboard_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) +{ + kUnused(data); + kUnused(keyboard); + kUnused(serial); + kUnused(surface); + kCall(g_active_func, false); +} + +// A key was pressed or released. The time argument is a timestamp with +// millisecond granularity, with an undefined base. +// serial: serial number of the key event +// time: timestamp with millisecond granularity +// key: key that produced the event +// state: physical state of the key +static void +keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) +{ + kUnused(data); + kUnused(keyboard); + kUnused(serial); + kUnused(time); + if(key < 512) { + Key kb_key = (Key) keycodes[key]; + bool is_pressed = (bool) (state == WL_KEYBOARD_KEY_STATE_PRESSED); + switch (kb_key) + { + case KB_KEY_LEFT_SHIFT: + case KB_KEY_RIGHT_SHIFT: + if(is_pressed) + g_window_data.mod_keys |= KB_MOD_SHIFT; + else + g_window_data.mod_keys &= ~KB_MOD_SHIFT; + break; + + case KB_KEY_LEFT_CONTROL: + case KB_KEY_RIGHT_CONTROL: + if(is_pressed) + g_window_data.mod_keys |= KB_MOD_CONTROL; + else + g_window_data.mod_keys &= ~KB_MOD_CONTROL; + break; + + case KB_KEY_LEFT_ALT: + case KB_KEY_RIGHT_ALT: + if(is_pressed) + g_window_data.mod_keys |= KB_MOD_ALT; + else + g_window_data.mod_keys &= ~KB_MOD_ALT; + break; + + case KB_KEY_LEFT_SUPER: + case KB_KEY_RIGHT_SUPER: + if(is_pressed) + g_window_data.mod_keys |= KB_MOD_SUPER; + else + g_window_data.mod_keys &= ~KB_MOD_SUPER; + break; + } + + kCall(g_keyboard_func, kb_key, (KeyMod)g_window_data.mod_keys, is_pressed); + } +} + +// Notifies clients that the modifier and/or group state has changed, +// and it should update its local state. +// serial: serial number of the modifiers event +// mods_depressed: depressed modifiers +// mods_latched: latched modifiers +// mods_locked: locked modifiers +// group: keyboard layout +static void +keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) +{ + kUnused(data); + kUnused(keyboard); + kUnused(serial); + kUnused(mods_depressed); + kUnused(mods_latched); + kUnused(mods_locked); + kUnused(group); + // it is not easy to identify them here :( +} + +// Informs the client about the keyboard's repeat rate and delay. +// rate: the rate of repeating keys in characters per second +// delay: delay in milliseconds since key down until repeating starts +static void +keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay) +{ + kUnused(data); + kUnused(keyboard); + kUnused(rate); + kUnused(delay); } static const struct wl_keyboard_listener keyboard_listener = { - .keymap = NO_FUNC, - .enter = NO_FUNC, - .leave = NO_FUNC, - .key = keyboard_key, - .modifiers = NO_FUNC, - .repeat_info = NO_FUNC, + .keymap = keyboard_keymap, + .enter = keyboard_enter, + .leave = keyboard_leave, + .key = keyboard_key, + .modifiers = keyboard_modifiers, + .repeat_info = NULL, }; -static void seat_capabilities(void *data, struct wl_seat *seat, - enum wl_seat_capability caps) +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Notification that this seat's pointer is focused on a certain surface. +// +// When a seat's focus enters a surface, the pointer image is +// undefined and a client should respond to this event by setting +// an appropriate pointer image with the set_cursor request. +// +// serial: serial number of the enter event +// surface: surface entered by the pointer +// sx: surface-local x coordinate +// sy: surface-local y coordinate +static void +pointer_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t sx, wl_fixed_t sy) { - if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !wl.keyboard) - { - wl.keyboard = wl_seat_get_keyboard(seat); - wl_keyboard_add_listener(wl.keyboard, &keyboard_listener, NULL); - } - else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && wl.keyboard) - { - wl_keyboard_destroy(wl.keyboard); - wl.keyboard = NULL; - } + kUnused(data); + //kUnused(pointer); + //kUnused(serial); + kUnused(surface); + kUnused(sx); + kUnused(sy); + struct wl_buffer *buffer; + struct wl_cursor_image *image; + + image = g_window_data.default_cursor->images[0]; + buffer = wl_cursor_image_get_buffer(image); + + wl_pointer_set_cursor(pointer, serial, g_window_data.cursor_surface, image->hotspot_x, image->hotspot_y); + wl_surface_attach(g_window_data.cursor_surface, buffer, 0, 0); + wl_surface_damage(g_window_data.cursor_surface, 0, 0, image->width, image->height); + wl_surface_commit(g_window_data.cursor_surface); + //fprintf(stderr, "Pointer entered surface %p at %d %d\n", surface, sx, sy); +} + +// Notification that this seat's pointer is no longer focused on a certain surface. +// +// The leave notification is sent before the enter notification for the new focus. +// +// serial: serial number of the leave event +// surface: surface left by the pointer +static void +pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) +{ + kUnused(data); + kUnused(pointer); + kUnused(serial); + kUnused(surface); + //fprintf(stderr, "Pointer left surface %p\n", surface); +} + +// Notification of pointer location change. +// +// The arguments sx and sy are the location relative to the focused surface. +// +// time: timestamp with millisecond granularity +// sx: surface-local x coordinate +// sy: surface-local y coordinate +static void +pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy) +{ + kUnused(data); + kUnused(pointer); + kUnused(time); + //printf("Pointer moved at %f %f\n", sx / 256.0f, sy / 256.0f); + kCall(g_mouse_move_func, sx >> 24, sy >> 24); +} + +// Mouse button click and release notifications. +// +// The location of the click is given by the last motion or enter +// event. The time argument is a timestamp with millisecond +// granularity, with an undefined base. +// +// The button is a button code as defined in the Linux kernel's +// linux/input-event-codes.h header file, e.g. BTN_LEFT. +// +// Any 16-bit button code value is reserved for future additions to +// the kernel's event code list. All other button codes above +// 0xFFFF are currently undefined but may be used in future +// versions of this protocol. +// +// serial: serial number of the button event +// time: timestamp with millisecond granularity +// button: button that produced the event +// state: physical state of the button +static void +pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) +{ + kUnused(data); + kUnused(pointer); + kUnused(serial); + kUnused(time); + //printf("Pointer button '%d'(%d)\n", button, state); + kCall(g_mouse_btn_func, button - BTN_MOUSE + 1, g_window_data.mod_keys, state == 1); +} + +// Scroll and other axis notifications. +// +// For scroll events (vertical and horizontal scroll axes), the +// value parameter is the length of a vector along the specified +// axis in a coordinate space identical to those of motion events, +// representing a relative movement along the specified axis. +// +// For devices that support movements non-parallel to axes multiple +// axis events will be emitted. +// +// When applicable, for example for touch pads, the server can +// choose to emit scroll events where the motion vector is +// equivalent to a motion event vector. +// +// When applicable, a client can transform its content relative to +// the scroll distance. +// +// time: timestamp with millisecond granularity +// axis: axis type +// value: length of vector in surface-local coordinate space +static void +pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) +{ + kUnused(data); + kUnused(pointer); + kUnused(time); + kUnused(axis); + //printf("Pointer handle axis: axis: %d (0x%x)\n", axis, value); + if(axis == 0) { + kCall(g_mouse_wheel_func, g_window_data.mod_keys, 0.0f, -(value / 256.0f)); + } + else if(axis == 1) { + kCall(g_mouse_wheel_func, g_window_data.mod_keys, -(value / 256.0f), 0.0f); + } +} + +static void +frame(void *data, struct wl_pointer *pointer) { + kUnused(data); + kUnused(pointer); +} + +static void +axis_source(void *data, struct wl_pointer *pointer, uint32_t axis_source) { + kUnused(data); + kUnused(pointer); + kUnused(axis_source); +} + +static void +axis_stop(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis) { + kUnused(data); + kUnused(pointer); + kUnused(time); + kUnused(axis); +} + +static void +axis_discrete(void *data, struct wl_pointer *pointer, uint32_t axis, int32_t discrete) { + kUnused(data); + kUnused(pointer); + kUnused(axis); + kUnused(discrete); +} + +static const struct wl_pointer_listener pointer_listener = { + .enter = pointer_enter, + .leave = pointer_leave, + .motion = pointer_motion, + .button = pointer_button, + .axis = pointer_axis, + .frame = NULL, + .axis_source = NULL, + .axis_stop = NULL, + .axis_discrete = NULL, +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static void +seat_capabilities(void *data, struct wl_seat *seat, enum wl_seat_capability caps) +{ + kUnused(data); + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !g_window_data.keyboard) + { + g_window_data.keyboard = wl_seat_get_keyboard(seat); + wl_keyboard_add_listener(g_window_data.keyboard, &keyboard_listener, NULL); + } + else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && g_window_data.keyboard) + { + wl_keyboard_destroy(g_window_data.keyboard); + g_window_data.keyboard = NULL; + } + + if ((caps & WL_SEAT_CAPABILITY_POINTER) && !g_window_data.pointer) + { + g_window_data.pointer = wl_seat_get_pointer(seat); + wl_pointer_add_listener(g_window_data.pointer, &pointer_listener, NULL); + } + else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && g_window_data.pointer) + { + wl_pointer_destroy(g_window_data.pointer); + g_window_data.pointer = NULL; + } +} + +static void +seat_name(void *data, struct wl_seat *seat, const char *name) { + kUnused(data); + kUnused(seat); + printf("Seat '%s'n", name); } static const struct wl_seat_listener seat_listener = { - .capabilities = seat_capabilities, .name = NO_FUNC, + .capabilities = seat_capabilities, + .name = NULL, }; -static void shm_format(void *data, struct wl_shm *shm, uint32_t format) -{ - if (wl.shm_format == -1u) - { - switch (format) - { - // We could do RGBA, but that would not be what is expected from minifb... - /* case WL_SHM_FORMAT_ARGB8888: */ - case WL_SHM_FORMAT_XRGB8888: - wl.shm_format = format; - break; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - default: - break; - } - } +// pixel format description +// +// Informs the client about a valid pixel format that can be used +// for buffers. Known formats include argb8888 and xrgb8888. +// +// format: buffer pixel format +static void +shm_format(void *data, struct wl_shm *shm, uint32_t format) +{ + kUnused(data); + kUnused(shm); + if (g_window_data.shm_format == -1u) + { + switch (format) + { + // We could do RGBA, but that would not be what is expected from minifb... + // case WL_SHM_FORMAT_ARGB8888: + case WL_SHM_FORMAT_XRGB8888: + g_window_data.shm_format = format; + break; + + default: + break; + } + } } -static const struct wl_shm_listener shm_listener = {.format = shm_format}; +static const struct wl_shm_listener shm_listener = { + .format = shm_format +}; -static void registry_global(void *data, struct wl_registry *registry, - uint32_t id, char const *iface, uint32_t version) +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static void +registry_global(void *data, struct wl_registry *registry, uint32_t id, char const *iface, uint32_t version) { - if (strcmp(iface, "wl_compositor") == 0) - { - wl.compositor = - wl_registry_bind(registry, id, &wl_compositor_interface, 1); - } - else if (strcmp(iface, "wl_shm") == 0) - { - wl.shm = wl_registry_bind(registry, id, &wl_shm_interface, 1); - if (wl.shm) - wl_shm_add_listener(wl.shm, &shm_listener, NULL); - } - else if (strcmp(iface, "wl_shell") == 0) - { - wl.shell = wl_registry_bind(registry, id, &wl_shell_interface, 1); - } - else if (strcmp(iface, "wl_seat") == 0) - { - wl.seat = wl_registry_bind(registry, id, &wl_seat_interface, 1); - if (wl.seat) - { - wl_seat_add_listener(wl.seat, &seat_listener, NULL); - } - } + kUnused(data); + kUnused(version); + if (strcmp(iface, "wl_compositor") == 0) + { + g_window_data.compositor = (struct wl_compositor *) wl_registry_bind(registry, id, &wl_compositor_interface, 1); + } + else if (strcmp(iface, "wl_shm") == 0) + { + g_window_data.shm = (struct wl_shm *) wl_registry_bind(registry, id, &wl_shm_interface, 1); + if (g_window_data.shm) { + wl_shm_add_listener(g_window_data.shm, &shm_listener, NULL); + g_window_data.cursor_theme = wl_cursor_theme_load(NULL, 32, g_window_data.shm); + g_window_data.default_cursor = wl_cursor_theme_get_cursor(g_window_data.cursor_theme, "left_ptr"); + } + } + else if (strcmp(iface, "wl_shell") == 0) + { + g_window_data.shell = (struct wl_shell *) wl_registry_bind(registry, id, &wl_shell_interface, 1); + } + else if (strcmp(iface, "wl_seat") == 0) + { + g_window_data.seat = (struct wl_seat *) wl_registry_bind(registry, id, &wl_seat_interface, 1); + if (g_window_data.seat) + { + wl_seat_add_listener(g_window_data.seat, &seat_listener, NULL); + } + } } static const struct wl_registry_listener registry_listener = { - .global = registry_global, .global_remove = NO_FUNC, + .global = registry_global, + .global_remove = NULL, }; -int mfb_open(const char *title, int width, int height) +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int +mfb_open_ex(const char* title, int width, int height, int flags) { + // TODO: Not yet + kUnused(flags); + return mfb_open(title, width, height); +} + +int +mfb_open(const char *title, int width, int height) { - int fd = -1; + int fd = -1; - wl.display = wl_display_connect(NULL); - if (!wl.display) - return -1; - wl.registry = wl_display_get_registry(wl.display); - wl_registry_add_listener(wl.registry, ®istry_listener, NULL); - if (wl_display_roundtrip(wl.display) == -1 || - wl_display_roundtrip(wl.display) == -1) - { - return -1; - } + g_window_data.shm_format = -1u; - // did not get a format we want... meh - if (wl.shm_format == -1) - goto out; - if (!wl.compositor) - goto out; + g_window_data.display = wl_display_connect(NULL); + if (!g_window_data.display) + return -1; + g_window_data.registry = wl_display_get_registry(g_window_data.display); + wl_registry_add_listener(g_window_data.registry, ®istry_listener, NULL); - char const *xdg_rt_dir = getenv("XDG_RUNTIME_DIR"); - char shmfile[PATH_MAX]; - int ret = snprintf(shmfile, sizeof(shmfile), "%s/WaylandMiniFB-SHM-XXXXXX", - xdg_rt_dir); - if (ret >= sizeof(shmfile)) - goto out; + init_keycodes(); - fd = mkstemp(shmfile); - if (fd == -1) - goto out; - unlink(shmfile); + if (wl_display_dispatch(g_window_data.display) == -1 || wl_display_roundtrip(g_window_data.display) == -1) + { + return -1; + } - uint32_t length = sizeof(uint32_t) * width * height; + // did not get a format we want... meh + if (g_window_data.shm_format == -1u) + goto out; + if (!g_window_data.compositor) + goto out; - if (ftruncate(fd, length) == -1) - goto out; + char const *xdg_rt_dir = getenv("XDG_RUNTIME_DIR"); + char shmfile[PATH_MAX]; + uint32_t ret = snprintf(shmfile, sizeof(shmfile), "%s/WaylandMiniFB-SHM-XXXXXX", xdg_rt_dir); + if (ret >= sizeof(shmfile)) + goto out; - wl.shm_ptr = mmap(NULL, length, PROT_WRITE, MAP_SHARED, fd, 0); - if (wl.shm_ptr == MAP_FAILED) - goto out; + fd = mkstemp(shmfile); + if (fd == -1) + goto out; + unlink(shmfile); - wl.width = width; - wl.height = height; - wl.stride = width * sizeof(uint32_t); - wl.shm_pool = wl_shm_create_pool(wl.shm, fd, length); - wl.buffer = wl_shm_pool_create_buffer(wl.shm_pool, 0, wl.width, wl.height, - wl.stride, wl.shm_format); + uint32_t length = sizeof(uint32_t) * width * height; - close(fd); - fd = -1; + if (ftruncate(fd, length) == -1) + goto out; - wl.surface = wl_compositor_create_surface(wl.compositor); - if (!wl.surface) - goto out; + g_window_data.shm_ptr = (uint32_t *) mmap(NULL, length, PROT_WRITE, MAP_SHARED, fd, 0); + if (g_window_data.shm_ptr == MAP_FAILED) + goto out; - // There should always be a shell, right? - if (wl.shell) - { - wl.shell_surface = wl_shell_get_shell_surface(wl.shell, wl.surface); - if (!wl.shell_surface) - goto out; + g_window_data.window_width = width; + g_window_data.window_height = height; + g_window_data.buffer_width = width; + g_window_data.buffer_height = height; + g_window_data.buffer_stride = width * sizeof(uint32_t); + g_window_data.dst_offset_x = 0; + g_window_data.dst_offset_y = 0; + g_window_data.dst_width = width; + g_window_data.dst_height = height; - wl_shell_surface_set_title(wl.shell_surface, title); - wl_shell_surface_set_toplevel(wl.shell_surface); - } + g_window_data.shm_pool = wl_shm_create_pool(g_window_data.shm, fd, length); + g_window_data.draw_buffer = wl_shm_pool_create_buffer(g_window_data.shm_pool, 0, + g_window_data.buffer_width, g_window_data.buffer_height, + g_window_data.buffer_stride, g_window_data.shm_format); - wl_surface_attach(wl.surface, wl.buffer, 0, 0); - wl_surface_damage(wl.surface, 0, 0, width, height); - wl_surface_commit(wl.surface); + close(fd); + fd = -1; - return 1; + g_window_data.surface = wl_compositor_create_surface(g_window_data.compositor); + if (!g_window_data.surface) + goto out; + + g_window_data.cursor_surface = wl_compositor_create_surface(g_window_data.compositor); + + // There should always be a shell, right? + if (g_window_data.shell) + { + g_window_data.shell_surface = wl_shell_get_shell_surface(g_window_data.shell, g_window_data.surface); + if (!g_window_data.shell_surface) + goto out; + + wl_shell_surface_set_title(g_window_data.shell_surface, title); + wl_shell_surface_set_toplevel(g_window_data.shell_surface); + } + + wl_surface_attach(g_window_data.surface, g_window_data.draw_buffer, g_window_data.dst_offset_x, g_window_data.dst_offset_y); + wl_surface_damage(g_window_data.surface, g_window_data.dst_offset_x, g_window_data.dst_offset_y, g_window_data.dst_width, g_window_data.dst_height); + wl_surface_commit(g_window_data.surface); + + if (g_keyboard_func == 0x0) { + mfb_keyboard_callback(keyboard_default); + } + + printf("Window created using Wayland API\n"); + + return 1; out: - close(fd); - destroy(); - return 0; -} - -static void frame_done(void *data, struct wl_callback *callback, - uint32_t cookie) -{ - wl_callback_destroy(callback); - *(uint32_t *)data = 1; -} - -static const struct wl_callback_listener frame_listener = { - .done = frame_done, -}; - -int mfb_update(void *buffer) -{ - uint32_t done = 0; - - if (!wl.display || wl_display_get_error(wl.display) != 0) - return -1; - - if (wl.should_close) - return -1; - - // update shm buffer - memcpy(wl.shm_ptr, buffer, wl.stride * wl.height); - - wl_surface_attach(wl.surface, wl.buffer, 0, 0); - wl_surface_damage(wl.surface, 0, 0, wl.width, wl.height); - - struct wl_callback *frame = wl_surface_frame(wl.surface); - if (!frame) - return -1; - - wl_callback_add_listener(frame, &frame_listener, &done); - - wl_surface_commit(wl.surface); - - while (!done) - if (wl_display_dispatch(wl.display) == -1) - { - wl_callback_destroy(frame); - return -1; - } - - return 0; + close(fd); + destroy(); + return 0; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void mfb_close(void) { destroy(); } +void keyboard_default(void *user_data, Key key, KeyMod mod, bool isPressed) { + kUnused(user_data); + kUnused(mod); + kUnused(isPressed); + if (key == KB_KEY_ESCAPE) + g_window_data.close = true; +} + +// done event +// +// Notify the client when the related request is done. +// +// callback_data: request-specific data for the callback +static void +frame_done(void *data, struct wl_callback *callback, uint32_t cookie) +{ + kUnused(cookie); + wl_callback_destroy(callback); + *(uint32_t *)data = 1; +} + +static const struct wl_callback_listener frame_listener = { + .done = frame_done, +}; + +int +mfb_update(void *buffer) +{ + uint32_t done = 0; + + if (!g_window_data.display || wl_display_get_error(g_window_data.display) != 0) + return -1; + + if (g_window_data.close == true) + return -1; + + // update shm buffer + memcpy(g_window_data.shm_ptr, buffer, g_window_data.buffer_stride * g_window_data.buffer_height); + + wl_surface_attach(g_window_data.surface, g_window_data.draw_buffer, g_window_data.dst_offset_x, g_window_data.dst_offset_y); + wl_surface_damage(g_window_data.surface, g_window_data.dst_offset_x, g_window_data.dst_offset_y, g_window_data.dst_width, g_window_data.dst_height); + + struct wl_callback *frame = wl_surface_frame(g_window_data.surface); + if (!frame) + return -1; + + wl_callback_add_listener(frame, &frame_listener, &done); + + wl_surface_commit(g_window_data.surface); + + while (!done && g_window_data.close == false) { + if (wl_display_dispatch(g_window_data.display) == -1 || wl_display_roundtrip(g_window_data.display) == -1) + { + wl_callback_destroy(frame); + return -1; + } + } + if(g_window_data.close == true) { + destroy(); + } + + //static int counter = 0; + //printf("update!: %d\n", counter++); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void +mfb_close(void) { + g_window_data.close = true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +extern short int keycodes[512]; + +void +init_keycodes(void) +{ + // Clear keys + for (size_t i = 0; i < sizeof(keycodes) / sizeof(keycodes[0]); ++i) + keycodes[i] = 0; + + keycodes[KEY_GRAVE] = KB_KEY_GRAVE_ACCENT; + keycodes[KEY_1] = KB_KEY_1; + keycodes[KEY_2] = KB_KEY_2; + keycodes[KEY_3] = KB_KEY_3; + keycodes[KEY_4] = KB_KEY_4; + keycodes[KEY_5] = KB_KEY_5; + keycodes[KEY_6] = KB_KEY_6; + keycodes[KEY_7] = KB_KEY_7; + keycodes[KEY_8] = KB_KEY_8; + keycodes[KEY_9] = KB_KEY_9; + keycodes[KEY_0] = KB_KEY_0; + keycodes[KEY_SPACE] = KB_KEY_SPACE; + keycodes[KEY_MINUS] = KB_KEY_MINUS; + keycodes[KEY_EQUAL] = KB_KEY_EQUAL; + keycodes[KEY_Q] = KB_KEY_Q; + keycodes[KEY_W] = KB_KEY_W; + keycodes[KEY_E] = KB_KEY_E; + keycodes[KEY_R] = KB_KEY_R; + keycodes[KEY_T] = KB_KEY_T; + keycodes[KEY_Y] = KB_KEY_Y; + keycodes[KEY_U] = KB_KEY_U; + keycodes[KEY_I] = KB_KEY_I; + keycodes[KEY_O] = KB_KEY_O; + keycodes[KEY_P] = KB_KEY_P; + keycodes[KEY_LEFTBRACE] = KB_KEY_LEFT_BRACKET; + keycodes[KEY_RIGHTBRACE] = KB_KEY_RIGHT_BRACKET; + keycodes[KEY_A] = KB_KEY_A; + keycodes[KEY_S] = KB_KEY_S; + keycodes[KEY_D] = KB_KEY_D; + keycodes[KEY_F] = KB_KEY_F; + keycodes[KEY_G] = KB_KEY_G; + keycodes[KEY_H] = KB_KEY_H; + keycodes[KEY_J] = KB_KEY_J; + keycodes[KEY_K] = KB_KEY_K; + keycodes[KEY_L] = KB_KEY_L; + keycodes[KEY_SEMICOLON] = KB_KEY_SEMICOLON; + keycodes[KEY_APOSTROPHE] = KB_KEY_APOSTROPHE; + keycodes[KEY_Z] = KB_KEY_Z; + keycodes[KEY_X] = KB_KEY_X; + keycodes[KEY_C] = KB_KEY_C; + keycodes[KEY_V] = KB_KEY_V; + keycodes[KEY_B] = KB_KEY_B; + keycodes[KEY_N] = KB_KEY_N; + keycodes[KEY_M] = KB_KEY_M; + keycodes[KEY_COMMA] = KB_KEY_COMMA; + keycodes[KEY_DOT] = KB_KEY_PERIOD; + keycodes[KEY_SLASH] = KB_KEY_SLASH; + keycodes[KEY_BACKSLASH] = KB_KEY_BACKSLASH; + keycodes[KEY_ESC] = KB_KEY_ESCAPE; + keycodes[KEY_TAB] = KB_KEY_TAB; + keycodes[KEY_LEFTSHIFT] = KB_KEY_LEFT_SHIFT; + keycodes[KEY_RIGHTSHIFT] = KB_KEY_RIGHT_SHIFT; + keycodes[KEY_LEFTCTRL] = KB_KEY_LEFT_CONTROL; + keycodes[KEY_RIGHTCTRL] = KB_KEY_RIGHT_CONTROL; + keycodes[KEY_LEFTALT] = KB_KEY_LEFT_ALT; + keycodes[KEY_RIGHTALT] = KB_KEY_RIGHT_ALT; + keycodes[KEY_LEFTMETA] = KB_KEY_LEFT_SUPER; + keycodes[KEY_RIGHTMETA] = KB_KEY_RIGHT_SUPER; + keycodes[KEY_MENU] = KB_KEY_MENU; + keycodes[KEY_NUMLOCK] = KB_KEY_NUM_LOCK; + keycodes[KEY_CAPSLOCK] = KB_KEY_CAPS_LOCK; + keycodes[KEY_PRINT] = KB_KEY_PRINT_SCREEN; + keycodes[KEY_SCROLLLOCK] = KB_KEY_SCROLL_LOCK; + keycodes[KEY_PAUSE] = KB_KEY_PAUSE; + keycodes[KEY_DELETE] = KB_KEY_DELETE; + keycodes[KEY_BACKSPACE] = KB_KEY_BACKSPACE; + keycodes[KEY_ENTER] = KB_KEY_ENTER; + keycodes[KEY_HOME] = KB_KEY_HOME; + keycodes[KEY_END] = KB_KEY_END; + keycodes[KEY_PAGEUP] = KB_KEY_PAGE_UP; + keycodes[KEY_PAGEDOWN] = KB_KEY_PAGE_DOWN; + keycodes[KEY_INSERT] = KB_KEY_INSERT; + keycodes[KEY_LEFT] = KB_KEY_LEFT; + keycodes[KEY_RIGHT] = KB_KEY_RIGHT; + keycodes[KEY_DOWN] = KB_KEY_DOWN; + keycodes[KEY_UP] = KB_KEY_UP; + keycodes[KEY_F1] = KB_KEY_F1; + keycodes[KEY_F2] = KB_KEY_F2; + keycodes[KEY_F3] = KB_KEY_F3; + keycodes[KEY_F4] = KB_KEY_F4; + keycodes[KEY_F5] = KB_KEY_F5; + keycodes[KEY_F6] = KB_KEY_F6; + keycodes[KEY_F7] = KB_KEY_F7; + keycodes[KEY_F8] = KB_KEY_F8; + keycodes[KEY_F9] = KB_KEY_F9; + keycodes[KEY_F10] = KB_KEY_F10; + keycodes[KEY_F11] = KB_KEY_F11; + keycodes[KEY_F12] = KB_KEY_F12; + keycodes[KEY_F13] = KB_KEY_F13; + keycodes[KEY_F14] = KB_KEY_F14; + keycodes[KEY_F15] = KB_KEY_F15; + keycodes[KEY_F16] = KB_KEY_F16; + keycodes[KEY_F17] = KB_KEY_F17; + keycodes[KEY_F18] = KB_KEY_F18; + keycodes[KEY_F19] = KB_KEY_F19; + keycodes[KEY_F20] = KB_KEY_F20; + keycodes[KEY_F21] = KB_KEY_F21; + keycodes[KEY_F22] = KB_KEY_F22; + keycodes[KEY_F23] = KB_KEY_F23; + keycodes[KEY_F24] = KB_KEY_F24; + keycodes[KEY_KPSLASH] = KB_KEY_KP_DIVIDE; + keycodes[KEY_KPDOT] = KB_KEY_KP_MULTIPLY; + keycodes[KEY_KPMINUS] = KB_KEY_KP_SUBTRACT; + keycodes[KEY_KPPLUS] = KB_KEY_KP_ADD; + keycodes[KEY_KP0] = KB_KEY_KP_0; + keycodes[KEY_KP1] = KB_KEY_KP_1; + keycodes[KEY_KP2] = KB_KEY_KP_2; + keycodes[KEY_KP3] = KB_KEY_KP_3; + keycodes[KEY_KP4] = KB_KEY_KP_4; + keycodes[KEY_KP5] = KB_KEY_KP_5; + keycodes[KEY_KP6] = KB_KEY_KP_6; + keycodes[KEY_KP7] = KB_KEY_KP_7; + keycodes[KEY_KP8] = KB_KEY_KP_8; + keycodes[KEY_KP9] = KB_KEY_KP_9; + keycodes[KEY_KPCOMMA] = KB_KEY_KP_DECIMAL; + keycodes[KEY_KPEQUAL] = KB_KEY_KP_EQUAL; + keycodes[KEY_KPENTER] = KB_KEY_KP_ENTER; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +bool +mfb_set_viewport(unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { + + if(offset_x + width > g_window_data.window_width) { + return false; + } + if(offset_y + height > g_window_data.window_height) { + return false; + } + + // TODO: Not yet + // g_window_data.dst_offset_x = offset_x; + // g_window_data.dst_offset_y = offset_y; + // g_window_data.dst_width = width; + // g_window_data.dst_height = height; + + return false; +} + diff --git a/src/wayland/WaylandWindowData.h b/src/wayland/WaylandWindowData.h new file mode 100644 index 0000000..bfd4c7d --- /dev/null +++ b/src/wayland/WaylandWindowData.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include + +struct wl_display; +struct wl_registry; +struct wl_compositor; +struct wl_shell; +struct wl_seat; +struct wl_keyboard; +struct wl_pointer; +struct wl_callback; +struct wl_shm; +struct wl_shm_pool; +struct wl_surface; +struct wl_shell_surface; +struct wl_buffer; + +typedef struct +{ + struct wl_display *display; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct wl_shell *shell; + struct wl_seat *seat; + struct wl_keyboard *keyboard; + + struct wl_pointer *pointer; + struct wl_cursor_theme *cursor_theme; + struct wl_cursor *default_cursor; + struct wl_surface *cursor_surface; + + struct wl_shm *shm; + struct wl_shm_pool *shm_pool; + struct wl_surface *surface; + struct wl_shell_surface *shell_surface; + + uint32_t seat_version; + uint32_t shm_format; + uint32_t *shm_ptr; + + uint32_t window_width; + uint32_t window_height; + uint32_t dst_offset_x; + uint32_t dst_offset_y; + uint32_t dst_width; + uint32_t dst_height; + + struct wl_buffer *draw_buffer; + uint32_t buffer_width; + uint32_t buffer_height; + uint32_t buffer_stride; + + uint32_t mod_keys; + bool close; +} SWindowData; diff --git a/src/windows/WinMiniFB.c b/src/windows/WinMiniFB.c index fdc1a03..1a2059a 100644 --- a/src/windows/WinMiniFB.c +++ b/src/windows/WinMiniFB.c @@ -1,146 +1,571 @@ -#include "MiniFB.h" - -#define WIN32_LEAN_AND_MEAN -#include +#include +#include +#include "WinWindowData.h" #include /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -static WNDCLASS s_wc; -static HWND s_wnd; -static int s_close = 0; -static int s_width; -static int s_height; -static HDC s_hdc; -static void* s_buffer; -static BITMAPINFO* s_bitmapInfo; +SWindowData g_window_data = { 0 }; + +long s_window_style = WS_POPUP | WS_SYSMENU | WS_CAPTION; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +uint32_t translate_mod(); +Key translate_key(unsigned int wParam, unsigned long lParam); + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - LRESULT res = 0; + LRESULT res = 0; - switch (message) - { - case WM_PAINT: - { - if (s_buffer) - { - StretchDIBits(s_hdc, 0, 0, s_width, s_height, 0, 0, s_width, s_height, s_buffer, - s_bitmapInfo, DIB_RGB_COLORS, SRCCOPY); + switch (message) + { + case WM_PAINT: + { + if (g_window_data.draw_buffer) + { + if (g_window_data.dst_offset_x > 0) { + BitBlt(g_window_data.s_hdc, 0, g_window_data.dst_offset_y, g_window_data.dst_offset_x, g_window_data.dst_height, 0, 0, 0, BLACKNESS); + } + if (g_window_data.dst_offset_y > 0) { + BitBlt(g_window_data.s_hdc, 0, 0, g_window_data.window_width, g_window_data.dst_offset_y, 0, 0, 0, BLACKNESS); + } + uint32_t offsetY = g_window_data.dst_offset_y + g_window_data.dst_height; + if (offsetY < g_window_data.window_height) { + BitBlt(g_window_data.s_hdc, 0, offsetY, g_window_data.window_width, g_window_data.window_height-offsetY, 0, 0, 0, BLACKNESS); + } + uint32_t offsetX = g_window_data.dst_offset_x + g_window_data.dst_width; + if (offsetX < g_window_data.window_width) { + BitBlt(g_window_data.s_hdc, offsetX, g_window_data.dst_offset_y, g_window_data.window_width-offsetX, g_window_data.dst_height, 0, 0, 0, BLACKNESS); + } - ValidateRect(hWnd, NULL); - } + StretchDIBits(g_window_data.s_hdc, g_window_data.dst_offset_x, g_window_data.dst_offset_y, g_window_data.dst_width, g_window_data.dst_height, 0, 0, g_window_data.buffer_width, g_window_data.buffer_height, g_window_data.draw_buffer, + g_window_data.s_bitmapInfo, DIB_RGB_COLORS, SRCCOPY); - break; - } + ValidateRect(hWnd, NULL); + } - case WM_KEYDOWN: - { - if ((wParam&0xFF) == 27) - s_close = 1; + break; + } - break; - } + case WM_DESTROY: + case WM_CLOSE: + { + g_window_data.close = true; + break; + } - case WM_CLOSE: - { - s_close = 1; - break; - } + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: + { + Key kb_key = translate_key((unsigned int)wParam, (unsigned long)lParam); + int is_pressed = !((lParam >> 31) & 1); + g_window_data.mod_keys = translate_mod(); - default: - { - res = DefWindowProc(hWnd, message, wParam, lParam); - } - } + if (kb_key == KB_KEY_UNKNOWN) + return FALSE; - return res; + kCall(g_keyboard_func, kb_key, g_window_data.mod_keys, is_pressed); + break; + } + + case WM_CHAR: + case WM_SYSCHAR: + case WM_UNICHAR: + { + + if(message == WM_UNICHAR && wParam == UNICODE_NOCHAR) { + // WM_UNICHAR is not sent by Windows, but is sent by some third-party input method engine + // Returning TRUE here announces support for this message + return TRUE; + } + + kCall(g_char_input_func, wParam); + break; + } + + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + case WM_XBUTTONUP: + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + case WM_RBUTTONDOWN: + case WM_RBUTTONDBLCLK: + case WM_MBUTTONDOWN: + case WM_MBUTTONDBLCLK: + case WM_XBUTTONDOWN: + case WM_XBUTTONDBLCLK: + { + MouseButton button = MOUSE_BTN_0; + g_window_data.mod_keys = translate_mod(); + int is_pressed = 0; + switch (message) { + case WM_LBUTTONDOWN: + is_pressed = 1; + case WM_LBUTTONUP: + button = MOUSE_BTN_1; + break; + case WM_RBUTTONDOWN: + is_pressed = 1; + case WM_RBUTTONUP: + button = MOUSE_BTN_2; + break; + case WM_MBUTTONDOWN: + is_pressed = 1; + case WM_MBUTTONUP: + button = MOUSE_BTN_3; + break; + + default: + button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? MOUSE_BTN_5 : MOUSE_BTN_6); + if (message == WM_XBUTTONDOWN) { + is_pressed = 1; + } + } + kCall(g_mouse_btn_func, button, g_window_data.mod_keys, is_pressed); + break; + } + + case WM_MOUSEWHEEL: + kCall(g_mouse_wheel_func, translate_mod(), 0.0f, (SHORT)HIWORD(wParam) / (float)WHEEL_DELTA); + break; + + case WM_MOUSEHWHEEL: + // This message is only sent on Windows Vista and later + // NOTE: The X-axis is inverted for consistency with macOS and X11 + kCall(g_mouse_wheel_func, translate_mod(), -((SHORT)HIWORD(wParam) / (float)WHEEL_DELTA), 0.0f); + break; + + case WM_MOUSEMOVE: + if(g_window_data.s_mouse_inside == false) { + g_window_data.s_mouse_inside = true; + TRACKMOUSEEVENT tme; + ZeroMemory(&tme, sizeof(tme)); + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = hWnd; + TrackMouseEvent(&tme); + } + kCall(g_mouse_move_func, ((int)(short)LOWORD(lParam)), ((int)(short)HIWORD(lParam))); + break; + + case WM_MOUSELEAVE: + g_window_data.s_mouse_inside = false; + break; + + case WM_SIZE: + { + g_window_data.dst_offset_x = 0; + g_window_data.dst_offset_y = 0; + g_window_data.dst_width = LOWORD(lParam); + g_window_data.dst_height = HIWORD(lParam); + g_window_data.window_width = g_window_data.dst_width; + g_window_data.window_height = g_window_data.dst_height; + kCall(g_resize_func, g_window_data.dst_width, g_window_data.dst_height); + break; + } + + case WM_SETFOCUS: + kCall(g_active_func, true); + break; + + case WM_KILLFOCUS: + kCall(g_active_func, false); + break; + + default: + { + res = DefWindowProc(hWnd, message, wParam, lParam); + } + } + + return res; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int mfb_open(const char* title, int width, int height) -{ - RECT rect = { 0 }; +int mfb_open_ex(const char* title, int width, int height, int flags) { + RECT rect = { 0 }; + int x, y; - s_wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW; - s_wc.lpfnWndProc = WndProc; - s_wc.hCursor = LoadCursor(0, IDC_ARROW); - s_wc.lpszClassName = title; - RegisterClass(&s_wc); + init_keycodes(); - rect.right = width; - rect.bottom = height; + g_window_data.buffer_width = width; + g_window_data.buffer_height = height; - AdjustWindowRect(&rect, WS_POPUP | WS_SYSMENU | WS_CAPTION, 0); + s_window_style = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME; + if (flags & WF_FULLSCREEN) { + flags = WF_FULLSCREEN; // Remove all other flags + x = 0; + y = 0; + rect.right = GetSystemMetrics(SM_CXSCREEN); + rect.bottom = GetSystemMetrics(SM_CYSCREEN); + s_window_style = WS_POPUP & ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU); - rect.right -= rect.left; - rect.bottom -= rect.top; + DEVMODE settings; + EnumDisplaySettings(0, 0, &settings); + settings.dmPelsWidth = GetSystemMetrics(SM_CXSCREEN); + settings.dmPelsHeight = GetSystemMetrics(SM_CYSCREEN); + settings.dmBitsPerPel = 32; + settings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; - s_width = width; - s_height = height; + if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { + flags = WF_FULLSCREEN_DESKTOP; + } + } - s_wnd = CreateWindowEx(0, - title, title, - WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME, - CW_USEDEFAULT, CW_USEDEFAULT, - rect.right, rect.bottom, - 0, 0, 0, 0); + if (flags & WF_BORDERLESS) { + s_window_style = WS_POPUP; + } - if (!s_wnd) - return 0; + if (flags & WF_RESIZABLE) { + s_window_style |= WS_MAXIMIZEBOX | WS_SIZEBOX; + } - ShowWindow(s_wnd, SW_NORMAL); + if (flags & WF_FULLSCREEN_DESKTOP) { + s_window_style = WS_OVERLAPPEDWINDOW; - s_bitmapInfo = (BITMAPINFO*)calloc(1, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 3); - s_bitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - s_bitmapInfo->bmiHeader.biPlanes = 1; - s_bitmapInfo->bmiHeader.biBitCount = 32; - s_bitmapInfo->bmiHeader.biCompression = BI_BITFIELDS; - s_bitmapInfo->bmiHeader.biWidth = width; - s_bitmapInfo->bmiHeader.biHeight = -height; - s_bitmapInfo->bmiColors[0].rgbRed = 0xff; - s_bitmapInfo->bmiColors[1].rgbGreen = 0xff; - s_bitmapInfo->bmiColors[2].rgbBlue = 0xff; + width = GetSystemMetrics(SM_CXFULLSCREEN); + height = GetSystemMetrics(SM_CYFULLSCREEN); - s_hdc = GetDC(s_wnd); + rect.right = width; + rect.bottom = height; + AdjustWindowRect(&rect, s_window_style, 0); + if (rect.left < 0) { + width += rect.left * 2; + rect.right += rect.left; + rect.left = 0; + } + if (rect.bottom > height) { + height -= (rect.bottom - height); + rect.bottom += (rect.bottom - height); + rect.top = 0; + } + x = 0; + y = 0; + } + else if (!(flags & WF_FULLSCREEN)) { + rect.right = width; + rect.bottom = height; - return 1; + AdjustWindowRect(&rect, s_window_style, 0); + + rect.right -= rect.left; + rect.bottom -= rect.top; + + x = (GetSystemMetrics(SM_CXSCREEN) - rect.right) / 2; + y = (GetSystemMetrics(SM_CYSCREEN) - rect.bottom + rect.top) / 2; + } + + g_window_data.s_wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW; + g_window_data.s_wc.lpfnWndProc = WndProc; + g_window_data.s_wc.hCursor = LoadCursor(0, IDC_ARROW); + g_window_data.s_wc.lpszClassName = title; + RegisterClass(&g_window_data.s_wc); + + if (g_window_data.dst_width == 0) + g_window_data.dst_width = width; + + if (g_window_data.dst_height == 0) + g_window_data.dst_height = height; + + g_window_data.window_width = rect.right; + g_window_data.window_height = rect.bottom; + + g_window_data.window = CreateWindowEx( + 0, + title, title, + s_window_style, + x, y, + g_window_data.window_width, g_window_data.window_height, + 0, 0, 0, 0); + + if (!g_window_data.window) + return 0; + + if (flags & WF_ALWAYS_ON_TOP) + SetWindowPos(g_window_data.window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + + ShowWindow(g_window_data.window, SW_NORMAL); + + g_window_data.s_bitmapInfo = (BITMAPINFO *) calloc(1, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 3); + g_window_data.s_bitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + g_window_data.s_bitmapInfo->bmiHeader.biPlanes = 1; + g_window_data.s_bitmapInfo->bmiHeader.biBitCount = 32; + g_window_data.s_bitmapInfo->bmiHeader.biCompression = BI_BITFIELDS; + g_window_data.s_bitmapInfo->bmiHeader.biWidth = g_window_data.buffer_width; + g_window_data.s_bitmapInfo->bmiHeader.biHeight = -(LONG)g_window_data.buffer_height; + g_window_data.s_bitmapInfo->bmiColors[0].rgbRed = 0xff; + g_window_data.s_bitmapInfo->bmiColors[1].rgbGreen = 0xff; + g_window_data.s_bitmapInfo->bmiColors[2].rgbBlue = 0xff; + + g_window_data.s_hdc = GetDC(g_window_data.window); + + if (g_keyboard_func == 0x0) { + mfb_keyboard_callback(keyboard_default); + } + + return 1; +} + +int mfb_open(const char* title, int width, int height) { + return mfb_open_ex(title, width, height, 0); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int mfb_update(void* buffer) { - MSG msg; - - s_buffer = buffer; + MSG msg; + + if (buffer == 0x0) + return -2; - InvalidateRect(s_wnd, NULL, TRUE); - SendMessage(s_wnd, WM_PAINT, 0, 0); + if (g_window_data.close == true) + return -1; - while (PeekMessage(&msg, s_wnd, 0, 0, PM_REMOVE)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } + g_window_data.draw_buffer = buffer; - if (s_close == 1) - return -1; + InvalidateRect(g_window_data.window, NULL, TRUE); + SendMessage(g_window_data.window, WM_PAINT, 0, 0); - return 0; + while (g_window_data.close == false && PeekMessage(&msg, g_window_data.window, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return 0; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void mfb_close() { - s_buffer = 0; - free(s_bitmapInfo); - ReleaseDC(s_wnd, s_hdc); - DestroyWindow(s_wnd); + g_window_data.draw_buffer = 0x0; + if (g_window_data.s_bitmapInfo != 0x0) { + free(g_window_data.s_bitmapInfo); + } + if (g_window_data.window != 0 && g_window_data.s_hdc != 0) { + ReleaseDC(g_window_data.window, g_window_data.s_hdc); + DestroyWindow(g_window_data.window); + } + + g_window_data.window = 0; + g_window_data.s_hdc = 0; + g_window_data.s_bitmapInfo = 0x0; + g_window_data.close = true; } +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void keyboard_default(void *user_data, Key key, KeyMod mod, bool isPressed) { + kUnused(user_data); + kUnused(mod); + kUnused(isPressed); + if (key == KB_KEY_ESCAPE) + g_window_data.close = true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +uint32_t translate_mod() { + uint32_t mods = 0; + + if (GetKeyState(VK_SHIFT) & 0x8000) + mods |= KB_MOD_SHIFT; + if (GetKeyState(VK_CONTROL) & 0x8000) + mods |= KB_MOD_CONTROL; + if (GetKeyState(VK_MENU) & 0x8000) + mods |= KB_MOD_ALT; + if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & 0x8000) + mods |= KB_MOD_SUPER; + if (GetKeyState(VK_CAPITAL) & 1) + mods |= KB_MOD_CAPS_LOCK; + if (GetKeyState(VK_NUMLOCK) & 1) + mods |= KB_MOD_NUM_LOCK; + + return mods; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +extern short int keycodes[512]; + +void init_keycodes() { + + // Clear keys + for (size_t i = 0; i < sizeof(keycodes) / sizeof(keycodes[0]); ++i) + keycodes[i] = 0; + + keycodes[0x00B] = KB_KEY_0; + keycodes[0x002] = KB_KEY_1; + keycodes[0x003] = KB_KEY_2; + keycodes[0x004] = KB_KEY_3; + keycodes[0x005] = KB_KEY_4; + keycodes[0x006] = KB_KEY_5; + keycodes[0x007] = KB_KEY_6; + keycodes[0x008] = KB_KEY_7; + keycodes[0x009] = KB_KEY_8; + keycodes[0x00A] = KB_KEY_9; + keycodes[0x01E] = KB_KEY_A; + keycodes[0x030] = KB_KEY_B; + keycodes[0x02E] = KB_KEY_C; + keycodes[0x020] = KB_KEY_D; + keycodes[0x012] = KB_KEY_E; + keycodes[0x021] = KB_KEY_F; + keycodes[0x022] = KB_KEY_G; + keycodes[0x023] = KB_KEY_H; + keycodes[0x017] = KB_KEY_I; + keycodes[0x024] = KB_KEY_J; + keycodes[0x025] = KB_KEY_K; + keycodes[0x026] = KB_KEY_L; + keycodes[0x032] = KB_KEY_M; + keycodes[0x031] = KB_KEY_N; + keycodes[0x018] = KB_KEY_O; + keycodes[0x019] = KB_KEY_P; + keycodes[0x010] = KB_KEY_Q; + keycodes[0x013] = KB_KEY_R; + keycodes[0x01F] = KB_KEY_S; + keycodes[0x014] = KB_KEY_T; + keycodes[0x016] = KB_KEY_U; + keycodes[0x02F] = KB_KEY_V; + keycodes[0x011] = KB_KEY_W; + keycodes[0x02D] = KB_KEY_X; + keycodes[0x015] = KB_KEY_Y; + keycodes[0x02C] = KB_KEY_Z; + + keycodes[0x028] = KB_KEY_APOSTROPHE; + keycodes[0x02B] = KB_KEY_BACKSLASH; + keycodes[0x033] = KB_KEY_COMMA; + keycodes[0x00D] = KB_KEY_EQUAL; + keycodes[0x029] = KB_KEY_GRAVE_ACCENT; + keycodes[0x01A] = KB_KEY_LEFT_BRACKET; + keycodes[0x00C] = KB_KEY_MINUS; + keycodes[0x034] = KB_KEY_PERIOD; + keycodes[0x01B] = KB_KEY_RIGHT_BRACKET; + keycodes[0x027] = KB_KEY_SEMICOLON; + keycodes[0x035] = KB_KEY_SLASH; + keycodes[0x056] = KB_KEY_WORLD_2; + + keycodes[0x00E] = KB_KEY_BACKSPACE; + keycodes[0x153] = KB_KEY_DELETE; + keycodes[0x14F] = KB_KEY_END; + keycodes[0x01C] = KB_KEY_ENTER; + keycodes[0x001] = KB_KEY_ESCAPE; + keycodes[0x147] = KB_KEY_HOME; + keycodes[0x152] = KB_KEY_INSERT; + keycodes[0x15D] = KB_KEY_MENU; + keycodes[0x151] = KB_KEY_PAGE_DOWN; + keycodes[0x149] = KB_KEY_PAGE_UP; + keycodes[0x045] = KB_KEY_PAUSE; + keycodes[0x146] = KB_KEY_PAUSE; + keycodes[0x039] = KB_KEY_SPACE; + keycodes[0x00F] = KB_KEY_TAB; + keycodes[0x03A] = KB_KEY_CAPS_LOCK; + keycodes[0x145] = KB_KEY_NUM_LOCK; + keycodes[0x046] = KB_KEY_SCROLL_LOCK; + keycodes[0x03B] = KB_KEY_F1; + keycodes[0x03C] = KB_KEY_F2; + keycodes[0x03D] = KB_KEY_F3; + keycodes[0x03E] = KB_KEY_F4; + keycodes[0x03F] = KB_KEY_F5; + keycodes[0x040] = KB_KEY_F6; + keycodes[0x041] = KB_KEY_F7; + keycodes[0x042] = KB_KEY_F8; + keycodes[0x043] = KB_KEY_F9; + keycodes[0x044] = KB_KEY_F10; + keycodes[0x057] = KB_KEY_F11; + keycodes[0x058] = KB_KEY_F12; + keycodes[0x064] = KB_KEY_F13; + keycodes[0x065] = KB_KEY_F14; + keycodes[0x066] = KB_KEY_F15; + keycodes[0x067] = KB_KEY_F16; + keycodes[0x068] = KB_KEY_F17; + keycodes[0x069] = KB_KEY_F18; + keycodes[0x06A] = KB_KEY_F19; + keycodes[0x06B] = KB_KEY_F20; + keycodes[0x06C] = KB_KEY_F21; + keycodes[0x06D] = KB_KEY_F22; + keycodes[0x06E] = KB_KEY_F23; + keycodes[0x076] = KB_KEY_F24; + keycodes[0x038] = KB_KEY_LEFT_ALT; + keycodes[0x01D] = KB_KEY_LEFT_CONTROL; + keycodes[0x02A] = KB_KEY_LEFT_SHIFT; + keycodes[0x15B] = KB_KEY_LEFT_SUPER; + keycodes[0x137] = KB_KEY_PRINT_SCREEN; + keycodes[0x138] = KB_KEY_RIGHT_ALT; + keycodes[0x11D] = KB_KEY_RIGHT_CONTROL; + keycodes[0x036] = KB_KEY_RIGHT_SHIFT; + keycodes[0x15C] = KB_KEY_RIGHT_SUPER; + keycodes[0x150] = KB_KEY_DOWN; + keycodes[0x14B] = KB_KEY_LEFT; + keycodes[0x14D] = KB_KEY_RIGHT; + keycodes[0x148] = KB_KEY_UP; + + keycodes[0x052] = KB_KEY_KP_0; + keycodes[0x04F] = KB_KEY_KP_1; + keycodes[0x050] = KB_KEY_KP_2; + keycodes[0x051] = KB_KEY_KP_3; + keycodes[0x04B] = KB_KEY_KP_4; + keycodes[0x04C] = KB_KEY_KP_5; + keycodes[0x04D] = KB_KEY_KP_6; + keycodes[0x047] = KB_KEY_KP_7; + keycodes[0x048] = KB_KEY_KP_8; + keycodes[0x049] = KB_KEY_KP_9; + keycodes[0x04E] = KB_KEY_KP_ADD; + keycodes[0x053] = KB_KEY_KP_DECIMAL; + keycodes[0x135] = KB_KEY_KP_DIVIDE; + keycodes[0x11C] = KB_KEY_KP_ENTER; + keycodes[0x037] = KB_KEY_KP_MULTIPLY; + keycodes[0x04A] = KB_KEY_KP_SUBTRACT; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +Key translate_key(unsigned int wParam, unsigned long lParam) { + if (wParam == VK_CONTROL) { + MSG next; + DWORD time; + + if (lParam & 0x01000000) + return KB_KEY_RIGHT_CONTROL; + + time = GetMessageTime(); + if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE)) + if (next.message == WM_KEYDOWN || next.message == WM_SYSKEYDOWN || next.message == WM_KEYUP || next.message == WM_SYSKEYUP) + if (next.wParam == VK_MENU && (next.lParam & 0x01000000) && next.time == time) + return KB_KEY_UNKNOWN; + + return KB_KEY_LEFT_CONTROL; + } + + if (wParam == VK_PROCESSKEY) + return KB_KEY_UNKNOWN; + + return (Key) keycodes[HIWORD(lParam) & 0x1FF]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +bool mfb_set_viewport(unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) +{ + if(offset_x + width > g_window_data.window_width) { + return false; + } + if(offset_y + height > g_window_data.window_height) { + return false; + } + + g_window_data.dst_offset_x = offset_x; + g_window_data.dst_offset_y = offset_y; + + g_window_data.dst_width = width; + g_window_data.dst_height = height; + + return true; +} diff --git a/src/windows/WinWindowData.h b/src/windows/WinWindowData.h new file mode 100644 index 0000000..57d5a8f --- /dev/null +++ b/src/windows/WinWindowData.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#define WIN32_LEAN_AND_MEAN +#include + + +typedef struct { + HWND window; + WNDCLASS s_wc; + HDC s_hdc; + BITMAPINFO *s_bitmapInfo; + bool s_mouse_inside; + + uint32_t window_width; + uint32_t window_height; + + uint32_t dst_offset_x; + uint32_t dst_offset_y; + uint32_t dst_width; + uint32_t dst_height; + + void *draw_buffer; + uint32_t buffer_width; + uint32_t buffer_height; + + uint32_t mod_keys; + bool close; +} SWindowData; diff --git a/src/x11/X11MiniFB.c b/src/x11/X11MiniFB.c index d2b46f4..0c0b413 100644 --- a/src/x11/X11MiniFB.c +++ b/src/x11/X11MiniFB.c @@ -1,148 +1,632 @@ -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#define KEY_FUNCTION 0xFF -#define KEY_ESC 0x1B - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -static Display* s_display; -static int s_screen; -static int s_width; -static int s_height; -static Window s_window; -static GC s_gc; -static XImage *s_ximage; - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int mfb_open(const char* title, int width, int height) -{ - int depth, i, formatCount, convDepth = -1; - XPixmapFormatValues* formats; - XSetWindowAttributes windowAttributes; - XSizeHints sizeHints; - Visual* visual; - - s_display = XOpenDisplay(0); - - if (!s_display) - return -1; - - s_screen = DefaultScreen(s_display); - visual = DefaultVisual(s_display, s_screen); - formats = XListPixmapFormats(s_display, &formatCount); - depth = DefaultDepth(s_display, s_screen); - Window defaultRootWindow = DefaultRootWindow(s_display); - - for (i = 0; i < formatCount; ++i) - { - if (depth == formats[i].depth) - { - convDepth = formats[i].bits_per_pixel; - break; - } - } - - XFree(formats); - - // We only support 32-bit right now - if (convDepth != 32) - { - XCloseDisplay(s_display); - return -1; - } - - int screenWidth = DisplayWidth(s_display, s_screen); - int screenHeight = DisplayHeight(s_display, s_screen); - - windowAttributes.border_pixel = BlackPixel(s_display, s_screen); - windowAttributes.background_pixel = BlackPixel(s_display, s_screen); - windowAttributes.backing_store = NotUseful; - - s_window = XCreateWindow(s_display, defaultRootWindow, (screenWidth - width) / 2, - (screenHeight - height) / 2, width, height, 0, depth, InputOutput, - visual, CWBackPixel | CWBorderPixel | CWBackingStore, - &windowAttributes); - if (!s_window) - return 0; - - XSelectInput(s_display, s_window, KeyPressMask | KeyReleaseMask); - XStoreName(s_display, s_window, title); - - sizeHints.flags = PPosition | PMinSize | PMaxSize; - sizeHints.x = 0; - sizeHints.y = 0; - sizeHints.min_width = width; - sizeHints.max_width = width; - sizeHints.min_height = height; - sizeHints.max_height = height; - - XSetWMNormalHints(s_display, s_window, &sizeHints); - XClearWindow(s_display, s_window); - XMapRaised(s_display, s_window); - XFlush(s_display); - - s_gc = DefaultGC(s_display, s_screen); - - s_ximage = XCreateImage(s_display, CopyFromParent, depth, ZPixmap, 0, NULL, width, height, 32, width * 4); - - s_width = width; - s_height = height; - - return 1; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -static int processEvents() -{ - XEvent event; - KeySym sym; - - if (!XPending(s_display)) - return 0; - - XNextEvent(s_display, &event); - - if (event.type != KeyPress) - return 0; - - sym = XLookupKeysym(&event.xkey, 0); - - if ((sym >> 8) != KEY_FUNCTION) - return 0; - - if ((sym & 0xFF) == KEY_ESC) - return -1; - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int mfb_update(void* buffer) -{ - s_ximage->data = (char*)buffer; - - XPutImage(s_display, s_window, s_gc, s_ximage, 0, 0, 0, 0, s_width, s_height); - XFlush(s_display); - - if (processEvents() < 0) - return -1; - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void mfb_close (void) -{ - s_ximage->data = NULL; - XDestroyImage(s_ximage); - XDestroyWindow(s_display, s_window); - XCloseDisplay(s_display); -} +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "X11WindowData.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +SWindowData g_window_data = { 0 }; + +extern void +stretch_image(uint32_t *srcImage, uint32_t srcX, uint32_t srcY, uint32_t srcWidth, uint32_t srcHeight, uint32_t srcPitch, + uint32_t *dstImage, uint32_t dstX, uint32_t dstY, uint32_t dstWidth, uint32_t dstHeight, uint32_t dstPitch); + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int mfb_open_ex(const char* title, int width, int height, int flags) { + int depth, i, formatCount, convDepth = -1; + XPixmapFormatValues* formats; + XSetWindowAttributes windowAttributes; + XSizeHints sizeHints; + Visual* visual; + + g_window_data.display = XOpenDisplay(0); + if (!g_window_data.display) + return -1; + + init_keycodes(); + + g_window_data.screen = DefaultScreen(g_window_data.display); + + visual = DefaultVisual(g_window_data.display, g_window_data.screen); + formats = XListPixmapFormats(g_window_data.display, &formatCount); + depth = DefaultDepth(g_window_data.display, g_window_data.screen); + + Window defaultRootWindow = DefaultRootWindow(g_window_data.display); + + for (i = 0; i < formatCount; ++i) + { + if (depth == formats[i].depth) + { + convDepth = formats[i].bits_per_pixel; + break; + } + } + + XFree(formats); + + // We only support 32-bit right now + if (convDepth != 32) + { + XCloseDisplay(g_window_data.display); + return -1; + } + + int screenWidth = DisplayWidth(g_window_data.display, g_window_data.screen); + int screenHeight = DisplayHeight(g_window_data.display, g_window_data.screen); + + windowAttributes.border_pixel = BlackPixel(g_window_data.display, g_window_data.screen); + windowAttributes.background_pixel = BlackPixel(g_window_data.display, g_window_data.screen); + windowAttributes.backing_store = NotUseful; + + int posX, posY; + int windowWidth, windowHeight; + + g_window_data.window_width = width; + g_window_data.window_height = height; + g_window_data.buffer_width = width; + g_window_data.buffer_height = height; + g_window_data.dst_offset_x = 0; + g_window_data.dst_offset_y = 0; + g_window_data.dst_width = width; + g_window_data.dst_height = height; + + if (flags & WF_FULLSCREEN_DESKTOP) { + posX = 0; + posY = 0; + windowWidth = screenWidth; + windowHeight = screenHeight; + } + else { + posX = (screenWidth - width) / 2; + posY = (screenHeight - height) / 2; + windowWidth = width; + windowHeight = height; + } + + g_window_data.window = XCreateWindow( + g_window_data.display, + defaultRootWindow, + posX, posY, + windowWidth, windowHeight, + 0, + depth, + InputOutput, + visual, + CWBackPixel | CWBorderPixel | CWBackingStore, + &windowAttributes); + if (!g_window_data.window) + return 0; + + XSelectInput(g_window_data.display, g_window_data.window, + KeyPressMask | KeyReleaseMask + | ButtonPressMask | ButtonReleaseMask | PointerMotionMask + | StructureNotifyMask | ExposureMask + | FocusChangeMask + | EnterWindowMask | LeaveWindowMask + ); + + XStoreName(g_window_data.display, g_window_data.window, title); + + if (flags & WF_BORDERLESS) { + struct StyleHints { + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long inputMode; + unsigned long status; + } sh = { + .flags = 2, + .functions = 0, + .decorations = 0, + .inputMode = 0, + .status = 0, + }; + Atom sh_p = XInternAtom(g_window_data.display, "_MOTIF_WM_HINTS", True); + XChangeProperty(g_window_data.display, g_window_data.window, sh_p, sh_p, 32, PropModeReplace, (unsigned char*)&sh, 5); + } + + if (flags & WF_ALWAYS_ON_TOP) { + Atom sa_p = XInternAtom(g_window_data.display, "_NET_WM_STATE_ABOVE", False); + XChangeProperty(g_window_data.display, g_window_data.window, XInternAtom(g_window_data.display, "_NET_WM_STATE", False), XA_ATOM, 32, PropModeReplace, (unsigned char *)&sa_p, 1); + } + + if (flags & WF_FULLSCREEN) { + Atom sf_p = XInternAtom(g_window_data.display, "_NET_WM_STATE_FULLSCREEN", True); + XChangeProperty(g_window_data.display, g_window_data.window, XInternAtom(g_window_data.display, "_NET_WM_STATE", True), XA_ATOM, 32, PropModeReplace, (unsigned char*)&sf_p, 1); + } + + sizeHints.flags = PPosition | PMinSize | PMaxSize; + sizeHints.x = 0; + sizeHints.y = 0; + sizeHints.min_width = width; + sizeHints.min_height = height; + if(flags & WF_RESIZABLE) { + sizeHints.max_width = screenWidth; + sizeHints.max_height = screenHeight; + } + else { + sizeHints.max_width = width; + sizeHints.max_height = height; + } + + XSetWMNormalHints(g_window_data.display, g_window_data.window, &sizeHints); + XClearWindow(g_window_data.display, g_window_data.window); + XMapRaised(g_window_data.display, g_window_data.window); + XFlush(g_window_data.display); + + g_window_data.gc = DefaultGC(g_window_data.display, g_window_data.screen); + + g_window_data.image = XCreateImage(g_window_data.display, CopyFromParent, depth, ZPixmap, 0, NULL, width, height, 32, width * 4); + + if (g_keyboard_func == 0x0) { + mfb_keyboard_callback(keyboard_default); + } + + printf("Window created using X11 API\n"); + + return 1; +} + +int mfb_open(const char* title, int width, int height) +{ + return mfb_open_ex(title, width, height, 0); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int translate_key(int scancode); +int translate_mod(int state); +int translate_mod_ex(int key, int state, int is_pressed); + +static int processEvents() +{ + XEvent event; + + while ((g_window_data.close == false) && XPending(g_window_data.display)) { + XNextEvent(g_window_data.display, &event); + + switch (event.type) { + case KeyPress: + case KeyRelease: + { + int kb_key = translate_key(event.xkey.keycode); + int is_pressed = (event.type == KeyPress); + g_window_data.mod_keys = translate_mod_ex(kb_key, event.xkey.state, is_pressed); + + kCall(g_keyboard_func, kb_key, g_window_data.mod_keys, is_pressed); + } + break; + + case ButtonPress: + case ButtonRelease: + { + MouseButton button = event.xbutton.button; + int is_pressed = (event.type == ButtonPress); + g_window_data.mod_keys = translate_mod(event.xkey.state); + switch (button) { + case Button1: + case Button2: + case Button3: + kCall(g_mouse_btn_func, button, g_window_data.mod_keys, is_pressed); + break; + + case Button4: + kCall(g_mouse_wheel_func, g_window_data.mod_keys, 0.0f, 1.0f); + break; + case Button5: + kCall(g_mouse_wheel_func, g_window_data.mod_keys, 0.0f, -1.0f); + break; + + case 6: + kCall(g_mouse_wheel_func, g_window_data.mod_keys, 1.0f, 0.0f); + break; + case 7: + kCall(g_mouse_wheel_func, g_window_data.mod_keys, -1.0f, 0.0f); + break; + + default: + kCall(g_mouse_btn_func, button - 4, g_window_data.mod_keys, is_pressed); + break; + } + } + break; + + case MotionNotify: + kCall(g_mouse_move_func, event.xmotion.x, event.xmotion.y); + break; + + case ConfigureNotify: + { + g_window_data.window_width = event.xconfigure.width; + g_window_data.window_height = event.xconfigure.height; + g_window_data.dst_offset_x = 0; + g_window_data.dst_offset_y = 0; + g_window_data.dst_width = g_window_data.window_width; + g_window_data.dst_height = g_window_data.window_height; + + XClearWindow(g_window_data.display, g_window_data.window); + kCall(g_resize_func, g_window_data.window_width, g_window_data.window_height); + } + break; + + case EnterNotify: + case LeaveNotify: + break; + + case FocusIn: + kCall(g_active_func, true); + break; + + case FocusOut: + kCall(g_active_func, false); + break; + + case DestroyNotify: + return -1; + break; + } + } + + if(g_window_data.close == true) + return -1; + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int mfb_update(void* buffer) +{ + if (buffer == 0x0) { + return -2; + } + + if (g_window_data.buffer_width != g_window_data.dst_width || g_window_data.buffer_height != g_window_data.dst_height) { + if(g_window_data.image_scaler_width != g_window_data.dst_width || g_window_data.image_scaler_height != g_window_data.dst_height) { + if(g_window_data.image_scaler != 0x0) { + g_window_data.image_scaler->data = 0x0; + XDestroyImage(g_window_data.image_scaler); + } + if(g_window_data.image_buffer != 0x0) { + free(g_window_data.image_buffer); + g_window_data.image_buffer = 0x0; + } + int depth = DefaultDepth(g_window_data.display, g_window_data.screen); + g_window_data.image_buffer = malloc(g_window_data.dst_width * g_window_data.dst_height * 4); + g_window_data.image_scaler_width = g_window_data.dst_width; + g_window_data.image_scaler_height = g_window_data.dst_height; + g_window_data.image_scaler = XCreateImage(g_window_data.display, CopyFromParent, depth, ZPixmap, 0, NULL, g_window_data.image_scaler_width, g_window_data.image_scaler_height, 32, g_window_data.image_scaler_width * 4); + } + } + + if(g_window_data.image_scaler != 0x0) { + stretch_image(buffer, 0, 0, g_window_data.buffer_width, g_window_data.buffer_height, g_window_data.buffer_width, g_window_data.image_buffer, 0, 0, g_window_data.dst_width, g_window_data.dst_height, g_window_data.dst_width); + g_window_data.image_scaler->data = g_window_data.image_buffer; + XPutImage(g_window_data.display, g_window_data.window, g_window_data.gc, g_window_data.image_scaler, 0, 0, g_window_data.dst_offset_x, g_window_data.dst_offset_y, g_window_data.dst_width, g_window_data.dst_height); + } + else { + g_window_data.image->data = (char *) buffer; + XPutImage(g_window_data.display, g_window_data.window, g_window_data.gc, g_window_data.image, 0, 0, g_window_data.dst_offset_x, g_window_data.dst_offset_y, g_window_data.dst_width, g_window_data.dst_height); + } + XFlush(g_window_data.display); + + if (processEvents() < 0) + return -1; + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void mfb_close(void) +{ + if(g_window_data.image != 0x0) { + g_window_data.image->data = 0x0; + XDestroyImage(g_window_data.image); + XDestroyWindow(g_window_data.display, g_window_data.window); + XCloseDisplay(g_window_data.display); + + g_window_data.image = 0x0; + g_window_data.display = 0x0; + g_window_data.window = 0; + } + g_window_data.close = true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +extern short int keycodes[512]; + +static int translateKeyCodeB(int keySym) { + + switch (keySym) + { + case XK_KP_0: return KB_KEY_KP_0; + case XK_KP_1: return KB_KEY_KP_1; + case XK_KP_2: return KB_KEY_KP_2; + case XK_KP_3: return KB_KEY_KP_3; + case XK_KP_4: return KB_KEY_KP_4; + case XK_KP_5: return KB_KEY_KP_5; + case XK_KP_6: return KB_KEY_KP_6; + case XK_KP_7: return KB_KEY_KP_7; + case XK_KP_8: return KB_KEY_KP_8; + case XK_KP_9: return KB_KEY_KP_9; + case XK_KP_Separator: + case XK_KP_Decimal: return KB_KEY_KP_DECIMAL; + case XK_KP_Equal: return KB_KEY_KP_EQUAL; + case XK_KP_Enter: return KB_KEY_KP_ENTER; + } + + return KB_KEY_UNKNOWN; +} + +static int translateKeyCodeA(int keySym) { + switch (keySym) + { + case XK_Escape: return KB_KEY_ESCAPE; + case XK_Tab: return KB_KEY_TAB; + case XK_Shift_L: return KB_KEY_LEFT_SHIFT; + case XK_Shift_R: return KB_KEY_RIGHT_SHIFT; + case XK_Control_L: return KB_KEY_LEFT_CONTROL; + case XK_Control_R: return KB_KEY_RIGHT_CONTROL; + case XK_Meta_L: + case XK_Alt_L: return KB_KEY_LEFT_ALT; + case XK_Mode_switch: // Mapped to Alt_R on many keyboards + case XK_ISO_Level3_Shift: // AltGr on at least some machines + case XK_Meta_R: + case XK_Alt_R: return KB_KEY_RIGHT_ALT; + case XK_Super_L: return KB_KEY_LEFT_SUPER; + case XK_Super_R: return KB_KEY_RIGHT_SUPER; + case XK_Menu: return KB_KEY_MENU; + case XK_Num_Lock: return KB_KEY_NUM_LOCK; + case XK_Caps_Lock: return KB_KEY_CAPS_LOCK; + case XK_Print: return KB_KEY_PRINT_SCREEN; + case XK_Scroll_Lock: return KB_KEY_SCROLL_LOCK; + case XK_Pause: return KB_KEY_PAUSE; + case XK_Delete: return KB_KEY_DELETE; + case XK_BackSpace: return KB_KEY_BACKSPACE; + case XK_Return: return KB_KEY_ENTER; + case XK_Home: return KB_KEY_HOME; + case XK_End: return KB_KEY_END; + case XK_Page_Up: return KB_KEY_PAGE_UP; + case XK_Page_Down: return KB_KEY_PAGE_DOWN; + case XK_Insert: return KB_KEY_INSERT; + case XK_Left: return KB_KEY_LEFT; + case XK_Right: return KB_KEY_RIGHT; + case XK_Down: return KB_KEY_DOWN; + case XK_Up: return KB_KEY_UP; + case XK_F1: return KB_KEY_F1; + case XK_F2: return KB_KEY_F2; + case XK_F3: return KB_KEY_F3; + case XK_F4: return KB_KEY_F4; + case XK_F5: return KB_KEY_F5; + case XK_F6: return KB_KEY_F6; + case XK_F7: return KB_KEY_F7; + case XK_F8: return KB_KEY_F8; + case XK_F9: return KB_KEY_F9; + case XK_F10: return KB_KEY_F10; + case XK_F11: return KB_KEY_F11; + case XK_F12: return KB_KEY_F12; + case XK_F13: return KB_KEY_F13; + case XK_F14: return KB_KEY_F14; + case XK_F15: return KB_KEY_F15; + case XK_F16: return KB_KEY_F16; + case XK_F17: return KB_KEY_F17; + case XK_F18: return KB_KEY_F18; + case XK_F19: return KB_KEY_F19; + case XK_F20: return KB_KEY_F20; + case XK_F21: return KB_KEY_F21; + case XK_F22: return KB_KEY_F22; + case XK_F23: return KB_KEY_F23; + case XK_F24: return KB_KEY_F24; + case XK_F25: return KB_KEY_F25; + + // Numeric keypad + case XK_KP_Divide: return KB_KEY_KP_DIVIDE; + case XK_KP_Multiply: return KB_KEY_KP_MULTIPLY; + case XK_KP_Subtract: return KB_KEY_KP_SUBTRACT; + case XK_KP_Add: return KB_KEY_KP_ADD; + + // These should have been detected in secondary keysym test above! + case XK_KP_Insert: return KB_KEY_KP_0; + case XK_KP_End: return KB_KEY_KP_1; + case XK_KP_Down: return KB_KEY_KP_2; + case XK_KP_Page_Down: return KB_KEY_KP_3; + case XK_KP_Left: return KB_KEY_KP_4; + case XK_KP_Right: return KB_KEY_KP_6; + case XK_KP_Home: return KB_KEY_KP_7; + case XK_KP_Up: return KB_KEY_KP_8; + case XK_KP_Page_Up: return KB_KEY_KP_9; + case XK_KP_Delete: return KB_KEY_KP_DECIMAL; + case XK_KP_Equal: return KB_KEY_KP_EQUAL; + case XK_KP_Enter: return KB_KEY_KP_ENTER; + + // Last resort: Check for printable keys (should not happen if the XKB + // extension is available). This will give a layout dependent mapping + // (which is wrong, and we may miss some keys, especially on non-US + // keyboards), but it's better than nothing... + case XK_a: return KB_KEY_A; + case XK_b: return KB_KEY_B; + case XK_c: return KB_KEY_C; + case XK_d: return KB_KEY_D; + case XK_e: return KB_KEY_E; + case XK_f: return KB_KEY_F; + case XK_g: return KB_KEY_G; + case XK_h: return KB_KEY_H; + case XK_i: return KB_KEY_I; + case XK_j: return KB_KEY_J; + case XK_k: return KB_KEY_K; + case XK_l: return KB_KEY_L; + case XK_m: return KB_KEY_M; + case XK_n: return KB_KEY_N; + case XK_o: return KB_KEY_O; + case XK_p: return KB_KEY_P; + case XK_q: return KB_KEY_Q; + case XK_r: return KB_KEY_R; + case XK_s: return KB_KEY_S; + case XK_t: return KB_KEY_T; + case XK_u: return KB_KEY_U; + case XK_v: return KB_KEY_V; + case XK_w: return KB_KEY_W; + case XK_x: return KB_KEY_X; + case XK_y: return KB_KEY_Y; + case XK_z: return KB_KEY_Z; + case XK_1: return KB_KEY_1; + case XK_2: return KB_KEY_2; + case XK_3: return KB_KEY_3; + case XK_4: return KB_KEY_4; + case XK_5: return KB_KEY_5; + case XK_6: return KB_KEY_6; + case XK_7: return KB_KEY_7; + case XK_8: return KB_KEY_8; + case XK_9: return KB_KEY_9; + case XK_0: return KB_KEY_0; + case XK_space: return KB_KEY_SPACE; + case XK_minus: return KB_KEY_MINUS; + case XK_equal: return KB_KEY_EQUAL; + case XK_bracketleft: return KB_KEY_LEFT_BRACKET; + case XK_bracketright: return KB_KEY_RIGHT_BRACKET; + case XK_backslash: return KB_KEY_BACKSLASH; + case XK_semicolon: return KB_KEY_SEMICOLON; + case XK_apostrophe: return KB_KEY_APOSTROPHE; + case XK_grave: return KB_KEY_GRAVE_ACCENT; + case XK_comma: return KB_KEY_COMMA; + case XK_period: return KB_KEY_PERIOD; + case XK_slash: return KB_KEY_SLASH; + case XK_less: return KB_KEY_WORLD_1; // At least in some layouts... + default: break; + } + + return KB_KEY_UNKNOWN; +} + +void init_keycodes() { + size_t i; + int keySym; + + // Clear keys + for (i = 0; i < sizeof(keycodes) / sizeof(keycodes[0]); ++i) + keycodes[i] = KB_KEY_UNKNOWN; + + // Valid key code range is [8,255], according to the Xlib manual + for(int i=8; i<=255; ++i) { + // Try secondary keysym, for numeric keypad keys + keySym = XkbKeycodeToKeysym(g_window_data.display, i, 0, 1); + keycodes[i] = translateKeyCodeB(keySym); + if(keycodes[i] == KB_KEY_UNKNOWN) { + keySym = XkbKeycodeToKeysym(g_window_data.display, i, 0, 0); + keycodes[i] = translateKeyCodeA(keySym); + } + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int translate_key(int scancode) { + if (scancode < 0 || scancode > 255) + return KB_KEY_UNKNOWN; + + return keycodes[scancode]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int translate_mod(int state) { + int mod_keys = 0; + + if (state & ShiftMask) + mod_keys |= KB_MOD_SHIFT; + if (state & ControlMask) + mod_keys |= KB_MOD_CONTROL; + if (state & Mod1Mask) + mod_keys |= KB_MOD_ALT; + if (state & Mod4Mask) + mod_keys |= KB_MOD_SUPER; + if (state & LockMask) + mod_keys |= KB_MOD_CAPS_LOCK; + if (state & Mod2Mask) + mod_keys |= KB_MOD_NUM_LOCK; + + return mod_keys; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int translate_mod_ex(int key, int state, int is_pressed) { + int mod_keys = 0; + + mod_keys = translate_mod(state); + + switch (key) + { + case KB_KEY_LEFT_SHIFT: + case KB_KEY_RIGHT_SHIFT: + if(is_pressed) + mod_keys |= KB_MOD_SHIFT; + else + mod_keys &= ~KB_MOD_SHIFT; + break; + + case KB_KEY_LEFT_CONTROL: + case KB_KEY_RIGHT_CONTROL: + if(is_pressed) + mod_keys |= KB_MOD_CONTROL; + else + mod_keys &= ~KB_MOD_CONTROL; + break; + + case KB_KEY_LEFT_ALT: + case KB_KEY_RIGHT_ALT: + if(is_pressed) + mod_keys |= KB_MOD_ALT; + else + mod_keys &= ~KB_MOD_ALT; + break; + + case KB_KEY_LEFT_SUPER: + case KB_KEY_RIGHT_SUPER: + if(is_pressed) + mod_keys |= KB_MOD_SUPER; + else + mod_keys &= ~KB_MOD_SUPER; + break; + } + + return mod_keys; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void keyboard_default(void *user_data, Key key, KeyMod mod, bool isPressed) { + kUnused(user_data); + kUnused(mod); + kUnused(isPressed); + if (key == KB_KEY_ESCAPE) { + g_window_data.close = true; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +bool mfb_set_viewport(unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) +{ + if(offset_x + width > g_window_data.window_width) { + return false; + } + if(offset_y + height > g_window_data.window_height) { + return false; + } + + g_window_data.dst_offset_x = offset_x; + g_window_data.dst_offset_y = offset_y; + g_window_data.dst_width = width; + g_window_data.dst_height = height; + return true; +} diff --git a/src/x11/X11WindowData.h b/src/x11/X11WindowData.h new file mode 100644 index 0000000..e09ac30 --- /dev/null +++ b/src/x11/X11WindowData.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include + + +typedef struct { + Window window; + uint32_t window_width; + uint32_t window_height; + + uint32_t dst_offset_x; + uint32_t dst_offset_y; + uint32_t dst_width; + uint32_t dst_height; + + void *draw_buffer; + uint32_t buffer_width; + uint32_t buffer_height; + + uint32_t mod_keys; + bool close; + + Display *display; + int screen; + GC gc; + XImage *image; + + void *image_buffer; + XImage *image_scaler; + uint32_t image_scaler_width; + uint32_t image_scaler_height; +} SWindowData; diff --git a/tests/noise.c b/tests/noise.c index e067a95..0fe3b53 100644 --- a/tests/noise.c +++ b/tests/noise.c @@ -1,42 +1,163 @@ #include +#include +#include + +#define kUnused(var) (void) var; #define WIDTH 800 #define HEIGHT 600 static unsigned int s_buffer[WIDTH * HEIGHT]; +//------------------------------------- +// C interface +//------------------------------------- +void active(void *user_data, bool isActive) { + kUnused(user_data); + fprintf(stdout, "active: %d\n", isActive); +} + +void resize(void *user_data, int width, int height) { + uint32_t x = 0; + uint32_t y = 0; + + kUnused(user_data); + fprintf(stdout, "resize: %d, %d\n", width, height); + if(width > WIDTH) { + x = (width - WIDTH) >> 1; + width = WIDTH; + } + if(height > HEIGHT) { + y = (height - HEIGHT) >> 1; + height = HEIGHT; + } + mfb_set_viewport(x, y, width, height); +} + +void keyboard(void *user_data, Key key, KeyMod mod, bool isPressed) { + kUnused(user_data); + fprintf(stdout, "keyboard: key: %s (pressed: %d) [KeyMod: %x]\n", mfb_get_key_name(key), isPressed, mod); + if(key == KB_KEY_ESCAPE) { + mfb_close(); + } +} + +void char_input(void *user_data, unsigned int charCode) { + kUnused(user_data); + fprintf(stdout, "charCode: %d\n", charCode); +} + +void mouse_btn(void *user_data, MouseButton button, KeyMod mod, bool isPressed) { + kUnused(user_data); + fprintf(stdout, "mouse_btn: button: %d (pressed: %d) [KeyMod: %x]\n", button, isPressed, mod); +} + +void mouse_move(void *user_data, int x, int y) { + kUnused(user_data); + kUnused(x); + kUnused(y); + //fprintf(stdout, "mouse_move: %d, %d\n", x, y); +} + +void mouse_scroll(void *user_data, KeyMod mod, float deltaX, float deltaY) { + kUnused(user_data); + fprintf(stdout, "mouse_scroll: x: %f, y: %f [KeyMod: %x]\n", deltaX, deltaY, mod); +} + +//------------------------------------- +// C++ interface (calling C functions) +//------------------------------------- +#if defined(__cplusplus) + +class Events { +public: + void active(void *user_data, bool isActive) { + ::active(user_data, isActive); + } + + void resize(void *user_data, int width, int height) { + ::resize(user_data, width, height); + } + + void keyboard(void *user_data, Key key, KeyMod mod, bool isPressed) { + ::keyboard(user_data, key, mod, isPressed); + } + + void char_input(void *user_data, unsigned int charCode) { + ::char_input(user_data, charCode); + } + + void mouse_btn(void *user_data, MouseButton button, KeyMod mod, bool isPressed) { + ::mouse_btn(user_data, button, mod, isPressed); + } + + void mouse_move(void *user_data, int x, int y) { + ::mouse_move(user_data, x, y); + } + + void mouse_scroll(void *user_data, KeyMod mod, float deltaX, float deltaY) { + ::mouse_scroll(user_data, mod, deltaX, deltaY); + } +}; + +#endif + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int main() { - int noise, carry, seed = 0xbeef; + int noise, carry, seed = 0xbeef; - if (!mfb_open("Noise Test", WIDTH, HEIGHT)) - return 0; +#if defined(__cplusplus) - for (;;) - { - int i, state; + Events e; - for (i = 0; i < WIDTH * HEIGHT; ++i) - { - noise = seed; - noise >>= 3; - noise ^= seed; - carry = noise & 1; - noise >>= 1; - seed >>= 1; - seed |= (carry << 30); - noise &= 0xFF; - s_buffer[i] = MFB_RGB(noise, noise, noise); - } + mfb_active_callback(&e, &Events::active); + mfb_resize_callback(&e, &Events::resize); + mfb_keyboard_callback(&e, &Events::keyboard); + mfb_char_input_callback(&e, &Events::char_input); + mfb_mouse_button_callback(&e, &Events::mouse_btn); + mfb_mouse_move_callback(&e, &Events::mouse_move); + mfb_mouse_scroll_callback(&e, &Events::mouse_scroll); - state = mfb_update(s_buffer); +#else - if (state < 0) - break; - } + mfb_active_callback(active); + mfb_resize_callback(resize); + mfb_keyboard_callback(keyboard); + mfb_char_input_callback(char_input); + mfb_mouse_button_callback(mouse_btn); + mfb_mouse_move_callback(mouse_move); + mfb_mouse_scroll_callback(mouse_scroll); - mfb_close(); +#endif - return 0; + if (!mfb_open_ex("Noise Test", WIDTH, HEIGHT, WF_RESIZABLE)) + return 0; + + for (;;) + { + int i, state; + + for (i = 0; i < WIDTH * HEIGHT; ++i) + { + noise = seed; + noise >>= 3; + noise ^= seed; + carry = noise & 1; + noise >>= 1; + seed >>= 1; + seed |= (carry << 30); + noise &= 0xFF; + s_buffer[i] = MFB_RGB(noise, noise, noise); + } + + state = mfb_update(s_buffer); + + if (state < 0) + break; + } + + mfb_close(); + + return 0; } From 21d9377822bba4402401ea6ddecf3ef7c622de42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Aragon=C3=A9s?= <9335325+Darky-Lucera@users.noreply.github.com> Date: Sat, 8 Jun 2019 20:34:05 +0200 Subject: [PATCH 03/14] Add multiple windows2 (#19) * MacOSX with input events and mfb_set_viewport * Windows with input events and mfb_set_viewport * Minor changes in macosx and windows * X11 with input and mfb_set_viewport * Minor changes on X11 * Fix bug in X11 resize event * Fix bug in windows resize * added scale image to X11 * Added stretch_image with & without bilinear interpolation * moved MiniFB_internal.h * Added wayland events * minor changes * unify a bit the window structs * More work on wayland * Added cmake file * minor fix on windows * modified test * Fix on wayland. Unset wayland as default for linux * Use stdbool instead of our own macro eBool Remove prefix e from all enums * Remove _ex sufix in common files * merge X11MiniFB_ex.c into X11MiniFB.c * Merge WaylandMiniFB_ex.c into WaylandMiniFB.c * Add user_data to callbacks * Merge WinMiniFB_ex.c into WinMiniFB.c * Some minor changes on Windows * Fix bug on Wayland * Multiple Windows for MacOS X & Linux * Multiple Windows for Windows Refactor * Refactor * Added mfb_get_key_name * remove some warnings * Events per window working on MacOS & Linux (maybe Windows) * Fix on Windows * Added default key callback on macos & wayland * Unify keyboard_default on all platforms * keyboard_default on all platforms --- CMakeLists.txt | 151 +++---- include/MiniFB.h | 40 +- include/MiniFB_cpp.h | 110 ++--- include/MiniFB_enums.h | 22 + src/MiniFB_common.c | 101 +++-- src/MiniFB_cpp.cpp | 58 ++- src/MiniFB_internal.c | 2 +- src/MiniFB_internal.h | 17 +- src/WindowData.h | 33 ++ src/macosx/MacMiniFB.m | 374 ++++++++-------- src/macosx/OSXWindow.h | 12 +- src/macosx/OSXWindow.m | 74 ++-- src/macosx/OSXWindowData.h | 22 - src/macosx/OSXWindowFrameView.h | 21 +- src/macosx/OSXWindowFrameView.m | 62 +-- src/macosx/WindowData_OSX.h | 21 + src/wayland/WaylandMiniFB.c | 411 ++++++++++-------- .../{WaylandWindowData.h => WindowData_Way.h} | 2 +- src/windows/WinMiniFB.c | 320 ++++++++------ src/windows/WinWindowData.h | 30 -- src/windows/WindowData_Win.h | 15 + src/x11/{X11WindowData.h => WindowData_X11.h} | 16 +- src/x11/X11MiniFB.c | 299 +++++++------ tests/noise.c | 310 ++++++++++--- 24 files changed, 1471 insertions(+), 1052 deletions(-) create mode 100644 src/WindowData.h delete mode 100644 src/macosx/OSXWindowData.h create mode 100644 src/macosx/WindowData_OSX.h rename src/wayland/{WaylandWindowData.h => WindowData_Way.h} (98%) delete mode 100644 src/windows/WinWindowData.h create mode 100644 src/windows/WindowData_Win.h rename src/x11/{X11WindowData.h => WindowData_X11.h} (51%) diff --git a/CMakeLists.txt b/CMakeLists.txt index b286d7a..aec5d34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,75 +1,76 @@ -cmake_minimum_required(VERSION 2.8.9) -project (noise) - -include_directories(include src) - -file(GLOB SrcLib "src/*.c" - "src/*.cpp" - "include/*.h") -file(GLOB SrcWindows "src/windows/*.c" - "src/windows/*.h") -file(GLOB SrcMacOSX "src/macosx/*.c" - "src/macosx/*.cpp" - "src/macosx/*.m" - "src/macosx/*.mm" - "src/macosx/*.h") -file(GLOB SrcWayland "src/wayland/*.c") -file(GLOB SrcX11 "src/x11/*.c") - -if (NOT MSVC) - set (CMAKE_C_FLAGS "-g -Wall -Wextra -Wno-switch -Wno-unused-function") - set (CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11") - set (CMAKE_OBJC_FLAGS "${CMAKE_C_FLAGS}") - set (CMAKE_OBJCXX_FLAGS "${CMAKE_CXX_FLAGS}") -endif() - -if (APPLE) - OPTION(USE_METAL_API "Build the project using metal API code" ON) -elseif (UNIX) - OPTION(USE_WAYLAND_API "Build the project using wayland API code" OFF) -endif() - -if (MSVC) - add_definitions(-D_CRT_SECURE_NO_WARNINGS) - add_definitions(-D_WIN32_WINNT=0x0600) - list (APPEND SrcLib ${SrcWindows}) -elseif (MINGW) - add_definitions(-D_WIN32_WINNT=0x0600) - list(APPEND SrcLib ${SrcWindows}) -elseif (APPLE) - if(USE_METAL_API) - add_definitions(-DUSE_METAL_API) - endif() - list(APPEND SrcLib ${SrcMacOSX}) -elseif (UNIX) - if(USE_WAYLAND_API) - list(APPEND SrcLib ${SrcWayland}) - else() - list(APPEND SrcLib ${SrcX11}) - endif() -endif() - -add_library(minifb STATIC - ${SrcLib} -) - -add_executable(noise - tests/noise.c -) - -target_link_libraries(noise minifb) - -if (MSVC) -elseif (MINGW) -elseif (APPLE) - target_link_libraries(noise "-framework Cocoa") - target_link_libraries(noise "-framework QuartzCore") - target_link_libraries(noise "-framework Metal") - target_link_libraries(noise "-framework MetalKit") -elseif (UNIX) - if(USE_WAYLAND_API) - target_link_libraries(noise -lwayland-client -lwayland-cursor) - else() - target_link_libraries(noise -lX11) - endif() -endif() +cmake_minimum_required(VERSION 2.8.11) +project (noise) + +include_directories(include src) + +file(GLOB SrcLib "src/*.c" + "src/*.cpp" + "src/*.h" + "include/*.h") +file(GLOB SrcWindows "src/windows/*.c" + "src/windows/*.h") +file(GLOB SrcMacOSX "src/macosx/*.c" + "src/macosx/*.cpp" + "src/macosx/*.m" + "src/macosx/*.mm" + "src/macosx/*.h") +file(GLOB SrcWayland "src/wayland/*.c") +file(GLOB SrcX11 "src/x11/*.c") + +if (NOT MSVC) + set (CMAKE_C_FLAGS "-g -Wall -Wextra -pedantic -Wno-switch -Wno-unused-function") + set (CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11") + set (CMAKE_OBJC_FLAGS "${CMAKE_C_FLAGS}") + set (CMAKE_OBJCXX_FLAGS "${CMAKE_CXX_FLAGS}") +endif() + +if (APPLE) + OPTION(USE_METAL_API "Build the project using metal API code" ON) +elseif (UNIX) + OPTION(USE_WAYLAND_API "Build the project using wayland API code" OFF) +endif() + +if (MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + add_definitions(-D_WIN32_WINNT=0x0600) + list (APPEND SrcLib ${SrcWindows}) +elseif (MINGW) + add_definitions(-D_WIN32_WINNT=0x0600) + list(APPEND SrcLib ${SrcWindows}) +elseif (APPLE) + if(USE_METAL_API) + add_definitions(-DUSE_METAL_API) + endif() + list(APPEND SrcLib ${SrcMacOSX}) +elseif (UNIX) + if(USE_WAYLAND_API) + list(APPEND SrcLib ${SrcWayland}) + else() + list(APPEND SrcLib ${SrcX11}) + endif() +endif() + +add_library(minifb STATIC + ${SrcLib} +) + +add_executable(noise + tests/noise.c +) + +target_link_libraries(noise minifb) + +if (MSVC) +elseif (MINGW) +elseif (APPLE) + target_link_libraries(noise "-framework Cocoa") + target_link_libraries(noise "-framework QuartzCore") + target_link_libraries(noise "-framework Metal") + target_link_libraries(noise "-framework MetalKit") +elseif (UNIX) + if(USE_WAYLAND_API) + target_link_libraries(noise -lwayland-client -lwayland-cursor) + else() + target_link_libraries(noise -lX11) + endif() +endif() diff --git a/include/MiniFB.h b/include/MiniFB.h index 6f302b0..81a62c6 100644 --- a/include/MiniFB.h +++ b/include/MiniFB.h @@ -9,43 +9,35 @@ extern "C" { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#define MFB_RGB(r, g, b) (((unsigned int)r) << 16) | (((unsigned int)g) << 8) | b +#define MFB_RGB(r, g, b) (((unsigned int) r) << 16) | (((unsigned int) g) << 8) | (b) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Create a window that is used to display the buffer sent into the mfb_update function, returns 0 if fails -int mfb_open(const char* name, int width, int height); -int mfb_open_ex(const char* name, int width, int height, int flags); +struct Window *mfb_open(const char *title, int width, int height); +struct Window *mfb_open_ex(const char *title, int width, int height, int flags); // Update the display. Input buffer is assumed to be a 32-bit buffer of the size given in the open call -// Will return -1 when ESC key is pressed (later on will return keycode and -1 on other close signal) -int mfb_update(void* buffer); +// Will return a negative status if something went wrong or the user want to exit. +UpdateState mfb_update(struct Window *window, void* buffer); // Close the window -void mfb_close(); +void mfb_close(struct Window *window); // Set user data -void mfb_set_user_data(void *user_data); +void mfb_set_user_data(struct Window *window, void *user_data); +void *mfb_get_user_data(struct Window *window); // Set viewport (useful when resize) -bool mfb_set_viewport(unsigned offset_x, unsigned offset_y, unsigned width, unsigned height); +bool mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height); -// Event callbacks -typedef void(*mfb_active_func)(void *user_data, bool isActive); -typedef void(*mfb_resize_func)(void *user_data, int width, int height); -typedef void(*mfb_keyboard_func)(void *user_data, Key key, KeyMod mod, bool isPressed); -typedef void(*mfb_char_input_func)(void *user_data, unsigned int code); -typedef void(*mfb_mouse_btn_func)(void *user_data, MouseButton button, KeyMod mod, bool isPressed); -typedef void(*mfb_mouse_move_func)(void *user_data, int x, int y); -typedef void(*mfb_mouse_scroll_func)(void *user_data, KeyMod mod, float deltaX, float deltaY); - -void mfb_active_callback(mfb_active_func callback); -void mfb_resize_callback(mfb_resize_func callback); -void mfb_keyboard_callback(mfb_keyboard_func callback); -void mfb_char_input_callback(mfb_char_input_func callback); -void mfb_mouse_button_callback(mfb_mouse_btn_func callback); -void mfb_mouse_move_callback(mfb_mouse_move_func callback); -void mfb_mouse_scroll_callback(mfb_mouse_scroll_func callback); +void mfb_active_callback(struct Window *window, mfb_active_func callback); +void mfb_resize_callback(struct Window *window, mfb_resize_func callback); +void mfb_keyboard_callback(struct Window *window, mfb_keyboard_func callback); +void mfb_char_input_callback(struct Window *window, mfb_char_input_func callback); +void mfb_mouse_button_callback(struct Window *window, mfb_mouse_btn_func callback); +void mfb_mouse_move_callback(struct Window *window, mfb_mouse_move_func callback); +void mfb_mouse_scroll_callback(struct Window *window, mfb_mouse_scroll_func callback); const char *mfb_get_key_name(Key key); diff --git a/include/MiniFB_cpp.h b/include/MiniFB_cpp.h index f665a0b..c8247d6 100755 --- a/include/MiniFB_cpp.h +++ b/include/MiniFB_cpp.h @@ -6,119 +6,129 @@ #include "MiniFB.h" template -void mfb_active_callback(T *obj, void (T::*method)(void *, bool)); +void mfb_active_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, bool)); template -void mfb_resize_callback(T *obj, void (T::*method)(void *, int, int)); +void mfb_resize_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, int, int)); template -void mfb_keyboard_callback(T *obj, void (T::*method)(void *, Key, KeyMod, bool)); +void mfb_keyboard_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, Key, KeyMod, bool)); template -void mfb_char_input_callback(T *obj, void (T::*method)(void *, unsigned int)); +void mfb_char_input_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, unsigned int)); template -void mfb_mouse_button_callback(T *obj, void (T::*method)(void *, MouseButton, KeyMod, bool)); +void mfb_mouse_button_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, MouseButton, KeyMod, bool)); template -void mfb_mouse_move_callback(T *obj, void (T::*method)(void *, int, int)); +void mfb_mouse_move_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, int, int)); template -void mfb_mouse_scroll_callback(T *obj, void (T::*method)(void *, KeyMod, float, float)); +void mfb_mouse_scroll_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, KeyMod, float, float)); //------------------------------------- // To avoid clumsy hands //------------------------------------- class Stub { template - friend void mfb_active_callback(T *obj, void (T::*method)(void *, bool)); + friend void mfb_active_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, bool)); template - friend void mfb_resize_callback(T *obj, void (T::*method)(void *, int, int)); + friend void mfb_resize_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, int, int)); template - friend void mfb_mouse_button_callback(T *obj, void (T::*method)(void *, MouseButton, KeyMod, bool)); + friend void mfb_mouse_button_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, MouseButton, KeyMod, bool)); template - friend void mfb_keyboard_callback(T *obj, void (T::*method)(void *, Key, KeyMod, bool)); + friend void mfb_keyboard_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, Key, KeyMod, bool)); template - friend void mfb_char_input_callback(T *obj, void (T::*method)(void *, unsigned int)); + friend void mfb_char_input_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, unsigned int)); template - friend void mfb_mouse_button_callback(T *obj, void (T::*method)(void *, MouseButton, KeyMod, bool)); + friend void mfb_mouse_button_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, MouseButton, KeyMod, bool)); template - friend void mfb_mouse_move_callback(T *obj, void (T::*method)(void *, int, int)); + friend void mfb_mouse_move_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, int, int)); template - friend void mfb_mouse_scroll_callback(T *obj, void (T::*method)(void *, KeyMod, float, float)); + friend void mfb_mouse_scroll_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, KeyMod, float, float)); - static void active_stub(void *user_data, bool isActive); - static void resize_stub(void *user_data, int width, int height); - static void keyboard_stub(void *user_data, Key key, KeyMod mod, bool isPressed); - static void char_input_stub(void *user_data, unsigned int); - static void mouse_btn_stub(void *user_data, MouseButton button, KeyMod mod, bool isPressed); - static void mouse_move_stub(void *user_data, int x, int y); - static void scroll_stub(void *user_data, KeyMod mod, float deltaX, float deltaY); + static Stub *GetInstance(struct Window *window); - static std::function m_active; - static std::function m_resize; - static std::function m_keyboard; - static std::function m_char_input; - static std::function m_mouse_btn; - static std::function m_mouse_move; - static std::function m_scroll; + static void active_stub(struct Window *window, bool isActive); + static void resize_stub(struct Window *window, int width, int height); + static void keyboard_stub(struct Window *window, Key key, KeyMod mod, bool isPressed); + static void char_input_stub(struct Window *window, unsigned int); + static void mouse_btn_stub(struct Window *window, MouseButton button, KeyMod mod, bool isPressed); + static void mouse_move_stub(struct Window *window, int x, int y); + static void scroll_stub(struct Window *window, KeyMod mod, float deltaX, float deltaY); + + struct Window *m_window; + std::function m_active; + std::function m_resize; + std::function m_keyboard; + std::function m_char_input; + std::function m_mouse_btn; + std::function m_mouse_move; + std::function m_scroll; }; //------------------------------------- template -inline void mfb_active_callback(T *obj, void (T::*method)(void *user_data, bool)) { +inline void mfb_active_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, bool)) { using namespace std::placeholders; - Stub::m_active = std::bind(method, obj, _1, _2); - mfb_active_callback(Stub::active_stub); + Stub *stub = Stub::GetInstance(window); + stub->m_active = std::bind(method, obj, _1, _2); + mfb_active_callback(window, Stub::active_stub); } template -inline void mfb_resize_callback(T *obj, void (T::*method)(void *user_data, int, int)) { +inline void mfb_resize_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, int, int)) { using namespace std::placeholders; - Stub::m_resize = std::bind(method, obj, _1, _2, _3); - mfb_resize_callback(Stub::resize_stub); + Stub *stub = Stub::GetInstance(window); + stub->m_resize = std::bind(method, obj, _1, _2, _3); + mfb_resize_callback(window, Stub::resize_stub); } template -inline void mfb_keyboard_callback(T *obj, void (T::*method)(void *user_data, Key, KeyMod, bool)) { +inline void mfb_keyboard_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, Key, KeyMod, bool)) { using namespace std::placeholders; - Stub::m_keyboard = std::bind(method, obj, _1, _2, _3, _4); - mfb_keyboard_callback(Stub::keyboard_stub); + Stub *stub = Stub::GetInstance(window); + stub->m_keyboard = std::bind(method, obj, _1, _2, _3, _4); + mfb_keyboard_callback(window, Stub::keyboard_stub); } template -inline void mfb_char_input_callback(T *obj, void (T::*method)(void *user_data, unsigned int)) { +inline void mfb_char_input_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, unsigned int)) { using namespace std::placeholders; - Stub::m_char_input = std::bind(method, obj, _1, _2); - mfb_char_input_callback(Stub::char_input_stub); + Stub *stub = Stub::GetInstance(window); + stub->m_char_input = std::bind(method, obj, _1, _2); + mfb_char_input_callback(window, Stub::char_input_stub); } template -inline void mfb_mouse_button_callback(T *obj, void (T::*method)(void *user_data, MouseButton, KeyMod, bool)) { +inline void mfb_mouse_button_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, MouseButton, KeyMod, bool)) { using namespace std::placeholders; - Stub::m_mouse_btn = std::bind(method, obj, _1, _2, _3, _4); - mfb_mouse_button_callback(Stub::mouse_btn_stub); + Stub *stub = Stub::GetInstance(window); + stub->m_mouse_btn = std::bind(method, obj, _1, _2, _3, _4); + mfb_mouse_button_callback(window, Stub::mouse_btn_stub); } template -inline void mfb_mouse_move_callback(T *obj, void (T::*method)(void *user_data, int, int)) { +inline void mfb_mouse_move_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, int, int)) { using namespace std::placeholders; - Stub::m_mouse_move = std::bind(method, obj, _1, _2, _3); - mfb_mouse_move_callback(Stub::mouse_move_stub); + Stub *stub = Stub::GetInstance(window); + stub->m_mouse_move = std::bind(method, obj, _1, _2, _3); + mfb_mouse_move_callback(window, Stub::mouse_move_stub); } template -inline void mfb_mouse_scroll_callback(T *obj, void (T::*method)(void *user_data, KeyMod, float, float)) { +inline void mfb_mouse_scroll_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, KeyMod, float, float)) { using namespace std::placeholders; - Stub::m_scroll = std::bind(method, obj, _1, _2, _3, _4); - mfb_mouse_scroll_callback(Stub::scroll_stub); + Stub *stub = Stub::GetInstance(window); + stub->m_scroll = std::bind(method, obj, _1, _2, _3, _4); + mfb_mouse_scroll_callback(window, Stub::scroll_stub); } #endif diff --git a/include/MiniFB_enums.h b/include/MiniFB_enums.h index cc7b6fd..4d4058e 100755 --- a/include/MiniFB_enums.h +++ b/include/MiniFB_enums.h @@ -2,6 +2,15 @@ #include +// Enums +typedef enum { + STATE_OK = 0, + STATE_EXIT = -1, + STATE_INVALID_WINDOW = -2, + STATE_INVALID_BUFFER = -3, + STATE_INTERNAL_ERROR = -4, +} UpdateState; + typedef enum { MOUSE_BTN_0, // No mouse button MOUSE_BTN_1, @@ -161,3 +170,16 @@ typedef enum { WF_BORDERLESS = 0x08, WF_ALWAYS_ON_TOP = 0x10, } WindowFlags; + +// Opaque pointer +struct Window; + +// Event callbacks +typedef void(*mfb_active_func)(struct Window *window, bool isActive); +typedef void(*mfb_resize_func)(struct Window *window, int width, int height); +typedef void(*mfb_keyboard_func)(struct Window *window, Key key, KeyMod mod, bool isPressed); +typedef void(*mfb_char_input_func)(struct Window *window, unsigned int code); +typedef void(*mfb_mouse_btn_func)(struct Window *window, MouseButton button, KeyMod mod, bool isPressed); +typedef void(*mfb_mouse_move_func)(struct Window *window, int x, int y); +typedef void(*mfb_mouse_scroll_func)(struct Window *window, KeyMod mod, float deltaX, float deltaY); + diff --git a/src/MiniFB_common.c b/src/MiniFB_common.c index 3e24254..4941b1a 100755 --- a/src/MiniFB_common.c +++ b/src/MiniFB_common.c @@ -1,56 +1,101 @@ #include "MiniFB.h" +#include "WindowData.h" +#include //------------------------------------- -mfb_active_func g_active_func = 0x0; -mfb_resize_func g_resize_func = 0x0; -mfb_keyboard_func g_keyboard_func = 0x0; -mfb_char_input_func g_char_input_func = 0x0; -mfb_mouse_btn_func g_mouse_btn_func = 0x0; -mfb_mouse_move_func g_mouse_move_func = 0x0; -mfb_mouse_scroll_func g_mouse_wheel_func = 0x0; - -void *g_user_data = 0x0; - -//------------------------------------- -void mfb_active_callback(mfb_active_func callback) { - g_active_func = callback; +void mfb_active_callback(struct Window *window, mfb_active_func callback) { + if(window != 0x0) { + SWindowData *window_data = (SWindowData *) window; + window_data->active_func = callback; + } } //------------------------------------- -void mfb_resize_callback(mfb_resize_func callback) { - g_resize_func = callback; +void mfb_resize_callback(struct Window *window, mfb_resize_func callback) { + if(window != 0x0) { + SWindowData *window_data = (SWindowData *) window; + window_data->resize_func = callback; + } } //------------------------------------- -void mfb_keyboard_callback(mfb_keyboard_func callback) { - g_keyboard_func = callback; +void mfb_keyboard_callback(struct Window *window, mfb_keyboard_func callback) { + if(window != 0x0) { + SWindowData *window_data = (SWindowData *) window; + window_data->keyboard_func = callback; + } } //------------------------------------- -void mfb_char_input_callback(mfb_char_input_func callback) { - g_char_input_func = callback; +void mfb_char_input_callback(struct Window *window, mfb_char_input_func callback) { + if(window != 0x0) { + SWindowData *window_data = (SWindowData *) window; + window_data->char_input_func = callback; + } } //------------------------------------- -void mfb_mouse_button_callback(mfb_mouse_btn_func callback) { - g_mouse_btn_func = callback; +void mfb_mouse_button_callback(struct Window *window, mfb_mouse_btn_func callback) { + if(window != 0x0) { + SWindowData *window_data = (SWindowData *) window; + window_data->mouse_btn_func = callback; + } } //------------------------------------- -void mfb_mouse_move_callback(mfb_mouse_move_func callback) { - g_mouse_move_func = callback; +void mfb_mouse_move_callback(struct Window *window, mfb_mouse_move_func callback) { + if(window != 0x0) { + SWindowData *window_data = (SWindowData *) window; + window_data->mouse_move_func = callback; + } } //------------------------------------- -void mfb_mouse_scroll_callback(mfb_mouse_scroll_func callback) { - g_mouse_wheel_func = callback; +void mfb_mouse_scroll_callback(struct Window *window, mfb_mouse_scroll_func callback) { + if(window != 0x0) { + SWindowData *window_data = (SWindowData *) window; + window_data->mouse_wheel_func = callback; + } } //------------------------------------- -void mfb_set_user_data(void *user_data) { - g_user_data = user_data; +void mfb_set_user_data(struct Window *window, void *user_data) { + if(window != 0x0) { + SWindowData *window_data = (SWindowData *) window; + window_data->user_data = user_data; + } } +//------------------------------------- +void *mfb_get_user_data(struct Window *window) { + if(window != 0x0) { + SWindowData *window_data = (SWindowData *) window; + return window_data->user_data; + } + + return 0x0; +} + +//------------------------------------- +void mfb_close(struct Window *window) +{ + if(window != 0x0) { + SWindowData *window_data = (SWindowData *) window; + window_data->close = true; + } +} + +//------------------------------------- +void keyboard_default(struct Window *window, Key key, KeyMod mod, bool isPressed) { + kUnused(mod); + kUnused(isPressed); + if (key == KB_KEY_ESCAPE) { + SWindowData *window_data = (SWindowData *) window; + window_data->close = true; + } +} + + //------------------------------------- const char *mfb_get_key_name(Key key) { @@ -418,4 +463,4 @@ const char *mfb_get_key_name(Key key) { } return "Unknown"; -} \ No newline at end of file +} diff --git a/src/MiniFB_cpp.cpp b/src/MiniFB_cpp.cpp index eb38303..bfaf56a 100755 --- a/src/MiniFB_cpp.cpp +++ b/src/MiniFB_cpp.cpp @@ -1,38 +1,54 @@ #include #include +#include -std::function Stub::m_active; -std::function Stub::m_resize; -std::function Stub::m_keyboard; -std::function Stub::m_char_input; -std::function Stub::m_mouse_btn; -std::function Stub::m_mouse_move; -std::function Stub::m_scroll; +Stub * +Stub::GetInstance(struct Window *window) { + static std::vector s_instances; -void Stub::active_stub(void *user_data, bool isActive) { - m_active(user_data, isActive); + for(Stub *instance : s_instances) { + if(instance->m_window == window) { + return instance; + } + } + + s_instances.push_back(new Stub); + s_instances.back()->m_window = window; + + return s_instances.back(); } -void Stub::resize_stub(void *user_data, int width, int height) { - m_resize(user_data, width, height); +void Stub::active_stub(struct Window *window, bool isActive) { + Stub *stub = Stub::GetInstance(window); + stub->m_active(window, isActive); } -void Stub::keyboard_stub(void *user_data, Key key, KeyMod mod, bool isPressed) { - m_keyboard(user_data, key, mod, isPressed); +void Stub::resize_stub(struct Window *window, int width, int height) { + Stub *stub = Stub::GetInstance(window); + stub->m_resize(window, width, height); } -void Stub::char_input_stub(void *user_data, unsigned int code) { - m_char_input(user_data, code); +void Stub::keyboard_stub(struct Window *window, Key key, KeyMod mod, bool isPressed) { + Stub *stub = Stub::GetInstance(window); + stub->m_keyboard(window, key, mod, isPressed); } -void Stub::mouse_btn_stub(void *user_data, MouseButton button, KeyMod mod, bool isPressed) { - m_mouse_btn(user_data, button, mod, isPressed); +void Stub::char_input_stub(struct Window *window, unsigned int code) { + Stub *stub = Stub::GetInstance(window); + stub->m_char_input(window, code); } -void Stub::mouse_move_stub(void *user_data, int x, int y) { - m_mouse_move(user_data, x, y); +void Stub::mouse_btn_stub(struct Window *window, MouseButton button, KeyMod mod, bool isPressed) { + Stub *stub = Stub::GetInstance(window); + stub->m_mouse_btn(window, button, mod, isPressed); } -void Stub::scroll_stub(void *user_data, KeyMod mod, float deltaX, float deltaY) { - m_scroll(user_data, mod, deltaX, deltaY); +void Stub::mouse_move_stub(struct Window *window, int x, int y) { + Stub *stub = Stub::GetInstance(window); + stub->m_mouse_move(window, x, y); +} + +void Stub::scroll_stub(struct Window *window, KeyMod mod, float deltaX, float deltaY) { + Stub *stub = Stub::GetInstance(window); + stub->m_scroll(window, mod, deltaX, deltaY); } diff --git a/src/MiniFB_internal.c b/src/MiniFB_internal.c index 5b74a3b..ed23e8e 100644 --- a/src/MiniFB_internal.c +++ b/src/MiniFB_internal.c @@ -72,4 +72,4 @@ void stretch_image(uint32_t *srcImage, uint32_t srcX, uint32_t srcY, uint32_t sr } dstImage += dstPitch; } -} \ No newline at end of file +} diff --git a/src/MiniFB_internal.h b/src/MiniFB_internal.h index f7b2010..c82148b 100755 --- a/src/MiniFB_internal.h +++ b/src/MiniFB_internal.h @@ -1,11 +1,10 @@ #pragma once #include "MiniFB.h" +#include "MiniFB_enums.h" -extern void *g_user_data; - -#define kCall(f, ...) if((f)) (f)(g_user_data, __VA_ARGS__); -#define kUnused(var) (void) var; +#define kCall(func, ...) if(window_data && window_data->func) window_data->func((struct Window *) window_data, __VA_ARGS__); +#define kUnused(var) (void) var; #if defined(__cplusplus) extern "C" { @@ -13,15 +12,7 @@ extern "C" { short int keycodes[512]; void init_keycodes(); - void keyboard_default(void *user_data, Key key, KeyMod mod, bool isPressed); - - extern mfb_active_func g_active_func; - extern mfb_resize_func g_resize_func; - extern mfb_keyboard_func g_keyboard_func; - extern mfb_char_input_func g_char_input_func; - extern mfb_mouse_btn_func g_mouse_btn_func; - extern mfb_mouse_move_func g_mouse_move_func; - extern mfb_mouse_scroll_func g_mouse_wheel_func; + void keyboard_default(struct Window *window, Key key, KeyMod mod, bool isPressed); #if defined(__cplusplus) } diff --git a/src/WindowData.h b/src/WindowData.h new file mode 100644 index 0000000..79ffcb8 --- /dev/null +++ b/src/WindowData.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include + +typedef struct { + void *specific; + void *user_data; + + mfb_active_func active_func; + mfb_resize_func resize_func; + mfb_keyboard_func keyboard_func; + mfb_char_input_func char_input_func; + mfb_mouse_btn_func mouse_btn_func; + mfb_mouse_move_func mouse_move_func; + mfb_mouse_scroll_func mouse_wheel_func; + + uint32_t window_width; + uint32_t window_height; + + uint32_t dst_offset_x; + uint32_t dst_offset_y; + uint32_t dst_width; + uint32_t dst_height; + + void *draw_buffer; + uint32_t buffer_width; + uint32_t buffer_height; + uint32_t buffer_stride; + uint32_t mod_keys; + bool close; +} SWindowData; diff --git a/src/macosx/MacMiniFB.m b/src/macosx/MacMiniFB.m index a990b70..8cecd81 100644 --- a/src/macosx/MacMiniFB.m +++ b/src/macosx/MacMiniFB.m @@ -1,6 +1,6 @@ #include "OSXWindow.h" #include "OSXWindowFrameView.h" -#include "OSXWindowData.h" +#include "WindowData_OSX.h" #include #include #include @@ -11,15 +11,11 @@ #endif #include -SWindowData g_window_data = { 0 }; - void init_keycodes(); #if defined(USE_METAL_API) -extern id g_metal_device; -extern id g_command_queue; -extern id g_library; -extern id g_pipeline_state; +id g_metal_device; +id g_library; Vertex gVertices[4] = { {-1.0, -1.0, 0, 1}, @@ -32,93 +28,93 @@ Vertex gVertices[4] = { NSString* g_shadersSrc = @ " #include \n" - "using namespace metal;\n" + "using namespace metal;\n" - "struct VertexOutput {\n" - "float4 pos [[position]];\n" - "float2 texcoord;\n" - "};\n" + "struct VertexOutput {\n" + "float4 pos [[position]];\n" + "float2 texcoord;\n" + "};\n" - "vertex VertexOutput vertFunc(unsigned int vID[[vertex_id]])\n" - "{\n" - "VertexOutput out;\n" + "vertex VertexOutput vertFunc(unsigned int vID[[vertex_id]])\n" + "{\n" + "VertexOutput out;\n" - "out.pos.x = (float)(vID / 2) * 4.0 - 1.0;\n" - "out.pos.y = (float)(vID % 2) * 4.0 - 1.0;\n" - "out.pos.z = 0.0;\n" - "out.pos.w = 1.0;\n" + "out.pos.x = (float)(vID / 2) * 4.0 - 1.0;\n" + "out.pos.y = (float)(vID % 2) * 4.0 - 1.0;\n" + "out.pos.z = 0.0;\n" + "out.pos.w = 1.0;\n" - "out.texcoord.x = (float)(vID / 2) * 2.0;\n" - "out.texcoord.y = 1.0 - (float)(vID % 2) * 2.0;\n" + "out.texcoord.x = (float)(vID / 2) * 2.0;\n" + "out.texcoord.y = 1.0 - (float)(vID % 2) * 2.0;\n" - "return out;\n" - "}\n" + "return out;\n" + "}\n" "struct Vertex\n" "{\n" "float4 position [[position]];\n" "};\n" - "vertex VertexOutput vertFunc2(unsigned int vID[[vertex_id]], device Vertex *pos [[buffer(0)]])\n" - "{\n" - "VertexOutput out;\n" + "vertex VertexOutput vertFunc2(unsigned int vID[[vertex_id]], device Vertex *pos [[buffer(0)]])\n" + "{\n" + "VertexOutput out;\n" - "out.pos = pos[vID].position;\n" + "out.pos = pos[vID].position;\n" - "out.texcoord.x = (float)(vID / 2);\n" - "out.texcoord.y = 1.0 - (float)(vID % 2);\n" + "out.texcoord.x = (float)(vID / 2);\n" + "out.texcoord.y = 1.0 - (float)(vID % 2);\n" - "return out;\n" - "}\n" + "return out;\n" + "}\n" - "fragment float4 fragFunc(VertexOutput input [[stage_in]],\n" - "texture2d colorTexture [[ texture(0) ]])\n" - "{\n" - "constexpr sampler textureSampler(mag_filter::nearest, min_filter::nearest);\n" + "fragment float4 fragFunc(VertexOutput input [[stage_in]],\n" + "texture2d colorTexture [[ texture(0) ]])\n" + "{\n" + "constexpr sampler textureSampler(mag_filter::nearest, min_filter::nearest);\n" - // Sample the texture to obtain a color - "const half4 colorSample = colorTexture.sample(textureSampler, input.texcoord);\n" + // Sample the texture to obtain a color + "const half4 colorSample = colorTexture.sample(textureSampler, input.texcoord);\n" - // We return the color of the texture - "return float4(colorSample);\n" - //"return float4(input.texcoord.x, input.texcoord.y, 0.0, 1.0);\n" - "}\n"; + // We return the color of the texture + "return float4(colorSample);\n" + //"return float4(input.texcoord.x, input.texcoord.y, 0.0, 1.0);\n" + "}\n"; #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #if defined(USE_METAL_API) -static bool create_shaders() { - // Error - NSError* nsError = NULL; - NSError** nsErrorPtr = &nsError; +static bool create_shaders(SWindowData_OSX *window_data_osx) { + // Error + NSError* nsError = 0x0; + NSError** nsErrorPtr = &nsError; - id library = [g_metal_device newLibraryWithSource:g_shadersSrc - options:[[MTLCompileOptions alloc] init] - error:nsErrorPtr]; + id library = [g_metal_device newLibraryWithSource:g_shadersSrc + options:[[MTLCompileOptions alloc] init] + error:nsErrorPtr]; - // Error update - if (nsError || !library) { - NSLog(@"Unable to create shaders %@", nsError); - return false; - } + // Error update + if (nsError || !library) { + NSLog(@"Unable to create shaders %@", nsError); + return false; + } - g_library = library; - NSLog(@"Names %@", [g_library functionNames]); + g_library = library; + NSLog(@"Names %@", [g_library functionNames]); - id vertex_shader_func = [g_library newFunctionWithName:@"vertFunc2"]; - id fragment_shader_func = [g_library newFunctionWithName:@"fragFunc"]; + id vertex_shader_func = [g_library newFunctionWithName:@"vertFunc2"]; + id fragment_shader_func = [g_library newFunctionWithName:@"fragFunc"]; - if (!vertex_shader_func) { - printf("Unable to get vertFunc!\n"); - return false; - } + if (!vertex_shader_func) { + printf("Unable to get vertFunc!\n"); + return false; + } - if (!fragment_shader_func) { - printf("Unable to get fragFunc!\n"); - return false; - } + if (!fragment_shader_func) { + printf("Unable to get fragFunc!\n"); + return false; + } // Create a reusable pipeline state MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; @@ -127,100 +123,108 @@ static bool create_shaders() { pipelineStateDescriptor.fragmentFunction = fragment_shader_func; pipelineStateDescriptor.colorAttachments[0].pixelFormat = 80; //bgra8Unorm; - NSError *error = NULL; - g_pipeline_state = [g_metal_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error]; - if (!g_pipeline_state) + NSError *error = 0x0; + window_data_osx->metal.pipeline_state = [g_metal_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error]; + if (!window_data_osx->metal.pipeline_state) { NSLog(@"Failed to created pipeline state, error %@", error); } - return true; + return true; } #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int mfb_open(const char* name, int width, int height) +struct Window *mfb_open(const char *title, int width, int height) { - return mfb_open_ex(name, width, height, 0); + return mfb_open_ex(title, width, height, 0); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int mfb_open_ex(const char* name, int width, int height, int flags) +struct Window *mfb_open_ex(const char *title, int width, int height, int flags) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; init_keycodes(); - g_window_data.window_width = width; - g_window_data.window_height = height; + SWindowData *window_data = malloc(sizeof(SWindowData)); + memset(window_data, 0, sizeof(SWindowData)); - g_window_data.dst_width = width; - g_window_data.dst_height = height; + SWindowData_OSX *window_data_osx = malloc(sizeof(SWindowData_OSX)); + memset(window_data_osx, 0, sizeof(SWindowData_OSX)); + window_data->specific = window_data_osx; - g_window_data.buffer_width = width; - g_window_data.buffer_height = height; + window_data->window_width = width; + window_data->window_height = height; - [NSApplication sharedApplication]; - [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + window_data->dst_width = width; + window_data->dst_height = height; + + window_data->buffer_width = width; + window_data->buffer_height = height; + window_data->buffer_stride = width * 4; + + [NSApplication sharedApplication]; + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; #if defined(USE_METAL_API) - g_metal_device = MTLCreateSystemDefaultDevice(); + g_metal_device = MTLCreateSystemDefaultDevice(); - if (!g_metal_device) { - printf("Your device/OS doesn't support Metal."); - return -1; - } + if (!g_metal_device) { + printf("Your device/OS doesn't support Metal."); + return 0x0; + } - if (!create_shaders()) { - return -2; - } + if (!create_shaders((SWindowData_OSX *) window_data->specific)) { + return 0x0; + } #endif - NSWindowStyleMask styles = NSWindowStyleMaskClosable | NSWindowStyleMaskTitled; + NSWindowStyleMask styles = NSWindowStyleMaskClosable | NSWindowStyleMaskTitled; - if (flags & WF_BORDERLESS) - styles |= NSWindowStyleMaskBorderless; + if (flags & WF_BORDERLESS) + styles |= NSWindowStyleMaskBorderless; - if (flags & WF_RESIZABLE) - styles |= NSWindowStyleMaskResizable; + if (flags & WF_RESIZABLE) + styles |= NSWindowStyleMaskResizable; - NSRect rectangle = NSMakeRect(0, 0, width, height); - g_window_data.window = [[OSXWindow alloc] initWithContentRect:rectangle styleMask:styles backing:NSBackingStoreBuffered defer:NO]; - if (!g_window_data.window) - return -3; + NSRect rectangle = NSMakeRect(0, 0, width, height); + window_data_osx->window = [[OSXWindow alloc] initWithContentRect:rectangle styleMask:styles backing:NSBackingStoreBuffered defer:NO windowData:window_data]; + if (!window_data_osx->window) + return 0x0; #if defined(USE_METAL_API) - g_window_data.draw_buffer = malloc(width * height * 4); + window_data->draw_buffer = malloc(width * height * 4); - if (!g_window_data.draw_buffer) - return -4; + if (!window_data->draw_buffer) + return 0x0; - // Setup command queue - g_command_queue = [g_metal_device newCommandQueue]; + // Setup command queue + window_data_osx->metal.command_queue = [g_metal_device newCommandQueue]; WindowViewController* viewController = [WindowViewController new]; - MTLTextureDescriptor* textureDescriptor = [[MTLTextureDescriptor alloc] init]; + MTLTextureDescriptor* textureDescriptor = [[MTLTextureDescriptor alloc] init]; - // Indicate that each pixel has a blue, green, red, and alpha channel, where each channel is - // an 8-bit unsigned normalized value (i.e. 0 maps to 0.0 and 255 maps to 1.0) - textureDescriptor.pixelFormat = MTLPixelFormatBGRA8Unorm; + // Indicate that each pixel has a blue, green, red, and alpha channel, where each channel is + // an 8-bit unsigned normalized value (i.e. 0 maps to 0.0 and 255 maps to 1.0) + textureDescriptor.pixelFormat = MTLPixelFormatBGRA8Unorm; - // Set the pixel dimensions of the texture - textureDescriptor.width = width; - textureDescriptor.height = height; + // Set the pixel dimensions of the texture + textureDescriptor.width = width; + textureDescriptor.height = height; - // Create the texture from the device by using the descriptor - - for (int i = 0; i < MaxBuffersInFlight; ++i) { - viewController->m_texture_buffers[i] = [g_metal_device newTextureWithDescriptor:textureDescriptor]; - } + // Create the texture from the device by using the descriptor + + for (int i = 0; i < MaxBuffersInFlight; ++i) { + viewController->m_texture_buffers[i] = [g_metal_device newTextureWithDescriptor:textureDescriptor]; + } - // Used for syncing the CPU and GPU - viewController->m_semaphore = dispatch_semaphore_create(MaxBuffersInFlight); - viewController->m_draw_buffer = g_window_data.draw_buffer; + // Used for syncing the CPU and GPU + viewController->m_semaphore = dispatch_semaphore_create(MaxBuffersInFlight); + viewController->m_draw_buffer = window_data->draw_buffer; viewController->m_width = width; viewController->m_height = height; @@ -228,30 +232,29 @@ int mfb_open_ex(const char* name, int width, int height, int flags) view.device = g_metal_device; view.delegate = viewController; view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; - [g_window_data.window.contentView addSubview:view]; + [window_data_osx->window.contentView addSubview:view]; - g_window_data.buffer_width = width; - g_window_data.buffer_height = height; + //window_data->buffer_width = width; + //window_data->buffer_height = height; + //window_data->buffer_stride = width * 4; - //[g_window_data.window updateSize]; + //[window_data->window updateSize]; #endif - [g_window_data.window setTitle:[NSString stringWithUTF8String:name]]; - [g_window_data.window setReleasedWhenClosed:NO]; - [g_window_data.window performSelectorOnMainThread:@selector(makeKeyAndOrderFront:) withObject:nil waitUntilDone:YES]; - [g_window_data.window setAcceptsMouseMovedEvents:YES]; + [window_data_osx->window setTitle:[NSString stringWithUTF8String:title]]; + [window_data_osx->window setReleasedWhenClosed:NO]; + [window_data_osx->window performSelectorOnMainThread:@selector(makeKeyAndOrderFront:) withObject:nil waitUntilDone:YES]; + [window_data_osx->window setAcceptsMouseMovedEvents:YES]; - [g_window_data.window center]; + [window_data_osx->window center]; - [NSApp activateIgnoringOtherApps:YES]; + [NSApp activateIgnoringOtherApps:YES]; #if defined(USE_METAL_API) - [NSApp finishLaunching]; + [NSApp finishLaunching]; #endif - if (g_keyboard_func == 0x0) { - mfb_keyboard_callback(keyboard_default); - } + mfb_keyboard_callback((struct Window *) window_data, keyboard_default); #if defined(USE_METAL_API) NSLog(@"Window created using Metal API"); @@ -259,41 +262,42 @@ int mfb_open_ex(const char* name, int width, int height, int flags) NSLog(@"Window created using Cocoa API"); #endif - [pool drain]; + [pool drain]; - return 1; + return (struct Window *) window_data; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void keyboard_default(void *user_data, Key key, KeyMod mod, bool isPressed) { - kUnused(user_data); - kUnused(mod); - kUnused(isPressed); - if (key == KB_KEY_ESCAPE) - g_window_data.close = true; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void mfb_close() +static void destroy_window_data(SWindowData *window_data) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + if(window_data == 0x0) + return; - g_window_data.close = true; - if (g_window_data.window) - [g_window_data.window close]; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific; + if(window_data_osx != 0x0) { + OSXWindow *window = window_data_osx->window; + [window removeWindowData]; + [window performClose:nil]; - [pool drain]; + memset(window_data_osx, 0, sizeof(SWindowData_OSX)); + free(window_data_osx); + } + memset(window_data, 0, sizeof(SWindowData)); + free(window_data); + + [pool drain]; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -static int update_events() +static void update_events(SWindowData *window_data) { - NSEvent* event; + NSEvent* event; - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; do { event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; @@ -301,57 +305,67 @@ static int update_events() [NSApp sendEvent:event]; } } - while ((g_window_data.close == false) && event); + while ((window_data->close == false) && event); - [pool release]; - - if(g_window_data.close == true) - return -1; - - return 0; + [pool release]; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int mfb_update(void* buffer) +UpdateState mfb_update(struct Window *window, void* buffer) { - if(buffer == 0x0) - return -2; + if(window == 0x0) { + return STATE_INVALID_WINDOW; + } + + SWindowData *window_data = (SWindowData *) window; + if(window_data->close) { + destroy_window_data(window_data); + return STATE_EXIT; + } + + if(buffer == 0x0) { + return STATE_INVALID_BUFFER; + } #if defined(USE_METAL_API) - memcpy(g_window_data.draw_buffer, buffer, g_window_data.buffer_width * g_window_data.buffer_height * 4); + memcpy(window_data->draw_buffer, buffer, window_data->buffer_width * window_data->buffer_height * 4); #else - g_window_data.draw_buffer = buffer; + window_data->draw_buffer = buffer; #endif - int state = update_events(); - if(g_window_data.close == false) - [[g_window_data.window contentView] setNeedsDisplay:YES]; + update_events(window_data); + if(window_data->close == false) { + SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific; + [[window_data_osx->window contentView] setNeedsDisplay:YES]; + } - return state; + return STATE_OK; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool mfb_set_viewport(unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) +bool mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { - if(offset_x + width > g_window_data.window_width) { + SWindowData *window_data = (SWindowData *) window; + + if(offset_x + width > window_data->window_width) { return false; } - if(offset_y + height > g_window_data.window_height) { + if(offset_y + height > window_data->window_height) { return false; } - g_window_data.dst_offset_x = offset_x; - g_window_data.dst_offset_y = offset_y; - g_window_data.dst_width = width; - g_window_data.dst_height = height; + window_data->dst_offset_x = offset_x; + window_data->dst_offset_y = offset_y; + window_data->dst_width = width; + window_data->dst_height = height; #if defined(USE_METAL_API) - float x1 = ((float) offset_x / g_window_data.window_width) * 2.0f - 1.0f; - float x2 = (((float) offset_x + width) / g_window_data.window_width) * 2.0f - 1.0f; - float y1 = ((float) offset_y / g_window_data.window_height) * 2.0f - 1.0f; - float y2 = (((float) offset_y + height) / g_window_data.window_height) * 2.0f - 1.0f; + float x1 = ((float) offset_x / window_data->window_width) * 2.0f - 1.0f; + float x2 = (((float) offset_x + width) / window_data->window_width) * 2.0f - 1.0f; + float y1 = ((float) offset_y / window_data->window_height) * 2.0f - 1.0f; + float y2 = (((float) offset_y + height) / window_data->window_height) * 2.0f - 1.0f; gVertices[0].x = x1; gVertices[0].y = y1; diff --git a/src/macosx/OSXWindow.h b/src/macosx/OSXWindow.h index 61a92e7..4dd0ba7 100644 --- a/src/macosx/OSXWindow.h +++ b/src/macosx/OSXWindow.h @@ -1,10 +1,18 @@ #import - +#include // @class OSXWindowFrameView; @interface OSXWindow : NSWindow { - NSView *childContentView; + NSView *childContentView; + @public SWindowData *window_data; } +- (id)initWithContentRect:(NSRect)contentRect + styleMask:(NSWindowStyleMask)windowStyle + backing:(NSBackingStoreType)bufferingType + defer:(BOOL)deferCreation + windowData:(SWindowData *) windowData; + +- (void) removeWindowData; @end diff --git a/src/macosx/OSXWindow.m b/src/macosx/OSXWindow.m index 9b1a4ab..c618a58 100644 --- a/src/macosx/OSXWindow.m +++ b/src/macosx/OSXWindow.m @@ -1,22 +1,20 @@ #import "OSXWindow.h" #import "OSXWindowFrameView.h" -#include "OSXWindowData.h" +#include "WindowData_OSX.h" #include #include -extern SWindowData g_window_data; extern short int g_keycodes[512]; -bool gActive = false; - @implementation OSXWindow /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - (id)initWithContentRect:(NSRect)contentRect - styleMask:(NSWindowStyleMask)windowStyle - backing:(NSBackingStoreType)bufferingType - defer:(BOOL)deferCreation + styleMask:(NSWindowStyleMask)windowStyle + backing:(NSBackingStoreType)bufferingType + defer:(BOOL)deferCreation + windowData:(SWindowData *) windowData { self = [super initWithContentRect:contentRect @@ -30,12 +28,24 @@ bool gActive = false; [self setBackgroundColor:[NSColor clearColor]]; self.delegate = self; + + self->window_data = windowData; + OSXWindowFrameView *view = (OSXWindowFrameView *) self->childContentView.superview; + view->window_data = windowData; } return self; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +- (void) removeWindowData { + self->window_data = 0x0; + OSXWindowFrameView *view = (OSXWindowFrameView *) self->childContentView.superview; + view->window_data = 0x0; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + - (void)dealloc { [[NSNotificationCenter defaultCenter] @@ -62,7 +72,7 @@ bool gActive = false; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// --(void)flagsChanged:(NSEvent *)event +- (void)flagsChanged:(NSEvent *)event { const uint32_t flags = [event modifierFlags]; uint32_t mod_keys = 0, mod_keys_aux = 0; @@ -88,32 +98,31 @@ bool gActive = false; mod_keys |= KB_MOD_NUM_LOCK; } - if(mod_keys != g_window_data.mod_keys) { + if(mod_keys != window_data->mod_keys) { short int keyCode = keycodes[[event keyCode] & 0x1ff]; if(keyCode != KB_KEY_UNKNOWN) { - mod_keys_aux = mod_keys ^ g_window_data.mod_keys; + mod_keys_aux = mod_keys ^ window_data->mod_keys; if(mod_keys_aux & KB_MOD_CAPS_LOCK) { - kCall(g_keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_CAPS_LOCK) != 0); + kCall(keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_CAPS_LOCK) != 0); } if(mod_keys_aux & KB_MOD_SHIFT) { - kCall(g_keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_SHIFT) != 0); + kCall(keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_SHIFT) != 0); } if(mod_keys_aux & KB_MOD_CONTROL) { - kCall(g_keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_CONTROL) != 0); + kCall(keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_CONTROL) != 0); } if(mod_keys_aux & KB_MOD_ALT) { - kCall(g_keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_ALT) != 0); + kCall(keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_ALT) != 0); } if(mod_keys_aux & KB_MOD_SUPER) { - kCall(g_keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_SUPER) != 0); + kCall(keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_SUPER) != 0); } if(mod_keys_aux & KB_MOD_NUM_LOCK) { - kCall(g_keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_NUM_LOCK) != 0); + kCall(keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_NUM_LOCK) != 0); } } } - g_window_data.mod_keys = mod_keys; - //NSLog(@"KeyCode: %d (%x) - %x", [event keyCode], [event keyCode], flags); + window_data->mod_keys = mod_keys; [super flagsChanged:event]; } @@ -123,7 +132,7 @@ bool gActive = false; - (void)keyDown:(NSEvent *)event { short int keyCode = keycodes[[event keyCode] & 0x1ff]; - kCall(g_keyboard_func, keyCode, g_window_data.mod_keys, true); + kCall(keyboard_func, keyCode, window_data->mod_keys, true); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -131,7 +140,7 @@ bool gActive = false; - (void)keyUp:(NSEvent *)event { short int keyCode = keycodes[[event keyCode] & 0x1ff]; - kCall(g_keyboard_func, keyCode, g_window_data.mod_keys, false); + kCall(keyboard_func, keyCode, window_data->mod_keys, false); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -155,7 +164,7 @@ bool gActive = false; if ((code & 0xff00) == 0xf700) continue; - kCall(g_char_input_func, code); + kCall(char_input_func, code); } } @@ -165,9 +174,10 @@ bool gActive = false; { kUnused(notification); - if(gActive == true) { - gActive = false; - kCall(g_active_func, false); + SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific; + if(window_data_osx->active == true) { + window_data_osx->active = false; + kCall(active_func, false); } } @@ -217,18 +227,20 @@ bool gActive = false; - (void)windowDidBecomeKey:(NSNotification *)notification { kUnused(notification); - kCall(g_active_func, true); + kCall(active_func, true); } - (void)windowDidResignKey:(NSNotification *)notification { kUnused(notification); - kCall(g_active_func, false); + kCall(active_func, false); } - (void)windowWillClose:(NSNotification *)notification { kUnused(notification); - g_window_data.close = true; + if(window_data) { + window_data->close = true; + } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -258,7 +270,7 @@ bool gActive = false; - (void)willClose { - g_window_data.close = true; + window_data->close = true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -267,10 +279,10 @@ bool gActive = false; kUnused(notification); CGSize size = [self contentRectForFrameRect:[self frame]].size; - g_window_data.window_width = size.width; - g_window_data.window_height = size.height; + window_data->window_width = size.width; + window_data->window_height = size.height; - kCall(g_resize_func, size.width, size.height); + kCall(resize_func, size.width, size.height); } @end diff --git a/src/macosx/OSXWindowData.h b/src/macosx/OSXWindowData.h deleted file mode 100644 index b0ebc0b..0000000 --- a/src/macosx/OSXWindowData.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include - -@class OSXWindow; - -typedef struct { - OSXWindow *window; - uint32_t window_width; - uint32_t window_height; - - uint32_t dst_offset_x; - uint32_t dst_offset_y; - uint32_t dst_width; - uint32_t dst_height; - - void *draw_buffer; - uint32_t buffer_width; - uint32_t buffer_height; - uint32_t mod_keys; - bool close; -} SWindowData; diff --git a/src/macosx/OSXWindowFrameView.h b/src/macosx/OSXWindowFrameView.h index 93e6173..d887b17 100644 --- a/src/macosx/OSXWindowFrameView.h +++ b/src/macosx/OSXWindowFrameView.h @@ -1,5 +1,7 @@ #import +#include "WindowData.h" + #if defined(USE_METAL_API) #import @@ -8,19 +10,19 @@ typedef struct Vertex { } Vertex; // Number of textures in flight (tripple buffered) -static const int MaxBuffersInFlight = 3; +enum { MaxBuffersInFlight = 3 }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @interface WindowViewController : NSViewController { - @public id m_texture_buffers[MaxBuffersInFlight]; - @public int m_current_buffer; - @public void* m_draw_buffer; - @public int m_width; - @public int m_height; - // Used for syncing with CPU/GPU - @public dispatch_semaphore_t m_semaphore; + @public id m_texture_buffers[MaxBuffersInFlight]; + @public int m_current_buffer; + @public void* m_draw_buffer; + @public int m_width; + @public int m_height; + // Used for syncing with CPU/GPU + @public dispatch_semaphore_t m_semaphore; } @end @@ -30,8 +32,9 @@ static const int MaxBuffersInFlight = 3; @interface OSXWindowFrameView : NSView { + @public SWindowData *window_data; #if defined(USE_METAL_API) - @private NSTrackingArea* trackingArea; + @private NSTrackingArea* trackingArea; #endif } diff --git a/src/macosx/OSXWindowFrameView.m b/src/macosx/OSXWindowFrameView.m index fc278ec..78c039c 100644 --- a/src/macosx/OSXWindowFrameView.m +++ b/src/macosx/OSXWindowFrameView.m @@ -1,31 +1,32 @@ #import "OSXWindowFrameView.h" #import "OSXWindow.h" -#include "OSXWindowData.h" +#include "WindowData_OSX.h" #include -extern SWindowData g_window_data; - #if defined(USE_METAL_API) #import -id g_metal_device; -id g_command_queue; -id g_library; -id g_pipeline_state; +extern id g_metal_device; +extern id g_library; extern Vertex gVertices[4]; @implementation WindowViewController --(void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size +- (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size { (void)view; (void)size; // resize } --(void)drawInMTKView:(nonnull MTKView *)view +- (void)drawInMTKView:(nonnull MTKView *)view { + OSXWindow *window = (OSXWindow *) view.window; + if(window->window_data == 0x0) { + return; + } + // Wait to ensure only MaxBuffersInFlight number of frames are getting proccessed // by any stage in the Metal pipeline (App, Metal, Drivers, GPU, etc) dispatch_semaphore_wait(m_semaphore, DISPATCH_TIME_FOREVER); @@ -42,7 +43,8 @@ extern Vertex gVertices[4]; mipmapLevel:0 withBytes:m_draw_buffer bytesPerRow:bytesPerRow]; // Create a new command buffer for each render pass to the current drawable - id commandBuffer = [g_command_queue commandBuffer]; + SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window->window_data->specific; + id commandBuffer = [window_data_osx->metal.command_queue commandBuffer]; commandBuffer.label = @"minifb_command_buffer"; // Add completion hander which signals _inFlightSemaphore when Metal and the GPU has fully @@ -69,7 +71,9 @@ extern Vertex gVertices[4]; renderEncoder.label = @"minifb_command_encoder"; // Set render command encoder state - [renderEncoder setRenderPipelineState:g_pipeline_state]; + OSXWindow *window = (OSXWindow *) view.window; + SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window->window_data->specific; + [renderEncoder setRenderPipelineState:window_data_osx->metal.pipeline_state]; [renderEncoder setVertexBytes:gVertices length:sizeof(gVertices) @@ -103,7 +107,7 @@ extern Vertex gVertices[4]; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #if defined(USE_METAL_API) --(void)updateTrackingAreas +- (void)updateTrackingAreas { if(trackingArea != nil) { [self removeTrackingArea:trackingArea]; @@ -142,16 +146,20 @@ extern Vertex gVertices[4]; { (void)rect; - if (!g_window_data.window || !g_window_data.draw_buffer) + if(!window_data) + return; + + SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific; + if (!window_data_osx || !window_data_osx->window || !window_data->draw_buffer) return; CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); - CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, g_window_data.draw_buffer, g_window_data.buffer_width * g_window_data.buffer_height * 4, NULL); + CGDataProviderRef provider = CGDataProviderCreateWithData(0x0, window_data->draw_buffer, window_data->buffer_width * window_data->buffer_height * 4, 0x0); - CGImageRef img = CGImageCreate(g_window_data.buffer_width, g_window_data.buffer_height, 8, 32, g_window_data.buffer_width * 4, space, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little, - provider, NULL, false, kCGRenderingIntentDefault); + CGImageRef img = CGImageCreate(window_data->buffer_width, window_data->buffer_height, 8, 32, window_data->buffer_width * 4, space, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little, + provider, 0x0, false, kCGRenderingIntentDefault); const CGFloat components[] = {0.0f, 0.0f, 0.0f, 1.0f}; const CGColorRef black = CGColorCreate(space, components); @@ -159,12 +167,12 @@ extern Vertex gVertices[4]; CGColorSpaceRelease(space); CGDataProviderRelease(provider); - if(g_window_data.dst_offset_x != 0 || g_window_data.dst_offset_y != 0 || g_window_data.dst_width != g_window_data.window_width || g_window_data.dst_height != g_window_data.window_height) { + if(window_data->dst_offset_x != 0 || window_data->dst_offset_y != 0 || window_data->dst_width != window_data->window_width || window_data->dst_height != window_data->window_height) { CGContextSetFillColorWithColor(context, black); - CGContextFillRect(context, CGRectMake(0, 0, g_window_data.window_width, g_window_data.window_height)); + CGContextFillRect(context, CGRectMake(0, 0, window_data->window_width, window_data->window_height)); } - CGContextDrawImage(context, CGRectMake(g_window_data.dst_offset_x, g_window_data.dst_offset_y, g_window_data.dst_width, g_window_data.dst_height), img); + CGContextDrawImage(context, CGRectMake(window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height), img); CGImageRelease(img); } @@ -183,7 +191,7 @@ extern Vertex gVertices[4]; - (void)mouseDown:(NSEvent*)event { (void)event; - kCall(g_mouse_btn_func, MOUSE_BTN_1, g_window_data.mod_keys, true); + kCall(mouse_btn_func, MOUSE_BTN_1, window_data->mod_keys, true); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -191,7 +199,7 @@ extern Vertex gVertices[4]; - (void)mouseUp:(NSEvent*)event { (void)event; - kCall(g_mouse_btn_func, MOUSE_BTN_1, g_window_data.mod_keys, false); + kCall(mouse_btn_func, MOUSE_BTN_1, window_data->mod_keys, false); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -199,7 +207,7 @@ extern Vertex gVertices[4]; - (void)rightMouseDown:(NSEvent*)event { (void)event; - kCall(g_mouse_btn_func, MOUSE_BTN_2, g_window_data.mod_keys, true); + kCall(mouse_btn_func, MOUSE_BTN_2, window_data->mod_keys, true); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -207,7 +215,7 @@ extern Vertex gVertices[4]; - (void)rightMouseUp:(NSEvent*)event { (void)event; - kCall(g_mouse_btn_func, MOUSE_BTN_1, g_window_data.mod_keys, false); + kCall(mouse_btn_func, MOUSE_BTN_1, window_data->mod_keys, false); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -215,7 +223,7 @@ extern Vertex gVertices[4]; - (void)otherMouseDown:(NSEvent *)event { (void)event; - kCall(g_mouse_btn_func, [event buttonNumber], g_window_data.mod_keys, true); + kCall(mouse_btn_func, [event buttonNumber], window_data->mod_keys, true); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -223,14 +231,14 @@ extern Vertex gVertices[4]; - (void)otherMouseUp:(NSEvent *)event { (void)event; - kCall(g_mouse_btn_func, [event buttonNumber], g_window_data.mod_keys, false); + kCall(mouse_btn_func, [event buttonNumber], window_data->mod_keys, false); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - (void)scrollWheel:(NSEvent *)event { - kCall(g_mouse_wheel_func, g_window_data.mod_keys, [event deltaX], [event deltaY]); + kCall(mouse_wheel_func, window_data->mod_keys, [event deltaX], [event deltaY]); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -254,7 +262,7 @@ extern Vertex gVertices[4]; { NSPoint point = [event locationInWindow]; //NSPoint localPoint = [self convertPoint:point fromView:nil]; - kCall(g_mouse_move_func, point.x, point.y); + kCall(mouse_move_func, point.x, point.y); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/macosx/WindowData_OSX.h b/src/macosx/WindowData_OSX.h new file mode 100644 index 0000000..4948315 --- /dev/null +++ b/src/macosx/WindowData_OSX.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +#if defined(USE_METAL_API) +#include +#endif + +@class OSXWindow; + +typedef struct { + OSXWindow *window; +#if defined(USE_METAL_API) + struct { + id command_queue; + id pipeline_state; + } metal; +#endif + bool active; +} SWindowData_OSX; diff --git a/src/wayland/WaylandMiniFB.c b/src/wayland/WaylandMiniFB.c index 73db7b5..c76560e 100644 --- a/src/wayland/WaylandMiniFB.c +++ b/src/wayland/WaylandMiniFB.c @@ -1,7 +1,8 @@ #include #include "MiniFB_internal.h" #include "MiniFB_enums.h" -#include "WaylandWindowData.h" +#include "WindowData.h" +#include "WindowData_Way.h" #include #include @@ -18,29 +19,48 @@ #include -SWindowData g_window_data = { 0 }; - static void -destroy(void) +destroy_window_data(SWindowData *window_data) { - if (! g_window_data.display) + if(window_data == 0x0) return; -#define KILL(NAME) \ - do \ - { \ - if (g_window_data.NAME) \ - wl_##NAME##_destroy(g_window_data.NAME); \ - } while (0); \ - g_window_data.NAME = 0x0; + SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific; + if(window_data_way != 0x0) { + memset(window_data_way, 0, sizeof(SWindowData_Way)); + free(window_data_way); + } + memset(window_data, 0, sizeof(SWindowData)); + free(window_data); +} + +static void +destroy(SWindowData *window_data) +{ + if(window_data == 0x0) + return; + + SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific; + if (window_data_way == 0x0 || window_data_way->display == 0x0) { + destroy_window_data(window_data); + return; + } + +#define KILL(NAME) \ + do \ + { \ + if (window_data_way->NAME) \ + wl_##NAME##_destroy(window_data_way->NAME); \ + } while (0); \ + window_data_way->NAME = 0x0; KILL(shell_surface); KILL(shell); KILL(surface); //KILL(buffer); - if(g_window_data.draw_buffer) { - wl_buffer_destroy(g_window_data.draw_buffer); - g_window_data.draw_buffer = 0x0; + if(window_data_way->draw_buffer) { + wl_buffer_destroy(window_data_way->draw_buffer); + window_data_way->draw_buffer = 0x0; } KILL(shm_pool); KILL(shm); @@ -49,8 +69,9 @@ destroy(void) KILL(seat); KILL(registry); #undef KILL - wl_display_disconnect(g_window_data.display); - memset(&g_window_data, 0, sizeof(SWindowData)); + wl_display_disconnect(window_data_way->display); + + destroy_window_data(window_data); } // This event provides a file descriptor to the client which can be memory-mapped @@ -75,12 +96,13 @@ keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int f static void keyboard_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { - kUnused(data); kUnused(keyboard); kUnused(serial); kUnused(surface); kUnused(keys); - kCall(g_active_func, true); + + SWindowData *window_data = (SWindowData *) data; + kCall(active_func, true); } // The leave notification is sent before the enter notification for the new focus. @@ -89,11 +111,12 @@ keyboard_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct static void keyboard_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) { - kUnused(data); kUnused(keyboard); kUnused(serial); kUnused(surface); - kCall(g_active_func, false); + + SWindowData *window_data = (SWindowData *) data; + kCall(active_func, false); } // A key was pressed or released. The time argument is a timestamp with @@ -105,10 +128,11 @@ keyboard_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct static void keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { - kUnused(data); kUnused(keyboard); kUnused(serial); kUnused(time); + + SWindowData *window_data = (SWindowData *) data; if(key < 512) { Key kb_key = (Key) keycodes[key]; bool is_pressed = (bool) (state == WL_KEYBOARD_KEY_STATE_PRESSED); @@ -117,37 +141,37 @@ keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t case KB_KEY_LEFT_SHIFT: case KB_KEY_RIGHT_SHIFT: if(is_pressed) - g_window_data.mod_keys |= KB_MOD_SHIFT; + window_data->mod_keys |= KB_MOD_SHIFT; else - g_window_data.mod_keys &= ~KB_MOD_SHIFT; + window_data->mod_keys &= ~KB_MOD_SHIFT; break; case KB_KEY_LEFT_CONTROL: case KB_KEY_RIGHT_CONTROL: if(is_pressed) - g_window_data.mod_keys |= KB_MOD_CONTROL; + window_data->mod_keys |= KB_MOD_CONTROL; else - g_window_data.mod_keys &= ~KB_MOD_CONTROL; + window_data->mod_keys &= ~KB_MOD_CONTROL; break; case KB_KEY_LEFT_ALT: case KB_KEY_RIGHT_ALT: if(is_pressed) - g_window_data.mod_keys |= KB_MOD_ALT; + window_data->mod_keys |= KB_MOD_ALT; else - g_window_data.mod_keys &= ~KB_MOD_ALT; + window_data->mod_keys &= ~KB_MOD_ALT; break; case KB_KEY_LEFT_SUPER: case KB_KEY_RIGHT_SUPER: if(is_pressed) - g_window_data.mod_keys |= KB_MOD_SUPER; + window_data->mod_keys |= KB_MOD_SUPER; else - g_window_data.mod_keys &= ~KB_MOD_SUPER; + window_data->mod_keys &= ~KB_MOD_SUPER; break; } - kCall(g_keyboard_func, kb_key, (KeyMod)g_window_data.mod_keys, is_pressed); + kCall(keyboard_func, kb_key, (KeyMod)window_data->mod_keys, is_pressed); } } @@ -189,7 +213,7 @@ static const struct wl_keyboard_listener keyboard_listener = { .leave = keyboard_leave, .key = keyboard_key, .modifiers = keyboard_modifiers, - .repeat_info = NULL, + .repeat_info = 0x0, }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -207,7 +231,6 @@ static const struct wl_keyboard_listener keyboard_listener = { static void pointer_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t sx, wl_fixed_t sy) { - kUnused(data); //kUnused(pointer); //kUnused(serial); kUnused(surface); @@ -216,13 +239,16 @@ pointer_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl struct wl_buffer *buffer; struct wl_cursor_image *image; - image = g_window_data.default_cursor->images[0]; + SWindowData *window_data = (SWindowData *) data; + SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific; + + image = window_data_way->default_cursor->images[0]; buffer = wl_cursor_image_get_buffer(image); - wl_pointer_set_cursor(pointer, serial, g_window_data.cursor_surface, image->hotspot_x, image->hotspot_y); - wl_surface_attach(g_window_data.cursor_surface, buffer, 0, 0); - wl_surface_damage(g_window_data.cursor_surface, 0, 0, image->width, image->height); - wl_surface_commit(g_window_data.cursor_surface); + wl_pointer_set_cursor(pointer, serial, window_data_way->cursor_surface, image->hotspot_x, image->hotspot_y); + wl_surface_attach(window_data_way->cursor_surface, buffer, 0, 0); + wl_surface_damage(window_data_way->cursor_surface, 0, 0, image->width, image->height); + wl_surface_commit(window_data_way->cursor_surface); //fprintf(stderr, "Pointer entered surface %p at %d %d\n", surface, sx, sy); } @@ -239,6 +265,7 @@ pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl kUnused(pointer); kUnused(serial); kUnused(surface); + //fprintf(stderr, "Pointer left surface %p\n", surface); } @@ -252,11 +279,12 @@ pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl static void pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy) { - kUnused(data); kUnused(pointer); kUnused(time); + //printf("Pointer moved at %f %f\n", sx / 256.0f, sy / 256.0f); - kCall(g_mouse_move_func, sx >> 24, sy >> 24); + SWindowData *window_data = (SWindowData *) data; + kCall(mouse_move_func, sx >> 24, sy >> 24); } // Mouse button click and release notifications. @@ -280,12 +308,13 @@ pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t static void pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { - kUnused(data); kUnused(pointer); kUnused(serial); kUnused(time); + //printf("Pointer button '%d'(%d)\n", button, state); - kCall(g_mouse_btn_func, button - BTN_MOUSE + 1, g_window_data.mod_keys, state == 1); + SWindowData *window_data = (SWindowData *) data; + kCall(mouse_btn_func, button - BTN_MOUSE + 1, window_data->mod_keys, state == 1); } // Scroll and other axis notifications. @@ -311,16 +340,17 @@ pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t static void pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { - kUnused(data); kUnused(pointer); kUnused(time); kUnused(axis); + //printf("Pointer handle axis: axis: %d (0x%x)\n", axis, value); + SWindowData *window_data = (SWindowData *) data; if(axis == 0) { - kCall(g_mouse_wheel_func, g_window_data.mod_keys, 0.0f, -(value / 256.0f)); + kCall(mouse_wheel_func, window_data->mod_keys, 0.0f, -(value / 256.0f)); } else if(axis == 1) { - kCall(g_mouse_wheel_func, g_window_data.mod_keys, -(value / 256.0f), 0.0f); + kCall(mouse_wheel_func, window_data->mod_keys, -(value / 256.0f), 0.0f); } } @@ -359,10 +389,10 @@ static const struct wl_pointer_listener pointer_listener = { .motion = pointer_motion, .button = pointer_button, .axis = pointer_axis, - .frame = NULL, - .axis_source = NULL, - .axis_stop = NULL, - .axis_discrete = NULL, + .frame = 0x0, + .axis_source = 0x0, + .axis_stop = 0x0, + .axis_discrete = 0x0, }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -371,26 +401,29 @@ static void seat_capabilities(void *data, struct wl_seat *seat, enum wl_seat_capability caps) { kUnused(data); - if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !g_window_data.keyboard) + + SWindowData *window_data = (SWindowData *) data; + SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific; + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !window_data_way->keyboard) { - g_window_data.keyboard = wl_seat_get_keyboard(seat); - wl_keyboard_add_listener(g_window_data.keyboard, &keyboard_listener, NULL); + window_data_way->keyboard = wl_seat_get_keyboard(seat); + wl_keyboard_add_listener(window_data_way->keyboard, &keyboard_listener, window_data); } - else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && g_window_data.keyboard) + else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && window_data_way->keyboard) { - wl_keyboard_destroy(g_window_data.keyboard); - g_window_data.keyboard = NULL; + wl_keyboard_destroy(window_data_way->keyboard); + window_data_way->keyboard = 0x0; } - if ((caps & WL_SEAT_CAPABILITY_POINTER) && !g_window_data.pointer) + if ((caps & WL_SEAT_CAPABILITY_POINTER) && !window_data_way->pointer) { - g_window_data.pointer = wl_seat_get_pointer(seat); - wl_pointer_add_listener(g_window_data.pointer, &pointer_listener, NULL); + window_data_way->pointer = wl_seat_get_pointer(seat); + wl_pointer_add_listener(window_data_way->pointer, &pointer_listener, window_data); } - else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && g_window_data.pointer) + else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && window_data_way->pointer) { - wl_pointer_destroy(g_window_data.pointer); - g_window_data.pointer = NULL; + wl_pointer_destroy(window_data_way->pointer); + window_data_way->pointer = 0x0; } } @@ -403,7 +436,7 @@ seat_name(void *data, struct wl_seat *seat, const char *name) { static const struct wl_seat_listener seat_listener = { .capabilities = seat_capabilities, - .name = NULL, + .name = 0x0, }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -417,16 +450,18 @@ static const struct wl_seat_listener seat_listener = { static void shm_format(void *data, struct wl_shm *shm, uint32_t format) { - kUnused(data); kUnused(shm); - if (g_window_data.shm_format == -1u) + + SWindowData *window_data = (SWindowData *) data; + SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific; + if (window_data_way->shm_format == -1u) { switch (format) { // We could do RGBA, but that would not be what is expected from minifb... // case WL_SHM_FORMAT_ARGB8888: case WL_SHM_FORMAT_XRGB8888: - g_window_data.shm_format = format; + window_data_way->shm_format = format; break; default: @@ -444,73 +479,112 @@ static const struct wl_shm_listener shm_listener = { static void registry_global(void *data, struct wl_registry *registry, uint32_t id, char const *iface, uint32_t version) { - kUnused(data); kUnused(version); + + SWindowData *window_data = (SWindowData *) data; + SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific; if (strcmp(iface, "wl_compositor") == 0) { - g_window_data.compositor = (struct wl_compositor *) wl_registry_bind(registry, id, &wl_compositor_interface, 1); + window_data_way->compositor = (struct wl_compositor *) wl_registry_bind(registry, id, &wl_compositor_interface, 1); } else if (strcmp(iface, "wl_shm") == 0) { - g_window_data.shm = (struct wl_shm *) wl_registry_bind(registry, id, &wl_shm_interface, 1); - if (g_window_data.shm) { - wl_shm_add_listener(g_window_data.shm, &shm_listener, NULL); - g_window_data.cursor_theme = wl_cursor_theme_load(NULL, 32, g_window_data.shm); - g_window_data.default_cursor = wl_cursor_theme_get_cursor(g_window_data.cursor_theme, "left_ptr"); + window_data_way->shm = (struct wl_shm *) wl_registry_bind(registry, id, &wl_shm_interface, 1); + if (window_data_way->shm) { + wl_shm_add_listener(window_data_way->shm, &shm_listener, window_data); + window_data_way->cursor_theme = wl_cursor_theme_load(0x0, 32, window_data_way->shm); + window_data_way->default_cursor = wl_cursor_theme_get_cursor(window_data_way->cursor_theme, "left_ptr"); } } else if (strcmp(iface, "wl_shell") == 0) { - g_window_data.shell = (struct wl_shell *) wl_registry_bind(registry, id, &wl_shell_interface, 1); + window_data_way->shell = (struct wl_shell *) wl_registry_bind(registry, id, &wl_shell_interface, 1); } else if (strcmp(iface, "wl_seat") == 0) { - g_window_data.seat = (struct wl_seat *) wl_registry_bind(registry, id, &wl_seat_interface, 1); - if (g_window_data.seat) + window_data_way->seat = (struct wl_seat *) wl_registry_bind(registry, id, &wl_seat_interface, 1); + if (window_data_way->seat) { - wl_seat_add_listener(g_window_data.seat, &seat_listener, NULL); + wl_seat_add_listener(window_data_way->seat, &seat_listener, window_data); } } } static const struct wl_registry_listener registry_listener = { .global = registry_global, - .global_remove = NULL, + .global_remove = 0x0, +}; + +static void +handle_ping(void *data, struct wl_shell_surface *shell_surface, uint32_t serial) +{ + kUnused(data); + wl_shell_surface_pong(shell_surface, serial); +} + +static void +handle_configure(void *data, struct wl_shell_surface *shell_surface, uint32_t edges, int32_t width, int32_t height) +{ + kUnused(data); + kUnused(shell_surface); + kUnused(edges); + kUnused(width); + kUnused(height); +} + +static void +handle_popup_done(void *data, struct wl_shell_surface *shell_surface) +{ + kUnused(data); + kUnused(shell_surface); +} + +static const struct wl_shell_surface_listener shell_surface_listener = { + handle_ping, + handle_configure, + handle_popup_done }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int -mfb_open_ex(const char* title, int width, int height, int flags) { +struct Window * +mfb_open_ex(const char *title, int width, int height, int flags) { // TODO: Not yet kUnused(flags); return mfb_open(title, width, height); } -int +struct Window * mfb_open(const char *title, int width, int height) { int fd = -1; - g_window_data.shm_format = -1u; + SWindowData *window_data = malloc(sizeof(SWindowData)); + memset(window_data, 0, sizeof(SWindowData)); - g_window_data.display = wl_display_connect(NULL); - if (!g_window_data.display) - return -1; - g_window_data.registry = wl_display_get_registry(g_window_data.display); - wl_registry_add_listener(g_window_data.registry, ®istry_listener, NULL); + SWindowData_Way *window_data_way = malloc(sizeof(SWindowData_Way)); + memset(window_data_way, 0, sizeof(SWindowData_Way)); + window_data->specific = window_data_way; + + window_data_way->shm_format = -1u; + + window_data_way->display = wl_display_connect(0x0); + if (!window_data_way->display) + return 0x0; + window_data_way->registry = wl_display_get_registry(window_data_way->display); + wl_registry_add_listener(window_data_way->registry, ®istry_listener, window_data); init_keycodes(); - if (wl_display_dispatch(g_window_data.display) == -1 || wl_display_roundtrip(g_window_data.display) == -1) + if (wl_display_dispatch(window_data_way->display) == -1 || wl_display_roundtrip(window_data_way->display) == -1) { - return -1; + return 0x0; } // did not get a format we want... meh - if (g_window_data.shm_format == -1u) + if (window_data_way->shm_format == -1u) goto out; - if (!g_window_data.compositor) + if (!window_data_way->compositor) goto out; char const *xdg_rt_dir = getenv("XDG_RUNTIME_DIR"); @@ -529,71 +603,60 @@ mfb_open(const char *title, int width, int height) if (ftruncate(fd, length) == -1) goto out; - g_window_data.shm_ptr = (uint32_t *) mmap(NULL, length, PROT_WRITE, MAP_SHARED, fd, 0); - if (g_window_data.shm_ptr == MAP_FAILED) + window_data_way->shm_ptr = (uint32_t *) mmap(0x0, length, PROT_WRITE, MAP_SHARED, fd, 0); + if (window_data_way->shm_ptr == MAP_FAILED) goto out; - g_window_data.window_width = width; - g_window_data.window_height = height; - g_window_data.buffer_width = width; - g_window_data.buffer_height = height; - g_window_data.buffer_stride = width * sizeof(uint32_t); - g_window_data.dst_offset_x = 0; - g_window_data.dst_offset_y = 0; - g_window_data.dst_width = width; - g_window_data.dst_height = height; + window_data->window_width = width; + window_data->window_height = height; + window_data->buffer_width = width; + window_data->buffer_height = height; + window_data->buffer_stride = width * sizeof(uint32_t); + window_data->dst_offset_x = 0; + window_data->dst_offset_y = 0; + window_data->dst_width = width; + window_data->dst_height = height; - g_window_data.shm_pool = wl_shm_create_pool(g_window_data.shm, fd, length); - g_window_data.draw_buffer = wl_shm_pool_create_buffer(g_window_data.shm_pool, 0, - g_window_data.buffer_width, g_window_data.buffer_height, - g_window_data.buffer_stride, g_window_data.shm_format); + window_data_way->shm_pool = wl_shm_create_pool(window_data_way->shm, fd, length); + window_data->draw_buffer = wl_shm_pool_create_buffer(window_data_way->shm_pool, 0, + window_data->buffer_width, window_data->buffer_height, + window_data->buffer_stride, window_data_way->shm_format); close(fd); fd = -1; - g_window_data.surface = wl_compositor_create_surface(g_window_data.compositor); - if (!g_window_data.surface) + window_data_way->surface = wl_compositor_create_surface(window_data_way->compositor); + if (!window_data_way->surface) goto out; - g_window_data.cursor_surface = wl_compositor_create_surface(g_window_data.compositor); + window_data_way->cursor_surface = wl_compositor_create_surface(window_data_way->compositor); // There should always be a shell, right? - if (g_window_data.shell) + if (window_data_way->shell) { - g_window_data.shell_surface = wl_shell_get_shell_surface(g_window_data.shell, g_window_data.surface); - if (!g_window_data.shell_surface) + window_data_way->shell_surface = wl_shell_get_shell_surface(window_data_way->shell, window_data_way->surface); + if (!window_data_way->shell_surface) goto out; - wl_shell_surface_set_title(g_window_data.shell_surface, title); - wl_shell_surface_set_toplevel(g_window_data.shell_surface); + wl_shell_surface_set_title(window_data_way->shell_surface, title); + wl_shell_surface_add_listener(window_data_way->shell_surface, &shell_surface_listener, 0x0); + wl_shell_surface_set_toplevel(window_data_way->shell_surface); } - wl_surface_attach(g_window_data.surface, g_window_data.draw_buffer, g_window_data.dst_offset_x, g_window_data.dst_offset_y); - wl_surface_damage(g_window_data.surface, g_window_data.dst_offset_x, g_window_data.dst_offset_y, g_window_data.dst_width, g_window_data.dst_height); - wl_surface_commit(g_window_data.surface); + wl_surface_attach(window_data_way->surface, window_data->draw_buffer, window_data->dst_offset_x, window_data->dst_offset_y); + wl_surface_damage(window_data_way->surface, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height); + wl_surface_commit(window_data_way->surface); - if (g_keyboard_func == 0x0) { - mfb_keyboard_callback(keyboard_default); - } + mfb_keyboard_callback((struct Window *) window_data, keyboard_default); printf("Window created using Wayland API\n"); - return 1; + return (struct Window *) window_data; out: close(fd); - destroy(); - return 0; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void keyboard_default(void *user_data, Key key, KeyMod mod, bool isPressed) { - kUnused(user_data); - kUnused(mod); - kUnused(isPressed); - if (key == KB_KEY_ESCAPE) - g_window_data.close = true; + destroy(window_data); + return 0x0; } // done event @@ -606,6 +669,7 @@ frame_done(void *data, struct wl_callback *callback, uint32_t cookie) { kUnused(cookie); wl_callback_destroy(callback); + *(uint32_t *)data = 1; } @@ -613,53 +677,50 @@ static const struct wl_callback_listener frame_listener = { .done = frame_done, }; -int -mfb_update(void *buffer) +UpdateState +mfb_update(struct Window *window, void *buffer) { uint32_t done = 0; - if (!g_window_data.display || wl_display_get_error(g_window_data.display) != 0) - return -1; + if(window == 0x0) { + return STATE_INVALID_WINDOW; + } - if (g_window_data.close == true) - return -1; + SWindowData *window_data = (SWindowData *) window; + if(window_data->close) { + destroy(window_data); + return STATE_EXIT; + } + + if(buffer == 0x0) { + return STATE_INVALID_BUFFER; + } + + SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific; + if (!window_data_way->display || wl_display_get_error(window_data_way->display) != 0) + return STATE_INTERNAL_ERROR; // update shm buffer - memcpy(g_window_data.shm_ptr, buffer, g_window_data.buffer_stride * g_window_data.buffer_height); + memcpy(window_data_way->shm_ptr, buffer, window_data->buffer_stride * window_data->buffer_height); - wl_surface_attach(g_window_data.surface, g_window_data.draw_buffer, g_window_data.dst_offset_x, g_window_data.dst_offset_y); - wl_surface_damage(g_window_data.surface, g_window_data.dst_offset_x, g_window_data.dst_offset_y, g_window_data.dst_width, g_window_data.dst_height); + wl_surface_attach(window_data_way->surface, window_data->draw_buffer, window_data->dst_offset_x, window_data->dst_offset_y); + wl_surface_damage(window_data_way->surface, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height); + struct wl_callback *frame_callback = wl_surface_frame(window_data_way->surface); + if (!frame_callback) { + return STATE_INTERNAL_ERROR; + } + wl_callback_add_listener(frame_callback, &frame_listener, &done); + wl_surface_commit(window_data_way->surface); - struct wl_callback *frame = wl_surface_frame(g_window_data.surface); - if (!frame) - return -1; - - wl_callback_add_listener(frame, &frame_listener, &done); - - wl_surface_commit(g_window_data.surface); - - while (!done && g_window_data.close == false) { - if (wl_display_dispatch(g_window_data.display) == -1 || wl_display_roundtrip(g_window_data.display) == -1) + while (!done && window_data->close == false) { + if (wl_display_dispatch(window_data_way->display) == -1 || wl_display_roundtrip(window_data_way->display) == -1) { - wl_callback_destroy(frame); - return -1; + wl_callback_destroy(frame_callback); + return STATE_INTERNAL_ERROR; } } - if(g_window_data.close == true) { - destroy(); - } - //static int counter = 0; - //printf("update!: %d\n", counter++); - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void -mfb_close(void) { - g_window_data.close = true; + return STATE_OK; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -795,20 +856,22 @@ init_keycodes(void) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool -mfb_set_viewport(unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { +mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { - if(offset_x + width > g_window_data.window_width) { + SWindowData *window_data = (SWindowData *) window; + + if(offset_x + width > window_data->window_width) { return false; } - if(offset_y + height > g_window_data.window_height) { + if(offset_y + height > window_data->window_height) { return false; } // TODO: Not yet - // g_window_data.dst_offset_x = offset_x; - // g_window_data.dst_offset_y = offset_y; - // g_window_data.dst_width = width; - // g_window_data.dst_height = height; + // window_data->dst_offset_x = offset_x; + // window_data->dst_offset_y = offset_y; + // window_data->dst_width = width; + // window_data->dst_height = height; return false; } diff --git a/src/wayland/WaylandWindowData.h b/src/wayland/WindowData_Way.h similarity index 98% rename from src/wayland/WaylandWindowData.h rename to src/wayland/WindowData_Way.h index bfd4c7d..888c4d6 100644 --- a/src/wayland/WaylandWindowData.h +++ b/src/wayland/WindowData_Way.h @@ -54,4 +54,4 @@ typedef struct uint32_t mod_keys; bool close; -} SWindowData; +} SWindowData_Way; diff --git a/src/windows/WinMiniFB.c b/src/windows/WinMiniFB.c index 1a2059a..84ed0cb 100644 --- a/src/windows/WinMiniFB.c +++ b/src/windows/WinMiniFB.c @@ -1,49 +1,55 @@ #include #include -#include "WinWindowData.h" +#include +#include "WindowData_Win.h" #include /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -SWindowData g_window_data = { 0 }; - -long s_window_style = WS_POPUP | WS_SYSMENU | WS_CAPTION; +long s_window_style = WS_POPUP | WS_SYSMENU | WS_CAPTION; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// uint32_t translate_mod(); Key translate_key(unsigned int wParam, unsigned long lParam); +void destroy_window_data(SWindowData *window_data); LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { LRESULT res = 0; + SWindowData *window_data = (SWindowData *) GetWindowLongPtr(hWnd, GWL_USERDATA); + SWindowData_Win *window_data_win = 0x0; + if(window_data != 0x0) { + window_data_win = (SWindowData_Win *) window_data->specific; + } + switch (message) { case WM_PAINT: { - if (g_window_data.draw_buffer) + if (window_data && window_data->draw_buffer && window_data_win) { - if (g_window_data.dst_offset_x > 0) { - BitBlt(g_window_data.s_hdc, 0, g_window_data.dst_offset_y, g_window_data.dst_offset_x, g_window_data.dst_height, 0, 0, 0, BLACKNESS); - } - if (g_window_data.dst_offset_y > 0) { - BitBlt(g_window_data.s_hdc, 0, 0, g_window_data.window_width, g_window_data.dst_offset_y, 0, 0, 0, BLACKNESS); - } - uint32_t offsetY = g_window_data.dst_offset_y + g_window_data.dst_height; - if (offsetY < g_window_data.window_height) { - BitBlt(g_window_data.s_hdc, 0, offsetY, g_window_data.window_width, g_window_data.window_height-offsetY, 0, 0, 0, BLACKNESS); - } - uint32_t offsetX = g_window_data.dst_offset_x + g_window_data.dst_width; - if (offsetX < g_window_data.window_width) { - BitBlt(g_window_data.s_hdc, offsetX, g_window_data.dst_offset_y, g_window_data.window_width-offsetX, g_window_data.dst_height, 0, 0, 0, BLACKNESS); - } + //if(window_data->dst_offset_x > 0) { + // BitBlt(window_data_win->hdc, 0, window_data->dst_offset_y, window_data->dst_offset_x, window_data->dst_height, 0, 0, 0, BLACKNESS); + //} + //if(window_data->dst_offset_y > 0) { + // BitBlt(window_data_win->hdc, 0, 0, window_data->window_width, window_data->dst_offset_y, 0, 0, 0, BLACKNESS); + //} + //uint32_t offsetY = window_data->dst_offset_y + window_data->dst_height; + //if(offsetY < window_data->window_height) { + // BitBlt(window_data_win->hdc, 0, offsetY, window_data->window_width, window_data->window_height - offsetY, 0, 0, 0, BLACKNESS); + //} + //uint32_t offsetX = window_data->dst_offset_x + window_data->dst_width; + //if(offsetX < window_data->window_width) { + // BitBlt(window_data_win->hdc, offsetX, window_data->dst_offset_y, window_data->window_width - offsetX, window_data->dst_height, 0, 0, 0, BLACKNESS); + //} - StretchDIBits(g_window_data.s_hdc, g_window_data.dst_offset_x, g_window_data.dst_offset_y, g_window_data.dst_width, g_window_data.dst_height, 0, 0, g_window_data.buffer_width, g_window_data.buffer_height, g_window_data.draw_buffer, - g_window_data.s_bitmapInfo, DIB_RGB_COLORS, SRCCOPY); + StretchDIBits(window_data_win->hdc, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height, 0, 0, window_data->buffer_width, window_data->buffer_height, window_data->draw_buffer, + window_data_win->bitmapInfo, DIB_RGB_COLORS, SRCCOPY); - ValidateRect(hWnd, NULL); + ValidateRect(hWnd, 0x0); } break; @@ -52,7 +58,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_DESTROY: case WM_CLOSE: { - g_window_data.close = true; + if(window_data) { + window_data->close = true; + } break; } @@ -61,14 +69,16 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_KEYUP: case WM_SYSKEYUP: { - Key kb_key = translate_key((unsigned int)wParam, (unsigned long)lParam); - int is_pressed = !((lParam >> 31) & 1); - g_window_data.mod_keys = translate_mod(); + if(window_data) { + Key kb_key = translate_key((unsigned int)wParam, (unsigned long)lParam); + int is_pressed = !((lParam >> 31) & 1); + window_data->mod_keys = translate_mod(); - if (kb_key == KB_KEY_UNKNOWN) - return FALSE; + if (kb_key == KB_KEY_UNKNOWN) + return FALSE; - kCall(g_keyboard_func, kb_key, g_window_data.mod_keys, is_pressed); + kCall(keyboard_func, kb_key, window_data->mod_keys, is_pressed); + } break; } @@ -77,13 +87,15 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_UNICHAR: { - if(message == WM_UNICHAR && wParam == UNICODE_NOCHAR) { - // WM_UNICHAR is not sent by Windows, but is sent by some third-party input method engine - // Returning TRUE here announces support for this message - return TRUE; - } + if(window_data) { + if(message == WM_UNICHAR && wParam == UNICODE_NOCHAR) { + // WM_UNICHAR is not sent by Windows, but is sent by some third-party input method engine + // Returning TRUE here announces support for this message + return TRUE; + } - kCall(g_char_input_func, wParam); + kCall(char_input_func, wParam); + } break; } @@ -100,10 +112,11 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: { - MouseButton button = MOUSE_BTN_0; - g_window_data.mod_keys = translate_mod(); - int is_pressed = 0; - switch (message) { + if(window_data) { + MouseButton button = MOUSE_BTN_0; + window_data->mod_keys = translate_mod(); + int is_pressed = 0; + switch(message) { case WM_LBUTTONDOWN: is_pressed = 1; case WM_LBUTTONUP: @@ -122,59 +135,73 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) default: button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? MOUSE_BTN_5 : MOUSE_BTN_6); - if (message == WM_XBUTTONDOWN) { + if(message == WM_XBUTTONDOWN) { is_pressed = 1; } + } + kCall(mouse_btn_func, button, window_data->mod_keys, is_pressed); } - kCall(g_mouse_btn_func, button, g_window_data.mod_keys, is_pressed); break; } case WM_MOUSEWHEEL: - kCall(g_mouse_wheel_func, translate_mod(), 0.0f, (SHORT)HIWORD(wParam) / (float)WHEEL_DELTA); + if(window_data) { + kCall(mouse_wheel_func, translate_mod(), 0.0f, (SHORT)HIWORD(wParam) / (float)WHEEL_DELTA); + } break; case WM_MOUSEHWHEEL: // This message is only sent on Windows Vista and later // NOTE: The X-axis is inverted for consistency with macOS and X11 - kCall(g_mouse_wheel_func, translate_mod(), -((SHORT)HIWORD(wParam) / (float)WHEEL_DELTA), 0.0f); + if(window_data) { + kCall(mouse_wheel_func, translate_mod(), -((SHORT)HIWORD(wParam) / (float)WHEEL_DELTA), 0.0f); + } break; case WM_MOUSEMOVE: - if(g_window_data.s_mouse_inside == false) { - g_window_data.s_mouse_inside = true; - TRACKMOUSEEVENT tme; - ZeroMemory(&tme, sizeof(tme)); - tme.cbSize = sizeof(tme); - tme.dwFlags = TME_LEAVE; - tme.hwndTrack = hWnd; - TrackMouseEvent(&tme); + if(window_data) { + if(window_data_win->mouse_inside == false) { + window_data_win->mouse_inside = true; + TRACKMOUSEEVENT tme; + ZeroMemory(&tme, sizeof(tme)); + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = hWnd; + TrackMouseEvent(&tme); + } + kCall(mouse_move_func, ((int)(short)LOWORD(lParam)), ((int)(short)HIWORD(lParam))); } - kCall(g_mouse_move_func, ((int)(short)LOWORD(lParam)), ((int)(short)HIWORD(lParam))); break; case WM_MOUSELEAVE: - g_window_data.s_mouse_inside = false; + if(window_data) { + window_data_win->mouse_inside = false; + } break; case WM_SIZE: - { - g_window_data.dst_offset_x = 0; - g_window_data.dst_offset_y = 0; - g_window_data.dst_width = LOWORD(lParam); - g_window_data.dst_height = HIWORD(lParam); - g_window_data.window_width = g_window_data.dst_width; - g_window_data.window_height = g_window_data.dst_height; - kCall(g_resize_func, g_window_data.dst_width, g_window_data.dst_height); + if(window_data) { + window_data->dst_offset_x = 0; + window_data->dst_offset_y = 0; + window_data->dst_width = LOWORD(lParam); + window_data->dst_height = HIWORD(lParam); + window_data->window_width = window_data->dst_width; + window_data->window_height = window_data->dst_height; + BitBlt(window_data_win->hdc, 0, 0, window_data->window_width, window_data->window_height, 0, 0, 0, BLACKNESS); + kCall(resize_func, window_data->dst_width, window_data->dst_height); + } break; - } case WM_SETFOCUS: - kCall(g_active_func, true); + if(window_data) { + kCall(active_func, true); + } break; case WM_KILLFOCUS: - kCall(g_active_func, false); + if(window_data) { + kCall(active_func, false); + } break; default: @@ -188,14 +215,22 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int mfb_open_ex(const char* title, int width, int height, int flags) { +struct Window *mfb_open_ex(const char *title, int width, int height, int flags) { RECT rect = { 0 }; int x, y; init_keycodes(); - g_window_data.buffer_width = width; - g_window_data.buffer_height = height; + SWindowData *window_data = malloc(sizeof(SWindowData)); + memset(window_data, 0, sizeof(SWindowData)); + + SWindowData_Win *window_data_win = malloc(sizeof(SWindowData_Win)); + memset(window_data_win, 0, sizeof(SWindowData_Win)); + window_data->specific = window_data_win; + + window_data->buffer_width = width; + window_data->buffer_height = height; + window_data->buffer_stride = width * 4; s_window_style = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME; if (flags & WF_FULLSCREEN) { @@ -261,114 +296,117 @@ int mfb_open_ex(const char* title, int width, int height, int flags) { y = (GetSystemMetrics(SM_CYSCREEN) - rect.bottom + rect.top) / 2; } - g_window_data.s_wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW; - g_window_data.s_wc.lpfnWndProc = WndProc; - g_window_data.s_wc.hCursor = LoadCursor(0, IDC_ARROW); - g_window_data.s_wc.lpszClassName = title; - RegisterClass(&g_window_data.s_wc); + window_data_win->wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW; + window_data_win->wc.lpfnWndProc = WndProc; + window_data_win->wc.hCursor = LoadCursor(0, IDC_ARROW); + window_data_win->wc.lpszClassName = title; + RegisterClass(&window_data_win->wc); - if (g_window_data.dst_width == 0) - g_window_data.dst_width = width; + if (window_data->dst_width == 0) + window_data->dst_width = width; - if (g_window_data.dst_height == 0) - g_window_data.dst_height = height; + if (window_data->dst_height == 0) + window_data->dst_height = height; - g_window_data.window_width = rect.right; - g_window_data.window_height = rect.bottom; + window_data->window_width = rect.right; + window_data->window_height = rect.bottom; - g_window_data.window = CreateWindowEx( + window_data_win->window = CreateWindowEx( 0, title, title, s_window_style, x, y, - g_window_data.window_width, g_window_data.window_height, + window_data->window_width, window_data->window_height, 0, 0, 0, 0); - if (!g_window_data.window) - return 0; + if (!window_data_win->window) + return 0x0; + + SetWindowLongPtr(window_data_win->window, GWLP_USERDATA, (LONG_PTR) window_data); if (flags & WF_ALWAYS_ON_TOP) - SetWindowPos(g_window_data.window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + SetWindowPos(window_data_win->window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); - ShowWindow(g_window_data.window, SW_NORMAL); + ShowWindow(window_data_win->window, SW_NORMAL); - g_window_data.s_bitmapInfo = (BITMAPINFO *) calloc(1, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 3); - g_window_data.s_bitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - g_window_data.s_bitmapInfo->bmiHeader.biPlanes = 1; - g_window_data.s_bitmapInfo->bmiHeader.biBitCount = 32; - g_window_data.s_bitmapInfo->bmiHeader.biCompression = BI_BITFIELDS; - g_window_data.s_bitmapInfo->bmiHeader.biWidth = g_window_data.buffer_width; - g_window_data.s_bitmapInfo->bmiHeader.biHeight = -(LONG)g_window_data.buffer_height; - g_window_data.s_bitmapInfo->bmiColors[0].rgbRed = 0xff; - g_window_data.s_bitmapInfo->bmiColors[1].rgbGreen = 0xff; - g_window_data.s_bitmapInfo->bmiColors[2].rgbBlue = 0xff; + window_data_win->bitmapInfo = (BITMAPINFO *) calloc(1, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 3); + window_data_win->bitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + window_data_win->bitmapInfo->bmiHeader.biPlanes = 1; + window_data_win->bitmapInfo->bmiHeader.biBitCount = 32; + window_data_win->bitmapInfo->bmiHeader.biCompression = BI_BITFIELDS; + window_data_win->bitmapInfo->bmiHeader.biWidth = window_data->buffer_width; + window_data_win->bitmapInfo->bmiHeader.biHeight = -(LONG)window_data->buffer_height; + window_data_win->bitmapInfo->bmiColors[0].rgbRed = 0xff; + window_data_win->bitmapInfo->bmiColors[1].rgbGreen = 0xff; + window_data_win->bitmapInfo->bmiColors[2].rgbBlue = 0xff; - g_window_data.s_hdc = GetDC(g_window_data.window); + window_data_win->hdc = GetDC(window_data_win->window); - if (g_keyboard_func == 0x0) { - mfb_keyboard_callback(keyboard_default); - } + mfb_keyboard_callback((struct Window *) window_data, keyboard_default); - return 1; + return (struct Window *) window_data; } -int mfb_open(const char* title, int width, int height) { +struct Window *mfb_open(const char *title, int width, int height) { return mfb_open_ex(title, width, height, 0); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int mfb_update(void* buffer) +UpdateState mfb_update(struct Window *window, void* buffer) { MSG msg; - if (buffer == 0x0) - return -2; + if(window == 0x0) { + return STATE_INVALID_WINDOW; + } - if (g_window_data.close == true) - return -1; + SWindowData *window_data = (SWindowData *)window; + if(window_data->close) { + destroy_window_data(window_data); + return STATE_EXIT; + } - g_window_data.draw_buffer = buffer; + if(buffer == 0x0) { + return STATE_INVALID_BUFFER; + } - InvalidateRect(g_window_data.window, NULL, TRUE); - SendMessage(g_window_data.window, WM_PAINT, 0, 0); + window_data->draw_buffer = buffer; - while (g_window_data.close == false && PeekMessage(&msg, g_window_data.window, 0, 0, PM_REMOVE)) + SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific; + InvalidateRect(window_data_win->window, 0x0, TRUE); + SendMessage(window_data_win->window, WM_PAINT, 0, 0); + + while (window_data->close == false && PeekMessage(&msg, window_data_win->window, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } - return 0; + return STATE_OK; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void mfb_close() -{ - g_window_data.draw_buffer = 0x0; - if (g_window_data.s_bitmapInfo != 0x0) { - free(g_window_data.s_bitmapInfo); +void destroy_window_data(SWindowData *window_data) { + if(window_data == 0x0) + return; + + SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific; + + window_data->draw_buffer = 0x0; + if(window_data_win->bitmapInfo != 0x0) { + free(window_data_win->bitmapInfo); } - if (g_window_data.window != 0 && g_window_data.s_hdc != 0) { - ReleaseDC(g_window_data.window, g_window_data.s_hdc); - DestroyWindow(g_window_data.window); + if(window_data_win->window != 0 && window_data_win->hdc != 0) { + ReleaseDC(window_data_win->window, window_data_win->hdc); + DestroyWindow(window_data_win->window); } - g_window_data.window = 0; - g_window_data.s_hdc = 0; - g_window_data.s_bitmapInfo = 0x0; - g_window_data.close = true; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void keyboard_default(void *user_data, Key key, KeyMod mod, bool isPressed) { - kUnused(user_data); - kUnused(mod); - kUnused(isPressed); - if (key == KB_KEY_ESCAPE) - g_window_data.close = true; + window_data_win->window = 0; + window_data_win->hdc = 0; + window_data_win->bitmapInfo = 0x0; + window_data->close = true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -536,7 +574,7 @@ Key translate_key(unsigned int wParam, unsigned long lParam) { return KB_KEY_RIGHT_CONTROL; time = GetMessageTime(); - if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE)) + if (PeekMessageW(&next, 0x0, 0, 0, PM_NOREMOVE)) if (next.message == WM_KEYDOWN || next.message == WM_SYSKEYDOWN || next.message == WM_KEYUP || next.message == WM_SYSKEYUP) if (next.wParam == VK_MENU && (next.lParam & 0x01000000) && next.time == time) return KB_KEY_UNKNOWN; @@ -552,20 +590,22 @@ Key translate_key(unsigned int wParam, unsigned long lParam) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool mfb_set_viewport(unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) +bool mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { - if(offset_x + width > g_window_data.window_width) { + SWindowData *window_data = (SWindowData *) window; + + if(offset_x + width > window_data->window_width) { return false; } - if(offset_y + height > g_window_data.window_height) { + if(offset_y + height > window_data->window_height) { return false; } - g_window_data.dst_offset_x = offset_x; - g_window_data.dst_offset_y = offset_y; + window_data->dst_offset_x = offset_x; + window_data->dst_offset_y = offset_y; - g_window_data.dst_width = width; - g_window_data.dst_height = height; + window_data->dst_width = width; + window_data->dst_height = height; return true; } diff --git a/src/windows/WinWindowData.h b/src/windows/WinWindowData.h deleted file mode 100644 index 57d5a8f..0000000 --- a/src/windows/WinWindowData.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include -#include -#define WIN32_LEAN_AND_MEAN -#include - - -typedef struct { - HWND window; - WNDCLASS s_wc; - HDC s_hdc; - BITMAPINFO *s_bitmapInfo; - bool s_mouse_inside; - - uint32_t window_width; - uint32_t window_height; - - uint32_t dst_offset_x; - uint32_t dst_offset_y; - uint32_t dst_width; - uint32_t dst_height; - - void *draw_buffer; - uint32_t buffer_width; - uint32_t buffer_height; - - uint32_t mod_keys; - bool close; -} SWindowData; diff --git a/src/windows/WindowData_Win.h b/src/windows/WindowData_Win.h new file mode 100644 index 0000000..fb8b8c1 --- /dev/null +++ b/src/windows/WindowData_Win.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include +#define WIN32_LEAN_AND_MEAN +#include + + +typedef struct { + HWND window; + WNDCLASS wc; + HDC hdc; + BITMAPINFO *bitmapInfo; + bool mouse_inside; +} SWindowData_Win; diff --git a/src/x11/X11WindowData.h b/src/x11/WindowData_X11.h similarity index 51% rename from src/x11/X11WindowData.h rename to src/x11/WindowData_X11.h index e09ac30..fb3490f 100644 --- a/src/x11/X11WindowData.h +++ b/src/x11/WindowData_X11.h @@ -7,20 +7,6 @@ typedef struct { Window window; - uint32_t window_width; - uint32_t window_height; - - uint32_t dst_offset_x; - uint32_t dst_offset_y; - uint32_t dst_width; - uint32_t dst_height; - - void *draw_buffer; - uint32_t buffer_width; - uint32_t buffer_height; - - uint32_t mod_keys; - bool close; Display *display; int screen; @@ -31,4 +17,4 @@ typedef struct { XImage *image_scaler; uint32_t image_scaler_width; uint32_t image_scaler_height; -} SWindowData; +} SWindowData_X11; diff --git a/src/x11/X11MiniFB.c b/src/x11/X11MiniFB.c index 0c0b413..26e7f61 100644 --- a/src/x11/X11MiniFB.c +++ b/src/x11/X11MiniFB.c @@ -4,41 +4,50 @@ #include #include #include +#include #include +#include #include #include -#include "X11WindowData.h" +#include "WindowData.h" +#include "WindowData_X11.h" /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -SWindowData g_window_data = { 0 }; - extern void stretch_image(uint32_t *srcImage, uint32_t srcX, uint32_t srcY, uint32_t srcWidth, uint32_t srcHeight, uint32_t srcPitch, uint32_t *dstImage, uint32_t dstX, uint32_t dstY, uint32_t dstWidth, uint32_t dstHeight, uint32_t dstPitch); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int mfb_open_ex(const char* title, int width, int height, int flags) { +struct Window * +mfb_open_ex(const char *title, int width, int height, int flags) { int depth, i, formatCount, convDepth = -1; XPixmapFormatValues* formats; XSetWindowAttributes windowAttributes; XSizeHints sizeHints; Visual* visual; - g_window_data.display = XOpenDisplay(0); - if (!g_window_data.display) - return -1; + SWindowData *window_data = (SWindowData *) malloc(sizeof(SWindowData)); + memset(window_data, 0, sizeof(SWindowData)); + + SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) malloc(sizeof(SWindowData_X11)); + memset(window_data_x11, 0, sizeof(SWindowData_X11)); + window_data->specific = window_data_x11; + + window_data_x11->display = XOpenDisplay(0); + if (!window_data_x11->display) + return 0x0; - init_keycodes(); + init_keycodes(window_data_x11); - g_window_data.screen = DefaultScreen(g_window_data.display); + window_data_x11->screen = DefaultScreen(window_data_x11->display); - visual = DefaultVisual(g_window_data.display, g_window_data.screen); - formats = XListPixmapFormats(g_window_data.display, &formatCount); - depth = DefaultDepth(g_window_data.display, g_window_data.screen); + visual = DefaultVisual(window_data_x11->display, window_data_x11->screen); + formats = XListPixmapFormats(window_data_x11->display, &formatCount); + depth = DefaultDepth(window_data_x11->display, window_data_x11->screen); - Window defaultRootWindow = DefaultRootWindow(g_window_data.display); + Window defaultRootWindow = DefaultRootWindow(window_data_x11->display); for (i = 0; i < formatCount; ++i) { @@ -54,28 +63,29 @@ int mfb_open_ex(const char* title, int width, int height, int flags) { // We only support 32-bit right now if (convDepth != 32) { - XCloseDisplay(g_window_data.display); - return -1; + XCloseDisplay(window_data_x11->display); + return 0x0; } - int screenWidth = DisplayWidth(g_window_data.display, g_window_data.screen); - int screenHeight = DisplayHeight(g_window_data.display, g_window_data.screen); + int screenWidth = DisplayWidth(window_data_x11->display, window_data_x11->screen); + int screenHeight = DisplayHeight(window_data_x11->display, window_data_x11->screen); - windowAttributes.border_pixel = BlackPixel(g_window_data.display, g_window_data.screen); - windowAttributes.background_pixel = BlackPixel(g_window_data.display, g_window_data.screen); + windowAttributes.border_pixel = BlackPixel(window_data_x11->display, window_data_x11->screen); + windowAttributes.background_pixel = BlackPixel(window_data_x11->display, window_data_x11->screen); windowAttributes.backing_store = NotUseful; int posX, posY; int windowWidth, windowHeight; - g_window_data.window_width = width; - g_window_data.window_height = height; - g_window_data.buffer_width = width; - g_window_data.buffer_height = height; - g_window_data.dst_offset_x = 0; - g_window_data.dst_offset_y = 0; - g_window_data.dst_width = width; - g_window_data.dst_height = height; + window_data->window_width = width; + window_data->window_height = height; + window_data->buffer_width = width; + window_data->buffer_height = height; + window_data->buffer_stride = width * 4; + window_data->dst_offset_x = 0; + window_data->dst_offset_y = 0; + window_data->dst_width = width; + window_data->dst_height = height; if (flags & WF_FULLSCREEN_DESKTOP) { posX = 0; @@ -90,8 +100,8 @@ int mfb_open_ex(const char* title, int width, int height, int flags) { windowHeight = height; } - g_window_data.window = XCreateWindow( - g_window_data.display, + window_data_x11->window = XCreateWindow( + window_data_x11->display, defaultRootWindow, posX, posY, windowWidth, windowHeight, @@ -101,10 +111,10 @@ int mfb_open_ex(const char* title, int width, int height, int flags) { visual, CWBackPixel | CWBorderPixel | CWBackingStore, &windowAttributes); - if (!g_window_data.window) - return 0; + if (!window_data_x11->window) + return 0x0; - XSelectInput(g_window_data.display, g_window_data.window, + XSelectInput(window_data_x11->display, window_data_x11->window, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | ExposureMask @@ -112,7 +122,7 @@ int mfb_open_ex(const char* title, int width, int height, int flags) { | EnterWindowMask | LeaveWindowMask ); - XStoreName(g_window_data.display, g_window_data.window, title); + XStoreName(window_data_x11->display, window_data_x11->window, title); if (flags & WF_BORDERLESS) { struct StyleHints { @@ -128,18 +138,18 @@ int mfb_open_ex(const char* title, int width, int height, int flags) { .inputMode = 0, .status = 0, }; - Atom sh_p = XInternAtom(g_window_data.display, "_MOTIF_WM_HINTS", True); - XChangeProperty(g_window_data.display, g_window_data.window, sh_p, sh_p, 32, PropModeReplace, (unsigned char*)&sh, 5); + Atom sh_p = XInternAtom(window_data_x11->display, "_MOTIF_WM_HINTS", True); + XChangeProperty(window_data_x11->display, window_data_x11->window, sh_p, sh_p, 32, PropModeReplace, (unsigned char*)&sh, 5); } if (flags & WF_ALWAYS_ON_TOP) { - Atom sa_p = XInternAtom(g_window_data.display, "_NET_WM_STATE_ABOVE", False); - XChangeProperty(g_window_data.display, g_window_data.window, XInternAtom(g_window_data.display, "_NET_WM_STATE", False), XA_ATOM, 32, PropModeReplace, (unsigned char *)&sa_p, 1); + Atom sa_p = XInternAtom(window_data_x11->display, "_NET_WM_STATE_ABOVE", False); + XChangeProperty(window_data_x11->display, window_data_x11->window, XInternAtom(window_data_x11->display, "_NET_WM_STATE", False), XA_ATOM, 32, PropModeReplace, (unsigned char *)&sa_p, 1); } if (flags & WF_FULLSCREEN) { - Atom sf_p = XInternAtom(g_window_data.display, "_NET_WM_STATE_FULLSCREEN", True); - XChangeProperty(g_window_data.display, g_window_data.window, XInternAtom(g_window_data.display, "_NET_WM_STATE", True), XA_ATOM, 32, PropModeReplace, (unsigned char*)&sf_p, 1); + Atom sf_p = XInternAtom(window_data_x11->display, "_NET_WM_STATE_FULLSCREEN", True); + XChangeProperty(window_data_x11->display, window_data_x11->window, XInternAtom(window_data_x11->display, "_NET_WM_STATE", True), XA_ATOM, 32, PropModeReplace, (unsigned char*)&sf_p, 1); } sizeHints.flags = PPosition | PMinSize | PMaxSize; @@ -156,25 +166,24 @@ int mfb_open_ex(const char* title, int width, int height, int flags) { sizeHints.max_height = height; } - XSetWMNormalHints(g_window_data.display, g_window_data.window, &sizeHints); - XClearWindow(g_window_data.display, g_window_data.window); - XMapRaised(g_window_data.display, g_window_data.window); - XFlush(g_window_data.display); + XSetWMNormalHints(window_data_x11->display, window_data_x11->window, &sizeHints); + XClearWindow(window_data_x11->display, window_data_x11->window); + XMapRaised(window_data_x11->display, window_data_x11->window); + XFlush(window_data_x11->display); - g_window_data.gc = DefaultGC(g_window_data.display, g_window_data.screen); + window_data_x11->gc = DefaultGC(window_data_x11->display, window_data_x11->screen); - g_window_data.image = XCreateImage(g_window_data.display, CopyFromParent, depth, ZPixmap, 0, NULL, width, height, 32, width * 4); + window_data_x11->image = XCreateImage(window_data_x11->display, CopyFromParent, depth, ZPixmap, 0, 0x0, width, height, 32, width * 4); - if (g_keyboard_func == 0x0) { - mfb_keyboard_callback(keyboard_default); - } + mfb_keyboard_callback((struct Window *) window_data, keyboard_default); printf("Window created using X11 API\n"); - return 1; + return (struct Window *) window_data; } -int mfb_open(const char* title, int width, int height) +struct Window * +mfb_open(const char *title, int width, int height) { return mfb_open_ex(title, width, height, 0); } @@ -185,74 +194,75 @@ int translate_key(int scancode); int translate_mod(int state); int translate_mod_ex(int key, int state, int is_pressed); -static int processEvents() +static void processEvents(SWindowData *window_data) { - XEvent event; + XEvent event; + SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; - while ((g_window_data.close == false) && XPending(g_window_data.display)) { - XNextEvent(g_window_data.display, &event); + while ((window_data->close == false) && XPending(window_data_x11->display)) { + XNextEvent(window_data_x11->display, &event); switch (event.type) { case KeyPress: case KeyRelease: { - int kb_key = translate_key(event.xkey.keycode); + Key kb_key = (Key) translate_key(event.xkey.keycode); int is_pressed = (event.type == KeyPress); - g_window_data.mod_keys = translate_mod_ex(kb_key, event.xkey.state, is_pressed); + window_data->mod_keys = translate_mod_ex(kb_key, event.xkey.state, is_pressed); - kCall(g_keyboard_func, kb_key, g_window_data.mod_keys, is_pressed); + kCall(keyboard_func, kb_key, (KeyMod) window_data->mod_keys, is_pressed); } break; case ButtonPress: case ButtonRelease: { - MouseButton button = event.xbutton.button; + MouseButton button = (MouseButton) event.xbutton.button; int is_pressed = (event.type == ButtonPress); - g_window_data.mod_keys = translate_mod(event.xkey.state); + window_data->mod_keys = translate_mod(event.xkey.state); switch (button) { case Button1: case Button2: case Button3: - kCall(g_mouse_btn_func, button, g_window_data.mod_keys, is_pressed); + kCall(mouse_btn_func, button, (KeyMod) window_data->mod_keys, is_pressed); break; case Button4: - kCall(g_mouse_wheel_func, g_window_data.mod_keys, 0.0f, 1.0f); + kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, 0.0f, 1.0f); break; case Button5: - kCall(g_mouse_wheel_func, g_window_data.mod_keys, 0.0f, -1.0f); + kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, 0.0f, -1.0f); break; case 6: - kCall(g_mouse_wheel_func, g_window_data.mod_keys, 1.0f, 0.0f); + kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, 1.0f, 0.0f); break; case 7: - kCall(g_mouse_wheel_func, g_window_data.mod_keys, -1.0f, 0.0f); + kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, -1.0f, 0.0f); break; default: - kCall(g_mouse_btn_func, button - 4, g_window_data.mod_keys, is_pressed); + kCall(mouse_btn_func, (MouseButton) (button - 4), (KeyMod) window_data->mod_keys, is_pressed); break; } } break; case MotionNotify: - kCall(g_mouse_move_func, event.xmotion.x, event.xmotion.y); + kCall(mouse_move_func, event.xmotion.x, event.xmotion.y); break; case ConfigureNotify: { - g_window_data.window_width = event.xconfigure.width; - g_window_data.window_height = event.xconfigure.height; - g_window_data.dst_offset_x = 0; - g_window_data.dst_offset_y = 0; - g_window_data.dst_width = g_window_data.window_width; - g_window_data.dst_height = g_window_data.window_height; + window_data->window_width = event.xconfigure.width; + window_data->window_height = event.xconfigure.height; + window_data->dst_offset_x = 0; + window_data->dst_offset_y = 0; + window_data->dst_width = window_data->window_width; + window_data->dst_height = window_data->window_height; - XClearWindow(g_window_data.display, g_window_data.window); - kCall(g_resize_func, g_window_data.window_width, g_window_data.window_height); + XClearWindow(window_data_x11->display, window_data_x11->window); + kCall(resize_func, window_data->window_width, window_data->window_height); } break; @@ -261,83 +271,95 @@ static int processEvents() break; case FocusIn: - kCall(g_active_func, true); + kCall(active_func, true); break; case FocusOut: - kCall(g_active_func, false); + kCall(active_func, false); break; case DestroyNotify: - return -1; + window_data->close = true; + return; break; } } - - if(g_window_data.close == true) - return -1; - - return 0; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int mfb_update(void* buffer) +void destroy(SWindowData *window_data); + +UpdateState mfb_update(struct Window *window, void* buffer) { - if (buffer == 0x0) { - return -2; + if(window == 0x0) { + return STATE_INVALID_WINDOW; } - if (g_window_data.buffer_width != g_window_data.dst_width || g_window_data.buffer_height != g_window_data.dst_height) { - if(g_window_data.image_scaler_width != g_window_data.dst_width || g_window_data.image_scaler_height != g_window_data.dst_height) { - if(g_window_data.image_scaler != 0x0) { - g_window_data.image_scaler->data = 0x0; - XDestroyImage(g_window_data.image_scaler); + SWindowData *window_data = (SWindowData *) window; + if(window_data->close) { + destroy(window_data); + return STATE_EXIT; + } + + if(buffer == 0x0) { + return STATE_INVALID_BUFFER; + } + + SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; + + if (window_data->buffer_width != window_data->dst_width || window_data->buffer_height != window_data->dst_height) { + if(window_data_x11->image_scaler_width != window_data->dst_width || window_data_x11->image_scaler_height != window_data->dst_height) { + if(window_data_x11->image_scaler != 0x0) { + window_data_x11->image_scaler->data = 0x0; + XDestroyImage(window_data_x11->image_scaler); } - if(g_window_data.image_buffer != 0x0) { - free(g_window_data.image_buffer); - g_window_data.image_buffer = 0x0; + if(window_data_x11->image_buffer != 0x0) { + free(window_data_x11->image_buffer); + window_data_x11->image_buffer = 0x0; } - int depth = DefaultDepth(g_window_data.display, g_window_data.screen); - g_window_data.image_buffer = malloc(g_window_data.dst_width * g_window_data.dst_height * 4); - g_window_data.image_scaler_width = g_window_data.dst_width; - g_window_data.image_scaler_height = g_window_data.dst_height; - g_window_data.image_scaler = XCreateImage(g_window_data.display, CopyFromParent, depth, ZPixmap, 0, NULL, g_window_data.image_scaler_width, g_window_data.image_scaler_height, 32, g_window_data.image_scaler_width * 4); + int depth = DefaultDepth(window_data_x11->display, window_data_x11->screen); + window_data_x11->image_buffer = malloc(window_data->dst_width * window_data->dst_height * 4); + window_data_x11->image_scaler_width = window_data->dst_width; + window_data_x11->image_scaler_height = window_data->dst_height; + window_data_x11->image_scaler = XCreateImage(window_data_x11->display, CopyFromParent, depth, ZPixmap, 0, 0x0, window_data_x11->image_scaler_width, window_data_x11->image_scaler_height, 32, window_data_x11->image_scaler_width * 4); } } - if(g_window_data.image_scaler != 0x0) { - stretch_image(buffer, 0, 0, g_window_data.buffer_width, g_window_data.buffer_height, g_window_data.buffer_width, g_window_data.image_buffer, 0, 0, g_window_data.dst_width, g_window_data.dst_height, g_window_data.dst_width); - g_window_data.image_scaler->data = g_window_data.image_buffer; - XPutImage(g_window_data.display, g_window_data.window, g_window_data.gc, g_window_data.image_scaler, 0, 0, g_window_data.dst_offset_x, g_window_data.dst_offset_y, g_window_data.dst_width, g_window_data.dst_height); + if(window_data_x11->image_scaler != 0x0) { + stretch_image((uint32_t *) buffer, 0, 0, window_data->buffer_width, window_data->buffer_height, window_data->buffer_width, (uint32_t *) window_data_x11->image_buffer, 0, 0, window_data->dst_width, window_data->dst_height, window_data->dst_width); + window_data_x11->image_scaler->data = (char *) window_data_x11->image_buffer; + XPutImage(window_data_x11->display, window_data_x11->window, window_data_x11->gc, window_data_x11->image_scaler, 0, 0, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height); } else { - g_window_data.image->data = (char *) buffer; - XPutImage(g_window_data.display, g_window_data.window, g_window_data.gc, g_window_data.image, 0, 0, g_window_data.dst_offset_x, g_window_data.dst_offset_y, g_window_data.dst_width, g_window_data.dst_height); + window_data_x11->image->data = (char *) buffer; + XPutImage(window_data_x11->display, window_data_x11->window, window_data_x11->gc, window_data_x11->image, 0, 0, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height); } - XFlush(g_window_data.display); - - if (processEvents() < 0) - return -1; - - return 0; + XFlush(window_data_x11->display); + processEvents(window_data); + + return STATE_OK; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void mfb_close(void) +void destroy(SWindowData *window_data) { - if(g_window_data.image != 0x0) { - g_window_data.image->data = 0x0; - XDestroyImage(g_window_data.image); - XDestroyWindow(g_window_data.display, g_window_data.window); - XCloseDisplay(g_window_data.display); - - g_window_data.image = 0x0; - g_window_data.display = 0x0; - g_window_data.window = 0; - } - g_window_data.close = true; + if(window_data != 0x0) { + if(window_data->specific != 0x0) { + SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; + if(window_data_x11->image != 0x0) { + window_data_x11->image->data = 0x0; + XDestroyImage(window_data_x11->image); + XDestroyWindow(window_data_x11->display, window_data_x11->window); + XCloseDisplay(window_data_x11->display); + } + memset(window_data_x11, 0, sizeof(SWindowData_X11)); + free(window_data_x11); + } + memset(window_data, 0, sizeof(SWindowData)); + free(window_data); + } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -507,7 +529,7 @@ static int translateKeyCodeA(int keySym) { return KB_KEY_UNKNOWN; } -void init_keycodes() { +void init_keycodes(SWindowData_X11 *window_data_x11) { size_t i; int keySym; @@ -518,10 +540,10 @@ void init_keycodes() { // Valid key code range is [8,255], according to the Xlib manual for(int i=8; i<=255; ++i) { // Try secondary keysym, for numeric keypad keys - keySym = XkbKeycodeToKeysym(g_window_data.display, i, 0, 1); + keySym = XkbKeycodeToKeysym(window_data_x11->display, i, 0, 1); keycodes[i] = translateKeyCodeB(keySym); if(keycodes[i] == KB_KEY_UNKNOWN) { - keySym = XkbKeycodeToKeysym(g_window_data.display, i, 0, 0); + keySym = XkbKeycodeToKeysym(window_data_x11->display, i, 0, 0); keycodes[i] = translateKeyCodeA(keySym); } } @@ -604,29 +626,20 @@ int translate_mod_ex(int key, int state, int is_pressed) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void keyboard_default(void *user_data, Key key, KeyMod mod, bool isPressed) { - kUnused(user_data); - kUnused(mod); - kUnused(isPressed); - if (key == KB_KEY_ESCAPE) { - g_window_data.close = true; - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool mfb_set_viewport(unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) +bool mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { - if(offset_x + width > g_window_data.window_width) { + SWindowData *window_data = (SWindowData *) window; + + if(offset_x + width > window_data->window_width) { return false; } - if(offset_y + height > g_window_data.window_height) { + if(offset_y + height > window_data->window_height) { return false; } - g_window_data.dst_offset_x = offset_x; - g_window_data.dst_offset_y = offset_y; - g_window_data.dst_width = width; - g_window_data.dst_height = height; + window_data->dst_offset_x = offset_x; + window_data->dst_offset_y = offset_y; + window_data->dst_width = width; + window_data->dst_height = height; return true; } diff --git a/tests/noise.c b/tests/noise.c index 0fe3b53..51cf936 100644 --- a/tests/noise.c +++ b/tests/noise.c @@ -4,63 +4,140 @@ #define kUnused(var) (void) var; -#define WIDTH 800 -#define HEIGHT 600 -static unsigned int s_buffer[WIDTH * HEIGHT]; +#define WIDTH_A 800 +#define HEIGHT_A 600 +static unsigned int g_buffer1[WIDTH_A * HEIGHT_A]; + +#define WIDTH_B 240 +#define HEIGHT_B 120 +static unsigned int g_buffer2[WIDTH_B * HEIGHT_B]; //------------------------------------- // C interface //------------------------------------- -void active(void *user_data, bool isActive) { - kUnused(user_data); - fprintf(stdout, "active: %d\n", isActive); +void active(struct Window *window, bool isActive) { + int id = 0; + if(window) { + id = *(int *) mfb_get_user_data(window); + } + fprintf(stdout, "active %d: %d\n", id, isActive); } -void resize(void *user_data, int width, int height) { +void resize(struct Window *window, int width, int height) { uint32_t x = 0; uint32_t y = 0; + int id = 0; + if(window) { + id = *(int *) mfb_get_user_data(window); + } - kUnused(user_data); - fprintf(stdout, "resize: %d, %d\n", width, height); - if(width > WIDTH) { - x = (width - WIDTH) >> 1; - width = WIDTH; + fprintf(stdout, "resize %d: %d, %d\n", id, width, height); + if(width > WIDTH_A) { + x = (width - WIDTH_A) >> 1; + width = WIDTH_A; } - if(height > HEIGHT) { - y = (height - HEIGHT) >> 1; - height = HEIGHT; + if(height > HEIGHT_A) { + y = (height - HEIGHT_A) >> 1; + height = HEIGHT_A; } - mfb_set_viewport(x, y, width, height); + mfb_set_viewport(window, x, y, width, height); } -void keyboard(void *user_data, Key key, KeyMod mod, bool isPressed) { - kUnused(user_data); - fprintf(stdout, "keyboard: key: %s (pressed: %d) [KeyMod: %x]\n", mfb_get_key_name(key), isPressed, mod); +void keyboard(struct Window *window, Key key, KeyMod mod, bool isPressed) { + int id = 0; + if(window) { + id = *(int *) mfb_get_user_data(window); + } + fprintf(stdout, "keyboard %d: key: %s (pressed: %d) [KeyMod: %x]\n", id, mfb_get_key_name(key), isPressed, mod); if(key == KB_KEY_ESCAPE) { - mfb_close(); + mfb_close(window); } } -void char_input(void *user_data, unsigned int charCode) { - kUnused(user_data); - fprintf(stdout, "charCode: %d\n", charCode); +void char_input(struct Window *window, unsigned int charCode) { + int id = 0; + if(window) { + id = *(int *) mfb_get_user_data(window); + } + fprintf(stdout, "charCode %d: %d\n", id, charCode); } -void mouse_btn(void *user_data, MouseButton button, KeyMod mod, bool isPressed) { - kUnused(user_data); - fprintf(stdout, "mouse_btn: button: %d (pressed: %d) [KeyMod: %x]\n", button, isPressed, mod); +void mouse_btn(struct Window *window, MouseButton button, KeyMod mod, bool isPressed) { + int id = 0; + if(window) { + id = *(int *) mfb_get_user_data(window); + } + fprintf(stdout, "mouse_btn %d: button: %d (pressed: %d) [KeyMod: %x]\n", id, button, isPressed, mod); } -void mouse_move(void *user_data, int x, int y) { - kUnused(user_data); +void mouse_move(struct Window *window, int x, int y) { + kUnused(window); + kUnused(x); + kUnused(y); + // int id = 0; + // if(window) { + // id = *(int *) mfb_get_user_data(window); + // } + //fprintf(stdout, "mouse_move %d: %d, %d\n", id, x, y); +} + +void mouse_scroll(struct Window *window, KeyMod mod, float deltaX, float deltaY) { + int id = 0; + if(window) { + id = *(int *) mfb_get_user_data(window); + } + fprintf(stdout, "mouse_scroll %d: x: %f, y: %f [KeyMod: %x]\n", id, deltaX, deltaY, mod); +} + +//-- +void active2(struct Window *window, bool isActive) { + kUnused(window); + fprintf(stdout, "active 2: %d\n", isActive); +} + +void resize2(struct Window *window, int width, int height) { + uint32_t x = 0; + uint32_t y = 0; + + fprintf(stdout, "resize 2: %d, %d\n", width, height); + if(width > WIDTH_A) { + x = (width - WIDTH_A) >> 1; + width = WIDTH_A; + } + if(height > HEIGHT_A) { + y = (height - HEIGHT_A) >> 1; + height = HEIGHT_A; + } + mfb_set_viewport(window, x, y, width, height); +} + +void keyboard2(struct Window *window, Key key, KeyMod mod, bool isPressed) { + fprintf(stdout, "keyboard 2: key: %s (pressed: %d) [KeyMod: %x]\n", mfb_get_key_name(key), isPressed, mod); + if(key == KB_KEY_ESCAPE) { + mfb_close(window); + } +} + +void char_input2(struct Window *window, unsigned int charCode) { + kUnused(window); + fprintf(stdout, "charCode 2: %d\n", charCode); +} + +void mouse_btn2(struct Window *window, MouseButton button, KeyMod mod, bool isPressed) { + kUnused(window); + fprintf(stdout, "mouse_btn 2: button: %d (pressed: %d) [KeyMod: %x]\n", button, isPressed, mod); +} + +void mouse_move2(struct Window *window, int x, int y) { + kUnused(window); kUnused(x); kUnused(y); //fprintf(stdout, "mouse_move: %d, %d\n", x, y); } -void mouse_scroll(void *user_data, KeyMod mod, float deltaX, float deltaY) { - kUnused(user_data); - fprintf(stdout, "mouse_scroll: x: %f, y: %f [KeyMod: %x]\n", deltaX, deltaY, mod); +void mouse_scroll2(struct Window *window, KeyMod mod, float deltaX, float deltaY) { + kUnused(window); + fprintf(stdout, "mouse_scroll 2: x: %f, y: %f [KeyMod: %x]\n", deltaX, deltaY, mod); } //------------------------------------- @@ -70,32 +147,77 @@ void mouse_scroll(void *user_data, KeyMod mod, float deltaX, float deltaY) { class Events { public: - void active(void *user_data, bool isActive) { - ::active(user_data, isActive); + void active(struct Window *window, bool isActive) { + printf("\nEvents 1 - "); + ::active(window, isActive); } - void resize(void *user_data, int width, int height) { - ::resize(user_data, width, height); + void resize(struct Window *window, int width, int height) { + printf("Events 1 - "); + ::resize(window, width, height); } - void keyboard(void *user_data, Key key, KeyMod mod, bool isPressed) { - ::keyboard(user_data, key, mod, isPressed); + void keyboard(struct Window *window, Key key, KeyMod mod, bool isPressed) { + printf("Events 1 - "); + ::keyboard(window, key, mod, isPressed); } - void char_input(void *user_data, unsigned int charCode) { - ::char_input(user_data, charCode); + void char_input(struct Window *window, unsigned int charCode) { + printf("Events 1 - "); + ::char_input(window, charCode); } - void mouse_btn(void *user_data, MouseButton button, KeyMod mod, bool isPressed) { - ::mouse_btn(user_data, button, mod, isPressed); + void mouse_btn(struct Window *window, MouseButton button, KeyMod mod, bool isPressed) { + printf("Events 1 - "); + ::mouse_btn(window, button, mod, isPressed); } - void mouse_move(void *user_data, int x, int y) { - ::mouse_move(user_data, x, y); + void mouse_move(struct Window *window, int x, int y) { + //printf("Events 1 - "); + ::mouse_move(window, x, y); } - void mouse_scroll(void *user_data, KeyMod mod, float deltaX, float deltaY) { - ::mouse_scroll(user_data, mod, deltaX, deltaY); + void mouse_scroll(struct Window *window, KeyMod mod, float deltaX, float deltaY) { + printf("Events 1 - "); + ::mouse_scroll(window, mod, deltaX, deltaY); + } +}; + +class Events2 { +public: + void active(struct Window *window, bool isActive) { + printf("\nEvents 2 - "); + ::active(window, isActive); + } + + void resize(struct Window *window, int width, int height) { + printf("Events 2 - "); + ::resize(window, width, height); + } + + void keyboard(struct Window *window, Key key, KeyMod mod, bool isPressed) { + printf("Events 2 - "); + ::keyboard(window, key, mod, isPressed); + } + + void char_input(struct Window *window, unsigned int charCode) { + printf("Events 2 - "); + ::char_input(window, charCode); + } + + void mouse_btn(struct Window *window, MouseButton button, KeyMod mod, bool isPressed) { + printf("Events 2 - "); + ::mouse_btn(window, button, mod, isPressed); + } + + void mouse_move(struct Window *window, int x, int y) { + //printf("Events 2 - "); + ::mouse_move(window, x, y); + } + + void mouse_scroll(struct Window *window, KeyMod mod, float deltaX, float deltaY) { + printf("Events 2 - "); + ::mouse_scroll(window, mod, deltaX, deltaY); } }; @@ -106,39 +228,75 @@ public: int main() { int noise, carry, seed = 0xbeef; + int id1 = 1, id2 = 2; + + struct Window *window1 = mfb_open_ex("Noise Test", WIDTH_A, HEIGHT_A, WF_RESIZABLE); + if (!window1) + return 0; + + mfb_set_user_data(window1, &id1); #if defined(__cplusplus) Events e; - mfb_active_callback(&e, &Events::active); - mfb_resize_callback(&e, &Events::resize); - mfb_keyboard_callback(&e, &Events::keyboard); - mfb_char_input_callback(&e, &Events::char_input); - mfb_mouse_button_callback(&e, &Events::mouse_btn); - mfb_mouse_move_callback(&e, &Events::mouse_move); - mfb_mouse_scroll_callback(&e, &Events::mouse_scroll); + mfb_active_callback(window1, &e, &Events::active); + mfb_resize_callback(window1, &e, &Events::resize); + mfb_keyboard_callback(window1, &e, &Events::keyboard); + mfb_char_input_callback(window1, &e, &Events::char_input); + mfb_mouse_button_callback(window1, &e, &Events::mouse_btn); + mfb_mouse_move_callback(window1, &e, &Events::mouse_move); + mfb_mouse_scroll_callback(window1, &e, &Events::mouse_scroll); #else - mfb_active_callback(active); - mfb_resize_callback(resize); - mfb_keyboard_callback(keyboard); - mfb_char_input_callback(char_input); - mfb_mouse_button_callback(mouse_btn); - mfb_mouse_move_callback(mouse_move); - mfb_mouse_scroll_callback(mouse_scroll); + mfb_active_callback(window1, active); + mfb_resize_callback(window1, resize); + mfb_keyboard_callback(window1, keyboard); + mfb_char_input_callback(window1, char_input); + mfb_mouse_button_callback(window1, mouse_btn); + mfb_mouse_move_callback(window1, mouse_move); + mfb_mouse_scroll_callback(window1, mouse_scroll); #endif - if (!mfb_open_ex("Noise Test", WIDTH, HEIGHT, WF_RESIZABLE)) + struct Window *window2 = mfb_open_ex("Noise Test", WIDTH_B, HEIGHT_B, WF_RESIZABLE); + if (!window2) return 0; + mfb_set_user_data(window2, &id2); + +#if defined(__cplusplus) + + Events2 e2; + + mfb_active_callback(window2, &e2, &Events2::active); + mfb_resize_callback(window2, &e2, &Events::resize); + mfb_keyboard_callback(window2, &e2, &Events::keyboard); + mfb_char_input_callback(window2, &e2, &Events::char_input); + mfb_mouse_button_callback(window2, &e2, &Events::mouse_btn); + mfb_mouse_move_callback(window2, &e2, &Events::mouse_move); + mfb_mouse_scroll_callback(window2, &e2, &Events::mouse_scroll); + +#else + + mfb_active_callback(window2, active2); + mfb_resize_callback(window2, resize2); + mfb_keyboard_callback(window2, keyboard2); + mfb_char_input_callback(window2, char_input2); + mfb_mouse_button_callback(window2, mouse_btn2); + mfb_mouse_move_callback(window2, mouse_move2); + mfb_mouse_scroll_callback(window2, mouse_scroll2); + +#endif + mfb_keyboard_callback(window2, 0x0); + for (;;) { - int i, state; + int i; + UpdateState state1, state2; - for (i = 0; i < WIDTH * HEIGHT; ++i) + for (i = 0; i < WIDTH_A * HEIGHT_A; ++i) { noise = seed; noise >>= 3; @@ -148,16 +306,36 @@ int main() seed >>= 1; seed |= (carry << 30); noise &= 0xFF; - s_buffer[i] = MFB_RGB(noise, noise, noise); + g_buffer1[i] = MFB_RGB(noise, noise, noise); } - state = mfb_update(s_buffer); + for (i = 0; i < WIDTH_B * HEIGHT_B; ++i) + { + noise = seed; + noise >>= 3; + noise ^= seed; + carry = noise & 1; + noise >>= 1; + seed >>= 1; + seed |= (carry << 30); + noise &= 0xFF; + g_buffer2[i] = MFB_RGB(noise, (~noise) & 0xff, 255 - noise); + } - if (state < 0) + state1 = mfb_update(window1, g_buffer1); + state2 = mfb_update(window2, g_buffer2); + if (state1 != STATE_OK) { + window1 = 0x0; + } + if (state2 != STATE_OK) { + window2 = 0x0; + } + if (state1 != STATE_OK && state2 != STATE_OK) { break; + } } - mfb_close(); + mfb_close(window1); return 0; } From e679c389559f426ad030f8889d5143a9a8395dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Aragon=C3=A9s?= <9335325+Darky-Lucera@users.noreply.github.com> Date: Sun, 9 Jun 2019 08:50:28 +0200 Subject: [PATCH 04/14] Add some examples for the new features (#21) * Added some examples * changed window names --- CMakeLists.txt | 40 ++++- tests/input_events.c | 133 ++++++++++++++++ tests/input_events_cpp.cpp | 138 ++++++++++++++++ tests/multiple_windows.c | 186 ++++++++++++++++++++++ tests/noise.c | 318 ++----------------------------------- 5 files changed, 507 insertions(+), 308 deletions(-) create mode 100644 tests/input_events.c create mode 100644 tests/input_events_cpp.cpp create mode 100644 tests/multiple_windows.c diff --git a/CMakeLists.txt b/CMakeLists.txt index aec5d34..06ba472 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,9 +57,23 @@ add_library(minifb STATIC add_executable(noise tests/noise.c ) - target_link_libraries(noise minifb) +add_executable(input_events + tests/input_events.c +) +target_link_libraries(input_events minifb) + +add_executable(input_events_cpp + tests/input_events_cpp.cpp +) +target_link_libraries(input_events_cpp minifb) + +add_executable(multiple_windows + tests/multiple_windows.c +) +target_link_libraries(multiple_windows minifb) + if (MSVC) elseif (MINGW) elseif (APPLE) @@ -67,10 +81,34 @@ elseif (APPLE) target_link_libraries(noise "-framework QuartzCore") target_link_libraries(noise "-framework Metal") target_link_libraries(noise "-framework MetalKit") + + target_link_libraries(input_events "-framework Cocoa") + target_link_libraries(input_events "-framework QuartzCore") + target_link_libraries(input_events "-framework Metal") + target_link_libraries(input_events "-framework MetalKit") + target_link_libraries(input_events_cpp "-framework Cocoa") + target_link_libraries(input_events_cpp "-framework QuartzCore") + target_link_libraries(input_events_cpp "-framework Metal") + target_link_libraries(input_events_cpp "-framework MetalKit") + + target_link_libraries(multiple_windows "-framework Cocoa") + target_link_libraries(multiple_windows "-framework QuartzCore") + target_link_libraries(multiple_windows "-framework Metal") + target_link_libraries(multiple_windows "-framework MetalKit") elseif (UNIX) if(USE_WAYLAND_API) target_link_libraries(noise -lwayland-client -lwayland-cursor) + + target_link_libraries(input_events -lwayland-client -lwayland-cursor) + target_link_libraries(input_events_cpp -lwayland-client -lwayland-cursor) + + target_link_libraries(multiple_windows -lwayland-client -lwayland-cursor) else() target_link_libraries(noise -lX11) + + target_link_libraries(input_events -lX11) + target_link_libraries(input_events_cpp -lX11) + + target_link_libraries(multiple_windows -lX11) endif() endif() diff --git a/tests/input_events.c b/tests/input_events.c new file mode 100644 index 0000000..ec028d2 --- /dev/null +++ b/tests/input_events.c @@ -0,0 +1,133 @@ +#include +#include +#include + +#define kUnused(var) (void) var; + +#define WIDTH 800 +#define HEIGHT 600 +static unsigned int g_buffer[WIDTH * HEIGHT]; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void active(struct Window *window, bool isActive) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > active: %d\n", window_title, isActive); +} + +void resize(struct Window *window, int width, int height) { + uint32_t x = 0; + uint32_t y = 0; + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + + fprintf(stdout, "%s > resize: %d, %d\n", window_title, width, height); + if(width > WIDTH) { + x = (width - WIDTH) >> 1; + width = WIDTH; + } + if(height > HEIGHT) { + y = (height - HEIGHT) >> 1; + height = HEIGHT; + } + mfb_set_viewport(window, x, y, width, height); +} + +void keyboard(struct Window *window, Key key, KeyMod mod, bool isPressed) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > keyboard: key: %s (pressed: %d) [KeyMod: %x]\n", window_title, mfb_get_key_name(key), isPressed, mod); + if(key == KB_KEY_ESCAPE) { + mfb_close(window); + } +} + +void char_input(struct Window *window, unsigned int charCode) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > charCode: %d\n", window_title, charCode); +} + +void mouse_btn(struct Window *window, MouseButton button, KeyMod mod, bool isPressed) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > mouse_btn: button: %d (pressed: %d) [KeyMod: %x]\n", window_title, button, isPressed, mod); +} + +void mouse_move(struct Window *window, int x, int y) { + kUnused(window); + kUnused(x); + kUnused(y); + // const char *window_title = ""; + // if(window) { + // window_t(const char *) itle = mfb_get_user_data(window); + // } + //fprintf(stdout, "%s > mouse_move: %d, %d\n", window_title, x, y); +} + +void mouse_scroll(struct Window *window, KeyMod mod, float deltaX, float deltaY) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > mouse_scroll: x: %f, y: %f [KeyMod: %x]\n", window_title, deltaX, deltaY, mod); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int main() +{ + int noise, carry, seed = 0xbeef; + + struct Window *window = mfb_open_ex("Input Events Test", WIDTH, HEIGHT, WF_RESIZABLE); + if (!window) + return 0; + + mfb_active_callback(window, active); + mfb_resize_callback(window, resize); + mfb_keyboard_callback(window, keyboard); + mfb_char_input_callback(window, char_input); + mfb_mouse_button_callback(window, mouse_btn); + mfb_mouse_move_callback(window, mouse_move); + mfb_mouse_scroll_callback(window, mouse_scroll); + + mfb_set_user_data(window, (void *) "Input Events Test"); + + for (;;) + { + int i; + UpdateState state; + + for (i = 0; i < WIDTH * HEIGHT; ++i) + { + noise = seed; + noise >>= 3; + noise ^= seed; + carry = noise & 1; + noise >>= 1; + seed >>= 1; + seed |= (carry << 30); + noise &= 0xFF; + g_buffer[i] = MFB_RGB(noise, noise, noise); + } + + state = mfb_update(window, g_buffer); + if (state != STATE_OK) { + window = 0x0; + break; + } + } + + return 0; +} diff --git a/tests/input_events_cpp.cpp b/tests/input_events_cpp.cpp new file mode 100644 index 0000000..2af5532 --- /dev/null +++ b/tests/input_events_cpp.cpp @@ -0,0 +1,138 @@ +#include +#include +#include + +#define kUnused(var) (void) var; + +#define WIDTH 800 +#define HEIGHT 600 +static unsigned int g_buffer[WIDTH * HEIGHT]; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class Events { +public: + void active(struct Window *window, bool isActive) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > active: %d\n", window_title, isActive); + } + + void resize(struct Window *window, int width, int height) { + uint32_t x = 0; + uint32_t y = 0; + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + + fprintf(stdout, "%s > resize: %d, %d\n", window_title, width, height); + if(width > WIDTH) { + x = (width - WIDTH) >> 1; + width = WIDTH; + } + if(height > HEIGHT) { + y = (height - HEIGHT) >> 1; + height = HEIGHT; + } + mfb_set_viewport(window, x, y, width, height); + } + + void keyboard(struct Window *window, Key key, KeyMod mod, bool isPressed) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > keyboard: key: %s (pressed: %d) [KeyMod: %x]\n", window_title, mfb_get_key_name(key), isPressed, mod); + if(key == KB_KEY_ESCAPE) { + mfb_close(window); + } + } + + void char_input(struct Window *window, unsigned int charCode) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > charCode: %d\n", window_title, charCode); + } + + void mouse_btn(struct Window *window, MouseButton button, KeyMod mod, bool isPressed) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > mouse_btn: button: %d (pressed: %d) [KeyMod: %x]\n", window_title, button, isPressed, mod); + } + + void mouse_move(struct Window *window, int x, int y) { + kUnused(window); + kUnused(x); + kUnused(y); + // const char *window_title = ""; + // if(window) { + // window_t(const char *) itle = mfb_get_user_data(window); + // } + //fprintf(stdout, "%s > mouse_move: %d, %d\n", window_title, x, y); + } + + void mouse_scroll(struct Window *window, KeyMod mod, float deltaX, float deltaY) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > mouse_scroll: x: %f, y: %f [KeyMod: %x]\n", window_title, deltaX, deltaY, mod); + } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int main() +{ + int noise, carry, seed = 0xbeef; + + struct Window *window = mfb_open_ex("Input Events CPP Test", WIDTH, HEIGHT, WF_RESIZABLE); + if (!window) + return 0; + + Events e; + + mfb_active_callback(window, &e, &Events::active); + mfb_resize_callback(window, &e, &Events::resize); + mfb_keyboard_callback(window, &e, &Events::keyboard); + mfb_char_input_callback(window, &e, &Events::char_input); + mfb_mouse_button_callback(window, &e, &Events::mouse_btn); + mfb_mouse_move_callback(window, &e, &Events::mouse_move); + mfb_mouse_scroll_callback(window, &e, &Events::mouse_scroll); + + mfb_set_user_data(window, (void *) "Input Events CPP Test"); + + for (;;) + { + int i; + UpdateState state; + + for (i = 0; i < WIDTH * HEIGHT; ++i) + { + noise = seed; + noise >>= 3; + noise ^= seed; + carry = noise & 1; + noise >>= 1; + seed >>= 1; + seed |= (carry << 30); + noise &= 0xFF; + g_buffer[i] = MFB_RGB(noise, noise, noise); + } + + state = mfb_update(window, g_buffer); + if (state != STATE_OK) { + window = 0x0; + break; + } + } + + return 0; +} diff --git a/tests/multiple_windows.c b/tests/multiple_windows.c new file mode 100644 index 0000000..4b301c0 --- /dev/null +++ b/tests/multiple_windows.c @@ -0,0 +1,186 @@ +#include +#include +#include +#include + +#define kUnused(var) (void) var; + +#define WIDTH_A 800 +#define HEIGHT_A 600 +static unsigned int g_buffer_a[WIDTH_A * HEIGHT_A]; + +#define WIDTH_B 320 +#define HEIGHT_B 240 +static unsigned int g_buffer_b[WIDTH_B * HEIGHT_B]; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void active(struct Window *window, bool isActive) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > active: %d\n", window_title, isActive); +} + +void resize(struct Window *window, int width, int height) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + + fprintf(stdout, "%s > resize: %d, %d\n", window_title, width, height); +} + +void keyboard(struct Window *window, Key key, KeyMod mod, bool isPressed) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > keyboard: key: %s (pressed: %d) [KeyMod: %x]\n", window_title, mfb_get_key_name(key), isPressed, mod); + if(key == KB_KEY_ESCAPE) { + mfb_close(window); + } +} + +void char_input(struct Window *window, unsigned int charCode) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > charCode: %d\n", window_title, charCode); +} + +void mouse_btn(struct Window *window, MouseButton button, KeyMod mod, bool isPressed) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > mouse_btn: button: %d (pressed: %d) [KeyMod: %x]\n", window_title, button, isPressed, mod); +} + +void mouse_move(struct Window *window, int x, int y) { + kUnused(window); + kUnused(x); + kUnused(y); + // const char *window_title = ""; + // if(window) { + // window_t(const char *) itle = mfb_get_user_data(window); + // } + //fprintf(stdout, "%s > mouse_move: %d, %d\n", window_title, x, y); +} + +void mouse_scroll(struct Window *window, KeyMod mod, float deltaX, float deltaY) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > mouse_scroll: x: %f, y: %f [KeyMod: %x]\n", window_title, deltaX, deltaY, mod); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int main() +{ + int noise, carry, seed = 0xbeef; + + struct Window *window_a = mfb_open_ex("Multiple Windows Test", WIDTH_A, HEIGHT_A, WF_RESIZABLE); + if (!window_a) + return 0; + + mfb_active_callback(window_a, active); + mfb_resize_callback(window_a, resize); + mfb_keyboard_callback(window_a, keyboard); + mfb_char_input_callback(window_a, char_input); + mfb_mouse_button_callback(window_a, mouse_btn); + mfb_mouse_move_callback(window_a, mouse_move); + mfb_mouse_scroll_callback(window_a, mouse_scroll); + + mfb_set_user_data(window_a, (void *) "Window A"); + + //-- + struct Window *window_b = mfb_open_ex("Secondary Window", WIDTH_B, HEIGHT_B, WF_RESIZABLE); + if (!window_b) + return 0; + + mfb_active_callback(window_b, active); + mfb_resize_callback(window_b, resize); + mfb_keyboard_callback(window_b, keyboard); + mfb_char_input_callback(window_b, char_input); + mfb_mouse_button_callback(window_b, mouse_btn); + mfb_mouse_move_callback(window_b, mouse_move); + mfb_mouse_scroll_callback(window_b, mouse_scroll); + + mfb_set_user_data(window_b, (void *) "Window B"); + + // Generate pallete for plasma effect + uint32_t pallete[512]; + float inc = 90.0f / 64.0f; + for(uint32_t c=0; c<64; ++c) { + int32_t col = (255.0f * sinf(c * inc * M_PI / 180.0f)) + 0.5f; + pallete[64*0 + c] = MFB_RGB(col, 0, 0); + pallete[64*1 + c] = MFB_RGB(255, col, 0); + pallete[64*2 + c] = MFB_RGB(255-col, 255, 0); + pallete[64*3 + c] = MFB_RGB(0, 255, col); + pallete[64*4 + c] = MFB_RGB(0, 255-col, 255); + pallete[64*5 + c] = MFB_RGB(col, 0, 255); + pallete[64*6 + c] = MFB_RGB(255, 0, 255-col); + pallete[64*7 + c] = MFB_RGB(255-col, 0, 0); + } + + //-- + float time = 0; + for (;;) + { + int i, x, y; + float dx, dy, time_x, time_y; + int index; + UpdateState state_a, state_b; + + for (i = 0; i < WIDTH_A * HEIGHT_A; ++i) + { + noise = seed; + noise >>= 3; + noise ^= seed; + carry = noise & 1; + noise >>= 1; + seed >>= 1; + seed |= (carry << 30); + noise &= 0xFF; + g_buffer_a[i] = MFB_RGB(noise, noise, noise); + } + + //-- + time_x = sinf(time * M_PI / 180.0f); + time_y = cosf(time * M_PI / 180.0f); + i = 0; + for(y=0; y #include -#define kUnused(var) (void) var; - -#define WIDTH_A 800 -#define HEIGHT_A 600 -static unsigned int g_buffer1[WIDTH_A * HEIGHT_A]; - -#define WIDTH_B 240 -#define HEIGHT_B 120 -static unsigned int g_buffer2[WIDTH_B * HEIGHT_B]; - -//------------------------------------- -// C interface -//------------------------------------- -void active(struct Window *window, bool isActive) { - int id = 0; - if(window) { - id = *(int *) mfb_get_user_data(window); - } - fprintf(stdout, "active %d: %d\n", id, isActive); -} - -void resize(struct Window *window, int width, int height) { - uint32_t x = 0; - uint32_t y = 0; - int id = 0; - if(window) { - id = *(int *) mfb_get_user_data(window); - } - - fprintf(stdout, "resize %d: %d, %d\n", id, width, height); - if(width > WIDTH_A) { - x = (width - WIDTH_A) >> 1; - width = WIDTH_A; - } - if(height > HEIGHT_A) { - y = (height - HEIGHT_A) >> 1; - height = HEIGHT_A; - } - mfb_set_viewport(window, x, y, width, height); -} - -void keyboard(struct Window *window, Key key, KeyMod mod, bool isPressed) { - int id = 0; - if(window) { - id = *(int *) mfb_get_user_data(window); - } - fprintf(stdout, "keyboard %d: key: %s (pressed: %d) [KeyMod: %x]\n", id, mfb_get_key_name(key), isPressed, mod); - if(key == KB_KEY_ESCAPE) { - mfb_close(window); - } -} - -void char_input(struct Window *window, unsigned int charCode) { - int id = 0; - if(window) { - id = *(int *) mfb_get_user_data(window); - } - fprintf(stdout, "charCode %d: %d\n", id, charCode); -} - -void mouse_btn(struct Window *window, MouseButton button, KeyMod mod, bool isPressed) { - int id = 0; - if(window) { - id = *(int *) mfb_get_user_data(window); - } - fprintf(stdout, "mouse_btn %d: button: %d (pressed: %d) [KeyMod: %x]\n", id, button, isPressed, mod); -} - -void mouse_move(struct Window *window, int x, int y) { - kUnused(window); - kUnused(x); - kUnused(y); - // int id = 0; - // if(window) { - // id = *(int *) mfb_get_user_data(window); - // } - //fprintf(stdout, "mouse_move %d: %d, %d\n", id, x, y); -} - -void mouse_scroll(struct Window *window, KeyMod mod, float deltaX, float deltaY) { - int id = 0; - if(window) { - id = *(int *) mfb_get_user_data(window); - } - fprintf(stdout, "mouse_scroll %d: x: %f, y: %f [KeyMod: %x]\n", id, deltaX, deltaY, mod); -} - -//-- -void active2(struct Window *window, bool isActive) { - kUnused(window); - fprintf(stdout, "active 2: %d\n", isActive); -} - -void resize2(struct Window *window, int width, int height) { - uint32_t x = 0; - uint32_t y = 0; - - fprintf(stdout, "resize 2: %d, %d\n", width, height); - if(width > WIDTH_A) { - x = (width - WIDTH_A) >> 1; - width = WIDTH_A; - } - if(height > HEIGHT_A) { - y = (height - HEIGHT_A) >> 1; - height = HEIGHT_A; - } - mfb_set_viewport(window, x, y, width, height); -} - -void keyboard2(struct Window *window, Key key, KeyMod mod, bool isPressed) { - fprintf(stdout, "keyboard 2: key: %s (pressed: %d) [KeyMod: %x]\n", mfb_get_key_name(key), isPressed, mod); - if(key == KB_KEY_ESCAPE) { - mfb_close(window); - } -} - -void char_input2(struct Window *window, unsigned int charCode) { - kUnused(window); - fprintf(stdout, "charCode 2: %d\n", charCode); -} - -void mouse_btn2(struct Window *window, MouseButton button, KeyMod mod, bool isPressed) { - kUnused(window); - fprintf(stdout, "mouse_btn 2: button: %d (pressed: %d) [KeyMod: %x]\n", button, isPressed, mod); -} - -void mouse_move2(struct Window *window, int x, int y) { - kUnused(window); - kUnused(x); - kUnused(y); - //fprintf(stdout, "mouse_move: %d, %d\n", x, y); -} - -void mouse_scroll2(struct Window *window, KeyMod mod, float deltaX, float deltaY) { - kUnused(window); - fprintf(stdout, "mouse_scroll 2: x: %f, y: %f [KeyMod: %x]\n", deltaX, deltaY, mod); -} - -//------------------------------------- -// C++ interface (calling C functions) -//------------------------------------- -#if defined(__cplusplus) - -class Events { -public: - void active(struct Window *window, bool isActive) { - printf("\nEvents 1 - "); - ::active(window, isActive); - } - - void resize(struct Window *window, int width, int height) { - printf("Events 1 - "); - ::resize(window, width, height); - } - - void keyboard(struct Window *window, Key key, KeyMod mod, bool isPressed) { - printf("Events 1 - "); - ::keyboard(window, key, mod, isPressed); - } - - void char_input(struct Window *window, unsigned int charCode) { - printf("Events 1 - "); - ::char_input(window, charCode); - } - - void mouse_btn(struct Window *window, MouseButton button, KeyMod mod, bool isPressed) { - printf("Events 1 - "); - ::mouse_btn(window, button, mod, isPressed); - } - - void mouse_move(struct Window *window, int x, int y) { - //printf("Events 1 - "); - ::mouse_move(window, x, y); - } - - void mouse_scroll(struct Window *window, KeyMod mod, float deltaX, float deltaY) { - printf("Events 1 - "); - ::mouse_scroll(window, mod, deltaX, deltaY); - } -}; - -class Events2 { -public: - void active(struct Window *window, bool isActive) { - printf("\nEvents 2 - "); - ::active(window, isActive); - } - - void resize(struct Window *window, int width, int height) { - printf("Events 2 - "); - ::resize(window, width, height); - } - - void keyboard(struct Window *window, Key key, KeyMod mod, bool isPressed) { - printf("Events 2 - "); - ::keyboard(window, key, mod, isPressed); - } - - void char_input(struct Window *window, unsigned int charCode) { - printf("Events 2 - "); - ::char_input(window, charCode); - } - - void mouse_btn(struct Window *window, MouseButton button, KeyMod mod, bool isPressed) { - printf("Events 2 - "); - ::mouse_btn(window, button, mod, isPressed); - } - - void mouse_move(struct Window *window, int x, int y) { - //printf("Events 2 - "); - ::mouse_move(window, x, y); - } - - void mouse_scroll(struct Window *window, KeyMod mod, float deltaX, float deltaY) { - printf("Events 2 - "); - ::mouse_scroll(window, mod, deltaX, deltaY); - } -}; - -#endif +#define WIDTH 800 +#define HEIGHT 600 +static unsigned int g_buffer[WIDTH * HEIGHT]; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int main() { int noise, carry, seed = 0xbeef; - int id1 = 1, id2 = 2; - struct Window *window1 = mfb_open_ex("Noise Test", WIDTH_A, HEIGHT_A, WF_RESIZABLE); - if (!window1) + struct Window *window = mfb_open_ex("Noise Test", WIDTH, HEIGHT, WF_RESIZABLE); + if (!window) return 0; - mfb_set_user_data(window1, &id1); - -#if defined(__cplusplus) - - Events e; - - mfb_active_callback(window1, &e, &Events::active); - mfb_resize_callback(window1, &e, &Events::resize); - mfb_keyboard_callback(window1, &e, &Events::keyboard); - mfb_char_input_callback(window1, &e, &Events::char_input); - mfb_mouse_button_callback(window1, &e, &Events::mouse_btn); - mfb_mouse_move_callback(window1, &e, &Events::mouse_move); - mfb_mouse_scroll_callback(window1, &e, &Events::mouse_scroll); - -#else - - mfb_active_callback(window1, active); - mfb_resize_callback(window1, resize); - mfb_keyboard_callback(window1, keyboard); - mfb_char_input_callback(window1, char_input); - mfb_mouse_button_callback(window1, mouse_btn); - mfb_mouse_move_callback(window1, mouse_move); - mfb_mouse_scroll_callback(window1, mouse_scroll); - -#endif - - struct Window *window2 = mfb_open_ex("Noise Test", WIDTH_B, HEIGHT_B, WF_RESIZABLE); - if (!window2) - return 0; - - mfb_set_user_data(window2, &id2); - -#if defined(__cplusplus) - - Events2 e2; - - mfb_active_callback(window2, &e2, &Events2::active); - mfb_resize_callback(window2, &e2, &Events::resize); - mfb_keyboard_callback(window2, &e2, &Events::keyboard); - mfb_char_input_callback(window2, &e2, &Events::char_input); - mfb_mouse_button_callback(window2, &e2, &Events::mouse_btn); - mfb_mouse_move_callback(window2, &e2, &Events::mouse_move); - mfb_mouse_scroll_callback(window2, &e2, &Events::mouse_scroll); - -#else - - mfb_active_callback(window2, active2); - mfb_resize_callback(window2, resize2); - mfb_keyboard_callback(window2, keyboard2); - mfb_char_input_callback(window2, char_input2); - mfb_mouse_button_callback(window2, mouse_btn2); - mfb_mouse_move_callback(window2, mouse_move2); - mfb_mouse_scroll_callback(window2, mouse_scroll2); - -#endif - mfb_keyboard_callback(window2, 0x0); - for (;;) { int i; - UpdateState state1, state2; + UpdateState state; - for (i = 0; i < WIDTH_A * HEIGHT_A; ++i) + for (i = 0; i < WIDTH * HEIGHT; ++i) { noise = seed; noise >>= 3; @@ -306,36 +31,15 @@ int main() seed >>= 1; seed |= (carry << 30); noise &= 0xFF; - g_buffer1[i] = MFB_RGB(noise, noise, noise); + g_buffer[i] = MFB_RGB(noise, noise, noise); } - for (i = 0; i < WIDTH_B * HEIGHT_B; ++i) - { - noise = seed; - noise >>= 3; - noise ^= seed; - carry = noise & 1; - noise >>= 1; - seed >>= 1; - seed |= (carry << 30); - noise &= 0xFF; - g_buffer2[i] = MFB_RGB(noise, (~noise) & 0xff, 255 - noise); - } - - state1 = mfb_update(window1, g_buffer1); - state2 = mfb_update(window2, g_buffer2); - if (state1 != STATE_OK) { - window1 = 0x0; - } - if (state2 != STATE_OK) { - window2 = 0x0; - } - if (state1 != STATE_OK && state2 != STATE_OK) { + state = mfb_update(window, g_buffer); + if (state != STATE_OK) { + window = 0x0; break; } } - mfb_close(window1); - return 0; } From 25a440f8226f12b8014d24288ad0587724005afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Aragon=C3=A9s?= <9335325+Darky-Lucera@users.noreply.github.com> Date: Sun, 9 Jun 2019 08:50:42 +0200 Subject: [PATCH 05/14] Update documentation (#20) * update documentation * Fix typo * Minor fix --- README.md | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e6732ac..e6dfe9a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ MiniFB MiniFB (Mini FrameBuffer) is a small cross platform library that makes it easy to render (32-bit) pixels in a window. An example is the best way to show how it works: - if (!mfb_open("my display", 800, 600)) + struct Window *window = mfb_open_ex("my display", 800, 600, WF_RESIZABLE); + if (!window) return 0; for (;;) @@ -18,10 +19,66 @@ MiniFB (Mini FrameBuffer) is a small cross platform library that makes it easy t break; } - mfb_close(); + +Furthermore, you can add callbacks to the windows: + + void active(struct Window *window, bool isActive) { + ... + } + + void resize(struct Window *window, int width, int height) { + ... + // Optionally you can also change the viewport size + mfb_set_viewport(window, x, y, width, height); + } + + void keyboard(struct Window *window, Key key, KeyMod mod, bool isPressed) { + ... + // Remember to close the window in some way + if(key == KB_KEY_ESCAPE) { + mfb_close(window); + } + } + + void char_input(struct Window *window, unsigned int charCode) { + ... + } + + void mouse_btn(struct Window *window, MouseButton button, KeyMod mod, bool isPressed) { + ... + } + + // Use wisely this event. It can be sent too often + void mouse_move(struct Window *window, int x, int y) { + ... + } + + // Mouse wheel + void mouse_scroll(struct Window *window, KeyMod mod, float deltaX, float deltaY) { + ... + } + + struct Window *window = mfb_open_ex("my display", 800, 600, WF_RESIZABLE); + if (!window) + return 0; + + mfb_active_callback(window, active); + mfb_resize_callback(window, resize); + mfb_keyboard_callback(window, keyboard); + mfb_char_input_callback(window, char_input); + mfb_mouse_button_callback(window, mouse_btn); + mfb_mouse_move_callback(window, mouse_move); + mfb_mouse_scroll_callback(window, mouse_scroll); -First the code creates window with the mfb_open call that is used to display the data, next it's the applications resposiblity to allocate a buffer (which has to be at least the size of the window and in 32-bit) Next when calling mfb_update function the buffer will be copied over to the window and displayed. Currently the mfb_update will return -1 if ESC key is pressed but later on it will support to return a key code for a pressed button. See https://github.com/emoon/minifb/blob/master/tests/noise.c for a complete example +Additionally you can set data per window and recover it + + mfb_set_user_data(window, (void *) myData); + ... + myData = (someCast *) mfb_get_user_data(window); + + +First the code creates window with the mfb_open call that is used to display the data, next it's the applications responsibility to allocate a buffer (which has to be at least the size of the window and in 32-bit) Next when calling mfb_update function the buffer will be copied over to the window and displayed. Currently the mfb_update will return -1 if ESC key is pressed but later on it will support to return a key code for a pressed button. See https://github.com/emoon/minifb/blob/master/tests/noise.c for a complete example MiniFB has been tested on Windows, Mac OS X and Linux but may of course have trouble depending on your setup. Currently the code will not do any converting of data if not a proper 32-bit display can be created. @@ -30,24 +87,56 @@ Build instructions MiniFB uses tundra https://github.com/deplinenoise/tundra as build system and is required to build the code as is but not many changes should be needed if you want to use it directly in your own code. +You can also use CMake as build system. + Mac --- Cocoa and clang is assumed to be installed on the system (downloading latest XCode + installing the command line tools should do the trick) then to build run: tundra2 macosx-clang-debug and you should be able to run the noise example (t2-output/macosx-clang-debug-default/noise) +MacOS X Mojave does not support Cocoa framework as expected. For that reason now you can switch to Metal API. +To enable it just compile defining the preprocessor macro USE_METAL_API. + +If you use CMake just enable the flag: + + mkdir build + cd build + cmake .. -DUSE_METAL_API=ON + +or if you don't want to use Metal API: + + mkdir build + cd build + cmake .. -DUSE_METAL_API=OFF + + Windows ------- Visual Studio (ver 2012 express has been tested) tools needed (using the vcvars32.bat (for 32-bit) will set up the enviroment) to build run: tundra2 win32-msvc-debug and you should be able to run noise in t2-output/win32-msvc-debug-default/noise.exe +If you use CMake the Visual Studio project will be generated (2015, 2017 and 2019 have been tested). + x11 (FreeBSD, Linux, *nix) -------------------------- gcc and x11-dev libs needs to be installed. To build the code run tundra2 x11-gcc-debug and you should be able to run t2-output/x11-gcc-debug-default/noise +If you use CMake just disable the flag: + + mkdir build + cd build + cmake .. -DUSE_WAYLAND_API=OFF + + wayland (Linux) -------------------------- -Depends on gcc and wayland-client. Built using the wayland-gcc variants. +Depends on gcc and wayland-client and wayland-cursor. Built using the wayland-gcc variants. +If you use CMake just enable the flag: + + mkdir build + cd build + cmake .. -DUSE_WAYLAND_API=ON From cdaa54f5d69a7d864af3e7e1d5363c290d4f42f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Aragon=C3=A9s?= <9335325+Darky-Lucera@users.noreply.github.com> Date: Thu, 14 Nov 2019 16:18:42 +0100 Subject: [PATCH 06/14] Direct mode (#23) * update documentation * Fix typo * Added some examples * changed window names * Minor fix * renamed callback setters (added _set_) Direct / Poll Mode for asking events: bool mfb_is_window_active(struct Window *window); unsigned mfb_get_window_width(struct Window *window); unsigned mfb_get_window_height(struct Window *window); int mfb_get_mouse_x(struct Window *window); // Last mouse pos X int mfb_get_mouse_y(struct Window *window); // Last mouse pos Y float mfb_get_mouse_scrool_x(struct Window *window); // Mouse wheel X as a sum. When you call this function it resets. float mfb_get_mouse_scrool_y(struct Window *window); // Mouse wheel Y as a sum. When you call this function it resets. const uint8_t * mfb_get_mouse_button_buffer(struct Window *window); // One byte for every button. Press (1), Release 0. const uint8_t * mfb_get_key_buffer(struct Window *window); // One byte for every key. Press (1), Release 0. * Minor fixes * Fixes related to mouse poll * Minor fix on Win64 --- README.md | 14 +- include/MiniFB.h | 42 +++-- include/MiniFB_cpp.h | 60 +++---- include/MiniFB_enums.h | 23 ++- src/MiniFB_common.c | 105 ++++++++++-- src/MiniFB_internal.h | 2 +- src/WindowData.h | 11 +- src/macosx/MacMiniFB.m | 236 +++++++++++++-------------- src/macosx/OSXWindow.m | 41 +++-- src/macosx/OSXWindowFrameView.m | 2 + src/macosx/WindowData_OSX.h | 1 - src/wayland/WaylandMiniFB.c | 273 ++++++++++++++++---------------- src/windows/WinMiniFB.c | 271 +++++++++++++++---------------- src/x11/X11MiniFB.c | 185 +++++++++++----------- tests/input_events.c | 14 +- tests/input_events_cpp.cpp | 14 +- tests/multiple_windows.c | 40 ++--- 17 files changed, 732 insertions(+), 602 deletions(-) diff --git a/README.md b/README.md index e6dfe9a..a6cc2ff 100644 --- a/README.md +++ b/README.md @@ -62,13 +62,13 @@ Furthermore, you can add callbacks to the windows: if (!window) return 0; - mfb_active_callback(window, active); - mfb_resize_callback(window, resize); - mfb_keyboard_callback(window, keyboard); - mfb_char_input_callback(window, char_input); - mfb_mouse_button_callback(window, mouse_btn); - mfb_mouse_move_callback(window, mouse_move); - mfb_mouse_scroll_callback(window, mouse_scroll); + mfb_set_active_callback(window, active); + mfb_set_resize_callback(window, resize); + mfb_set_keyboard_callback(window, keyboard); + mfb_set_char_input_callback(window, char_input); + mfb_set_mouse_button_callback(window, mouse_btn); + mfb_set_mouse_move_callback(window, mouse_move); + mfb_set_mouse_scroll_callback(window, mouse_scroll); Additionally you can set data per window and recover it diff --git a/include/MiniFB.h b/include/MiniFB.h index 81a62c6..6c4ea1d 100644 --- a/include/MiniFB.h +++ b/include/MiniFB.h @@ -9,37 +9,47 @@ extern "C" { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#define MFB_RGB(r, g, b) (((unsigned int) r) << 16) | (((unsigned int) g) << 8) | (b) +#define MFB_RGB(r, g, b) (((uint32_t) r) << 16) | (((uint32_t) g) << 8) | ((uint32_t) b) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Create a window that is used to display the buffer sent into the mfb_update function, returns 0 if fails -struct Window *mfb_open(const char *title, int width, int height); -struct Window *mfb_open_ex(const char *title, int width, int height, int flags); +struct Window * mfb_open(const char *title, unsigned width, unsigned height); +struct Window * mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags); // Update the display. Input buffer is assumed to be a 32-bit buffer of the size given in the open call // Will return a negative status if something went wrong or the user want to exit. -UpdateState mfb_update(struct Window *window, void* buffer); +UpdateState mfb_update(struct Window *window, void *buffer); // Close the window -void mfb_close(struct Window *window); +void mfb_close(struct Window *window); // Set user data -void mfb_set_user_data(struct Window *window, void *user_data); -void *mfb_get_user_data(struct Window *window); +void mfb_set_user_data(struct Window *window, void *user_data); +void * mfb_get_user_data(struct Window *window); // Set viewport (useful when resize) -bool mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height); +bool mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height); -void mfb_active_callback(struct Window *window, mfb_active_func callback); -void mfb_resize_callback(struct Window *window, mfb_resize_func callback); -void mfb_keyboard_callback(struct Window *window, mfb_keyboard_func callback); -void mfb_char_input_callback(struct Window *window, mfb_char_input_func callback); -void mfb_mouse_button_callback(struct Window *window, mfb_mouse_btn_func callback); -void mfb_mouse_move_callback(struct Window *window, mfb_mouse_move_func callback); -void mfb_mouse_scroll_callback(struct Window *window, mfb_mouse_scroll_func callback); +void mfb_set_active_callback(struct Window *window, mfb_active_func callback); +void mfb_set_resize_callback(struct Window *window, mfb_resize_func callback); +void mfb_set_keyboard_callback(struct Window *window, mfb_keyboard_func callback); +void mfb_set_char_input_callback(struct Window *window, mfb_char_input_func callback); +void mfb_set_mouse_button_callback(struct Window *window, mfb_mouse_button_func callback); +void mfb_set_mouse_move_callback(struct Window *window, mfb_mouse_move_func callback); +void mfb_set_mouse_scroll_callback(struct Window *window, mfb_mouse_scroll_func callback); -const char *mfb_get_key_name(Key key); +const char * mfb_get_key_name(Key key); + +bool mfb_is_window_active(struct Window *window); +unsigned mfb_get_window_width(struct Window *window); +unsigned mfb_get_window_height(struct Window *window); +int mfb_get_mouse_x(struct Window *window); // Last mouse pos X +int mfb_get_mouse_y(struct Window *window); // Last mouse pos Y +float mfb_get_mouse_scrool_x(struct Window *window); // Mouse wheel X as a sum. When you call this function it resets. +float mfb_get_mouse_scrool_y(struct Window *window); // Mouse wheel Y as a sum. When you call this function it resets. +const uint8_t * mfb_get_mouse_button_buffer(struct Window *window); // One byte for every button. Press (1), Release 0. +const uint8_t * mfb_get_key_buffer(struct Window *window); // One byte for every key. Press (1), Release 0. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/MiniFB_cpp.h b/include/MiniFB_cpp.h index c8247d6..acc5b4b 100755 --- a/include/MiniFB_cpp.h +++ b/include/MiniFB_cpp.h @@ -6,46 +6,48 @@ #include "MiniFB.h" template -void mfb_active_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, bool)); +void mfb_set_active_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, bool)); template -void mfb_resize_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, int, int)); +void mfb_set_resize_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, int, int)); template -void mfb_keyboard_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, Key, KeyMod, bool)); +void mfb_set_keyboard_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, Key, KeyMod, bool)); template -void mfb_char_input_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, unsigned int)); +void mfb_set_char_input_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, unsigned int)); template -void mfb_mouse_button_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, MouseButton, KeyMod, bool)); +void mfb_set_mouse_button_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, MouseButton, KeyMod, bool)); template -void mfb_mouse_move_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, int, int)); +void mfb_set_mouse_move_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, int, int)); template -void mfb_mouse_scroll_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, KeyMod, float, float)); +void mfb_set_mouse_scroll_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, KeyMod, float, float)); //------------------------------------- // To avoid clumsy hands //------------------------------------- class Stub { + Stub() : m_window(0x0) {} + template - friend void mfb_active_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, bool)); + friend void mfb_set_active_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, bool)); template - friend void mfb_resize_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, int, int)); + friend void mfb_set_resize_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, int, int)); template - friend void mfb_mouse_button_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, MouseButton, KeyMod, bool)); + friend void mfb_set_mouse_button_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, MouseButton, KeyMod, bool)); template - friend void mfb_keyboard_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, Key, KeyMod, bool)); + friend void mfb_set_keyboard_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, Key, KeyMod, bool)); template - friend void mfb_char_input_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, unsigned int)); + friend void mfb_set_char_input_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, unsigned int)); template - friend void mfb_mouse_button_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, MouseButton, KeyMod, bool)); + friend void mfb_set_mouse_button_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, MouseButton, KeyMod, bool)); template - friend void mfb_mouse_move_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, int, int)); + friend void mfb_set_mouse_move_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, int, int)); template - friend void mfb_mouse_scroll_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, KeyMod, float, float)); + friend void mfb_set_mouse_scroll_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, KeyMod, float, float)); static Stub *GetInstance(struct Window *window); @@ -69,66 +71,66 @@ class Stub { //------------------------------------- template -inline void mfb_active_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, bool)) { +inline void mfb_set_active_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, bool)) { using namespace std::placeholders; Stub *stub = Stub::GetInstance(window); stub->m_active = std::bind(method, obj, _1, _2); - mfb_active_callback(window, Stub::active_stub); + mfb_set_active_callback(window, Stub::active_stub); } template -inline void mfb_resize_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, int, int)) { +inline void mfb_set_resize_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, int, int)) { using namespace std::placeholders; Stub *stub = Stub::GetInstance(window); stub->m_resize = std::bind(method, obj, _1, _2, _3); - mfb_resize_callback(window, Stub::resize_stub); + mfb_set_resize_callback(window, Stub::resize_stub); } template -inline void mfb_keyboard_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, Key, KeyMod, bool)) { +inline void mfb_set_keyboard_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, Key, KeyMod, bool)) { using namespace std::placeholders; Stub *stub = Stub::GetInstance(window); stub->m_keyboard = std::bind(method, obj, _1, _2, _3, _4); - mfb_keyboard_callback(window, Stub::keyboard_stub); + mfb_set_keyboard_callback(window, Stub::keyboard_stub); } template -inline void mfb_char_input_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, unsigned int)) { +inline void mfb_set_char_input_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, unsigned int)) { using namespace std::placeholders; Stub *stub = Stub::GetInstance(window); stub->m_char_input = std::bind(method, obj, _1, _2); - mfb_char_input_callback(window, Stub::char_input_stub); + mfb_set_char_input_callback(window, Stub::char_input_stub); } template -inline void mfb_mouse_button_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, MouseButton, KeyMod, bool)) { +inline void mfb_set_mouse_button_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, MouseButton, KeyMod, bool)) { using namespace std::placeholders; Stub *stub = Stub::GetInstance(window); stub->m_mouse_btn = std::bind(method, obj, _1, _2, _3, _4); - mfb_mouse_button_callback(window, Stub::mouse_btn_stub); + mfb_set_mouse_button_callback(window, Stub::mouse_btn_stub); } template -inline void mfb_mouse_move_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, int, int)) { +inline void mfb_set_mouse_move_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, int, int)) { using namespace std::placeholders; Stub *stub = Stub::GetInstance(window); stub->m_mouse_move = std::bind(method, obj, _1, _2, _3); - mfb_mouse_move_callback(window, Stub::mouse_move_stub); + mfb_set_mouse_move_callback(window, Stub::mouse_move_stub); } template -inline void mfb_mouse_scroll_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, KeyMod, float, float)) { +inline void mfb_set_mouse_scroll_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, KeyMod, float, float)) { using namespace std::placeholders; Stub *stub = Stub::GetInstance(window); stub->m_scroll = std::bind(method, obj, _1, _2, _3, _4); - mfb_mouse_scroll_callback(window, Stub::scroll_stub); + mfb_set_mouse_scroll_callback(window, Stub::scroll_stub); } #endif diff --git a/include/MiniFB_enums.h b/include/MiniFB_enums.h index 4d4058e..df91e07 100755 --- a/include/MiniFB_enums.h +++ b/include/MiniFB_enums.h @@ -1,5 +1,6 @@ #pragma once +#include #include // Enums @@ -20,12 +21,10 @@ typedef enum { MOUSE_BTN_5, MOUSE_BTN_6, MOUSE_BTN_7, - MOUSE_BTN_8 } MouseButton; -#define MOUSE_LAST MOUSE_BTN_8 -#define MOUSE_LEFT MOUSE_BTN_0 -#define MOUSE_RIGHT MOUSE_BTN_1 -#define MOUSE_MIDDLE MOUSE_BTN_2 +#define MOUSE_LEFT MOUSE_BTN_1 +#define MOUSE_RIGHT MOUSE_BTN_2 +#define MOUSE_MIDDLE MOUSE_BTN_3 typedef enum { KB_KEY_UNKNOWN = -1, @@ -155,12 +154,12 @@ typedef enum { #define KB_KEY_LAST KB_KEY_MENU typedef enum { - KB_MOD_SHIFT = 0x0001, - KB_MOD_CONTROL = 0x0002, - KB_MOD_ALT = 0x0004, - KB_MOD_SUPER = 0x0008, - KB_MOD_CAPS_LOCK = 0x0010, - KB_MOD_NUM_LOCK = 0x0020 + KB_MOD_SHIFT = 0x0001, + KB_MOD_CONTROL = 0x0002, + KB_MOD_ALT = 0x0004, + KB_MOD_SUPER = 0x0008, + KB_MOD_CAPS_LOCK = 0x0010, + KB_MOD_NUM_LOCK = 0x0020 } KeyMod; typedef enum { @@ -179,7 +178,7 @@ typedef void(*mfb_active_func)(struct Window *window, bool isActive); typedef void(*mfb_resize_func)(struct Window *window, int width, int height); typedef void(*mfb_keyboard_func)(struct Window *window, Key key, KeyMod mod, bool isPressed); typedef void(*mfb_char_input_func)(struct Window *window, unsigned int code); -typedef void(*mfb_mouse_btn_func)(struct Window *window, MouseButton button, KeyMod mod, bool isPressed); +typedef void(*mfb_mouse_button_func)(struct Window *window, MouseButton button, KeyMod mod, bool isPressed); typedef void(*mfb_mouse_move_func)(struct Window *window, int x, int y); typedef void(*mfb_mouse_scroll_func)(struct Window *window, KeyMod mod, float deltaX, float deltaY); diff --git a/src/MiniFB_common.c b/src/MiniFB_common.c index 4941b1a..997babe 100755 --- a/src/MiniFB_common.c +++ b/src/MiniFB_common.c @@ -3,7 +3,11 @@ #include //------------------------------------- -void mfb_active_callback(struct Window *window, mfb_active_func callback) { +short int g_keycodes[512] = { 0 }; +//------------------------------------- + +//------------------------------------- +void mfb_set_active_callback(struct Window *window, mfb_active_func callback) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; window_data->active_func = callback; @@ -11,7 +15,7 @@ void mfb_active_callback(struct Window *window, mfb_active_func callback) { } //------------------------------------- -void mfb_resize_callback(struct Window *window, mfb_resize_func callback) { +void mfb_set_resize_callback(struct Window *window, mfb_resize_func callback) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; window_data->resize_func = callback; @@ -19,7 +23,7 @@ void mfb_resize_callback(struct Window *window, mfb_resize_func callback) { } //------------------------------------- -void mfb_keyboard_callback(struct Window *window, mfb_keyboard_func callback) { +void mfb_set_keyboard_callback(struct Window *window, mfb_keyboard_func callback) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; window_data->keyboard_func = callback; @@ -27,7 +31,7 @@ void mfb_keyboard_callback(struct Window *window, mfb_keyboard_func callback) { } //------------------------------------- -void mfb_char_input_callback(struct Window *window, mfb_char_input_func callback) { +void mfb_set_char_input_callback(struct Window *window, mfb_char_input_func callback) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; window_data->char_input_func = callback; @@ -35,7 +39,7 @@ void mfb_char_input_callback(struct Window *window, mfb_char_input_func callback } //------------------------------------- -void mfb_mouse_button_callback(struct Window *window, mfb_mouse_btn_func callback) { +void mfb_set_mouse_button_callback(struct Window *window, mfb_mouse_button_func callback) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; window_data->mouse_btn_func = callback; @@ -43,7 +47,7 @@ void mfb_mouse_button_callback(struct Window *window, mfb_mouse_btn_func callbac } //------------------------------------- -void mfb_mouse_move_callback(struct Window *window, mfb_mouse_move_func callback) { +void mfb_set_mouse_move_callback(struct Window *window, mfb_mouse_move_func callback) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; window_data->mouse_move_func = callback; @@ -51,7 +55,7 @@ void mfb_mouse_move_callback(struct Window *window, mfb_mouse_move_func callback } //------------------------------------- -void mfb_mouse_scroll_callback(struct Window *window, mfb_mouse_scroll_func callback) { +void mfb_set_mouse_scroll_callback(struct Window *window, mfb_mouse_scroll_func callback) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; window_data->mouse_wheel_func = callback; @@ -77,8 +81,7 @@ void *mfb_get_user_data(struct Window *window) { } //------------------------------------- -void mfb_close(struct Window *window) -{ +void mfb_close(struct Window *window) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; window_data->close = true; @@ -95,9 +98,91 @@ void keyboard_default(struct Window *window, Key key, KeyMod mod, bool isPressed } } +//------------------------------------- +bool mfb_is_window_active(struct Window *window) { + if(window != 0x0) { + SWindowData *window_data = (SWindowData *) window; + return window_data->is_active; + } + return false; +} //------------------------------------- -const char *mfb_get_key_name(Key key) { +unsigned mfb_get_window_width(struct Window *window) { + if(window != 0x0) { + SWindowData *window_data = (SWindowData *) window; + return window_data->window_width; + } + return 0; +} + +//------------------------------------- +unsigned mfb_get_window_height(struct Window *window) { + if(window != 0x0) { + SWindowData *window_data = (SWindowData *) window; + return window_data->window_height; + } + return 0; +} + +//------------------------------------- +int mfb_get_mouse_x(struct Window *window) { + if(window != 0x0) { + SWindowData *window_data = (SWindowData *) window; + return window_data->mouse_pos_x; + } + return 0; +} + +//------------------------------------- +int mfb_get_mouse_y(struct Window *window) { + if(window != 0x0) { + SWindowData *window_data = (SWindowData *) window; + return window_data->mouse_pos_y; + } + return 0; +} + +//------------------------------------- +float mfb_get_mouse_scrool_x(struct Window *window) { + if(window != 0x0) { + SWindowData *window_data = (SWindowData *) window; + return window_data->mouse_wheel_x; + } + return 0; +} + +//------------------------------------- +float mfb_get_mouse_scrool_y(struct Window *window) { + if(window != 0x0) { + SWindowData *window_data = (SWindowData *) window; + return window_data->mouse_wheel_y; + } + return 0; +} + +//------------------------------------- +const uint8_t * mfb_get_mouse_button_buffer(struct Window *window) { + if(window != 0x0) { + SWindowData *window_data = (SWindowData *) window; + return window_data->mouse_button_status; + } + return 0; +} + +//------------------------------------- +const uint8_t * mfb_get_key_buffer(struct Window *window) { + if(window != 0x0) { + SWindowData *window_data = (SWindowData *) window; + return window_data->key_status; + } + return 0; +} + + + +//------------------------------------- +const char * mfb_get_key_name(Key key) { switch (key) { diff --git a/src/MiniFB_internal.h b/src/MiniFB_internal.h index c82148b..365c70d 100755 --- a/src/MiniFB_internal.h +++ b/src/MiniFB_internal.h @@ -10,7 +10,7 @@ extern "C" { #endif - short int keycodes[512]; + extern short int g_keycodes[512]; void init_keycodes(); void keyboard_default(struct Window *window, Key key, KeyMod mod, bool isPressed); diff --git a/src/WindowData.h b/src/WindowData.h index 79ffcb8..ce69fd2 100644 --- a/src/WindowData.h +++ b/src/WindowData.h @@ -12,7 +12,7 @@ typedef struct { mfb_resize_func resize_func; mfb_keyboard_func keyboard_func; mfb_char_input_func char_input_func; - mfb_mouse_btn_func mouse_btn_func; + mfb_mouse_button_func mouse_btn_func; mfb_mouse_move_func mouse_move_func; mfb_mouse_scroll_func mouse_wheel_func; @@ -30,4 +30,13 @@ typedef struct { uint32_t buffer_stride; uint32_t mod_keys; bool close; + + bool is_active; + int32_t mouse_pos_x; + int32_t mouse_pos_y; + float mouse_wheel_x; + float mouse_wheel_y; + uint8_t mouse_button_status[8]; + uint8_t key_status[512]; + } SWindowData; diff --git a/src/macosx/MacMiniFB.m b/src/macosx/MacMiniFB.m index 8cecd81..23ef909 100644 --- a/src/macosx/MacMiniFB.m +++ b/src/macosx/MacMiniFB.m @@ -136,14 +136,14 @@ static bool create_shaders(SWindowData_OSX *window_data_osx) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -struct Window *mfb_open(const char *title, int width, int height) +struct Window *mfb_open(const char *title, unsigned width, unsigned height) { return mfb_open_ex(title, width, height, 0); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -struct Window *mfb_open_ex(const char *title, int width, int height, int flags) +struct Window *mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; @@ -254,7 +254,7 @@ struct Window *mfb_open_ex(const char *title, int width, int height, int flags) [NSApp finishLaunching]; #endif - mfb_keyboard_callback((struct Window *) window_data, keyboard_default); + mfb_set_keyboard_callback((struct Window *) window_data, keyboard_default); #if defined(USE_METAL_API) NSLog(@"Window created using Metal API"); @@ -312,7 +312,7 @@ static void update_events(SWindowData *window_data) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -UpdateState mfb_update(struct Window *window, void* buffer) +UpdateState mfb_update(struct Window *window, void *buffer) { if(window == 0x0) { return STATE_INVALID_WINDOW; @@ -385,126 +385,126 @@ bool mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -extern short int keycodes[512]; +extern short int g_keycodes[512]; void init_keycodes() { // Clear keys - for (unsigned int i = 0; i < sizeof(keycodes) / sizeof(keycodes[0]); ++i) - keycodes[i] = 0; + for (unsigned int i = 0; i < sizeof(g_keycodes) / sizeof(g_keycodes[0]); ++i) + g_keycodes[i] = 0; - keycodes[0x1D] = KB_KEY_0; - keycodes[0x12] = KB_KEY_1; - keycodes[0x13] = KB_KEY_2; - keycodes[0x14] = KB_KEY_3; - keycodes[0x15] = KB_KEY_4; - keycodes[0x17] = KB_KEY_5; - keycodes[0x16] = KB_KEY_6; - keycodes[0x1A] = KB_KEY_7; - keycodes[0x1C] = KB_KEY_8; - keycodes[0x19] = KB_KEY_9; - keycodes[0x00] = KB_KEY_A; - keycodes[0x0B] = KB_KEY_B; - keycodes[0x08] = KB_KEY_C; - keycodes[0x02] = KB_KEY_D; - keycodes[0x0E] = KB_KEY_E; - keycodes[0x03] = KB_KEY_F; - keycodes[0x05] = KB_KEY_G; - keycodes[0x04] = KB_KEY_H; - keycodes[0x22] = KB_KEY_I; - keycodes[0x26] = KB_KEY_J; - keycodes[0x28] = KB_KEY_K; - keycodes[0x25] = KB_KEY_L; - keycodes[0x2E] = KB_KEY_M; - keycodes[0x2D] = KB_KEY_N; - keycodes[0x1F] = KB_KEY_O; - keycodes[0x23] = KB_KEY_P; - keycodes[0x0C] = KB_KEY_Q; - keycodes[0x0F] = KB_KEY_R; - keycodes[0x01] = KB_KEY_S; - keycodes[0x11] = KB_KEY_T; - keycodes[0x20] = KB_KEY_U; - keycodes[0x09] = KB_KEY_V; - keycodes[0x0D] = KB_KEY_W; - keycodes[0x07] = KB_KEY_X; - keycodes[0x10] = KB_KEY_Y; - keycodes[0x06] = KB_KEY_Z; + g_keycodes[0x1D] = KB_KEY_0; + g_keycodes[0x12] = KB_KEY_1; + g_keycodes[0x13] = KB_KEY_2; + g_keycodes[0x14] = KB_KEY_3; + g_keycodes[0x15] = KB_KEY_4; + g_keycodes[0x17] = KB_KEY_5; + g_keycodes[0x16] = KB_KEY_6; + g_keycodes[0x1A] = KB_KEY_7; + g_keycodes[0x1C] = KB_KEY_8; + g_keycodes[0x19] = KB_KEY_9; + g_keycodes[0x00] = KB_KEY_A; + g_keycodes[0x0B] = KB_KEY_B; + g_keycodes[0x08] = KB_KEY_C; + g_keycodes[0x02] = KB_KEY_D; + g_keycodes[0x0E] = KB_KEY_E; + g_keycodes[0x03] = KB_KEY_F; + g_keycodes[0x05] = KB_KEY_G; + g_keycodes[0x04] = KB_KEY_H; + g_keycodes[0x22] = KB_KEY_I; + g_keycodes[0x26] = KB_KEY_J; + g_keycodes[0x28] = KB_KEY_K; + g_keycodes[0x25] = KB_KEY_L; + g_keycodes[0x2E] = KB_KEY_M; + g_keycodes[0x2D] = KB_KEY_N; + g_keycodes[0x1F] = KB_KEY_O; + g_keycodes[0x23] = KB_KEY_P; + g_keycodes[0x0C] = KB_KEY_Q; + g_keycodes[0x0F] = KB_KEY_R; + g_keycodes[0x01] = KB_KEY_S; + g_keycodes[0x11] = KB_KEY_T; + g_keycodes[0x20] = KB_KEY_U; + g_keycodes[0x09] = KB_KEY_V; + g_keycodes[0x0D] = KB_KEY_W; + g_keycodes[0x07] = KB_KEY_X; + g_keycodes[0x10] = KB_KEY_Y; + g_keycodes[0x06] = KB_KEY_Z; - keycodes[0x27] = KB_KEY_APOSTROPHE; - keycodes[0x2A] = KB_KEY_BACKSLASH; - keycodes[0x2B] = KB_KEY_COMMA; - keycodes[0x18] = KB_KEY_EQUAL; - keycodes[0x32] = KB_KEY_GRAVE_ACCENT; - keycodes[0x21] = KB_KEY_LEFT_BRACKET; - keycodes[0x1B] = KB_KEY_MINUS; - keycodes[0x2F] = KB_KEY_PERIOD; - keycodes[0x1E] = KB_KEY_RIGHT_BRACKET; - keycodes[0x29] = KB_KEY_SEMICOLON; - keycodes[0x2C] = KB_KEY_SLASH; - keycodes[0x0A] = KB_KEY_WORLD_1; + g_keycodes[0x27] = KB_KEY_APOSTROPHE; + g_keycodes[0x2A] = KB_KEY_BACKSLASH; + g_keycodes[0x2B] = KB_KEY_COMMA; + g_keycodes[0x18] = KB_KEY_EQUAL; + g_keycodes[0x32] = KB_KEY_GRAVE_ACCENT; + g_keycodes[0x21] = KB_KEY_LEFT_BRACKET; + g_keycodes[0x1B] = KB_KEY_MINUS; + g_keycodes[0x2F] = KB_KEY_PERIOD; + g_keycodes[0x1E] = KB_KEY_RIGHT_BRACKET; + g_keycodes[0x29] = KB_KEY_SEMICOLON; + g_keycodes[0x2C] = KB_KEY_SLASH; + g_keycodes[0x0A] = KB_KEY_WORLD_1; - keycodes[0x33] = KB_KEY_BACKSPACE; - keycodes[0x39] = KB_KEY_CAPS_LOCK; - keycodes[0x75] = KB_KEY_DELETE; - keycodes[0x7D] = KB_KEY_DOWN; - keycodes[0x77] = KB_KEY_END; - keycodes[0x24] = KB_KEY_ENTER; - keycodes[0x35] = KB_KEY_ESCAPE; - keycodes[0x7A] = KB_KEY_F1; - keycodes[0x78] = KB_KEY_F2; - keycodes[0x63] = KB_KEY_F3; - keycodes[0x76] = KB_KEY_F4; - keycodes[0x60] = KB_KEY_F5; - keycodes[0x61] = KB_KEY_F6; - keycodes[0x62] = KB_KEY_F7; - keycodes[0x64] = KB_KEY_F8; - keycodes[0x65] = KB_KEY_F9; - keycodes[0x6D] = KB_KEY_F10; - keycodes[0x67] = KB_KEY_F11; - keycodes[0x6F] = KB_KEY_F12; - keycodes[0x69] = KB_KEY_F13; - keycodes[0x6B] = KB_KEY_F14; - keycodes[0x71] = KB_KEY_F15; - keycodes[0x6A] = KB_KEY_F16; - keycodes[0x40] = KB_KEY_F17; - keycodes[0x4F] = KB_KEY_F18; - keycodes[0x50] = KB_KEY_F19; - keycodes[0x5A] = KB_KEY_F20; - keycodes[0x73] = KB_KEY_HOME; - keycodes[0x72] = KB_KEY_INSERT; - keycodes[0x7B] = KB_KEY_LEFT; - keycodes[0x3A] = KB_KEY_LEFT_ALT; - keycodes[0x3B] = KB_KEY_LEFT_CONTROL; - keycodes[0x38] = KB_KEY_LEFT_SHIFT; - keycodes[0x37] = KB_KEY_LEFT_SUPER; - keycodes[0x6E] = KB_KEY_MENU; - keycodes[0x47] = KB_KEY_NUM_LOCK; - keycodes[0x79] = KB_KEY_PAGE_DOWN; - keycodes[0x74] = KB_KEY_PAGE_UP; - keycodes[0x7C] = KB_KEY_RIGHT; - keycodes[0x3D] = KB_KEY_RIGHT_ALT; - keycodes[0x3E] = KB_KEY_RIGHT_CONTROL; - keycodes[0x3C] = KB_KEY_RIGHT_SHIFT; - keycodes[0x36] = KB_KEY_RIGHT_SUPER; - keycodes[0x31] = KB_KEY_SPACE; - keycodes[0x30] = KB_KEY_TAB; - keycodes[0x7E] = KB_KEY_UP; + g_keycodes[0x33] = KB_KEY_BACKSPACE; + g_keycodes[0x39] = KB_KEY_CAPS_LOCK; + g_keycodes[0x75] = KB_KEY_DELETE; + g_keycodes[0x7D] = KB_KEY_DOWN; + g_keycodes[0x77] = KB_KEY_END; + g_keycodes[0x24] = KB_KEY_ENTER; + g_keycodes[0x35] = KB_KEY_ESCAPE; + g_keycodes[0x7A] = KB_KEY_F1; + g_keycodes[0x78] = KB_KEY_F2; + g_keycodes[0x63] = KB_KEY_F3; + g_keycodes[0x76] = KB_KEY_F4; + g_keycodes[0x60] = KB_KEY_F5; + g_keycodes[0x61] = KB_KEY_F6; + g_keycodes[0x62] = KB_KEY_F7; + g_keycodes[0x64] = KB_KEY_F8; + g_keycodes[0x65] = KB_KEY_F9; + g_keycodes[0x6D] = KB_KEY_F10; + g_keycodes[0x67] = KB_KEY_F11; + g_keycodes[0x6F] = KB_KEY_F12; + g_keycodes[0x69] = KB_KEY_F13; + g_keycodes[0x6B] = KB_KEY_F14; + g_keycodes[0x71] = KB_KEY_F15; + g_keycodes[0x6A] = KB_KEY_F16; + g_keycodes[0x40] = KB_KEY_F17; + g_keycodes[0x4F] = KB_KEY_F18; + g_keycodes[0x50] = KB_KEY_F19; + g_keycodes[0x5A] = KB_KEY_F20; + g_keycodes[0x73] = KB_KEY_HOME; + g_keycodes[0x72] = KB_KEY_INSERT; + g_keycodes[0x7B] = KB_KEY_LEFT; + g_keycodes[0x3A] = KB_KEY_LEFT_ALT; + g_keycodes[0x3B] = KB_KEY_LEFT_CONTROL; + g_keycodes[0x38] = KB_KEY_LEFT_SHIFT; + g_keycodes[0x37] = KB_KEY_LEFT_SUPER; + g_keycodes[0x6E] = KB_KEY_MENU; + g_keycodes[0x47] = KB_KEY_NUM_LOCK; + g_keycodes[0x79] = KB_KEY_PAGE_DOWN; + g_keycodes[0x74] = KB_KEY_PAGE_UP; + g_keycodes[0x7C] = KB_KEY_RIGHT; + g_keycodes[0x3D] = KB_KEY_RIGHT_ALT; + g_keycodes[0x3E] = KB_KEY_RIGHT_CONTROL; + g_keycodes[0x3C] = KB_KEY_RIGHT_SHIFT; + g_keycodes[0x36] = KB_KEY_RIGHT_SUPER; + g_keycodes[0x31] = KB_KEY_SPACE; + g_keycodes[0x30] = KB_KEY_TAB; + g_keycodes[0x7E] = KB_KEY_UP; - keycodes[0x52] = KB_KEY_KP_0; - keycodes[0x53] = KB_KEY_KP_1; - keycodes[0x54] = KB_KEY_KP_2; - keycodes[0x55] = KB_KEY_KP_3; - keycodes[0x56] = KB_KEY_KP_4; - keycodes[0x57] = KB_KEY_KP_5; - keycodes[0x58] = KB_KEY_KP_6; - keycodes[0x59] = KB_KEY_KP_7; - keycodes[0x5B] = KB_KEY_KP_8; - keycodes[0x5C] = KB_KEY_KP_9; - keycodes[0x45] = KB_KEY_KP_ADD; - keycodes[0x41] = KB_KEY_KP_DECIMAL; - keycodes[0x4B] = KB_KEY_KP_DIVIDE; - keycodes[0x4C] = KB_KEY_KP_ENTER; - keycodes[0x51] = KB_KEY_KP_EQUAL; - keycodes[0x43] = KB_KEY_KP_MULTIPLY; - keycodes[0x4E] = KB_KEY_KP_SUBTRACT; + g_keycodes[0x52] = KB_KEY_KP_0; + g_keycodes[0x53] = KB_KEY_KP_1; + g_keycodes[0x54] = KB_KEY_KP_2; + g_keycodes[0x55] = KB_KEY_KP_3; + g_keycodes[0x56] = KB_KEY_KP_4; + g_keycodes[0x57] = KB_KEY_KP_5; + g_keycodes[0x58] = KB_KEY_KP_6; + g_keycodes[0x59] = KB_KEY_KP_7; + g_keycodes[0x5B] = KB_KEY_KP_8; + g_keycodes[0x5C] = KB_KEY_KP_9; + g_keycodes[0x45] = KB_KEY_KP_ADD; + g_keycodes[0x41] = KB_KEY_KP_DECIMAL; + g_keycodes[0x4B] = KB_KEY_KP_DIVIDE; + g_keycodes[0x4C] = KB_KEY_KP_ENTER; + g_keycodes[0x51] = KB_KEY_KP_EQUAL; + g_keycodes[0x43] = KB_KEY_KP_MULTIPLY; + g_keycodes[0x4E] = KB_KEY_KP_SUBTRACT; } diff --git a/src/macosx/OSXWindow.m b/src/macosx/OSXWindow.m index c618a58..17fe84f 100644 --- a/src/macosx/OSXWindow.m +++ b/src/macosx/OSXWindow.m @@ -4,8 +4,6 @@ #include #include -extern short int g_keycodes[512]; - @implementation OSXWindow /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -99,26 +97,32 @@ extern short int g_keycodes[512]; } if(mod_keys != window_data->mod_keys) { - short int keyCode = keycodes[[event keyCode] & 0x1ff]; - if(keyCode != KB_KEY_UNKNOWN) { + short int key_code = g_keycodes[[event keyCode] & 0x1ff]; + if(key_code != KB_KEY_UNKNOWN) { mod_keys_aux = mod_keys ^ window_data->mod_keys; if(mod_keys_aux & KB_MOD_CAPS_LOCK) { - kCall(keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_CAPS_LOCK) != 0); + window_data->key_status[key_code] = (mod_keys & KB_MOD_CAPS_LOCK) != 0; + kCall(keyboard_func, key_code, mod_keys, window_data->key_status[key_code]); } if(mod_keys_aux & KB_MOD_SHIFT) { - kCall(keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_SHIFT) != 0); + window_data->key_status[key_code] = (mod_keys & KB_MOD_SHIFT) != 0; + kCall(keyboard_func, key_code, mod_keys, window_data->key_status[key_code]); } if(mod_keys_aux & KB_MOD_CONTROL) { - kCall(keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_CONTROL) != 0); + window_data->key_status[key_code] = (mod_keys & KB_MOD_CONTROL) != 0; + kCall(keyboard_func, key_code, mod_keys, window_data->key_status[key_code]); } if(mod_keys_aux & KB_MOD_ALT) { - kCall(keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_ALT) != 0); + window_data->key_status[key_code] = (mod_keys & KB_MOD_ALT) != 0; + kCall(keyboard_func, key_code, mod_keys, window_data->key_status[key_code]); } if(mod_keys_aux & KB_MOD_SUPER) { - kCall(keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_SUPER) != 0); + window_data->key_status[key_code] = (mod_keys & KB_MOD_SUPER) != 0; + kCall(keyboard_func, key_code, mod_keys, window_data->key_status[key_code]); } if(mod_keys_aux & KB_MOD_NUM_LOCK) { - kCall(keyboard_func, keyCode, mod_keys, (mod_keys & KB_MOD_NUM_LOCK) != 0); + window_data->key_status[key_code] = (mod_keys & KB_MOD_NUM_LOCK) != 0; + kCall(keyboard_func, key_code, mod_keys, window_data->key_status[key_code]); } } } @@ -131,16 +135,18 @@ extern short int g_keycodes[512]; - (void)keyDown:(NSEvent *)event { - short int keyCode = keycodes[[event keyCode] & 0x1ff]; - kCall(keyboard_func, keyCode, window_data->mod_keys, true); + short int key_code = g_keycodes[[event keyCode] & 0x1ff]; + window_data->key_status[key_code] = true; + kCall(keyboard_func, key_code, window_data->mod_keys, true); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - (void)keyUp:(NSEvent *)event { - short int keyCode = keycodes[[event keyCode] & 0x1ff]; - kCall(keyboard_func, keyCode, window_data->mod_keys, false); + short int key_code = g_keycodes[[event keyCode] & 0x1ff]; + window_data->key_status[key_code] = false; + kCall(keyboard_func, key_code, window_data->mod_keys, false); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -174,9 +180,8 @@ extern short int g_keycodes[512]; { kUnused(notification); - SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific; - if(window_data_osx->active == true) { - window_data_osx->active = false; + if(window_data->is_active == true) { + window_data->is_active = false; kCall(active_func, false); } } @@ -227,12 +232,14 @@ extern short int g_keycodes[512]; - (void)windowDidBecomeKey:(NSNotification *)notification { kUnused(notification); + window_data->is_active = true; kCall(active_func, true); } - (void)windowDidResignKey:(NSNotification *)notification { kUnused(notification); + window_data->is_active = false; kCall(active_func, false); } diff --git a/src/macosx/OSXWindowFrameView.m b/src/macosx/OSXWindowFrameView.m index 78c039c..3c56d0d 100644 --- a/src/macosx/OSXWindowFrameView.m +++ b/src/macosx/OSXWindowFrameView.m @@ -262,6 +262,8 @@ extern Vertex gVertices[4]; { NSPoint point = [event locationInWindow]; //NSPoint localPoint = [self convertPoint:point fromView:nil]; + window_data->mouse_pos_x = point.x; + window_data->mouse_pos_y = point.y; kCall(mouse_move_func, point.x, point.y); } diff --git a/src/macosx/WindowData_OSX.h b/src/macosx/WindowData_OSX.h index 4948315..a3d6903 100644 --- a/src/macosx/WindowData_OSX.h +++ b/src/macosx/WindowData_OSX.h @@ -17,5 +17,4 @@ typedef struct { id pipeline_state; } metal; #endif - bool active; } SWindowData_OSX; diff --git a/src/wayland/WaylandMiniFB.c b/src/wayland/WaylandMiniFB.c index c76560e..2723bdc 100644 --- a/src/wayland/WaylandMiniFB.c +++ b/src/wayland/WaylandMiniFB.c @@ -102,6 +102,7 @@ keyboard_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct kUnused(keys); SWindowData *window_data = (SWindowData *) data; + window_data->is_active = true; kCall(active_func, true); } @@ -116,6 +117,7 @@ keyboard_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct kUnused(surface); SWindowData *window_data = (SWindowData *) data; + window_data->is_active = false; kCall(active_func, false); } @@ -134,9 +136,9 @@ keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t SWindowData *window_data = (SWindowData *) data; if(key < 512) { - Key kb_key = (Key) keycodes[key]; + Key key_code = (Key) g_keycodes[key]; bool is_pressed = (bool) (state == WL_KEYBOARD_KEY_STATE_PRESSED); - switch (kb_key) + switch (key_code) { case KB_KEY_LEFT_SHIFT: case KB_KEY_RIGHT_SHIFT: @@ -171,7 +173,8 @@ keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t break; } - kCall(keyboard_func, kb_key, (KeyMod)window_data->mod_keys, is_pressed); + window_data->key_status[key_code] = is_pressed; + kCall(keyboard_func, key_code, (KeyMod)window_data->mod_keys, is_pressed); } } @@ -284,7 +287,9 @@ pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t //printf("Pointer moved at %f %f\n", sx / 256.0f, sy / 256.0f); SWindowData *window_data = (SWindowData *) data; - kCall(mouse_move_func, sx >> 24, sy >> 24); + window_data->mouse_pos_x = sx >> 24; + window_data->mouse_pos_y = sy >> 24; + kCall(mouse_move_func, window_data->mouse_pos_x, window_data->mouse_pos_y); } // Mouse button click and release notifications. @@ -314,7 +319,7 @@ pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t //printf("Pointer button '%d'(%d)\n", button, state); SWindowData *window_data = (SWindowData *) data; - kCall(mouse_btn_func, button - BTN_MOUSE + 1, window_data->mod_keys, state == 1); + kCall(mouse_btn_func, (MouseButton) (button - BTN_MOUSE + 1), (KeyMod) window_data->mod_keys, state == 1); } // Scroll and other axis notifications. @@ -347,10 +352,10 @@ pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axi //printf("Pointer handle axis: axis: %d (0x%x)\n", axis, value); SWindowData *window_data = (SWindowData *) data; if(axis == 0) { - kCall(mouse_wheel_func, window_data->mod_keys, 0.0f, -(value / 256.0f)); + kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, 0.0f, -(value / 256.0f)); } else if(axis == 1) { - kCall(mouse_wheel_func, window_data->mod_keys, -(value / 256.0f), 0.0f); + kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, -(value / 256.0f), 0.0f); } } @@ -548,21 +553,21 @@ static const struct wl_shell_surface_listener shell_surface_listener = { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// struct Window * -mfb_open_ex(const char *title, int width, int height, int flags) { +mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) { // TODO: Not yet kUnused(flags); return mfb_open(title, width, height); } struct Window * -mfb_open(const char *title, int width, int height) +mfb_open(const char *title, unsigned width, unsigned height) { int fd = -1; - SWindowData *window_data = malloc(sizeof(SWindowData)); + SWindowData *window_data = (SWindowData *) malloc(sizeof(SWindowData)); memset(window_data, 0, sizeof(SWindowData)); - SWindowData_Way *window_data_way = malloc(sizeof(SWindowData_Way)); + SWindowData_Way *window_data_way = (SWindowData_Way *) malloc(sizeof(SWindowData_Way)); memset(window_data_way, 0, sizeof(SWindowData_Way)); window_data->specific = window_data_way; @@ -643,11 +648,11 @@ mfb_open(const char *title, int width, int height) wl_shell_surface_set_toplevel(window_data_way->shell_surface); } - wl_surface_attach(window_data_way->surface, window_data->draw_buffer, window_data->dst_offset_x, window_data->dst_offset_y); + wl_surface_attach(window_data_way->surface, (struct wl_buffer *) window_data->draw_buffer, window_data->dst_offset_x, window_data->dst_offset_y); wl_surface_damage(window_data_way->surface, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height); wl_surface_commit(window_data_way->surface); - mfb_keyboard_callback((struct Window *) window_data, keyboard_default); + mfb_set_keyboard_callback((struct Window *) window_data, keyboard_default); printf("Window created using Wayland API\n"); @@ -703,7 +708,7 @@ mfb_update(struct Window *window, void *buffer) // update shm buffer memcpy(window_data_way->shm_ptr, buffer, window_data->buffer_stride * window_data->buffer_height); - wl_surface_attach(window_data_way->surface, window_data->draw_buffer, window_data->dst_offset_x, window_data->dst_offset_y); + wl_surface_attach(window_data_way->surface, (struct wl_buffer *) window_data->draw_buffer, window_data->dst_offset_x, window_data->dst_offset_y); wl_surface_damage(window_data_way->surface, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height); struct wl_callback *frame_callback = wl_surface_frame(window_data_way->surface); if (!frame_callback) { @@ -725,132 +730,132 @@ mfb_update(struct Window *window, void *buffer) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -extern short int keycodes[512]; +extern short int g_keycodes[512]; void init_keycodes(void) { // Clear keys - for (size_t i = 0; i < sizeof(keycodes) / sizeof(keycodes[0]); ++i) - keycodes[i] = 0; + for (size_t i = 0; i < sizeof(g_keycodes) / sizeof(g_keycodes[0]); ++i) + g_keycodes[i] = 0; - keycodes[KEY_GRAVE] = KB_KEY_GRAVE_ACCENT; - keycodes[KEY_1] = KB_KEY_1; - keycodes[KEY_2] = KB_KEY_2; - keycodes[KEY_3] = KB_KEY_3; - keycodes[KEY_4] = KB_KEY_4; - keycodes[KEY_5] = KB_KEY_5; - keycodes[KEY_6] = KB_KEY_6; - keycodes[KEY_7] = KB_KEY_7; - keycodes[KEY_8] = KB_KEY_8; - keycodes[KEY_9] = KB_KEY_9; - keycodes[KEY_0] = KB_KEY_0; - keycodes[KEY_SPACE] = KB_KEY_SPACE; - keycodes[KEY_MINUS] = KB_KEY_MINUS; - keycodes[KEY_EQUAL] = KB_KEY_EQUAL; - keycodes[KEY_Q] = KB_KEY_Q; - keycodes[KEY_W] = KB_KEY_W; - keycodes[KEY_E] = KB_KEY_E; - keycodes[KEY_R] = KB_KEY_R; - keycodes[KEY_T] = KB_KEY_T; - keycodes[KEY_Y] = KB_KEY_Y; - keycodes[KEY_U] = KB_KEY_U; - keycodes[KEY_I] = KB_KEY_I; - keycodes[KEY_O] = KB_KEY_O; - keycodes[KEY_P] = KB_KEY_P; - keycodes[KEY_LEFTBRACE] = KB_KEY_LEFT_BRACKET; - keycodes[KEY_RIGHTBRACE] = KB_KEY_RIGHT_BRACKET; - keycodes[KEY_A] = KB_KEY_A; - keycodes[KEY_S] = KB_KEY_S; - keycodes[KEY_D] = KB_KEY_D; - keycodes[KEY_F] = KB_KEY_F; - keycodes[KEY_G] = KB_KEY_G; - keycodes[KEY_H] = KB_KEY_H; - keycodes[KEY_J] = KB_KEY_J; - keycodes[KEY_K] = KB_KEY_K; - keycodes[KEY_L] = KB_KEY_L; - keycodes[KEY_SEMICOLON] = KB_KEY_SEMICOLON; - keycodes[KEY_APOSTROPHE] = KB_KEY_APOSTROPHE; - keycodes[KEY_Z] = KB_KEY_Z; - keycodes[KEY_X] = KB_KEY_X; - keycodes[KEY_C] = KB_KEY_C; - keycodes[KEY_V] = KB_KEY_V; - keycodes[KEY_B] = KB_KEY_B; - keycodes[KEY_N] = KB_KEY_N; - keycodes[KEY_M] = KB_KEY_M; - keycodes[KEY_COMMA] = KB_KEY_COMMA; - keycodes[KEY_DOT] = KB_KEY_PERIOD; - keycodes[KEY_SLASH] = KB_KEY_SLASH; - keycodes[KEY_BACKSLASH] = KB_KEY_BACKSLASH; - keycodes[KEY_ESC] = KB_KEY_ESCAPE; - keycodes[KEY_TAB] = KB_KEY_TAB; - keycodes[KEY_LEFTSHIFT] = KB_KEY_LEFT_SHIFT; - keycodes[KEY_RIGHTSHIFT] = KB_KEY_RIGHT_SHIFT; - keycodes[KEY_LEFTCTRL] = KB_KEY_LEFT_CONTROL; - keycodes[KEY_RIGHTCTRL] = KB_KEY_RIGHT_CONTROL; - keycodes[KEY_LEFTALT] = KB_KEY_LEFT_ALT; - keycodes[KEY_RIGHTALT] = KB_KEY_RIGHT_ALT; - keycodes[KEY_LEFTMETA] = KB_KEY_LEFT_SUPER; - keycodes[KEY_RIGHTMETA] = KB_KEY_RIGHT_SUPER; - keycodes[KEY_MENU] = KB_KEY_MENU; - keycodes[KEY_NUMLOCK] = KB_KEY_NUM_LOCK; - keycodes[KEY_CAPSLOCK] = KB_KEY_CAPS_LOCK; - keycodes[KEY_PRINT] = KB_KEY_PRINT_SCREEN; - keycodes[KEY_SCROLLLOCK] = KB_KEY_SCROLL_LOCK; - keycodes[KEY_PAUSE] = KB_KEY_PAUSE; - keycodes[KEY_DELETE] = KB_KEY_DELETE; - keycodes[KEY_BACKSPACE] = KB_KEY_BACKSPACE; - keycodes[KEY_ENTER] = KB_KEY_ENTER; - keycodes[KEY_HOME] = KB_KEY_HOME; - keycodes[KEY_END] = KB_KEY_END; - keycodes[KEY_PAGEUP] = KB_KEY_PAGE_UP; - keycodes[KEY_PAGEDOWN] = KB_KEY_PAGE_DOWN; - keycodes[KEY_INSERT] = KB_KEY_INSERT; - keycodes[KEY_LEFT] = KB_KEY_LEFT; - keycodes[KEY_RIGHT] = KB_KEY_RIGHT; - keycodes[KEY_DOWN] = KB_KEY_DOWN; - keycodes[KEY_UP] = KB_KEY_UP; - keycodes[KEY_F1] = KB_KEY_F1; - keycodes[KEY_F2] = KB_KEY_F2; - keycodes[KEY_F3] = KB_KEY_F3; - keycodes[KEY_F4] = KB_KEY_F4; - keycodes[KEY_F5] = KB_KEY_F5; - keycodes[KEY_F6] = KB_KEY_F6; - keycodes[KEY_F7] = KB_KEY_F7; - keycodes[KEY_F8] = KB_KEY_F8; - keycodes[KEY_F9] = KB_KEY_F9; - keycodes[KEY_F10] = KB_KEY_F10; - keycodes[KEY_F11] = KB_KEY_F11; - keycodes[KEY_F12] = KB_KEY_F12; - keycodes[KEY_F13] = KB_KEY_F13; - keycodes[KEY_F14] = KB_KEY_F14; - keycodes[KEY_F15] = KB_KEY_F15; - keycodes[KEY_F16] = KB_KEY_F16; - keycodes[KEY_F17] = KB_KEY_F17; - keycodes[KEY_F18] = KB_KEY_F18; - keycodes[KEY_F19] = KB_KEY_F19; - keycodes[KEY_F20] = KB_KEY_F20; - keycodes[KEY_F21] = KB_KEY_F21; - keycodes[KEY_F22] = KB_KEY_F22; - keycodes[KEY_F23] = KB_KEY_F23; - keycodes[KEY_F24] = KB_KEY_F24; - keycodes[KEY_KPSLASH] = KB_KEY_KP_DIVIDE; - keycodes[KEY_KPDOT] = KB_KEY_KP_MULTIPLY; - keycodes[KEY_KPMINUS] = KB_KEY_KP_SUBTRACT; - keycodes[KEY_KPPLUS] = KB_KEY_KP_ADD; - keycodes[KEY_KP0] = KB_KEY_KP_0; - keycodes[KEY_KP1] = KB_KEY_KP_1; - keycodes[KEY_KP2] = KB_KEY_KP_2; - keycodes[KEY_KP3] = KB_KEY_KP_3; - keycodes[KEY_KP4] = KB_KEY_KP_4; - keycodes[KEY_KP5] = KB_KEY_KP_5; - keycodes[KEY_KP6] = KB_KEY_KP_6; - keycodes[KEY_KP7] = KB_KEY_KP_7; - keycodes[KEY_KP8] = KB_KEY_KP_8; - keycodes[KEY_KP9] = KB_KEY_KP_9; - keycodes[KEY_KPCOMMA] = KB_KEY_KP_DECIMAL; - keycodes[KEY_KPEQUAL] = KB_KEY_KP_EQUAL; - keycodes[KEY_KPENTER] = KB_KEY_KP_ENTER; + g_keycodes[KEY_GRAVE] = KB_KEY_GRAVE_ACCENT; + g_keycodes[KEY_1] = KB_KEY_1; + g_keycodes[KEY_2] = KB_KEY_2; + g_keycodes[KEY_3] = KB_KEY_3; + g_keycodes[KEY_4] = KB_KEY_4; + g_keycodes[KEY_5] = KB_KEY_5; + g_keycodes[KEY_6] = KB_KEY_6; + g_keycodes[KEY_7] = KB_KEY_7; + g_keycodes[KEY_8] = KB_KEY_8; + g_keycodes[KEY_9] = KB_KEY_9; + g_keycodes[KEY_0] = KB_KEY_0; + g_keycodes[KEY_SPACE] = KB_KEY_SPACE; + g_keycodes[KEY_MINUS] = KB_KEY_MINUS; + g_keycodes[KEY_EQUAL] = KB_KEY_EQUAL; + g_keycodes[KEY_Q] = KB_KEY_Q; + g_keycodes[KEY_W] = KB_KEY_W; + g_keycodes[KEY_E] = KB_KEY_E; + g_keycodes[KEY_R] = KB_KEY_R; + g_keycodes[KEY_T] = KB_KEY_T; + g_keycodes[KEY_Y] = KB_KEY_Y; + g_keycodes[KEY_U] = KB_KEY_U; + g_keycodes[KEY_I] = KB_KEY_I; + g_keycodes[KEY_O] = KB_KEY_O; + g_keycodes[KEY_P] = KB_KEY_P; + g_keycodes[KEY_LEFTBRACE] = KB_KEY_LEFT_BRACKET; + g_keycodes[KEY_RIGHTBRACE] = KB_KEY_RIGHT_BRACKET; + g_keycodes[KEY_A] = KB_KEY_A; + g_keycodes[KEY_S] = KB_KEY_S; + g_keycodes[KEY_D] = KB_KEY_D; + g_keycodes[KEY_F] = KB_KEY_F; + g_keycodes[KEY_G] = KB_KEY_G; + g_keycodes[KEY_H] = KB_KEY_H; + g_keycodes[KEY_J] = KB_KEY_J; + g_keycodes[KEY_K] = KB_KEY_K; + g_keycodes[KEY_L] = KB_KEY_L; + g_keycodes[KEY_SEMICOLON] = KB_KEY_SEMICOLON; + g_keycodes[KEY_APOSTROPHE] = KB_KEY_APOSTROPHE; + g_keycodes[KEY_Z] = KB_KEY_Z; + g_keycodes[KEY_X] = KB_KEY_X; + g_keycodes[KEY_C] = KB_KEY_C; + g_keycodes[KEY_V] = KB_KEY_V; + g_keycodes[KEY_B] = KB_KEY_B; + g_keycodes[KEY_N] = KB_KEY_N; + g_keycodes[KEY_M] = KB_KEY_M; + g_keycodes[KEY_COMMA] = KB_KEY_COMMA; + g_keycodes[KEY_DOT] = KB_KEY_PERIOD; + g_keycodes[KEY_SLASH] = KB_KEY_SLASH; + g_keycodes[KEY_BACKSLASH] = KB_KEY_BACKSLASH; + g_keycodes[KEY_ESC] = KB_KEY_ESCAPE; + g_keycodes[KEY_TAB] = KB_KEY_TAB; + g_keycodes[KEY_LEFTSHIFT] = KB_KEY_LEFT_SHIFT; + g_keycodes[KEY_RIGHTSHIFT] = KB_KEY_RIGHT_SHIFT; + g_keycodes[KEY_LEFTCTRL] = KB_KEY_LEFT_CONTROL; + g_keycodes[KEY_RIGHTCTRL] = KB_KEY_RIGHT_CONTROL; + g_keycodes[KEY_LEFTALT] = KB_KEY_LEFT_ALT; + g_keycodes[KEY_RIGHTALT] = KB_KEY_RIGHT_ALT; + g_keycodes[KEY_LEFTMETA] = KB_KEY_LEFT_SUPER; + g_keycodes[KEY_RIGHTMETA] = KB_KEY_RIGHT_SUPER; + g_keycodes[KEY_MENU] = KB_KEY_MENU; + g_keycodes[KEY_NUMLOCK] = KB_KEY_NUM_LOCK; + g_keycodes[KEY_CAPSLOCK] = KB_KEY_CAPS_LOCK; + g_keycodes[KEY_PRINT] = KB_KEY_PRINT_SCREEN; + g_keycodes[KEY_SCROLLLOCK] = KB_KEY_SCROLL_LOCK; + g_keycodes[KEY_PAUSE] = KB_KEY_PAUSE; + g_keycodes[KEY_DELETE] = KB_KEY_DELETE; + g_keycodes[KEY_BACKSPACE] = KB_KEY_BACKSPACE; + g_keycodes[KEY_ENTER] = KB_KEY_ENTER; + g_keycodes[KEY_HOME] = KB_KEY_HOME; + g_keycodes[KEY_END] = KB_KEY_END; + g_keycodes[KEY_PAGEUP] = KB_KEY_PAGE_UP; + g_keycodes[KEY_PAGEDOWN] = KB_KEY_PAGE_DOWN; + g_keycodes[KEY_INSERT] = KB_KEY_INSERT; + g_keycodes[KEY_LEFT] = KB_KEY_LEFT; + g_keycodes[KEY_RIGHT] = KB_KEY_RIGHT; + g_keycodes[KEY_DOWN] = KB_KEY_DOWN; + g_keycodes[KEY_UP] = KB_KEY_UP; + g_keycodes[KEY_F1] = KB_KEY_F1; + g_keycodes[KEY_F2] = KB_KEY_F2; + g_keycodes[KEY_F3] = KB_KEY_F3; + g_keycodes[KEY_F4] = KB_KEY_F4; + g_keycodes[KEY_F5] = KB_KEY_F5; + g_keycodes[KEY_F6] = KB_KEY_F6; + g_keycodes[KEY_F7] = KB_KEY_F7; + g_keycodes[KEY_F8] = KB_KEY_F8; + g_keycodes[KEY_F9] = KB_KEY_F9; + g_keycodes[KEY_F10] = KB_KEY_F10; + g_keycodes[KEY_F11] = KB_KEY_F11; + g_keycodes[KEY_F12] = KB_KEY_F12; + g_keycodes[KEY_F13] = KB_KEY_F13; + g_keycodes[KEY_F14] = KB_KEY_F14; + g_keycodes[KEY_F15] = KB_KEY_F15; + g_keycodes[KEY_F16] = KB_KEY_F16; + g_keycodes[KEY_F17] = KB_KEY_F17; + g_keycodes[KEY_F18] = KB_KEY_F18; + g_keycodes[KEY_F19] = KB_KEY_F19; + g_keycodes[KEY_F20] = KB_KEY_F20; + g_keycodes[KEY_F21] = KB_KEY_F21; + g_keycodes[KEY_F22] = KB_KEY_F22; + g_keycodes[KEY_F23] = KB_KEY_F23; + g_keycodes[KEY_F24] = KB_KEY_F24; + g_keycodes[KEY_KPSLASH] = KB_KEY_KP_DIVIDE; + g_keycodes[KEY_KPDOT] = KB_KEY_KP_MULTIPLY; + g_keycodes[KEY_KPMINUS] = KB_KEY_KP_SUBTRACT; + g_keycodes[KEY_KPPLUS] = KB_KEY_KP_ADD; + g_keycodes[KEY_KP0] = KB_KEY_KP_0; + g_keycodes[KEY_KP1] = KB_KEY_KP_1; + g_keycodes[KEY_KP2] = KB_KEY_KP_2; + g_keycodes[KEY_KP3] = KB_KEY_KP_3; + g_keycodes[KEY_KP4] = KB_KEY_KP_4; + g_keycodes[KEY_KP5] = KB_KEY_KP_5; + g_keycodes[KEY_KP6] = KB_KEY_KP_6; + g_keycodes[KEY_KP7] = KB_KEY_KP_7; + g_keycodes[KEY_KP8] = KB_KEY_KP_8; + g_keycodes[KEY_KP9] = KB_KEY_KP_9; + g_keycodes[KEY_KPCOMMA] = KB_KEY_KP_DECIMAL; + g_keycodes[KEY_KPEQUAL] = KB_KEY_KP_EQUAL; + g_keycodes[KEY_KPENTER] = KB_KEY_KP_ENTER; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/windows/WinMiniFB.c b/src/windows/WinMiniFB.c index 84ed0cb..e69702d 100644 --- a/src/windows/WinMiniFB.c +++ b/src/windows/WinMiniFB.c @@ -19,7 +19,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { LRESULT res = 0; - SWindowData *window_data = (SWindowData *) GetWindowLongPtr(hWnd, GWL_USERDATA); + SWindowData *window_data = (SWindowData *) GetWindowLongPtr(hWnd, GWLP_USERDATA); SWindowData_Win *window_data_win = 0x0; if(window_data != 0x0) { window_data_win = (SWindowData_Win *) window_data->specific; @@ -70,14 +70,15 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_SYSKEYUP: { if(window_data) { - Key kb_key = translate_key((unsigned int)wParam, (unsigned long)lParam); + Key key_code = translate_key((unsigned int)wParam, (unsigned long)lParam); int is_pressed = !((lParam >> 31) & 1); window_data->mod_keys = translate_mod(); - if (kb_key == KB_KEY_UNKNOWN) + if (key_code == KB_KEY_UNKNOWN) return FALSE; - kCall(keyboard_func, kb_key, window_data->mod_keys, is_pressed); + window_data->key_status[key_code] = is_pressed; + kCall(keyboard_func, key_code, window_data->mod_keys, is_pressed); } break; } @@ -169,7 +170,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) tme.hwndTrack = hWnd; TrackMouseEvent(&tme); } - kCall(mouse_move_func, ((int)(short)LOWORD(lParam)), ((int)(short)HIWORD(lParam))); + window_data->mouse_pos_x = (int)(short) LOWORD(lParam); + window_data->mouse_pos_y = (int)(short) HIWORD(lParam); + kCall(mouse_move_func, window_data->mouse_pos_x, window_data->mouse_pos_y); } break; @@ -194,12 +197,14 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_SETFOCUS: if(window_data) { + window_data->is_active = true; kCall(active_func, true); } break; case WM_KILLFOCUS: if(window_data) { + window_data->is_active = false; kCall(active_func, false); } break; @@ -215,7 +220,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -struct Window *mfb_open_ex(const char *title, int width, int height, int flags) { +struct Window *mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) { RECT rect = { 0 }; int x, y; @@ -241,7 +246,7 @@ struct Window *mfb_open_ex(const char *title, int width, int height, int flags) rect.bottom = GetSystemMetrics(SM_CYSCREEN); s_window_style = WS_POPUP & ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU); - DEVMODE settings; + DEVMODE settings = { 0 }; EnumDisplaySettings(0, 0, &settings); settings.dmPelsWidth = GetSystemMetrics(SM_CXSCREEN); settings.dmPelsHeight = GetSystemMetrics(SM_CYSCREEN); @@ -275,7 +280,7 @@ struct Window *mfb_open_ex(const char *title, int width, int height, int flags) rect.right += rect.left; rect.left = 0; } - if (rect.bottom > height) { + if (rect.bottom > (LONG) height) { height -= (rect.bottom - height); rect.bottom += (rect.bottom - height); rect.top = 0; @@ -342,18 +347,18 @@ struct Window *mfb_open_ex(const char *title, int width, int height, int flags) window_data_win->hdc = GetDC(window_data_win->window); - mfb_keyboard_callback((struct Window *) window_data, keyboard_default); + mfb_set_keyboard_callback((struct Window *) window_data, keyboard_default); return (struct Window *) window_data; } -struct Window *mfb_open(const char *title, int width, int height) { +struct Window *mfb_open(const char *title, unsigned width, unsigned height) { return mfb_open_ex(title, width, height, 0); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -UpdateState mfb_update(struct Window *window, void* buffer) +UpdateState mfb_update(struct Window *window, void *buffer) { MSG msg; @@ -432,135 +437,135 @@ uint32_t translate_mod() { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -extern short int keycodes[512]; +extern short int g_keycodes[512]; void init_keycodes() { // Clear keys - for (size_t i = 0; i < sizeof(keycodes) / sizeof(keycodes[0]); ++i) - keycodes[i] = 0; + for (size_t i = 0; i < sizeof(g_keycodes) / sizeof(g_keycodes[0]); ++i) + g_keycodes[i] = 0; - keycodes[0x00B] = KB_KEY_0; - keycodes[0x002] = KB_KEY_1; - keycodes[0x003] = KB_KEY_2; - keycodes[0x004] = KB_KEY_3; - keycodes[0x005] = KB_KEY_4; - keycodes[0x006] = KB_KEY_5; - keycodes[0x007] = KB_KEY_6; - keycodes[0x008] = KB_KEY_7; - keycodes[0x009] = KB_KEY_8; - keycodes[0x00A] = KB_KEY_9; - keycodes[0x01E] = KB_KEY_A; - keycodes[0x030] = KB_KEY_B; - keycodes[0x02E] = KB_KEY_C; - keycodes[0x020] = KB_KEY_D; - keycodes[0x012] = KB_KEY_E; - keycodes[0x021] = KB_KEY_F; - keycodes[0x022] = KB_KEY_G; - keycodes[0x023] = KB_KEY_H; - keycodes[0x017] = KB_KEY_I; - keycodes[0x024] = KB_KEY_J; - keycodes[0x025] = KB_KEY_K; - keycodes[0x026] = KB_KEY_L; - keycodes[0x032] = KB_KEY_M; - keycodes[0x031] = KB_KEY_N; - keycodes[0x018] = KB_KEY_O; - keycodes[0x019] = KB_KEY_P; - keycodes[0x010] = KB_KEY_Q; - keycodes[0x013] = KB_KEY_R; - keycodes[0x01F] = KB_KEY_S; - keycodes[0x014] = KB_KEY_T; - keycodes[0x016] = KB_KEY_U; - keycodes[0x02F] = KB_KEY_V; - keycodes[0x011] = KB_KEY_W; - keycodes[0x02D] = KB_KEY_X; - keycodes[0x015] = KB_KEY_Y; - keycodes[0x02C] = KB_KEY_Z; + g_keycodes[0x00B] = KB_KEY_0; + g_keycodes[0x002] = KB_KEY_1; + g_keycodes[0x003] = KB_KEY_2; + g_keycodes[0x004] = KB_KEY_3; + g_keycodes[0x005] = KB_KEY_4; + g_keycodes[0x006] = KB_KEY_5; + g_keycodes[0x007] = KB_KEY_6; + g_keycodes[0x008] = KB_KEY_7; + g_keycodes[0x009] = KB_KEY_8; + g_keycodes[0x00A] = KB_KEY_9; + g_keycodes[0x01E] = KB_KEY_A; + g_keycodes[0x030] = KB_KEY_B; + g_keycodes[0x02E] = KB_KEY_C; + g_keycodes[0x020] = KB_KEY_D; + g_keycodes[0x012] = KB_KEY_E; + g_keycodes[0x021] = KB_KEY_F; + g_keycodes[0x022] = KB_KEY_G; + g_keycodes[0x023] = KB_KEY_H; + g_keycodes[0x017] = KB_KEY_I; + g_keycodes[0x024] = KB_KEY_J; + g_keycodes[0x025] = KB_KEY_K; + g_keycodes[0x026] = KB_KEY_L; + g_keycodes[0x032] = KB_KEY_M; + g_keycodes[0x031] = KB_KEY_N; + g_keycodes[0x018] = KB_KEY_O; + g_keycodes[0x019] = KB_KEY_P; + g_keycodes[0x010] = KB_KEY_Q; + g_keycodes[0x013] = KB_KEY_R; + g_keycodes[0x01F] = KB_KEY_S; + g_keycodes[0x014] = KB_KEY_T; + g_keycodes[0x016] = KB_KEY_U; + g_keycodes[0x02F] = KB_KEY_V; + g_keycodes[0x011] = KB_KEY_W; + g_keycodes[0x02D] = KB_KEY_X; + g_keycodes[0x015] = KB_KEY_Y; + g_keycodes[0x02C] = KB_KEY_Z; - keycodes[0x028] = KB_KEY_APOSTROPHE; - keycodes[0x02B] = KB_KEY_BACKSLASH; - keycodes[0x033] = KB_KEY_COMMA; - keycodes[0x00D] = KB_KEY_EQUAL; - keycodes[0x029] = KB_KEY_GRAVE_ACCENT; - keycodes[0x01A] = KB_KEY_LEFT_BRACKET; - keycodes[0x00C] = KB_KEY_MINUS; - keycodes[0x034] = KB_KEY_PERIOD; - keycodes[0x01B] = KB_KEY_RIGHT_BRACKET; - keycodes[0x027] = KB_KEY_SEMICOLON; - keycodes[0x035] = KB_KEY_SLASH; - keycodes[0x056] = KB_KEY_WORLD_2; + g_keycodes[0x028] = KB_KEY_APOSTROPHE; + g_keycodes[0x02B] = KB_KEY_BACKSLASH; + g_keycodes[0x033] = KB_KEY_COMMA; + g_keycodes[0x00D] = KB_KEY_EQUAL; + g_keycodes[0x029] = KB_KEY_GRAVE_ACCENT; + g_keycodes[0x01A] = KB_KEY_LEFT_BRACKET; + g_keycodes[0x00C] = KB_KEY_MINUS; + g_keycodes[0x034] = KB_KEY_PERIOD; + g_keycodes[0x01B] = KB_KEY_RIGHT_BRACKET; + g_keycodes[0x027] = KB_KEY_SEMICOLON; + g_keycodes[0x035] = KB_KEY_SLASH; + g_keycodes[0x056] = KB_KEY_WORLD_2; - keycodes[0x00E] = KB_KEY_BACKSPACE; - keycodes[0x153] = KB_KEY_DELETE; - keycodes[0x14F] = KB_KEY_END; - keycodes[0x01C] = KB_KEY_ENTER; - keycodes[0x001] = KB_KEY_ESCAPE; - keycodes[0x147] = KB_KEY_HOME; - keycodes[0x152] = KB_KEY_INSERT; - keycodes[0x15D] = KB_KEY_MENU; - keycodes[0x151] = KB_KEY_PAGE_DOWN; - keycodes[0x149] = KB_KEY_PAGE_UP; - keycodes[0x045] = KB_KEY_PAUSE; - keycodes[0x146] = KB_KEY_PAUSE; - keycodes[0x039] = KB_KEY_SPACE; - keycodes[0x00F] = KB_KEY_TAB; - keycodes[0x03A] = KB_KEY_CAPS_LOCK; - keycodes[0x145] = KB_KEY_NUM_LOCK; - keycodes[0x046] = KB_KEY_SCROLL_LOCK; - keycodes[0x03B] = KB_KEY_F1; - keycodes[0x03C] = KB_KEY_F2; - keycodes[0x03D] = KB_KEY_F3; - keycodes[0x03E] = KB_KEY_F4; - keycodes[0x03F] = KB_KEY_F5; - keycodes[0x040] = KB_KEY_F6; - keycodes[0x041] = KB_KEY_F7; - keycodes[0x042] = KB_KEY_F8; - keycodes[0x043] = KB_KEY_F9; - keycodes[0x044] = KB_KEY_F10; - keycodes[0x057] = KB_KEY_F11; - keycodes[0x058] = KB_KEY_F12; - keycodes[0x064] = KB_KEY_F13; - keycodes[0x065] = KB_KEY_F14; - keycodes[0x066] = KB_KEY_F15; - keycodes[0x067] = KB_KEY_F16; - keycodes[0x068] = KB_KEY_F17; - keycodes[0x069] = KB_KEY_F18; - keycodes[0x06A] = KB_KEY_F19; - keycodes[0x06B] = KB_KEY_F20; - keycodes[0x06C] = KB_KEY_F21; - keycodes[0x06D] = KB_KEY_F22; - keycodes[0x06E] = KB_KEY_F23; - keycodes[0x076] = KB_KEY_F24; - keycodes[0x038] = KB_KEY_LEFT_ALT; - keycodes[0x01D] = KB_KEY_LEFT_CONTROL; - keycodes[0x02A] = KB_KEY_LEFT_SHIFT; - keycodes[0x15B] = KB_KEY_LEFT_SUPER; - keycodes[0x137] = KB_KEY_PRINT_SCREEN; - keycodes[0x138] = KB_KEY_RIGHT_ALT; - keycodes[0x11D] = KB_KEY_RIGHT_CONTROL; - keycodes[0x036] = KB_KEY_RIGHT_SHIFT; - keycodes[0x15C] = KB_KEY_RIGHT_SUPER; - keycodes[0x150] = KB_KEY_DOWN; - keycodes[0x14B] = KB_KEY_LEFT; - keycodes[0x14D] = KB_KEY_RIGHT; - keycodes[0x148] = KB_KEY_UP; + g_keycodes[0x00E] = KB_KEY_BACKSPACE; + g_keycodes[0x153] = KB_KEY_DELETE; + g_keycodes[0x14F] = KB_KEY_END; + g_keycodes[0x01C] = KB_KEY_ENTER; + g_keycodes[0x001] = KB_KEY_ESCAPE; + g_keycodes[0x147] = KB_KEY_HOME; + g_keycodes[0x152] = KB_KEY_INSERT; + g_keycodes[0x15D] = KB_KEY_MENU; + g_keycodes[0x151] = KB_KEY_PAGE_DOWN; + g_keycodes[0x149] = KB_KEY_PAGE_UP; + g_keycodes[0x045] = KB_KEY_PAUSE; + g_keycodes[0x146] = KB_KEY_PAUSE; + g_keycodes[0x039] = KB_KEY_SPACE; + g_keycodes[0x00F] = KB_KEY_TAB; + g_keycodes[0x03A] = KB_KEY_CAPS_LOCK; + g_keycodes[0x145] = KB_KEY_NUM_LOCK; + g_keycodes[0x046] = KB_KEY_SCROLL_LOCK; + g_keycodes[0x03B] = KB_KEY_F1; + g_keycodes[0x03C] = KB_KEY_F2; + g_keycodes[0x03D] = KB_KEY_F3; + g_keycodes[0x03E] = KB_KEY_F4; + g_keycodes[0x03F] = KB_KEY_F5; + g_keycodes[0x040] = KB_KEY_F6; + g_keycodes[0x041] = KB_KEY_F7; + g_keycodes[0x042] = KB_KEY_F8; + g_keycodes[0x043] = KB_KEY_F9; + g_keycodes[0x044] = KB_KEY_F10; + g_keycodes[0x057] = KB_KEY_F11; + g_keycodes[0x058] = KB_KEY_F12; + g_keycodes[0x064] = KB_KEY_F13; + g_keycodes[0x065] = KB_KEY_F14; + g_keycodes[0x066] = KB_KEY_F15; + g_keycodes[0x067] = KB_KEY_F16; + g_keycodes[0x068] = KB_KEY_F17; + g_keycodes[0x069] = KB_KEY_F18; + g_keycodes[0x06A] = KB_KEY_F19; + g_keycodes[0x06B] = KB_KEY_F20; + g_keycodes[0x06C] = KB_KEY_F21; + g_keycodes[0x06D] = KB_KEY_F22; + g_keycodes[0x06E] = KB_KEY_F23; + g_keycodes[0x076] = KB_KEY_F24; + g_keycodes[0x038] = KB_KEY_LEFT_ALT; + g_keycodes[0x01D] = KB_KEY_LEFT_CONTROL; + g_keycodes[0x02A] = KB_KEY_LEFT_SHIFT; + g_keycodes[0x15B] = KB_KEY_LEFT_SUPER; + g_keycodes[0x137] = KB_KEY_PRINT_SCREEN; + g_keycodes[0x138] = KB_KEY_RIGHT_ALT; + g_keycodes[0x11D] = KB_KEY_RIGHT_CONTROL; + g_keycodes[0x036] = KB_KEY_RIGHT_SHIFT; + g_keycodes[0x15C] = KB_KEY_RIGHT_SUPER; + g_keycodes[0x150] = KB_KEY_DOWN; + g_keycodes[0x14B] = KB_KEY_LEFT; + g_keycodes[0x14D] = KB_KEY_RIGHT; + g_keycodes[0x148] = KB_KEY_UP; - keycodes[0x052] = KB_KEY_KP_0; - keycodes[0x04F] = KB_KEY_KP_1; - keycodes[0x050] = KB_KEY_KP_2; - keycodes[0x051] = KB_KEY_KP_3; - keycodes[0x04B] = KB_KEY_KP_4; - keycodes[0x04C] = KB_KEY_KP_5; - keycodes[0x04D] = KB_KEY_KP_6; - keycodes[0x047] = KB_KEY_KP_7; - keycodes[0x048] = KB_KEY_KP_8; - keycodes[0x049] = KB_KEY_KP_9; - keycodes[0x04E] = KB_KEY_KP_ADD; - keycodes[0x053] = KB_KEY_KP_DECIMAL; - keycodes[0x135] = KB_KEY_KP_DIVIDE; - keycodes[0x11C] = KB_KEY_KP_ENTER; - keycodes[0x037] = KB_KEY_KP_MULTIPLY; - keycodes[0x04A] = KB_KEY_KP_SUBTRACT; + g_keycodes[0x052] = KB_KEY_KP_0; + g_keycodes[0x04F] = KB_KEY_KP_1; + g_keycodes[0x050] = KB_KEY_KP_2; + g_keycodes[0x051] = KB_KEY_KP_3; + g_keycodes[0x04B] = KB_KEY_KP_4; + g_keycodes[0x04C] = KB_KEY_KP_5; + g_keycodes[0x04D] = KB_KEY_KP_6; + g_keycodes[0x047] = KB_KEY_KP_7; + g_keycodes[0x048] = KB_KEY_KP_8; + g_keycodes[0x049] = KB_KEY_KP_9; + g_keycodes[0x04E] = KB_KEY_KP_ADD; + g_keycodes[0x053] = KB_KEY_KP_DECIMAL; + g_keycodes[0x135] = KB_KEY_KP_DIVIDE; + g_keycodes[0x11C] = KB_KEY_KP_ENTER; + g_keycodes[0x037] = KB_KEY_KP_MULTIPLY; + g_keycodes[0x04A] = KB_KEY_KP_SUBTRACT; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -585,7 +590,7 @@ Key translate_key(unsigned int wParam, unsigned long lParam) { if (wParam == VK_PROCESSKEY) return KB_KEY_UNKNOWN; - return (Key) keycodes[HIWORD(lParam) & 0x1FF]; + return (Key) g_keycodes[HIWORD(lParam) & 0x1FF]; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/x11/X11MiniFB.c b/src/x11/X11MiniFB.c index 26e7f61..442faa5 100644 --- a/src/x11/X11MiniFB.c +++ b/src/x11/X11MiniFB.c @@ -21,7 +21,7 @@ stretch_image(uint32_t *srcImage, uint32_t srcX, uint32_t srcY, uint32_t srcWidt /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// struct Window * -mfb_open_ex(const char *title, int width, int height, int flags) { +mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) { int depth, i, formatCount, convDepth = -1; XPixmapFormatValues* formats; XSetWindowAttributes windowAttributes; @@ -175,7 +175,7 @@ mfb_open_ex(const char *title, int width, int height, int flags) { window_data_x11->image = XCreateImage(window_data_x11->display, CopyFromParent, depth, ZPixmap, 0, 0x0, width, height, 32, width * 4); - mfb_keyboard_callback((struct Window *) window_data, keyboard_default); + mfb_set_keyboard_callback((struct Window *) window_data, keyboard_default); printf("Window created using X11 API\n"); @@ -183,9 +183,9 @@ mfb_open_ex(const char *title, int width, int height, int flags) { } struct Window * -mfb_open(const char *title, int width, int height) +mfb_open(const char *title, unsigned width, unsigned height) { - return mfb_open_ex(title, width, height, 0); + return mfb_open_ex(title, width, height, 0); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -196,101 +196,106 @@ int translate_mod_ex(int key, int state, int is_pressed); static void processEvents(SWindowData *window_data) { - XEvent event; + XEvent event; SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; - while ((window_data->close == false) && XPending(window_data_x11->display)) { - XNextEvent(window_data_x11->display, &event); + while ((window_data->close == false) && XPending(window_data_x11->display)) { + XNextEvent(window_data_x11->display, &event); - switch (event.type) { - case KeyPress: - case KeyRelease: - { - Key kb_key = (Key) translate_key(event.xkey.keycode); - int is_pressed = (event.type == KeyPress); - window_data->mod_keys = translate_mod_ex(kb_key, event.xkey.state, is_pressed); + switch (event.type) { + case KeyPress: + case KeyRelease: + { + Key key_code = (Key) translate_key(event.xkey.keycode); + int is_pressed = (event.type == KeyPress); + window_data->mod_keys = translate_mod_ex(key_code, event.xkey.state, is_pressed); - kCall(keyboard_func, kb_key, (KeyMod) window_data->mod_keys, is_pressed); - } - break; + window_data->key_status[key_code] = is_pressed; + kCall(keyboard_func, key_code, (KeyMod) window_data->mod_keys, is_pressed); + } + break; - case ButtonPress: - case ButtonRelease: - { - MouseButton button = (MouseButton) event.xbutton.button; - int is_pressed = (event.type == ButtonPress); - window_data->mod_keys = translate_mod(event.xkey.state); - switch (button) { - case Button1: - case Button2: - case Button3: - kCall(mouse_btn_func, button, (KeyMod) window_data->mod_keys, is_pressed); - break; + case ButtonPress: + case ButtonRelease: + { + MouseButton button = (MouseButton) event.xbutton.button; + int is_pressed = (event.type == ButtonPress); + window_data->mod_keys = translate_mod(event.xkey.state); + switch (button) { + case Button1: + case Button2: + case Button3: + kCall(mouse_btn_func, button, (KeyMod) window_data->mod_keys, is_pressed); + break; - case Button4: - kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, 0.0f, 1.0f); - break; - case Button5: - kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, 0.0f, -1.0f); - break; + case Button4: + kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, 0.0f, 1.0f); + break; + case Button5: + kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, 0.0f, -1.0f); + break; - case 6: - kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, 1.0f, 0.0f); - break; - case 7: - kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, -1.0f, 0.0f); - break; + case 6: + kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, 1.0f, 0.0f); + break; + case 7: + kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, -1.0f, 0.0f); + break; - default: - kCall(mouse_btn_func, (MouseButton) (button - 4), (KeyMod) window_data->mod_keys, is_pressed); - break; - } - } - break; + default: + kCall(mouse_btn_func, (MouseButton) (button - 4), (KeyMod) window_data->mod_keys, is_pressed); + break; + } + } + break; - case MotionNotify: - kCall(mouse_move_func, event.xmotion.x, event.xmotion.y); - break; + case MotionNotify: + window_data->mouse_pos_x = event.xmotion.x; + window_data->mouse_pos_y = event.xmotion.y; + kCall(mouse_move_func, event.xmotion.x, event.xmotion.y); + break; - case ConfigureNotify: - { - window_data->window_width = event.xconfigure.width; - window_data->window_height = event.xconfigure.height; - window_data->dst_offset_x = 0; - window_data->dst_offset_y = 0; - window_data->dst_width = window_data->window_width; - window_data->dst_height = window_data->window_height; + case ConfigureNotify: + { + window_data->window_width = event.xconfigure.width; + window_data->window_height = event.xconfigure.height; + window_data->dst_offset_x = 0; + window_data->dst_offset_y = 0; + window_data->dst_width = window_data->window_width; + window_data->dst_height = window_data->window_height; - XClearWindow(window_data_x11->display, window_data_x11->window); - kCall(resize_func, window_data->window_width, window_data->window_height); - } - break; + XClearWindow(window_data_x11->display, window_data_x11->window); + kCall(resize_func, window_data->window_width, window_data->window_height); + } + break; - case EnterNotify: - case LeaveNotify: - break; + case EnterNotify: + case LeaveNotify: + break; - case FocusIn: - kCall(active_func, true); - break; + case FocusIn: + window_data->is_active = true; + kCall(active_func, true); + break; - case FocusOut: - kCall(active_func, false); - break; + case FocusOut: + window_data->is_active = false; + kCall(active_func, false); + break; - case DestroyNotify: - window_data->close = true; + case DestroyNotify: + window_data->close = true; return; - break; - } - } + break; + } + } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void destroy(SWindowData *window_data); -UpdateState mfb_update(struct Window *window, void* buffer) +UpdateState mfb_update(struct Window *window, void *buffer) { if(window == 0x0) { return STATE_INVALID_WINDOW; @@ -329,16 +334,16 @@ UpdateState mfb_update(struct Window *window, void* buffer) if(window_data_x11->image_scaler != 0x0) { stretch_image((uint32_t *) buffer, 0, 0, window_data->buffer_width, window_data->buffer_height, window_data->buffer_width, (uint32_t *) window_data_x11->image_buffer, 0, 0, window_data->dst_width, window_data->dst_height, window_data->dst_width); window_data_x11->image_scaler->data = (char *) window_data_x11->image_buffer; - XPutImage(window_data_x11->display, window_data_x11->window, window_data_x11->gc, window_data_x11->image_scaler, 0, 0, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height); + XPutImage(window_data_x11->display, window_data_x11->window, window_data_x11->gc, window_data_x11->image_scaler, 0, 0, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height); } else { - window_data_x11->image->data = (char *) buffer; - XPutImage(window_data_x11->display, window_data_x11->window, window_data_x11->gc, window_data_x11->image, 0, 0, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height); + window_data_x11->image->data = (char *) buffer; + XPutImage(window_data_x11->display, window_data_x11->window, window_data_x11->gc, window_data_x11->image, 0, 0, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height); } - XFlush(window_data_x11->display); - processEvents(window_data); + XFlush(window_data_x11->display); + processEvents(window_data); - return STATE_OK; + return STATE_OK; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -364,7 +369,7 @@ void destroy(SWindowData *window_data) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -extern short int keycodes[512]; +extern short int g_keycodes[512]; static int translateKeyCodeB(int keySym) { @@ -534,17 +539,17 @@ void init_keycodes(SWindowData_X11 *window_data_x11) { int keySym; // Clear keys - for (i = 0; i < sizeof(keycodes) / sizeof(keycodes[0]); ++i) - keycodes[i] = KB_KEY_UNKNOWN; + for (i = 0; i < sizeof(g_keycodes) / sizeof(g_keycodes[0]); ++i) + g_keycodes[i] = KB_KEY_UNKNOWN; // Valid key code range is [8,255], according to the Xlib manual for(int i=8; i<=255; ++i) { // Try secondary keysym, for numeric keypad keys keySym = XkbKeycodeToKeysym(window_data_x11->display, i, 0, 1); - keycodes[i] = translateKeyCodeB(keySym); - if(keycodes[i] == KB_KEY_UNKNOWN) { + g_keycodes[i] = translateKeyCodeB(keySym); + if(g_keycodes[i] == KB_KEY_UNKNOWN) { keySym = XkbKeycodeToKeysym(window_data_x11->display, i, 0, 0); - keycodes[i] = translateKeyCodeA(keySym); + g_keycodes[i] = translateKeyCodeA(keySym); } } } @@ -555,7 +560,7 @@ int translate_key(int scancode) { if (scancode < 0 || scancode > 255) return KB_KEY_UNKNOWN; - return keycodes[scancode]; + return g_keycodes[scancode]; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/tests/input_events.c b/tests/input_events.c index ec028d2..08b9531 100644 --- a/tests/input_events.c +++ b/tests/input_events.c @@ -94,13 +94,13 @@ int main() if (!window) return 0; - mfb_active_callback(window, active); - mfb_resize_callback(window, resize); - mfb_keyboard_callback(window, keyboard); - mfb_char_input_callback(window, char_input); - mfb_mouse_button_callback(window, mouse_btn); - mfb_mouse_move_callback(window, mouse_move); - mfb_mouse_scroll_callback(window, mouse_scroll); + mfb_set_active_callback(window, active); + mfb_set_resize_callback(window, resize); + mfb_set_keyboard_callback(window, keyboard); + mfb_set_char_input_callback(window, char_input); + mfb_set_mouse_button_callback(window, mouse_btn); + mfb_set_mouse_move_callback(window, mouse_move); + mfb_set_mouse_scroll_callback(window, mouse_scroll); mfb_set_user_data(window, (void *) "Input Events Test"); diff --git a/tests/input_events_cpp.cpp b/tests/input_events_cpp.cpp index 2af5532..4429cda 100644 --- a/tests/input_events_cpp.cpp +++ b/tests/input_events_cpp.cpp @@ -99,13 +99,13 @@ int main() Events e; - mfb_active_callback(window, &e, &Events::active); - mfb_resize_callback(window, &e, &Events::resize); - mfb_keyboard_callback(window, &e, &Events::keyboard); - mfb_char_input_callback(window, &e, &Events::char_input); - mfb_mouse_button_callback(window, &e, &Events::mouse_btn); - mfb_mouse_move_callback(window, &e, &Events::mouse_move); - mfb_mouse_scroll_callback(window, &e, &Events::mouse_scroll); + mfb_set_active_callback(window, &e, &Events::active); + mfb_set_resize_callback(window, &e, &Events::resize); + mfb_set_keyboard_callback(window, &e, &Events::keyboard); + mfb_set_char_input_callback(window, &e, &Events::char_input); + mfb_set_mouse_button_callback(window, &e, &Events::mouse_btn); + mfb_set_mouse_move_callback(window, &e, &Events::mouse_move); + mfb_set_mouse_scroll_callback(window, &e, &Events::mouse_scroll); mfb_set_user_data(window, (void *) "Input Events CPP Test"); diff --git a/tests/multiple_windows.c b/tests/multiple_windows.c index 4b301c0..f8a3499 100644 --- a/tests/multiple_windows.c +++ b/tests/multiple_windows.c @@ -1,8 +1,10 @@ #include #include #include +#define _USE_MATH_DEFINES #include +#define kPI 3.14159265358979323846f #define kUnused(var) (void) var; #define WIDTH_A 800 @@ -88,13 +90,13 @@ int main() if (!window_a) return 0; - mfb_active_callback(window_a, active); - mfb_resize_callback(window_a, resize); - mfb_keyboard_callback(window_a, keyboard); - mfb_char_input_callback(window_a, char_input); - mfb_mouse_button_callback(window_a, mouse_btn); - mfb_mouse_move_callback(window_a, mouse_move); - mfb_mouse_scroll_callback(window_a, mouse_scroll); + mfb_set_active_callback(window_a, active); + mfb_set_resize_callback(window_a, resize); + mfb_set_keyboard_callback(window_a, keyboard); + mfb_set_char_input_callback(window_a, char_input); + mfb_set_mouse_button_callback(window_a, mouse_btn); + mfb_set_mouse_move_callback(window_a, mouse_move); + mfb_set_mouse_scroll_callback(window_a, mouse_scroll); mfb_set_user_data(window_a, (void *) "Window A"); @@ -103,13 +105,13 @@ int main() if (!window_b) return 0; - mfb_active_callback(window_b, active); - mfb_resize_callback(window_b, resize); - mfb_keyboard_callback(window_b, keyboard); - mfb_char_input_callback(window_b, char_input); - mfb_mouse_button_callback(window_b, mouse_btn); - mfb_mouse_move_callback(window_b, mouse_move); - mfb_mouse_scroll_callback(window_b, mouse_scroll); + mfb_set_active_callback(window_b, active); + mfb_set_resize_callback(window_b, resize); + mfb_set_keyboard_callback(window_b, keyboard); + mfb_set_char_input_callback(window_b, char_input); + mfb_set_mouse_button_callback(window_b, mouse_btn); + mfb_set_mouse_move_callback(window_b, mouse_move); + mfb_set_mouse_scroll_callback(window_b, mouse_scroll); mfb_set_user_data(window_b, (void *) "Window B"); @@ -117,7 +119,7 @@ int main() uint32_t pallete[512]; float inc = 90.0f / 64.0f; for(uint32_t c=0; c<64; ++c) { - int32_t col = (255.0f * sinf(c * inc * M_PI / 180.0f)) + 0.5f; + int32_t col = (int32_t) ((255.0f * sinf(c * inc * kPI / 180.0f)) + 0.5f); pallete[64*0 + c] = MFB_RGB(col, 0, 0); pallete[64*1 + c] = MFB_RGB(255, col, 0); pallete[64*2 + c] = MFB_RGB(255-col, 255, 0); @@ -151,13 +153,13 @@ int main() } //-- - time_x = sinf(time * M_PI / 180.0f); - time_y = cosf(time * M_PI / 180.0f); + time_x = sinf(time * kPI / 180.0f); + time_y = cosf(time * kPI / 180.0f); i = 0; for(y=0; y Date: Sat, 14 Dec 2019 11:20:59 +0100 Subject: [PATCH 07/14] mfb_update_events (#27) * update documentation * Fix typo * Added some examples * changed window names * Minor fix * Added mfb_update_events to all platforms. Checked on Windows, X11 and Wayland --- CMakeLists.txt | 2 +- include/MiniFB.h | 9 +++- src/macosx/MacMiniFB.m | 23 +++++++++ src/wayland/WaylandMiniFB.c | 29 +++++++++++- src/windows/WinMiniFB.c | 93 +++++++++++++++++++++++-------------- src/x11/X11MiniFB.c | 74 +++++++++++++++++------------ tests/input_events.c | 34 ++++++++------ 7 files changed, 181 insertions(+), 83 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 06ba472..7087aab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ file(GLOB SrcWayland "src/wayland/*.c") file(GLOB SrcX11 "src/x11/*.c") if (NOT MSVC) - set (CMAKE_C_FLAGS "-g -Wall -Wextra -pedantic -Wno-switch -Wno-unused-function") + set (CMAKE_C_FLAGS "-g -Wall -Wextra -pedantic -Wno-switch -Wno-unused-function -Wno-implicit-fallthrough") set (CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11") set (CMAKE_OBJC_FLAGS "${CMAKE_C_FLAGS}") set (CMAKE_OBJCXX_FLAGS "${CMAKE_CXX_FLAGS}") diff --git a/include/MiniFB.h b/include/MiniFB.h index 6c4ea1d..7139a7b 100644 --- a/include/MiniFB.h +++ b/include/MiniFB.h @@ -17,10 +17,15 @@ extern "C" { struct Window * mfb_open(const char *title, unsigned width, unsigned height); struct Window * mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags); -// Update the display. Input buffer is assumed to be a 32-bit buffer of the size given in the open call -// Will return a negative status if something went wrong or the user want to exit. +// Update the display +// Input buffer is assumed to be a 32-bit buffer of the size given in the open call +// Will return a negative status if something went wrong or the user want to exit +// Also updates the window events UpdateState mfb_update(struct Window *window, void *buffer); +// Only updates the window events +UpdateState mfb_update_events(struct Window *window); + // Close the window void mfb_close(struct Window *window); diff --git a/src/macosx/MacMiniFB.m b/src/macosx/MacMiniFB.m index 23ef909..3f3c334 100644 --- a/src/macosx/MacMiniFB.m +++ b/src/macosx/MacMiniFB.m @@ -345,6 +345,29 @@ UpdateState mfb_update(struct Window *window, void *buffer) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +UpdateState mfb_update_events(struct Window *window) +{ + if(window == 0x0) { + return STATE_INVALID_WINDOW; + } + + SWindowData *window_data = (SWindowData *) window; + if(window_data->close) { + destroy_window_data(window_data); + return STATE_EXIT; + } + + update_events(window_data); + if(window_data->close == false) { + SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific; + [[window_data_osx->window contentView] setNeedsDisplay:YES]; + } + + return STATE_OK; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { SWindowData *window_data = (SWindowData *) window; diff --git a/src/wayland/WaylandMiniFB.c b/src/wayland/WaylandMiniFB.c index 2723bdc..fe8e758 100644 --- a/src/wayland/WaylandMiniFB.c +++ b/src/wayland/WaylandMiniFB.c @@ -718,8 +718,7 @@ mfb_update(struct Window *window, void *buffer) wl_surface_commit(window_data_way->surface); while (!done && window_data->close == false) { - if (wl_display_dispatch(window_data_way->display) == -1 || wl_display_roundtrip(window_data_way->display) == -1) - { + if (wl_display_dispatch(window_data_way->display) == -1 || wl_display_roundtrip(window_data_way->display) == -1) { wl_callback_destroy(frame_callback); return STATE_INTERNAL_ERROR; } @@ -730,6 +729,32 @@ mfb_update(struct Window *window, void *buffer) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +UpdateState +mfb_update_events(struct Window *window) +{ + if(window == 0x0) { + return STATE_INVALID_WINDOW; + } + + SWindowData *window_data = (SWindowData *) window; + if(window_data->close) { + destroy(window_data); + return STATE_EXIT; + } + + SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific; + if (!window_data_way->display || wl_display_get_error(window_data_way->display) != 0) + return STATE_INTERNAL_ERROR; + + if (wl_display_dispatch(window_data_way->display) == -1 || wl_display_roundtrip(window_data_way->display) == -1) { + return STATE_INTERNAL_ERROR; + } + + return STATE_OK; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + extern short int g_keycodes[512]; void diff --git a/src/windows/WinMiniFB.c b/src/windows/WinMiniFB.c index e69702d..e725f3f 100644 --- a/src/windows/WinMiniFB.c +++ b/src/windows/WinMiniFB.c @@ -15,13 +15,12 @@ uint32_t translate_mod(); Key translate_key(unsigned int wParam, unsigned long lParam); void destroy_window_data(SWindowData *window_data); -LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { LRESULT res = 0; SWindowData *window_data = (SWindowData *) GetWindowLongPtr(hWnd, GWLP_USERDATA); SWindowData_Win *window_data_win = 0x0; - if(window_data != 0x0) { + if (window_data != 0x0) { window_data_win = (SWindowData_Win *) window_data->specific; } @@ -31,18 +30,18 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { if (window_data && window_data->draw_buffer && window_data_win) { - //if(window_data->dst_offset_x > 0) { + //if (window_data->dst_offset_x > 0) { // BitBlt(window_data_win->hdc, 0, window_data->dst_offset_y, window_data->dst_offset_x, window_data->dst_height, 0, 0, 0, BLACKNESS); //} - //if(window_data->dst_offset_y > 0) { + //if (window_data->dst_offset_y > 0) { // BitBlt(window_data_win->hdc, 0, 0, window_data->window_width, window_data->dst_offset_y, 0, 0, 0, BLACKNESS); //} //uint32_t offsetY = window_data->dst_offset_y + window_data->dst_height; - //if(offsetY < window_data->window_height) { + //if (offsetY < window_data->window_height) { // BitBlt(window_data_win->hdc, 0, offsetY, window_data->window_width, window_data->window_height - offsetY, 0, 0, 0, BLACKNESS); //} //uint32_t offsetX = window_data->dst_offset_x + window_data->dst_width; - //if(offsetX < window_data->window_width) { + //if (offsetX < window_data->window_width) { // BitBlt(window_data_win->hdc, offsetX, window_data->dst_offset_y, window_data->window_width - offsetX, window_data->dst_height, 0, 0, 0, BLACKNESS); //} @@ -58,7 +57,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_DESTROY: case WM_CLOSE: { - if(window_data) { + if (window_data) { window_data->close = true; } break; @@ -69,7 +68,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_KEYUP: case WM_SYSKEYUP: { - if(window_data) { + if (window_data) { Key key_code = translate_key((unsigned int)wParam, (unsigned long)lParam); int is_pressed = !((lParam >> 31) & 1); window_data->mod_keys = translate_mod(); @@ -88,14 +87,14 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_UNICHAR: { - if(window_data) { - if(message == WM_UNICHAR && wParam == UNICODE_NOCHAR) { + if (window_data) { + if (message == WM_UNICHAR && wParam == UNICODE_NOCHAR) { // WM_UNICHAR is not sent by Windows, but is sent by some third-party input method engine // Returning TRUE here announces support for this message return TRUE; } - kCall(char_input_func, wParam); + kCall(char_input_func, (unsigned int) wParam); } break; } @@ -113,7 +112,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: { - if(window_data) { + if (window_data) { MouseButton button = MOUSE_BTN_0; window_data->mod_keys = translate_mod(); int is_pressed = 0; @@ -136,7 +135,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) default: button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? MOUSE_BTN_5 : MOUSE_BTN_6); - if(message == WM_XBUTTONDOWN) { + if (message == WM_XBUTTONDOWN) { is_pressed = 1; } } @@ -146,7 +145,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } case WM_MOUSEWHEEL: - if(window_data) { + if (window_data) { kCall(mouse_wheel_func, translate_mod(), 0.0f, (SHORT)HIWORD(wParam) / (float)WHEEL_DELTA); } break; @@ -154,14 +153,14 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_MOUSEHWHEEL: // This message is only sent on Windows Vista and later // NOTE: The X-axis is inverted for consistency with macOS and X11 - if(window_data) { + if (window_data) { kCall(mouse_wheel_func, translate_mod(), -((SHORT)HIWORD(wParam) / (float)WHEEL_DELTA), 0.0f); } break; case WM_MOUSEMOVE: - if(window_data) { - if(window_data_win->mouse_inside == false) { + if (window_data) { + if (window_data_win->mouse_inside == false) { window_data_win->mouse_inside = true; TRACKMOUSEEVENT tme; ZeroMemory(&tme, sizeof(tme)); @@ -177,13 +176,13 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_MOUSELEAVE: - if(window_data) { + if (window_data) { window_data_win->mouse_inside = false; } break; case WM_SIZE: - if(window_data) { + if (window_data) { window_data->dst_offset_x = 0; window_data->dst_offset_y = 0; window_data->dst_width = LOWORD(lParam); @@ -196,14 +195,14 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_SETFOCUS: - if(window_data) { + if (window_data) { window_data->is_active = true; kCall(active_func, true); } break; case WM_KILLFOCUS: - if(window_data) { + if (window_data) { window_data->is_active = false; kCall(active_func, false); } @@ -358,21 +357,20 @@ struct Window *mfb_open(const char *title, unsigned width, unsigned height) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -UpdateState mfb_update(struct Window *window, void *buffer) -{ +UpdateState mfb_update(struct Window *window, void *buffer) { MSG msg; - if(window == 0x0) { + if (window == 0x0) { return STATE_INVALID_WINDOW; } SWindowData *window_data = (SWindowData *)window; - if(window_data->close) { + if (window_data->close) { destroy_window_data(window_data); return STATE_EXIT; } - if(buffer == 0x0) { + if (buffer == 0x0) { return STATE_INVALID_BUFFER; } @@ -382,8 +380,31 @@ UpdateState mfb_update(struct Window *window, void *buffer) InvalidateRect(window_data_win->window, 0x0, TRUE); SendMessage(window_data_win->window, WM_PAINT, 0, 0); - while (window_data->close == false && PeekMessage(&msg, window_data_win->window, 0, 0, PM_REMOVE)) - { + while (window_data->close == false && PeekMessage(&msg, window_data_win->window, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return STATE_OK; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +UpdateState mfb_update_events(struct Window *window) { + MSG msg; + + if (window == 0x0) { + return STATE_INVALID_WINDOW; + } + + SWindowData *window_data = (SWindowData *)window; + if (window_data->close) { + destroy_window_data(window_data); + return STATE_EXIT; + } + + SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific; + while (window_data->close == false && PeekMessage(&msg, window_data_win->window, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } @@ -394,16 +415,17 @@ UpdateState mfb_update(struct Window *window, void *buffer) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void destroy_window_data(SWindowData *window_data) { - if(window_data == 0x0) + if (window_data == 0x0) return; SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific; window_data->draw_buffer = 0x0; - if(window_data_win->bitmapInfo != 0x0) { + if (window_data_win->bitmapInfo != 0x0) { free(window_data_win->bitmapInfo); } - if(window_data_win->window != 0 && window_data_win->hdc != 0) { + + if (window_data_win->window != 0 && window_data_win->hdc != 0) { ReleaseDC(window_data_win->window, window_data_win->hdc); DestroyWindow(window_data_win->window); } @@ -595,14 +617,13 @@ Key translate_key(unsigned int wParam, unsigned long lParam) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) -{ +bool mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { SWindowData *window_data = (SWindowData *) window; - if(offset_x + width > window_data->window_width) { + if (offset_x + width > window_data->window_width) { return false; } - if(offset_y + height > window_data->window_height) { + if (offset_y + height > window_data->window_height) { return false; } diff --git a/src/x11/X11MiniFB.c b/src/x11/X11MiniFB.c index 442faa5..42d966e 100644 --- a/src/x11/X11MiniFB.c +++ b/src/x11/X11MiniFB.c @@ -157,7 +157,7 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) sizeHints.y = 0; sizeHints.min_width = width; sizeHints.min_height = height; - if(flags & WF_RESIZABLE) { + if (flags & WF_RESIZABLE) { sizeHints.max_width = screenWidth; sizeHints.max_height = screenHeight; } @@ -183,8 +183,7 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) } struct Window * -mfb_open(const char *title, unsigned width, unsigned height) -{ +mfb_open(const char *title, unsigned width, unsigned height) { return mfb_open_ex(title, width, height, 0); } @@ -194,8 +193,7 @@ int translate_key(int scancode); int translate_mod(int state); int translate_mod_ex(int key, int state, int is_pressed); -static void processEvents(SWindowData *window_data) -{ +static void processEvents(SWindowData *window_data) { XEvent event; SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; @@ -295,31 +293,30 @@ static void processEvents(SWindowData *window_data) void destroy(SWindowData *window_data); -UpdateState mfb_update(struct Window *window, void *buffer) -{ - if(window == 0x0) { +UpdateState mfb_update(struct Window *window, void *buffer) { + if (window == 0x0) { return STATE_INVALID_WINDOW; } SWindowData *window_data = (SWindowData *) window; - if(window_data->close) { + if (window_data->close) { destroy(window_data); return STATE_EXIT; } - if(buffer == 0x0) { + if (buffer == 0x0) { return STATE_INVALID_BUFFER; } SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; if (window_data->buffer_width != window_data->dst_width || window_data->buffer_height != window_data->dst_height) { - if(window_data_x11->image_scaler_width != window_data->dst_width || window_data_x11->image_scaler_height != window_data->dst_height) { - if(window_data_x11->image_scaler != 0x0) { + if (window_data_x11->image_scaler_width != window_data->dst_width || window_data_x11->image_scaler_height != window_data->dst_height) { + if (window_data_x11->image_scaler != 0x0) { window_data_x11->image_scaler->data = 0x0; XDestroyImage(window_data_x11->image_scaler); } - if(window_data_x11->image_buffer != 0x0) { + if (window_data_x11->image_buffer != 0x0) { free(window_data_x11->image_buffer); window_data_x11->image_buffer = 0x0; } @@ -331,7 +328,7 @@ UpdateState mfb_update(struct Window *window, void *buffer) } } - if(window_data_x11->image_scaler != 0x0) { + if (window_data_x11->image_scaler != 0x0) { stretch_image((uint32_t *) buffer, 0, 0, window_data->buffer_width, window_data->buffer_height, window_data->buffer_width, (uint32_t *) window_data_x11->image_buffer, 0, 0, window_data->dst_width, window_data->dst_height, window_data->dst_width); window_data_x11->image_scaler->data = (char *) window_data_x11->image_buffer; XPutImage(window_data_x11->display, window_data_x11->window, window_data_x11->gc, window_data_x11->image_scaler, 0, 0, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height); @@ -348,12 +345,31 @@ UpdateState mfb_update(struct Window *window, void *buffer) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void destroy(SWindowData *window_data) -{ - if(window_data != 0x0) { - if(window_data->specific != 0x0) { +UpdateState mfb_update_events(struct Window *window) { + if (window == 0x0) { + return STATE_INVALID_WINDOW; + } + + SWindowData *window_data = (SWindowData *) window; + if (window_data->close) { + destroy(window_data); + return STATE_EXIT; + } + + SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; + XFlush(window_data_x11->display); + processEvents(window_data); + + return STATE_OK; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void destroy(SWindowData *window_data) { + if (window_data != 0x0) { + if (window_data->specific != 0x0) { SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; - if(window_data_x11->image != 0x0) { + if (window_data_x11->image != 0x0) { window_data_x11->image->data = 0x0; XDestroyImage(window_data_x11->image); XDestroyWindow(window_data_x11->display, window_data_x11->window); @@ -543,11 +559,11 @@ void init_keycodes(SWindowData_X11 *window_data_x11) { g_keycodes[i] = KB_KEY_UNKNOWN; // Valid key code range is [8,255], according to the Xlib manual - for(int i=8; i<=255; ++i) { + for (int i=8; i<=255; ++i) { // Try secondary keysym, for numeric keypad keys keySym = XkbKeycodeToKeysym(window_data_x11->display, i, 0, 1); g_keycodes[i] = translateKeyCodeB(keySym); - if(g_keycodes[i] == KB_KEY_UNKNOWN) { + if (g_keycodes[i] == KB_KEY_UNKNOWN) { keySym = XkbKeycodeToKeysym(window_data_x11->display, i, 0, 0); g_keycodes[i] = translateKeyCodeA(keySym); } @@ -595,7 +611,7 @@ int translate_mod_ex(int key, int state, int is_pressed) { { case KB_KEY_LEFT_SHIFT: case KB_KEY_RIGHT_SHIFT: - if(is_pressed) + if (is_pressed) mod_keys |= KB_MOD_SHIFT; else mod_keys &= ~KB_MOD_SHIFT; @@ -603,7 +619,7 @@ int translate_mod_ex(int key, int state, int is_pressed) { case KB_KEY_LEFT_CONTROL: case KB_KEY_RIGHT_CONTROL: - if(is_pressed) + if (is_pressed) mod_keys |= KB_MOD_CONTROL; else mod_keys &= ~KB_MOD_CONTROL; @@ -611,7 +627,7 @@ int translate_mod_ex(int key, int state, int is_pressed) { case KB_KEY_LEFT_ALT: case KB_KEY_RIGHT_ALT: - if(is_pressed) + if (is_pressed) mod_keys |= KB_MOD_ALT; else mod_keys &= ~KB_MOD_ALT; @@ -619,7 +635,7 @@ int translate_mod_ex(int key, int state, int is_pressed) { case KB_KEY_LEFT_SUPER: case KB_KEY_RIGHT_SUPER: - if(is_pressed) + if (is_pressed) mod_keys |= KB_MOD_SUPER; else mod_keys &= ~KB_MOD_SUPER; @@ -631,14 +647,13 @@ int translate_mod_ex(int key, int state, int is_pressed) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) -{ +bool mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { SWindowData *window_data = (SWindowData *) window; - if(offset_x + width > window_data->window_width) { + if (offset_x + width > window_data->window_width) { return false; } - if(offset_y + height > window_data->window_height) { + if (offset_y + height > window_data->window_height) { return false; } @@ -646,5 +661,6 @@ bool mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_ window_data->dst_offset_y = offset_y; window_data->dst_width = width; window_data->dst_height = height; + return true; } diff --git a/tests/input_events.c b/tests/input_events.c index 08b9531..b99fa2f 100644 --- a/tests/input_events.c +++ b/tests/input_events.c @@ -2,11 +2,12 @@ #include #include -#define kUnused(var) (void) var; +#define kUnused(var) (void) var #define WIDTH 800 #define HEIGHT 600 static unsigned int g_buffer[WIDTH * HEIGHT]; +static bool g_active = true; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -16,6 +17,7 @@ void active(struct Window *window, bool isActive) { window_title = (const char *) mfb_get_user_data(window); } fprintf(stdout, "%s > active: %d\n", window_title, isActive); + g_active = isActive; } void resize(struct Window *window, int width, int height) { @@ -109,20 +111,26 @@ int main() int i; UpdateState state; - for (i = 0; i < WIDTH * HEIGHT; ++i) + if(g_active) { - noise = seed; - noise >>= 3; - noise ^= seed; - carry = noise & 1; - noise >>= 1; - seed >>= 1; - seed |= (carry << 30); - noise &= 0xFF; - g_buffer[i] = MFB_RGB(noise, noise, noise); - } + for (i = 0; i < WIDTH * HEIGHT; ++i) + { + noise = seed; + noise >>= 3; + noise ^= seed; + carry = noise & 1; + noise >>= 1; + seed >>= 1; + seed |= (carry << 30); + noise &= 0xFF; + g_buffer[i] = MFB_RGB(noise, noise, noise); + } - state = mfb_update(window, g_buffer); + state = mfb_update(window, g_buffer); + } + else { + state = mfb_update_events(window); + } if (state != STATE_OK) { window = 0x0; break; From f10bcfeabf7f3a65f08715a7b1b213a9eb5d7ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Aragon=C3=A9s?= <9335325+Darky-Lucera@users.noreply.github.com> Date: Sat, 4 Jan 2020 18:21:45 +0100 Subject: [PATCH 08/14] Simplify cmake (#28) * update documentation * Fix typo * Added some examples * changed window names * Minor fix * Added mfb_update_events to all platforms. Checked on Windows, X11 and Wayland * simplify CMake * Upgrade to CMake 3.5, simplify script and generalize it Now the users only have to add_directory and link_libraries(minifb) in CMake --- CMakeLists.txt | 163 +++++++++++++++++++++++++++++++------------------ 1 file changed, 104 insertions(+), 59 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7087aab..2ee43e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,114 +1,159 @@ -cmake_minimum_required(VERSION 2.8.11) -project (noise) +cmake_minimum_required(VERSION 3.5) -include_directories(include src) +set(PROJECT_NAME MiniFB) +project(${PROJECT_NAME}) -file(GLOB SrcLib "src/*.c" - "src/*.cpp" - "src/*.h" - "include/*.h") -file(GLOB SrcWindows "src/windows/*.c" - "src/windows/*.h") -file(GLOB SrcMacOSX "src/macosx/*.c" - "src/macosx/*.cpp" - "src/macosx/*.m" - "src/macosx/*.mm" - "src/macosx/*.h") -file(GLOB SrcWayland "src/wayland/*.c") -file(GLOB SrcX11 "src/x11/*.c") +message("Processing " ${PROJECT_NAME}) +set(SrcLib + include/MiniFB.h + include/MiniFB_cpp.h + include/MiniFB_enums.h + + src/MiniFB_common.c + src/MiniFB_cpp.cpp + src/MiniFB_internal.c + src/MiniFB_internal.h + src/WindowData.h +) + +set(SrcWindows + src/windows/WinMiniFB.c + src/windows/WindowData_Win.h +) + +set(SrcMacOSX + src/macosx/MacMiniFB.m + src/macosx/OSXWindow.h + src/macosx/OSXWindow.m + src/macosx/OSXWindowFrameView.h + src/macosx/OSXWindowFrameView.m + src/macosx/WindowData_OSX.h +) + +set(SrcWayland + src/wayland/WaylandMiniFB.c + src/wayland/WindowData_Way.h +) + +set(SrcX11 + src/x11/X11MiniFB.c + src/x11/WindowData_X11.h +) + +# Avoid RelWithDebInfo and MinSizeRel +#-------------------------------------- +set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE) + +# Define Release by default +#-------------------------------------- +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release") + message(STATUS "Build type not specified: Use Release by default") +endif(NOT CMAKE_BUILD_TYPE) + +# Set GCC/Clang flags +#-------------------------------------- if (NOT MSVC) - set (CMAKE_C_FLAGS "-g -Wall -Wextra -pedantic -Wno-switch -Wno-unused-function -Wno-implicit-fallthrough") + # Avoid default flag values + #-------------------------------------- + set(CMAKE_C_FLAGS "" CACHE STRING "" FORCE) + set(CMAKE_C_FLAGS_DEBUG "" CACHE STRING "" FORCE) + set(CMAKE_C_FLAGS_RELEASE "" CACHE STRING "" FORCE) + + set(CMAKE_CXX_FLAGS "" CACHE STRING "" FORCE) + set(CMAKE_CXX_FLAGS_DEBUG "" CACHE STRING "" FORCE) + set(CMAKE_CXX_FLAGS_RELEASE "" CACHE STRING "" FORCE) + + set(CMAKE_OBJC_FLAGS "" CACHE STRING "" FORCE) + set(CMAKE_OBJC_FLAGS_DEBUG "" CACHE STRING "" FORCE) + set(CMAKE_OBJC_FLAGS_RELEASE "" CACHE STRING "" FORCE) + + set(CMAKE_OBJCXX_FLAGS "" CACHE STRING "" FORCE) + set(CMAKE_OBJCXX_FLAGS_DEBUG "" CACHE STRING "" FORCE) + set(CMAKE_OBJCXX_FLAGS_RELEASE "" CACHE STRING "" FORCE) + + # Set our flags + #-------------------------------------- + add_compile_options("$<$:-g>") + add_compile_options("$,-O0,-O2>") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -pedantic -Wno-switch -Wno-unused-function -Wno-implicit-fallthrough") set (CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11") set (CMAKE_OBJC_FLAGS "${CMAKE_C_FLAGS}") set (CMAKE_OBJCXX_FLAGS "${CMAKE_CXX_FLAGS}") endif() +# Set default cmake flags +#-------------------------------------- if (APPLE) OPTION(USE_METAL_API "Build the project using metal API code" ON) elseif (UNIX) OPTION(USE_WAYLAND_API "Build the project using wayland API code" OFF) endif() +# Set compiler/platform specific flags and dependencies +#-------------------------------------- if (MSVC) add_definitions(-D_CRT_SECURE_NO_WARNINGS) add_definitions(-D_WIN32_WINNT=0x0600) + list (APPEND SrcLib ${SrcWindows}) elseif (MINGW) add_definitions(-D_WIN32_WINNT=0x0600) + list(APPEND SrcLib ${SrcWindows}) elseif (APPLE) if(USE_METAL_API) add_definitions(-DUSE_METAL_API) endif() + + link_libraries("-framework Cocoa") + link_libraries("-framework QuartzCore") + link_libraries("-framework Metal") + link_libraries("-framework MetalKit") + list(APPEND SrcLib ${SrcMacOSX}) elseif (UNIX) if(USE_WAYLAND_API) + link_libraries("-lwayland-client") + link_libraries("-lwayland-cursor") + list(APPEND SrcLib ${SrcWayland}) else() + link_libraries("-lX11") + list(APPEND SrcLib ${SrcX11}) endif() endif() +# Library +#-------------------------------------- add_library(minifb STATIC ${SrcLib} ) +# For all projects +#-------------------------------------- +target_include_directories(minifb PUBLIC include) +target_include_directories(minifb PRIVATE src) +link_libraries(minifb) + +# Examples +#-------------------------------------- add_executable(noise tests/noise.c ) -target_link_libraries(noise minifb) add_executable(input_events tests/input_events.c ) -target_link_libraries(input_events minifb) add_executable(input_events_cpp tests/input_events_cpp.cpp ) -target_link_libraries(input_events_cpp minifb) add_executable(multiple_windows tests/multiple_windows.c ) -target_link_libraries(multiple_windows minifb) -if (MSVC) -elseif (MINGW) -elseif (APPLE) - target_link_libraries(noise "-framework Cocoa") - target_link_libraries(noise "-framework QuartzCore") - target_link_libraries(noise "-framework Metal") - target_link_libraries(noise "-framework MetalKit") - - target_link_libraries(input_events "-framework Cocoa") - target_link_libraries(input_events "-framework QuartzCore") - target_link_libraries(input_events "-framework Metal") - target_link_libraries(input_events "-framework MetalKit") - target_link_libraries(input_events_cpp "-framework Cocoa") - target_link_libraries(input_events_cpp "-framework QuartzCore") - target_link_libraries(input_events_cpp "-framework Metal") - target_link_libraries(input_events_cpp "-framework MetalKit") - - target_link_libraries(multiple_windows "-framework Cocoa") - target_link_libraries(multiple_windows "-framework QuartzCore") - target_link_libraries(multiple_windows "-framework Metal") - target_link_libraries(multiple_windows "-framework MetalKit") -elseif (UNIX) - if(USE_WAYLAND_API) - target_link_libraries(noise -lwayland-client -lwayland-cursor) - - target_link_libraries(input_events -lwayland-client -lwayland-cursor) - target_link_libraries(input_events_cpp -lwayland-client -lwayland-cursor) - - target_link_libraries(multiple_windows -lwayland-client -lwayland-cursor) - else() - target_link_libraries(noise -lX11) - - target_link_libraries(input_events -lX11) - target_link_libraries(input_events_cpp -lX11) - - target_link_libraries(multiple_windows -lX11) - endif() -endif() +message("Done " ${PROJECT_NAME}) From 219e7d0c20ea162f74e123bba5a856809a9d6ac8 Mon Sep 17 00:00:00 2001 From: Shotaro Uchida Date: Tue, 25 Feb 2020 22:57:25 -0800 Subject: [PATCH 09/14] Fix shader warning for macOS Catalina (#30) In Catalina, shader creation will fail because of the following issue: ``` Compilation succeeded with: program_source:22:21: warning: writable resources in non-void vertex function vertex VertexOutput vertFunc2(unsigned int vID[[vertex_id]], device Vertex *pos [[buffer(0)]]) ^ program_source:22:77: note: writable buffer defined here vertex VertexOutput vertFunc2(unsigned int vID[[vertex_id]], device Vertex *pos [[buffer(0)]]) ^ ``` Adding const to ensure the buffer is read-only. --- src/macosx/MacMiniFB.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/macosx/MacMiniFB.m b/src/macosx/MacMiniFB.m index 3f3c334..933f095 100644 --- a/src/macosx/MacMiniFB.m +++ b/src/macosx/MacMiniFB.m @@ -55,7 +55,7 @@ NSString* g_shadersSrc = @ "float4 position [[position]];\n" "};\n" - "vertex VertexOutput vertFunc2(unsigned int vID[[vertex_id]], device Vertex *pos [[buffer(0)]])\n" + "vertex VertexOutput vertFunc2(unsigned int vID[[vertex_id]], const device Vertex *pos [[buffer(0)]])\n" "{\n" "VertexOutput out;\n" From 4286f055c6e11517c9f2f739b71bc7bff0ecd2f8 Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Thu, 5 Mar 2020 18:51:57 +0100 Subject: [PATCH 10/14] Fix issue #32 (#33) * update documentation * Fix typo * Added some examples * changed window names * Minor fix * Added mfb_update_events to all platforms. Checked on Windows, X11 and Wayland * simplify CMake * Upgrade to CMake 3.5, simplify script and generalize it Now the users only have to add_directory and link_libraries(minifb) in CMake * Renamed typo scrool by scroll Added some checks Removed some warnings * fix issue 32 --- include/MiniFB.h | 12 ++++++------ src/MiniFB_common.c | 4 ++-- src/wayland/WaylandMiniFB.c | 12 +++++++++++- src/windows/WinMiniFB.c | 32 +++++++++++++++++++++++--------- src/x11/X11MiniFB.c | 21 +++++++++++++++++---- 5 files changed, 59 insertions(+), 22 deletions(-) diff --git a/include/MiniFB.h b/include/MiniFB.h index 7139a7b..99d7b08 100644 --- a/include/MiniFB.h +++ b/include/MiniFB.h @@ -49,12 +49,12 @@ const char * mfb_get_key_name(Key key); bool mfb_is_window_active(struct Window *window); unsigned mfb_get_window_width(struct Window *window); unsigned mfb_get_window_height(struct Window *window); -int mfb_get_mouse_x(struct Window *window); // Last mouse pos X -int mfb_get_mouse_y(struct Window *window); // Last mouse pos Y -float mfb_get_mouse_scrool_x(struct Window *window); // Mouse wheel X as a sum. When you call this function it resets. -float mfb_get_mouse_scrool_y(struct Window *window); // Mouse wheel Y as a sum. When you call this function it resets. -const uint8_t * mfb_get_mouse_button_buffer(struct Window *window); // One byte for every button. Press (1), Release 0. -const uint8_t * mfb_get_key_buffer(struct Window *window); // One byte for every key. Press (1), Release 0. +int mfb_get_mouse_x(struct Window *window); // Last mouse pos X +int mfb_get_mouse_y(struct Window *window); // Last mouse pos Y +float mfb_get_mouse_scroll_x(struct Window *window); // Mouse wheel X as a sum. When you call this function it resets. +float mfb_get_mouse_scroll_y(struct Window *window); // Mouse wheel Y as a sum. When you call this function it resets. +const uint8_t * mfb_get_mouse_button_buffer(struct Window *window); // One byte for every button. Press (1), Release 0. (up to 8 buttons) +const uint8_t * mfb_get_key_buffer(struct Window *window); // One byte for every key. Press (1), Release 0. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/MiniFB_common.c b/src/MiniFB_common.c index 997babe..16adb2d 100755 --- a/src/MiniFB_common.c +++ b/src/MiniFB_common.c @@ -144,7 +144,7 @@ int mfb_get_mouse_y(struct Window *window) { } //------------------------------------- -float mfb_get_mouse_scrool_x(struct Window *window) { +float mfb_get_mouse_scroll_x(struct Window *window) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; return window_data->mouse_wheel_x; @@ -153,7 +153,7 @@ float mfb_get_mouse_scrool_x(struct Window *window) { } //------------------------------------- -float mfb_get_mouse_scrool_y(struct Window *window) { +float mfb_get_mouse_scroll_y(struct Window *window) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; return window_data->mouse_wheel_y; diff --git a/src/wayland/WaylandMiniFB.c b/src/wayland/WaylandMiniFB.c index fe8e758..de15923 100644 --- a/src/wayland/WaylandMiniFB.c +++ b/src/wayland/WaylandMiniFB.c @@ -565,17 +565,27 @@ mfb_open(const char *title, unsigned width, unsigned height) int fd = -1; SWindowData *window_data = (SWindowData *) malloc(sizeof(SWindowData)); + if(window_data == 0x0) { + return 0x0; + } memset(window_data, 0, sizeof(SWindowData)); SWindowData_Way *window_data_way = (SWindowData_Way *) malloc(sizeof(SWindowData_Way)); + if(window_data_way == 0x0) { + free(window_data); + return 0x0; + } memset(window_data_way, 0, sizeof(SWindowData_Way)); window_data->specific = window_data_way; window_data_way->shm_format = -1u; window_data_way->display = wl_display_connect(0x0); - if (!window_data_way->display) + if (!window_data_way->display) { + free(window_data); + free(window_data_way); return 0x0; + } window_data_way->registry = wl_display_get_registry(window_data_way->display); wl_registry_add_listener(window_data_way->registry, ®istry_listener, window_data); diff --git a/src/windows/WinMiniFB.c b/src/windows/WinMiniFB.c index e725f3f..6f2964d 100644 --- a/src/windows/WinMiniFB.c +++ b/src/windows/WinMiniFB.c @@ -69,14 +69,14 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_SYSKEYUP: { if (window_data) { - Key key_code = translate_key((unsigned int)wParam, (unsigned long)lParam); - int is_pressed = !((lParam >> 31) & 1); + Key key_code = translate_key((unsigned int)wParam, (unsigned long)lParam); + int is_pressed = !((lParam >> 31) & 1); window_data->mod_keys = translate_mod(); if (key_code == KB_KEY_UNKNOWN) return FALSE; - window_data->key_status[key_code] = is_pressed; + window_data->key_status[key_code] = (uint8_t) is_pressed; kCall(keyboard_func, key_code, window_data->mod_keys, is_pressed); } break; @@ -221,14 +221,21 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) struct Window *mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) { RECT rect = { 0 }; - int x, y; + int x = 0, y = 0; init_keycodes(); SWindowData *window_data = malloc(sizeof(SWindowData)); + if (window_data == 0x0) { + return 0x0; + } memset(window_data, 0, sizeof(SWindowData)); SWindowData_Win *window_data_win = malloc(sizeof(SWindowData_Win)); + if(window_data_win == 0x0) { + free(window_data); + return 0x0; + } memset(window_data_win, 0, sizeof(SWindowData_Win)); window_data->specific = window_data_win; @@ -239,8 +246,6 @@ struct Window *mfb_open_ex(const char *title, unsigned width, unsigned height, u s_window_style = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME; if (flags & WF_FULLSCREEN) { flags = WF_FULLSCREEN; // Remove all other flags - x = 0; - y = 0; rect.right = GetSystemMetrics(SM_CXSCREEN); rect.bottom = GetSystemMetrics(SM_CYSCREEN); s_window_style = WS_POPUP & ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU); @@ -284,8 +289,6 @@ struct Window *mfb_open_ex(const char *title, unsigned width, unsigned height, u rect.bottom += (rect.bottom - height); rect.top = 0; } - x = 0; - y = 0; } else if (!(flags & WF_FULLSCREEN)) { rect.right = width; @@ -323,8 +326,11 @@ struct Window *mfb_open_ex(const char *title, unsigned width, unsigned height, u window_data->window_width, window_data->window_height, 0, 0, 0, 0); - if (!window_data_win->window) + if (!window_data_win->window) { + free(window_data); + free(window_data_win); return 0x0; + } SetWindowLongPtr(window_data_win->window, GWLP_USERDATA, (LONG_PTR) window_data); @@ -334,6 +340,11 @@ struct Window *mfb_open_ex(const char *title, unsigned width, unsigned height, u ShowWindow(window_data_win->window, SW_NORMAL); window_data_win->bitmapInfo = (BITMAPINFO *) calloc(1, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 3); + if(window_data_win->bitmapInfo == 0x0) { + free(window_data); + free(window_data_win); + return 0x0; + } window_data_win->bitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); window_data_win->bitmapInfo->bmiHeader.biPlanes = 1; window_data_win->bitmapInfo->bmiHeader.biBitCount = 32; @@ -405,6 +416,9 @@ UpdateState mfb_update_events(struct Window *window) { SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific; while (window_data->close == false && PeekMessage(&msg, window_data_win->window, 0, 0, PM_REMOVE)) { + if(msg.message == WM_PAINT) + return; + TranslateMessage(&msg); DispatchMessage(&msg); } diff --git a/src/x11/X11MiniFB.c b/src/x11/X11MiniFB.c index 42d966e..1463d7e 100644 --- a/src/x11/X11MiniFB.c +++ b/src/x11/X11MiniFB.c @@ -29,15 +29,25 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) Visual* visual; SWindowData *window_data = (SWindowData *) malloc(sizeof(SWindowData)); + if (!window_data) { + return 0x0; + } memset(window_data, 0, sizeof(SWindowData)); SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) malloc(sizeof(SWindowData_X11)); + if (!window_data_x11) { + free(window_data); + return 0x0; + } memset(window_data_x11, 0, sizeof(SWindowData_X11)); window_data->specific = window_data_x11; window_data_x11->display = XOpenDisplay(0); - if (!window_data_x11->display) + if (!window_data_x11->display) { + free(window_data); + free(window_data_x11); return 0x0; + } init_keycodes(window_data_x11); @@ -322,6 +332,9 @@ UpdateState mfb_update(struct Window *window, void *buffer) { } int depth = DefaultDepth(window_data_x11->display, window_data_x11->screen); window_data_x11->image_buffer = malloc(window_data->dst_width * window_data->dst_height * 4); + if(window_data_x11->image_buffer == 0x0) { + return STATE_INTERNAL_ERROR; + } window_data_x11->image_scaler_width = window_data->dst_width; window_data_x11->image_scaler_height = window_data->dst_height; window_data_x11->image_scaler = XCreateImage(window_data_x11->display, CopyFromParent, depth, ZPixmap, 0, 0x0, window_data_x11->image_scaler_width, window_data_x11->image_scaler_height, 32, window_data_x11->image_scaler_width * 4); @@ -551,15 +564,15 @@ static int translateKeyCodeA(int keySym) { } void init_keycodes(SWindowData_X11 *window_data_x11) { - size_t i; - int keySym; + size_t i; + int keySym; // Clear keys for (i = 0; i < sizeof(g_keycodes) / sizeof(g_keycodes[0]); ++i) g_keycodes[i] = KB_KEY_UNKNOWN; // Valid key code range is [8,255], according to the Xlib manual - for (int i=8; i<=255; ++i) { + for (i=8; i<=255; ++i) { // Try secondary keysym, for numeric keypad keys keySym = XkbKeycodeToKeysym(window_data_x11->display, i, 0, 1); g_keycodes[i] = translateKeyCodeB(keySym); From 6b30baa7e460d6320bd4f97642dcca5b81610db1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Aragon=C3=A9s?= <9335325+Darky-Lucera@users.noreply.github.com> Date: Fri, 6 Mar 2020 07:06:54 +0100 Subject: [PATCH 11/14] Type prefixes (#34) * update documentation * Fix typo * Added some examples * changed window names * Minor fix * Added mfb_update_events to all platforms. Checked on Windows, X11 and Wayland * simplify CMake * Upgrade to CMake 3.5, simplify script and generalize it Now the users only have to add_directory and link_libraries(minifb) in CMake * Renamed typo scrool by scroll Added some checks Removed some warnings * working Windows, X11 and Wayland * fix issue 32 Co-authored-by: Carlos Aragones <> Co-authored-by: caragones --- CMakeLists.txt | 318 ++++++++++++++--------------- README.md | 305 +++++++++++++++------------- include/MiniFB.h | 50 ++--- include/MiniFB_cpp.h | 108 +++++----- include/MiniFB_enums.h | 26 +-- src/MiniFB_common.c | 65 +++--- src/MiniFB_cpp.cpp | 53 +++-- src/MiniFB_internal.c | 8 +- src/MiniFB_internal.h | 4 +- src/macosx/MacMiniFB.m | 31 +-- src/wayland/WaylandMiniFB.c | 46 +++-- src/windows/WinMiniFB.c | 46 +++-- src/x11/WindowData_X11.h | 40 ++-- src/x11/X11MiniFB.c | 60 +++--- tests/input_events.c | 290 ++++++++++++++------------- tests/input_events_cpp.cpp | 277 +++++++++++++------------- tests/multiple_windows.c | 385 ++++++++++++++++++------------------ tests/noise.c | 91 ++++----- 18 files changed, 1157 insertions(+), 1046 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ee43e2..ed7d20d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,159 +1,159 @@ -cmake_minimum_required(VERSION 3.5) - -set(PROJECT_NAME MiniFB) -project(${PROJECT_NAME}) - -message("Processing " ${PROJECT_NAME}) - -set(SrcLib - include/MiniFB.h - include/MiniFB_cpp.h - include/MiniFB_enums.h - - src/MiniFB_common.c - src/MiniFB_cpp.cpp - src/MiniFB_internal.c - src/MiniFB_internal.h - src/WindowData.h -) - -set(SrcWindows - src/windows/WinMiniFB.c - src/windows/WindowData_Win.h -) - -set(SrcMacOSX - src/macosx/MacMiniFB.m - src/macosx/OSXWindow.h - src/macosx/OSXWindow.m - src/macosx/OSXWindowFrameView.h - src/macosx/OSXWindowFrameView.m - src/macosx/WindowData_OSX.h -) - -set(SrcWayland - src/wayland/WaylandMiniFB.c - src/wayland/WindowData_Way.h -) - -set(SrcX11 - src/x11/X11MiniFB.c - src/x11/WindowData_X11.h -) - -# Avoid RelWithDebInfo and MinSizeRel -#-------------------------------------- -set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE) - -# Define Release by default -#-------------------------------------- -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "Release") - message(STATUS "Build type not specified: Use Release by default") -endif(NOT CMAKE_BUILD_TYPE) - -# Set GCC/Clang flags -#-------------------------------------- -if (NOT MSVC) - # Avoid default flag values - #-------------------------------------- - set(CMAKE_C_FLAGS "" CACHE STRING "" FORCE) - set(CMAKE_C_FLAGS_DEBUG "" CACHE STRING "" FORCE) - set(CMAKE_C_FLAGS_RELEASE "" CACHE STRING "" FORCE) - - set(CMAKE_CXX_FLAGS "" CACHE STRING "" FORCE) - set(CMAKE_CXX_FLAGS_DEBUG "" CACHE STRING "" FORCE) - set(CMAKE_CXX_FLAGS_RELEASE "" CACHE STRING "" FORCE) - - set(CMAKE_OBJC_FLAGS "" CACHE STRING "" FORCE) - set(CMAKE_OBJC_FLAGS_DEBUG "" CACHE STRING "" FORCE) - set(CMAKE_OBJC_FLAGS_RELEASE "" CACHE STRING "" FORCE) - - set(CMAKE_OBJCXX_FLAGS "" CACHE STRING "" FORCE) - set(CMAKE_OBJCXX_FLAGS_DEBUG "" CACHE STRING "" FORCE) - set(CMAKE_OBJCXX_FLAGS_RELEASE "" CACHE STRING "" FORCE) - - # Set our flags - #-------------------------------------- - add_compile_options("$<$:-g>") - add_compile_options("$,-O0,-O2>") - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -pedantic -Wno-switch -Wno-unused-function -Wno-implicit-fallthrough") - set (CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11") - set (CMAKE_OBJC_FLAGS "${CMAKE_C_FLAGS}") - set (CMAKE_OBJCXX_FLAGS "${CMAKE_CXX_FLAGS}") -endif() - -# Set default cmake flags -#-------------------------------------- -if (APPLE) - OPTION(USE_METAL_API "Build the project using metal API code" ON) -elseif (UNIX) - OPTION(USE_WAYLAND_API "Build the project using wayland API code" OFF) -endif() - -# Set compiler/platform specific flags and dependencies -#-------------------------------------- -if (MSVC) - add_definitions(-D_CRT_SECURE_NO_WARNINGS) - add_definitions(-D_WIN32_WINNT=0x0600) - - list (APPEND SrcLib ${SrcWindows}) -elseif (MINGW) - add_definitions(-D_WIN32_WINNT=0x0600) - - list(APPEND SrcLib ${SrcWindows}) -elseif (APPLE) - if(USE_METAL_API) - add_definitions(-DUSE_METAL_API) - endif() - - link_libraries("-framework Cocoa") - link_libraries("-framework QuartzCore") - link_libraries("-framework Metal") - link_libraries("-framework MetalKit") - - list(APPEND SrcLib ${SrcMacOSX}) -elseif (UNIX) - if(USE_WAYLAND_API) - link_libraries("-lwayland-client") - link_libraries("-lwayland-cursor") - - list(APPEND SrcLib ${SrcWayland}) - else() - link_libraries("-lX11") - - list(APPEND SrcLib ${SrcX11}) - endif() -endif() - -# Library -#-------------------------------------- -add_library(minifb STATIC - ${SrcLib} -) - -# For all projects -#-------------------------------------- -target_include_directories(minifb PUBLIC include) -target_include_directories(minifb PRIVATE src) -link_libraries(minifb) - -# Examples -#-------------------------------------- -add_executable(noise - tests/noise.c -) - -add_executable(input_events - tests/input_events.c -) - -add_executable(input_events_cpp - tests/input_events_cpp.cpp -) - -add_executable(multiple_windows - tests/multiple_windows.c -) - -message("Done " ${PROJECT_NAME}) +cmake_minimum_required(VERSION 3.5) + +set(PROJECT_NAME MiniFB) +project(${PROJECT_NAME}) + +message("Processing " ${PROJECT_NAME}) + +set(SrcLib + include/MiniFB.h + include/MiniFB_cpp.h + include/MiniFB_enums.h + + src/MiniFB_common.c + src/MiniFB_cpp.cpp + src/MiniFB_internal.c + src/MiniFB_internal.h + src/WindowData.h +) + +set(SrcWindows + src/windows/WinMiniFB.c + src/windows/WindowData_Win.h +) + +set(SrcMacOSX + src/macosx/MacMiniFB.m + src/macosx/OSXWindow.h + src/macosx/OSXWindow.m + src/macosx/OSXWindowFrameView.h + src/macosx/OSXWindowFrameView.m + src/macosx/WindowData_OSX.h +) + +set(SrcWayland + src/wayland/WaylandMiniFB.c + src/wayland/WindowData_Way.h +) + +set(SrcX11 + src/x11/X11MiniFB.c + src/x11/WindowData_X11.h +) + +# Avoid RelWithDebInfo and MinSizeRel +#-------------------------------------- +set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE) + +# Define Release by default +#-------------------------------------- +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release") + message(STATUS "Build type not specified: Use Release by default") +endif(NOT CMAKE_BUILD_TYPE) + +# Set GCC/Clang flags +#-------------------------------------- +if (NOT MSVC) + # Avoid default flag values + #-------------------------------------- + set(CMAKE_C_FLAGS "" CACHE STRING "" FORCE) + set(CMAKE_C_FLAGS_DEBUG "" CACHE STRING "" FORCE) + set(CMAKE_C_FLAGS_RELEASE "" CACHE STRING "" FORCE) + + set(CMAKE_CXX_FLAGS "" CACHE STRING "" FORCE) + set(CMAKE_CXX_FLAGS_DEBUG "" CACHE STRING "" FORCE) + set(CMAKE_CXX_FLAGS_RELEASE "" CACHE STRING "" FORCE) + + set(CMAKE_OBJC_FLAGS "" CACHE STRING "" FORCE) + set(CMAKE_OBJC_FLAGS_DEBUG "" CACHE STRING "" FORCE) + set(CMAKE_OBJC_FLAGS_RELEASE "" CACHE STRING "" FORCE) + + set(CMAKE_OBJCXX_FLAGS "" CACHE STRING "" FORCE) + set(CMAKE_OBJCXX_FLAGS_DEBUG "" CACHE STRING "" FORCE) + set(CMAKE_OBJCXX_FLAGS_RELEASE "" CACHE STRING "" FORCE) + + # Set our flags + #-------------------------------------- + add_compile_options("$<$:-g>") + add_compile_options("$,-O0,-O2>") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -pedantic -Wno-switch -Wno-unused-function -Wno-implicit-fallthrough") + set (CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11") + set (CMAKE_OBJC_FLAGS "${CMAKE_C_FLAGS}") + set (CMAKE_OBJCXX_FLAGS "${CMAKE_CXX_FLAGS}") +endif() + +# Set default cmake flags +#-------------------------------------- +if (APPLE) + OPTION(USE_METAL_API "Build the project using metal API code" ON) +elseif (UNIX) + OPTION(USE_WAYLAND_API "Build the project using wayland API code" OFF) +endif() + +# Set compiler/platform specific flags and dependencies +#-------------------------------------- +if (MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + add_definitions(-D_WIN32_WINNT=0x0600) + + list (APPEND SrcLib ${SrcWindows}) +elseif (MINGW) + add_definitions(-D_WIN32_WINNT=0x0600) + + list(APPEND SrcLib ${SrcWindows}) +elseif (APPLE) + if(USE_METAL_API) + add_definitions(-DUSE_METAL_API) + endif() + + link_libraries("-framework Cocoa") + link_libraries("-framework QuartzCore") + link_libraries("-framework Metal") + link_libraries("-framework MetalKit") + + list(APPEND SrcLib ${SrcMacOSX}) +elseif (UNIX) + if(USE_WAYLAND_API) + link_libraries("-lwayland-client") + link_libraries("-lwayland-cursor") + + list(APPEND SrcLib ${SrcWayland}) + else() + link_libraries("-lX11") + + list(APPEND SrcLib ${SrcX11}) + endif() +endif() + +# Library +#-------------------------------------- +add_library(minifb STATIC + ${SrcLib} +) + +# For all projects +#-------------------------------------- +target_include_directories(minifb PUBLIC include) +target_include_directories(minifb PRIVATE src) +link_libraries(minifb) + +# Examples +#-------------------------------------- +add_executable(noise + tests/noise.c +) + +add_executable(input_events + tests/input_events.c +) + +add_executable(input_events_cpp + tests/input_events_cpp.cpp +) + +add_executable(multiple_windows + tests/multiple_windows.c +) + +message("Done " ${PROJECT_NAME}) diff --git a/README.md b/README.md index a6cc2ff..9cf7769 100644 --- a/README.md +++ b/README.md @@ -1,142 +1,163 @@ -MiniFB -====== - -MiniFB (Mini FrameBuffer) is a small cross platform library that makes it easy to render (32-bit) pixels in a window. An example is the best way to show how it works: - - struct Window *window = mfb_open_ex("my display", 800, 600, WF_RESIZABLE); - if (!window) - return 0; - - for (;;) - { - int state; - - // TODO: add some fancy rendering to the buffer of size 800 * 600 - - state = mfb_update(buffer); - - if (state < 0) - break; - } - - -Furthermore, you can add callbacks to the windows: - - void active(struct Window *window, bool isActive) { - ... - } - - void resize(struct Window *window, int width, int height) { - ... - // Optionally you can also change the viewport size - mfb_set_viewport(window, x, y, width, height); - } - - void keyboard(struct Window *window, Key key, KeyMod mod, bool isPressed) { - ... - // Remember to close the window in some way - if(key == KB_KEY_ESCAPE) { - mfb_close(window); - } - } - - void char_input(struct Window *window, unsigned int charCode) { - ... - } - - void mouse_btn(struct Window *window, MouseButton button, KeyMod mod, bool isPressed) { - ... - } - - // Use wisely this event. It can be sent too often - void mouse_move(struct Window *window, int x, int y) { - ... - } - - // Mouse wheel - void mouse_scroll(struct Window *window, KeyMod mod, float deltaX, float deltaY) { - ... - } - - struct Window *window = mfb_open_ex("my display", 800, 600, WF_RESIZABLE); - if (!window) - return 0; - - mfb_set_active_callback(window, active); - mfb_set_resize_callback(window, resize); - mfb_set_keyboard_callback(window, keyboard); - mfb_set_char_input_callback(window, char_input); - mfb_set_mouse_button_callback(window, mouse_btn); - mfb_set_mouse_move_callback(window, mouse_move); - mfb_set_mouse_scroll_callback(window, mouse_scroll); - - -Additionally you can set data per window and recover it - - mfb_set_user_data(window, (void *) myData); - ... - myData = (someCast *) mfb_get_user_data(window); - - -First the code creates window with the mfb_open call that is used to display the data, next it's the applications responsibility to allocate a buffer (which has to be at least the size of the window and in 32-bit) Next when calling mfb_update function the buffer will be copied over to the window and displayed. Currently the mfb_update will return -1 if ESC key is pressed but later on it will support to return a key code for a pressed button. See https://github.com/emoon/minifb/blob/master/tests/noise.c for a complete example - -MiniFB has been tested on Windows, Mac OS X and Linux but may of course have trouble depending on your setup. Currently the code will not do any converting of data if not a proper 32-bit display can be created. - -Build instructions ------------------- - -MiniFB uses tundra https://github.com/deplinenoise/tundra as build system and is required to build the code as is but not many changes should be needed if you want to use it directly in your own code. - -You can also use CMake as build system. - -Mac ---- - -Cocoa and clang is assumed to be installed on the system (downloading latest XCode + installing the command line tools should do the trick) then to build run: tundra2 macosx-clang-debug and you should be able to run the noise example (t2-output/macosx-clang-debug-default/noise) - -MacOS X Mojave does not support Cocoa framework as expected. For that reason now you can switch to Metal API. -To enable it just compile defining the preprocessor macro USE_METAL_API. - -If you use CMake just enable the flag: - - mkdir build - cd build - cmake .. -DUSE_METAL_API=ON - -or if you don't want to use Metal API: - - mkdir build - cd build - cmake .. -DUSE_METAL_API=OFF - - -Windows -------- - -Visual Studio (ver 2012 express has been tested) tools needed (using the vcvars32.bat (for 32-bit) will set up the enviroment) to build run: tundra2 win32-msvc-debug and you should be able to run noise in t2-output/win32-msvc-debug-default/noise.exe - -If you use CMake the Visual Studio project will be generated (2015, 2017 and 2019 have been tested). - - -x11 (FreeBSD, Linux, *nix) --------------------------- - -gcc and x11-dev libs needs to be installed. To build the code run tundra2 x11-gcc-debug and you should be able to run t2-output/x11-gcc-debug-default/noise - -If you use CMake just disable the flag: - - mkdir build - cd build - cmake .. -DUSE_WAYLAND_API=OFF - - -wayland (Linux) --------------------------- - -Depends on gcc and wayland-client and wayland-cursor. Built using the wayland-gcc variants. - -If you use CMake just enable the flag: - - mkdir build - cd build - cmake .. -DUSE_WAYLAND_API=ON +MiniFB +====== + +MiniFB (Mini FrameBuffer) is a small cross platform library that makes it easy to render (32-bit) pixels in a window. An example is the best way to show how it works: + + struct mfb_window *window = mfb_open_ex("my display", 800, 600, WF_RESIZABLE); + if (!window) + return 0; + + for (;;) + { + int state; + + // TODO: add some fancy rendering to the buffer of size 800 * 600 + + state = mfb_update(buffer); + + if (state < 0) + break; + } + + +Furthermore, you can add callbacks to the windows: + + void active(struct mfb_window *window, bool isActive) { + ... + } + + void resize(struct mfb_window *window, int width, int height) { + ... + // Optionally you can also change the viewport size + mfb_set_viewport(window, x, y, width, height); + } + + void keyboard(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed) { + ... + // Remember to close the window in some way + if(key == KB_KEY_ESCAPE) { + mfb_close(window); + } + + fprintf(stdout, "%s > keyboard: key: %s (pressed: %d) [key_mod: %x]\n", window_title, mfb_get_key_name(key), isPressed, mod); + + } + + void char_input(struct mfb_window *window, unsigned int charCode) { + ... + } + + void mouse_btn(struct mfb_window *window, mfb_mouse_button button, mfb_key_mod mod, bool isPressed) { + ... + } + + // Use wisely this event. It can be sent too often + void mouse_move(struct mfb_window *window, int x, int y) { + ... + } + + // Mouse wheel + void mouse_scroll(struct mfb_window *window, mfb_key_mod mod, float deltaX, float deltaY) { + ... + } + + struct mfb_window *window = mfb_open_ex("my display", 800, 600, WF_RESIZABLE); + if (!window) + return 0; + + mfb_set_active_callback(window, active); + mfb_set_resize_callback(window, resize); + mfb_set_keyboard_callback(window, keyboard); + mfb_set_char_input_callback(window, char_input); + mfb_set_mouse_button_callback(window, mouse_btn); + mfb_set_mouse_move_callback(window, mouse_move); + mfb_set_mouse_scroll_callback(window, mouse_scroll); + + +Additionally you can set data per window and recover it + + mfb_set_user_data(window, (void *) myData); + ... + myData = (someCast *) mfb_get_user_data(window); + + +Finally, you can get information about the events in the window directly: + + bool mfb_is_window_active(struct mfb_window *window); + + unsigned mfb_get_window_width(struct mfb_window *window); + unsigned mfb_get_window_height(struct mfb_window *window); + + int mfb_get_mouse_x(struct mfb_window *window); // Last mouse pos X + int mfb_get_mouse_y(struct mfb_window *window); // Last mouse pos Y + + float mfb_get_mouse_scroll_x(struct mfb_window *window); // Mouse wheel X as a sum. When you call this function it resets. + float mfb_get_mouse_scroll_y(struct mfb_window *window); // Mouse wheel Y as a sum. When you call this function it resets. + + const uint8_t * mfb_get_mouse_button_buffer(struct mfb_window *window); // One byte for every button. Press (1), Release 0. (up to 8 buttons) + + const uint8_t * mfb_get_key_buffer(struct mfb_window *window); // One byte for every key. Press (1), Release 0. + + +First the code creates window with the mfb_open call that is used to display the data, next it's the applications responsibility to allocate a buffer (which has to be at least the size of the window and in 32-bit) Next when calling mfb_update function the buffer will be copied over to the window and displayed. Currently the mfb_update will return -1 if ESC key is pressed but later on it will support to return a key code for a pressed button. See https://github.com/emoon/minifb/blob/master/tests/noise.c for a complete example + +MiniFB has been tested on Windows, Mac OS X and Linux but may of course have trouble depending on your setup. Currently the code will not do any converting of data if not a proper 32-bit display can be created. + +Build instructions +------------------ + +MiniFB uses tundra https://github.com/deplinenoise/tundra as build system and is required to build the code as is but not many changes should be needed if you want to use it directly in your own code. + +You can also use CMake as build system. + +Mac +--- + +Cocoa and clang is assumed to be installed on the system (downloading latest XCode + installing the command line tools should do the trick) then to build run: tundra2 macosx-clang-debug and you should be able to run the noise example (t2-output/macosx-clang-debug-default/noise) + +MacOS X Mojave does not support Cocoa framework as expected. For that reason now you can switch to Metal API. +To enable it just compile defining the preprocessor macro USE_METAL_API. + +If you use CMake just enable the flag: + + mkdir build + cd build + cmake .. -DUSE_METAL_API=ON + +or if you don't want to use Metal API: + + mkdir build + cd build + cmake .. -DUSE_METAL_API=OFF + + +Windows +------- + +Visual Studio (ver 2012 express has been tested) tools needed (using the vcvars32.bat (for 32-bit) will set up the enviroment) to build run: tundra2 win32-msvc-debug and you should be able to run noise in t2-output/win32-msvc-debug-default/noise.exe + +If you use CMake the Visual Studio project will be generated (2015, 2017 and 2019 have been tested). + + +x11 (FreeBSD, Linux, *nix) +-------------------------- + +gcc and x11-dev libs needs to be installed. To build the code run tundra2 x11-gcc-debug and you should be able to run t2-output/x11-gcc-debug-default/noise + +If you use CMake just disable the flag: + + mkdir build + cd build + cmake .. -DUSE_WAYLAND_API=OFF + + +wayland (Linux) +-------------------------- + +Depends on gcc and wayland-client and wayland-cursor. Built using the wayland-gcc variants. + +If you use CMake just enable the flag: + + mkdir build + cd build + cmake .. -DUSE_WAYLAND_API=ON diff --git a/include/MiniFB.h b/include/MiniFB.h index 99d7b08..c1a9763 100644 --- a/include/MiniFB.h +++ b/include/MiniFB.h @@ -14,47 +14,47 @@ extern "C" { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Create a window that is used to display the buffer sent into the mfb_update function, returns 0 if fails -struct Window * mfb_open(const char *title, unsigned width, unsigned height); -struct Window * mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags); +struct mfb_window * mfb_open(const char *title, unsigned width, unsigned height); +struct mfb_window * mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags); // Update the display // Input buffer is assumed to be a 32-bit buffer of the size given in the open call // Will return a negative status if something went wrong or the user want to exit // Also updates the window events -UpdateState mfb_update(struct Window *window, void *buffer); +mfb_update_state mfb_update(struct mfb_window *window, void *buffer); // Only updates the window events -UpdateState mfb_update_events(struct Window *window); +mfb_update_state mfb_update_events(struct mfb_window *window); // Close the window -void mfb_close(struct Window *window); +void mfb_close(struct mfb_window *window); // Set user data -void mfb_set_user_data(struct Window *window, void *user_data); -void * mfb_get_user_data(struct Window *window); +void mfb_set_user_data(struct mfb_window *window, void *user_data); +void * mfb_get_user_data(struct mfb_window *window); // Set viewport (useful when resize) -bool mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height); +bool mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height); -void mfb_set_active_callback(struct Window *window, mfb_active_func callback); -void mfb_set_resize_callback(struct Window *window, mfb_resize_func callback); -void mfb_set_keyboard_callback(struct Window *window, mfb_keyboard_func callback); -void mfb_set_char_input_callback(struct Window *window, mfb_char_input_func callback); -void mfb_set_mouse_button_callback(struct Window *window, mfb_mouse_button_func callback); -void mfb_set_mouse_move_callback(struct Window *window, mfb_mouse_move_func callback); -void mfb_set_mouse_scroll_callback(struct Window *window, mfb_mouse_scroll_func callback); +void mfb_set_active_callback(struct mfb_window *window, mfb_active_func callback); +void mfb_set_resize_callback(struct mfb_window *window, mfb_resize_func callback); +void mfb_set_keyboard_callback(struct mfb_window *window, mfb_keyboard_func callback); +void mfb_set_char_input_callback(struct mfb_window *window, mfb_char_input_func callback); +void mfb_set_mouse_button_callback(struct mfb_window *window, mfb_mouse_button_func callback); +void mfb_set_mouse_move_callback(struct mfb_window *window, mfb_mouse_move_func callback); +void mfb_set_mouse_scroll_callback(struct mfb_window *window, mfb_mouse_scroll_func callback); -const char * mfb_get_key_name(Key key); +const char * mfb_get_key_name(mfb_key key); -bool mfb_is_window_active(struct Window *window); -unsigned mfb_get_window_width(struct Window *window); -unsigned mfb_get_window_height(struct Window *window); -int mfb_get_mouse_x(struct Window *window); // Last mouse pos X -int mfb_get_mouse_y(struct Window *window); // Last mouse pos Y -float mfb_get_mouse_scroll_x(struct Window *window); // Mouse wheel X as a sum. When you call this function it resets. -float mfb_get_mouse_scroll_y(struct Window *window); // Mouse wheel Y as a sum. When you call this function it resets. -const uint8_t * mfb_get_mouse_button_buffer(struct Window *window); // One byte for every button. Press (1), Release 0. (up to 8 buttons) -const uint8_t * mfb_get_key_buffer(struct Window *window); // One byte for every key. Press (1), Release 0. +bool mfb_is_window_active(struct mfb_window *window); +unsigned mfb_get_window_width(struct mfb_window *window); +unsigned mfb_get_window_height(struct mfb_window *window); +int mfb_get_mouse_x(struct mfb_window *window); // Last mouse pos X +int mfb_get_mouse_y(struct mfb_window *window); // Last mouse pos Y +float mfb_get_mouse_scroll_x(struct mfb_window *window); // Mouse wheel X as a sum. When you call this function it resets. +float mfb_get_mouse_scroll_y(struct mfb_window *window); // Mouse wheel Y as a sum. When you call this function it resets. +const uint8_t * mfb_get_mouse_button_buffer(struct mfb_window *window); // One byte for every button. Press (1), Release 0. (up to 8 buttons) +const uint8_t * mfb_get_key_buffer(struct mfb_window *window); // One byte for every key. Press (1), Release 0. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/MiniFB_cpp.h b/include/MiniFB_cpp.h index acc5b4b..8fa32ea 100755 --- a/include/MiniFB_cpp.h +++ b/include/MiniFB_cpp.h @@ -6,131 +6,131 @@ #include "MiniFB.h" template -void mfb_set_active_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, bool)); +void mfb_set_active_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, bool)); template -void mfb_set_resize_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, int, int)); +void mfb_set_resize_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, int, int)); template -void mfb_set_keyboard_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, Key, KeyMod, bool)); +void mfb_set_keyboard_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_key, mfb_key_mod, bool)); template -void mfb_set_char_input_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, unsigned int)); +void mfb_set_char_input_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, unsigned int)); template -void mfb_set_mouse_button_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, MouseButton, KeyMod, bool)); +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)); template -void mfb_set_mouse_move_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, int, int)); +void mfb_set_mouse_move_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, int, int)); template -void mfb_set_mouse_scroll_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, KeyMod, float, float)); +void mfb_set_mouse_scroll_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_key_mod, float, float)); //------------------------------------- // To avoid clumsy hands //------------------------------------- -class Stub { - Stub() : m_window(0x0) {} +class mfb_stub { + mfb_stub() : m_window(0x0) {} template - friend void mfb_set_active_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, bool)); + friend void mfb_set_active_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, bool)); template - friend void mfb_set_resize_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, int, int)); + friend void mfb_set_resize_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, int, int)); template - friend void mfb_set_mouse_button_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, MouseButton, KeyMod, bool)); + 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)); template - friend void mfb_set_keyboard_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, Key, KeyMod, bool)); + friend void mfb_set_keyboard_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_key, mfb_key_mod, bool)); template - friend void mfb_set_char_input_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, unsigned int)); + friend void mfb_set_char_input_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, unsigned int)); template - friend void mfb_set_mouse_button_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, MouseButton, KeyMod, bool)); + 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)); template - friend void mfb_set_mouse_move_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, int, int)); + friend void mfb_set_mouse_move_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, int, int)); template - friend void mfb_set_mouse_scroll_callback(struct Window *window, T *obj, void (T::*method)(struct Window *, KeyMod, float, float)); + friend void mfb_set_mouse_scroll_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *, mfb_key_mod, float, float)); - static Stub *GetInstance(struct Window *window); + static mfb_stub *GetInstance(struct mfb_window *window); - static void active_stub(struct Window *window, bool isActive); - static void resize_stub(struct Window *window, int width, int height); - static void keyboard_stub(struct Window *window, Key key, KeyMod mod, bool isPressed); - static void char_input_stub(struct Window *window, unsigned int); - static void mouse_btn_stub(struct Window *window, MouseButton button, KeyMod mod, bool isPressed); - static void mouse_move_stub(struct Window *window, int x, int y); - static void scroll_stub(struct Window *window, KeyMod mod, float deltaX, float deltaY); + static void active_stub(struct mfb_window *window, bool isActive); + static void resize_stub(struct mfb_window *window, int width, int height); + static void keyboard_stub(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed); + static void char_input_stub(struct mfb_window *window, unsigned int); + static void mouse_btn_stub(struct mfb_window *window, mfb_mouse_button button, mfb_key_mod mod, bool isPressed); + static void mouse_move_stub(struct mfb_window *window, int x, int y); + static void scroll_stub(struct mfb_window *window, mfb_key_mod mod, float deltaX, float deltaY); - struct Window *m_window; - std::function m_active; - std::function m_resize; - std::function m_keyboard; - std::function m_char_input; - std::function m_mouse_btn; - std::function m_mouse_move; - std::function m_scroll; + struct mfb_window *m_window; + std::function m_active; + std::function m_resize; + std::function m_keyboard; + std::function m_char_input; + std::function m_mouse_btn; + std::function m_mouse_move; + std::function m_scroll; }; //------------------------------------- template -inline void mfb_set_active_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, bool)) { +inline void mfb_set_active_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, bool)) { using namespace std::placeholders; - Stub *stub = Stub::GetInstance(window); + mfb_stub *stub = mfb_stub::GetInstance(window); stub->m_active = std::bind(method, obj, _1, _2); - mfb_set_active_callback(window, Stub::active_stub); + mfb_set_active_callback(window, mfb_stub::active_stub); } template -inline void mfb_set_resize_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, int, int)) { +inline void mfb_set_resize_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, int, int)) { using namespace std::placeholders; - Stub *stub = Stub::GetInstance(window); + mfb_stub *stub = mfb_stub::GetInstance(window); stub->m_resize = std::bind(method, obj, _1, _2, _3); - mfb_set_resize_callback(window, Stub::resize_stub); + mfb_set_resize_callback(window, mfb_stub::resize_stub); } template -inline void mfb_set_keyboard_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, Key, KeyMod, bool)) { +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)) { using namespace std::placeholders; - Stub *stub = Stub::GetInstance(window); + mfb_stub *stub = mfb_stub::GetInstance(window); stub->m_keyboard = std::bind(method, obj, _1, _2, _3, _4); - mfb_set_keyboard_callback(window, Stub::keyboard_stub); + mfb_set_keyboard_callback(window, mfb_stub::keyboard_stub); } template -inline void mfb_set_char_input_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, unsigned int)) { +inline void mfb_set_char_input_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, unsigned int)) { using namespace std::placeholders; - Stub *stub = Stub::GetInstance(window); + mfb_stub *stub = mfb_stub::GetInstance(window); stub->m_char_input = std::bind(method, obj, _1, _2); - mfb_set_char_input_callback(window, Stub::char_input_stub); + mfb_set_char_input_callback(window, mfb_stub::char_input_stub); } template -inline void mfb_set_mouse_button_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, MouseButton, KeyMod, bool)) { +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)) { using namespace std::placeholders; - Stub *stub = Stub::GetInstance(window); + mfb_stub *stub = mfb_stub::GetInstance(window); stub->m_mouse_btn = std::bind(method, obj, _1, _2, _3, _4); - mfb_set_mouse_button_callback(window, Stub::mouse_btn_stub); + mfb_set_mouse_button_callback(window, mfb_stub::mouse_btn_stub); } template -inline void mfb_set_mouse_move_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, int, int)) { +inline void mfb_set_mouse_move_callback(struct mfb_window *window, T *obj, void (T::*method)(struct mfb_window *window, int, int)) { using namespace std::placeholders; - Stub *stub = Stub::GetInstance(window); + mfb_stub *stub = mfb_stub::GetInstance(window); stub->m_mouse_move = std::bind(method, obj, _1, _2, _3); - mfb_set_mouse_move_callback(window, Stub::mouse_move_stub); + mfb_set_mouse_move_callback(window, mfb_stub::mouse_move_stub); } template -inline void mfb_set_mouse_scroll_callback(struct Window *window, T *obj, void (T::*method)(struct Window *window, KeyMod, float, float)) { +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)) { using namespace std::placeholders; - Stub *stub = Stub::GetInstance(window); + mfb_stub *stub = mfb_stub::GetInstance(window); stub->m_scroll = std::bind(method, obj, _1, _2, _3, _4); - mfb_set_mouse_scroll_callback(window, Stub::scroll_stub); + mfb_set_mouse_scroll_callback(window, mfb_stub::scroll_stub); } #endif diff --git a/include/MiniFB_enums.h b/include/MiniFB_enums.h index df91e07..ea12eb5 100755 --- a/include/MiniFB_enums.h +++ b/include/MiniFB_enums.h @@ -10,7 +10,7 @@ typedef enum { STATE_INVALID_WINDOW = -2, STATE_INVALID_BUFFER = -3, STATE_INTERNAL_ERROR = -4, -} UpdateState; +} mfb_update_state; typedef enum { MOUSE_BTN_0, // No mouse button @@ -21,7 +21,7 @@ typedef enum { MOUSE_BTN_5, MOUSE_BTN_6, MOUSE_BTN_7, -} MouseButton; +} mfb_mouse_button; #define MOUSE_LEFT MOUSE_BTN_1 #define MOUSE_RIGHT MOUSE_BTN_2 #define MOUSE_MIDDLE MOUSE_BTN_3 @@ -150,7 +150,7 @@ typedef enum { KB_KEY_RIGHT_ALT = 346, KB_KEY_RIGHT_SUPER = 347, KB_KEY_MENU = 348 -} Key; +} mfb_key; #define KB_KEY_LAST KB_KEY_MENU typedef enum { @@ -160,7 +160,7 @@ typedef enum { KB_MOD_SUPER = 0x0008, KB_MOD_CAPS_LOCK = 0x0010, KB_MOD_NUM_LOCK = 0x0020 -} KeyMod; +} mfb_key_mod; typedef enum { WF_RESIZABLE = 0x01, @@ -168,17 +168,17 @@ typedef enum { WF_FULLSCREEN_DESKTOP = 0x04, WF_BORDERLESS = 0x08, WF_ALWAYS_ON_TOP = 0x10, -} WindowFlags; +} mfb_window_flags; // Opaque pointer -struct Window; +struct mfb_window; // Event callbacks -typedef void(*mfb_active_func)(struct Window *window, bool isActive); -typedef void(*mfb_resize_func)(struct Window *window, int width, int height); -typedef void(*mfb_keyboard_func)(struct Window *window, Key key, KeyMod mod, bool isPressed); -typedef void(*mfb_char_input_func)(struct Window *window, unsigned int code); -typedef void(*mfb_mouse_button_func)(struct Window *window, MouseButton button, KeyMod mod, bool isPressed); -typedef void(*mfb_mouse_move_func)(struct Window *window, int x, int y); -typedef void(*mfb_mouse_scroll_func)(struct Window *window, KeyMod mod, float deltaX, float deltaY); +typedef void(*mfb_active_func)(struct mfb_window *window, bool isActive); +typedef void(*mfb_resize_func)(struct mfb_window *window, int width, int height); +typedef void(*mfb_keyboard_func)(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed); +typedef void(*mfb_char_input_func)(struct mfb_window *window, unsigned int code); +typedef void(*mfb_mouse_button_func)(struct mfb_window *window, mfb_mouse_button button, mfb_key_mod mod, bool isPressed); +typedef void(*mfb_mouse_move_func)(struct mfb_window *window, int x, int y); +typedef void(*mfb_mouse_scroll_func)(struct mfb_window *window, mfb_key_mod mod, float deltaX, float deltaY); diff --git a/src/MiniFB_common.c b/src/MiniFB_common.c index 16adb2d..b6e1aca 100755 --- a/src/MiniFB_common.c +++ b/src/MiniFB_common.c @@ -7,7 +7,8 @@ short int g_keycodes[512] = { 0 }; //------------------------------------- //------------------------------------- -void mfb_set_active_callback(struct Window *window, mfb_active_func callback) { +void +mfb_set_active_callback(struct mfb_window *window, mfb_active_func callback) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; window_data->active_func = callback; @@ -15,7 +16,8 @@ void mfb_set_active_callback(struct Window *window, mfb_active_func callback) { } //------------------------------------- -void mfb_set_resize_callback(struct Window *window, mfb_resize_func callback) { +void +mfb_set_resize_callback(struct mfb_window *window, mfb_resize_func callback) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; window_data->resize_func = callback; @@ -23,7 +25,8 @@ void mfb_set_resize_callback(struct Window *window, mfb_resize_func callback) { } //------------------------------------- -void mfb_set_keyboard_callback(struct Window *window, mfb_keyboard_func callback) { +void +mfb_set_keyboard_callback(struct mfb_window *window, mfb_keyboard_func callback) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; window_data->keyboard_func = callback; @@ -31,7 +34,8 @@ void mfb_set_keyboard_callback(struct Window *window, mfb_keyboard_func callback } //------------------------------------- -void mfb_set_char_input_callback(struct Window *window, mfb_char_input_func callback) { +void +mfb_set_char_input_callback(struct mfb_window *window, mfb_char_input_func callback) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; window_data->char_input_func = callback; @@ -39,7 +43,8 @@ void mfb_set_char_input_callback(struct Window *window, mfb_char_input_func call } //------------------------------------- -void mfb_set_mouse_button_callback(struct Window *window, mfb_mouse_button_func callback) { +void +mfb_set_mouse_button_callback(struct mfb_window *window, mfb_mouse_button_func callback) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; window_data->mouse_btn_func = callback; @@ -47,7 +52,8 @@ void mfb_set_mouse_button_callback(struct Window *window, mfb_mouse_button_func } //------------------------------------- -void mfb_set_mouse_move_callback(struct Window *window, mfb_mouse_move_func callback) { +void +mfb_set_mouse_move_callback(struct mfb_window *window, mfb_mouse_move_func callback) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; window_data->mouse_move_func = callback; @@ -55,7 +61,8 @@ void mfb_set_mouse_move_callback(struct Window *window, mfb_mouse_move_func call } //------------------------------------- -void mfb_set_mouse_scroll_callback(struct Window *window, mfb_mouse_scroll_func callback) { +void +mfb_set_mouse_scroll_callback(struct mfb_window *window, mfb_mouse_scroll_func callback) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; window_data->mouse_wheel_func = callback; @@ -63,7 +70,8 @@ void mfb_set_mouse_scroll_callback(struct Window *window, mfb_mouse_scroll_func } //------------------------------------- -void mfb_set_user_data(struct Window *window, void *user_data) { +void +mfb_set_user_data(struct mfb_window *window, void *user_data) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; window_data->user_data = user_data; @@ -71,7 +79,8 @@ void mfb_set_user_data(struct Window *window, void *user_data) { } //------------------------------------- -void *mfb_get_user_data(struct Window *window) { +void * +mfb_get_user_data(struct mfb_window *window) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; return window_data->user_data; @@ -81,7 +90,8 @@ void *mfb_get_user_data(struct Window *window) { } //------------------------------------- -void mfb_close(struct Window *window) { +void +mfb_close(struct mfb_window *window) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; window_data->close = true; @@ -89,7 +99,8 @@ void mfb_close(struct Window *window) { } //------------------------------------- -void keyboard_default(struct Window *window, Key key, KeyMod mod, bool isPressed) { +void +keyboard_default(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed) { kUnused(mod); kUnused(isPressed); if (key == KB_KEY_ESCAPE) { @@ -99,7 +110,8 @@ void keyboard_default(struct Window *window, Key key, KeyMod mod, bool isPressed } //------------------------------------- -bool mfb_is_window_active(struct Window *window) { +bool +mfb_is_window_active(struct mfb_window *window) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; return window_data->is_active; @@ -108,7 +120,8 @@ bool mfb_is_window_active(struct Window *window) { } //------------------------------------- -unsigned mfb_get_window_width(struct Window *window) { +unsigned +mfb_get_window_width(struct mfb_window *window) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; return window_data->window_width; @@ -117,7 +130,8 @@ unsigned mfb_get_window_width(struct Window *window) { } //------------------------------------- -unsigned mfb_get_window_height(struct Window *window) { +unsigned +mfb_get_window_height(struct mfb_window *window) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; return window_data->window_height; @@ -126,7 +140,8 @@ unsigned mfb_get_window_height(struct Window *window) { } //------------------------------------- -int mfb_get_mouse_x(struct Window *window) { +int +mfb_get_mouse_x(struct mfb_window *window) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; return window_data->mouse_pos_x; @@ -135,7 +150,8 @@ int mfb_get_mouse_x(struct Window *window) { } //------------------------------------- -int mfb_get_mouse_y(struct Window *window) { +int +mfb_get_mouse_y(struct mfb_window *window) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; return window_data->mouse_pos_y; @@ -144,7 +160,8 @@ int mfb_get_mouse_y(struct Window *window) { } //------------------------------------- -float mfb_get_mouse_scroll_x(struct Window *window) { +float +mfb_get_mouse_scroll_x(struct mfb_window *window) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; return window_data->mouse_wheel_x; @@ -153,7 +170,8 @@ float mfb_get_mouse_scroll_x(struct Window *window) { } //------------------------------------- -float mfb_get_mouse_scroll_y(struct Window *window) { +float +mfb_get_mouse_scroll_y(struct mfb_window *window) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; return window_data->mouse_wheel_y; @@ -162,7 +180,8 @@ float mfb_get_mouse_scroll_y(struct Window *window) { } //------------------------------------- -const uint8_t * mfb_get_mouse_button_buffer(struct Window *window) { +const uint8_t * +mfb_get_mouse_button_buffer(struct mfb_window *window) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; return window_data->mouse_button_status; @@ -171,7 +190,8 @@ const uint8_t * mfb_get_mouse_button_buffer(struct Window *window) { } //------------------------------------- -const uint8_t * mfb_get_key_buffer(struct Window *window) { +const uint8_t * +mfb_get_key_buffer(struct mfb_window *window) { if(window != 0x0) { SWindowData *window_data = (SWindowData *) window; return window_data->key_status; @@ -179,10 +199,9 @@ const uint8_t * mfb_get_key_buffer(struct Window *window) { return 0; } - - //------------------------------------- -const char * mfb_get_key_name(Key key) { +const char * +mfb_get_key_name(mfb_key key) { switch (key) { diff --git a/src/MiniFB_cpp.cpp b/src/MiniFB_cpp.cpp index bfaf56a..b513803 100755 --- a/src/MiniFB_cpp.cpp +++ b/src/MiniFB_cpp.cpp @@ -2,53 +2,68 @@ #include #include -Stub * -Stub::GetInstance(struct Window *window) { - static std::vector s_instances; +//------------------------------------- +mfb_stub * +mfb_stub::GetInstance(struct mfb_window *window) { + static std::vector s_instances; - for(Stub *instance : s_instances) { + for(mfb_stub *instance : s_instances) { if(instance->m_window == window) { return instance; } } - s_instances.push_back(new Stub); + s_instances.push_back(new mfb_stub); s_instances.back()->m_window = window; return s_instances.back(); } -void Stub::active_stub(struct Window *window, bool isActive) { - Stub *stub = Stub::GetInstance(window); +//------------------------------------- +void +mfb_stub::active_stub(struct mfb_window *window, bool isActive) { + mfb_stub *stub = mfb_stub::GetInstance(window); stub->m_active(window, isActive); } -void Stub::resize_stub(struct Window *window, int width, int height) { - Stub *stub = Stub::GetInstance(window); +//------------------------------------- +void +mfb_stub::resize_stub(struct mfb_window *window, int width, int height) { + mfb_stub *stub = mfb_stub::GetInstance(window); stub->m_resize(window, width, height); } -void Stub::keyboard_stub(struct Window *window, Key key, KeyMod mod, bool isPressed) { - Stub *stub = Stub::GetInstance(window); +//------------------------------------- +void +mfb_stub::keyboard_stub(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed) { + mfb_stub *stub = mfb_stub::GetInstance(window); stub->m_keyboard(window, key, mod, isPressed); } -void Stub::char_input_stub(struct Window *window, unsigned int code) { - Stub *stub = Stub::GetInstance(window); +//------------------------------------- +void +mfb_stub::char_input_stub(struct mfb_window *window, unsigned int code) { + mfb_stub *stub = mfb_stub::GetInstance(window); stub->m_char_input(window, code); } -void Stub::mouse_btn_stub(struct Window *window, MouseButton button, KeyMod mod, bool isPressed) { - Stub *stub = Stub::GetInstance(window); +//------------------------------------- +void +mfb_stub::mouse_btn_stub(struct mfb_window *window, mfb_mouse_button button, mfb_key_mod mod, bool isPressed) { + mfb_stub *stub = mfb_stub::GetInstance(window); stub->m_mouse_btn(window, button, mod, isPressed); } -void Stub::mouse_move_stub(struct Window *window, int x, int y) { - Stub *stub = Stub::GetInstance(window); +//------------------------------------- +void +mfb_stub::mouse_move_stub(struct mfb_window *window, int x, int y) { + mfb_stub *stub = mfb_stub::GetInstance(window); stub->m_mouse_move(window, x, y); } -void Stub::scroll_stub(struct Window *window, KeyMod mod, float deltaX, float deltaY) { - Stub *stub = Stub::GetInstance(window); +//------------------------------------- +void +mfb_stub::scroll_stub(struct mfb_window *window, mfb_key_mod mod, float deltaX, float deltaY) { + mfb_stub *stub = mfb_stub::GetInstance(window); stub->m_scroll(window, mod, deltaX, deltaY); } diff --git a/src/MiniFB_internal.c b/src/MiniFB_internal.c index ed23e8e..c44623d 100644 --- a/src/MiniFB_internal.c +++ b/src/MiniFB_internal.c @@ -4,7 +4,8 @@ //#define kUseBilinearInterpolation #if defined(kUseBilinearInterpolation) -static uint32_t 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) { +static uint32_t +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) { uint32_t incX = x + 1 < srcWidth ? 1 : 0; uint32_t incY = y + 1 < srcHeight ? srcPitch : 0; uint8_t *p00 = (uint8_t *) &srcImage[(srcOffsetX >> 16)]; @@ -38,8 +39,9 @@ static uint32_t interpolate(uint32_t *srcImage, uint32_t x, uint32_t y, uint32_t #endif // Only for 32 bits images -void stretch_image(uint32_t *srcImage, uint32_t srcX, uint32_t srcY, uint32_t srcWidth, uint32_t srcHeight, uint32_t srcPitch, - uint32_t *dstImage, uint32_t dstX, uint32_t dstY, uint32_t dstWidth, uint32_t dstHeight, uint32_t dstPitch) { +void +stretch_image(uint32_t *srcImage, uint32_t srcX, uint32_t srcY, uint32_t srcWidth, uint32_t srcHeight, uint32_t srcPitch, + uint32_t *dstImage, uint32_t dstX, uint32_t dstY, uint32_t dstWidth, uint32_t dstHeight, uint32_t dstPitch) { uint32_t x, y; uint32_t srcOffsetX, srcOffsetY; diff --git a/src/MiniFB_internal.h b/src/MiniFB_internal.h index 365c70d..5a8b720 100755 --- a/src/MiniFB_internal.h +++ b/src/MiniFB_internal.h @@ -3,7 +3,7 @@ #include "MiniFB.h" #include "MiniFB_enums.h" -#define kCall(func, ...) if(window_data && window_data->func) window_data->func((struct Window *) window_data, __VA_ARGS__); +#define kCall(func, ...) if(window_data && window_data->func) window_data->func((struct mfb_window *) window_data, __VA_ARGS__); #define kUnused(var) (void) var; #if defined(__cplusplus) @@ -12,7 +12,7 @@ extern "C" { extern short int g_keycodes[512]; void init_keycodes(); - void keyboard_default(struct Window *window, Key key, KeyMod mod, bool isPressed); + void keyboard_default(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed); #if defined(__cplusplus) } diff --git a/src/macosx/MacMiniFB.m b/src/macosx/MacMiniFB.m index 933f095..e2c2992 100644 --- a/src/macosx/MacMiniFB.m +++ b/src/macosx/MacMiniFB.m @@ -85,7 +85,8 @@ NSString* g_shadersSrc = @ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #if defined(USE_METAL_API) -static bool create_shaders(SWindowData_OSX *window_data_osx) { +static bool +create_shaders(SWindowData_OSX *window_data_osx) { // Error NSError* nsError = 0x0; NSError** nsErrorPtr = &nsError; @@ -136,14 +137,16 @@ static bool create_shaders(SWindowData_OSX *window_data_osx) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -struct Window *mfb_open(const char *title, unsigned width, unsigned height) +struct mfb_window * +mfb_open(const char *title, unsigned width, unsigned height) { return mfb_open_ex(title, width, height, 0); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -struct Window *mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) +struct mfb_window * +mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; @@ -254,7 +257,7 @@ struct Window *mfb_open_ex(const char *title, unsigned width, unsigned height, u [NSApp finishLaunching]; #endif - mfb_set_keyboard_callback((struct Window *) window_data, keyboard_default); + mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default); #if defined(USE_METAL_API) NSLog(@"Window created using Metal API"); @@ -264,12 +267,13 @@ struct Window *mfb_open_ex(const char *title, unsigned width, unsigned height, u [pool drain]; - return (struct Window *) window_data; + return (struct mfb_window *) window_data; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -static void destroy_window_data(SWindowData *window_data) +static void +destroy_window_data(SWindowData *window_data) { if(window_data == 0x0) return; @@ -293,7 +297,8 @@ static void destroy_window_data(SWindowData *window_data) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -static void update_events(SWindowData *window_data) +static void +update_events(SWindowData *window_data) { NSEvent* event; @@ -312,7 +317,8 @@ static void update_events(SWindowData *window_data) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -UpdateState mfb_update(struct Window *window, void *buffer) +mfb_update_state +mfb_update(struct mfb_window *window, void *buffer) { if(window == 0x0) { return STATE_INVALID_WINDOW; @@ -345,7 +351,8 @@ UpdateState mfb_update(struct Window *window, void *buffer) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -UpdateState mfb_update_events(struct Window *window) +mfb_update_state +mfb_update_events(struct mfb_window *window) { if(window == 0x0) { return STATE_INVALID_WINDOW; @@ -368,7 +375,8 @@ UpdateState mfb_update_events(struct Window *window) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) +bool +mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { SWindowData *window_data = (SWindowData *) window; @@ -410,7 +418,8 @@ bool mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_ extern short int g_keycodes[512]; -void init_keycodes() +void +init_keycodes() { // Clear keys for (unsigned int i = 0; i < sizeof(g_keycodes) / sizeof(g_keycodes[0]); ++i) diff --git a/src/wayland/WaylandMiniFB.c b/src/wayland/WaylandMiniFB.c index de15923..3b75bd2 100644 --- a/src/wayland/WaylandMiniFB.c +++ b/src/wayland/WaylandMiniFB.c @@ -136,7 +136,7 @@ keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t SWindowData *window_data = (SWindowData *) data; if(key < 512) { - Key key_code = (Key) g_keycodes[key]; + mfb_key key_code = (mfb_key) g_keycodes[key]; bool is_pressed = (bool) (state == WL_KEYBOARD_KEY_STATE_PRESSED); switch (key_code) { @@ -174,7 +174,7 @@ keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t } window_data->key_status[key_code] = is_pressed; - kCall(keyboard_func, key_code, (KeyMod)window_data->mod_keys, is_pressed); + kCall(keyboard_func, key_code, (mfb_key_mod) window_data->mod_keys, is_pressed); } } @@ -210,7 +210,8 @@ keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int kUnused(delay); } -static const struct wl_keyboard_listener keyboard_listener = { +static const struct +wl_keyboard_listener keyboard_listener = { .keymap = keyboard_keymap, .enter = keyboard_enter, .leave = keyboard_leave, @@ -319,7 +320,7 @@ pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t //printf("Pointer button '%d'(%d)\n", button, state); SWindowData *window_data = (SWindowData *) data; - kCall(mouse_btn_func, (MouseButton) (button - BTN_MOUSE + 1), (KeyMod) window_data->mod_keys, state == 1); + kCall(mouse_btn_func, (mfb_mouse_button) (button - BTN_MOUSE + 1), (mfb_key_mod) window_data->mod_keys, state == 1); } // Scroll and other axis notifications. @@ -352,10 +353,10 @@ pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axi //printf("Pointer handle axis: axis: %d (0x%x)\n", axis, value); SWindowData *window_data = (SWindowData *) data; if(axis == 0) { - kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, 0.0f, -(value / 256.0f)); + kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 0.0f, -(value / 256.0f)); } else if(axis == 1) { - kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, -(value / 256.0f), 0.0f); + kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, -(value / 256.0f), 0.0f); } } @@ -388,7 +389,8 @@ axis_discrete(void *data, struct wl_pointer *pointer, uint32_t axis, int32_t dis kUnused(discrete); } -static const struct wl_pointer_listener pointer_listener = { +static const struct +wl_pointer_listener pointer_listener = { .enter = pointer_enter, .leave = pointer_leave, .motion = pointer_motion, @@ -439,7 +441,8 @@ seat_name(void *data, struct wl_seat *seat, const char *name) { printf("Seat '%s'n", name); } -static const struct wl_seat_listener seat_listener = { +static const struct +wl_seat_listener seat_listener = { .capabilities = seat_capabilities, .name = 0x0, }; @@ -475,7 +478,8 @@ shm_format(void *data, struct wl_shm *shm, uint32_t format) } } -static const struct wl_shm_listener shm_listener = { +static const struct +wl_shm_listener shm_listener = { .format = shm_format }; @@ -515,7 +519,8 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id, char cons } } -static const struct wl_registry_listener registry_listener = { +static const struct +wl_registry_listener registry_listener = { .global = registry_global, .global_remove = 0x0, }; @@ -552,14 +557,14 @@ static const struct wl_shell_surface_listener shell_surface_listener = { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -struct Window * +struct mfb_window * mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) { // TODO: Not yet kUnused(flags); return mfb_open(title, width, height); } -struct Window * +struct mfb_window * mfb_open(const char *title, unsigned width, unsigned height) { int fd = -1; @@ -662,11 +667,11 @@ mfb_open(const char *title, unsigned width, unsigned height) wl_surface_damage(window_data_way->surface, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height); wl_surface_commit(window_data_way->surface); - mfb_set_keyboard_callback((struct Window *) window_data, keyboard_default); + mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default); printf("Window created using Wayland API\n"); - return (struct Window *) window_data; + return (struct mfb_window *) window_data; out: close(fd); @@ -688,12 +693,13 @@ frame_done(void *data, struct wl_callback *callback, uint32_t cookie) *(uint32_t *)data = 1; } -static const struct wl_callback_listener frame_listener = { +static const struct +wl_callback_listener frame_listener = { .done = frame_done, }; -UpdateState -mfb_update(struct Window *window, void *buffer) +mfb_update_state +mfb_update(struct mfb_window *window, void *buffer) { uint32_t done = 0; @@ -739,8 +745,8 @@ mfb_update(struct Window *window, void *buffer) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -UpdateState -mfb_update_events(struct Window *window) +mfb_update_state +mfb_update_events(struct mfb_window *window) { if(window == 0x0) { return STATE_INVALID_WINDOW; @@ -896,7 +902,7 @@ init_keycodes(void) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool -mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { +mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { SWindowData *window_data = (SWindowData *) window; diff --git a/src/windows/WinMiniFB.c b/src/windows/WinMiniFB.c index 6f2964d..cca2c4d 100644 --- a/src/windows/WinMiniFB.c +++ b/src/windows/WinMiniFB.c @@ -12,10 +12,11 @@ long s_window_style = WS_POPUP | WS_SYSMENU | WS_CAPTION; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// uint32_t translate_mod(); -Key translate_key(unsigned int wParam, unsigned long lParam); -void destroy_window_data(SWindowData *window_data); +mfb_key translate_key(unsigned int wParam, unsigned long lParam); +void destroy_window_data(SWindowData *window_data); -LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { +LRESULT CALLBACK +WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { LRESULT res = 0; SWindowData *window_data = (SWindowData *) GetWindowLongPtr(hWnd, GWLP_USERDATA); @@ -69,7 +70,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_SYSKEYUP: { if (window_data) { - Key key_code = translate_key((unsigned int)wParam, (unsigned long)lParam); + mfb_key key_code = translate_key((unsigned int)wParam, (unsigned long)lParam); int is_pressed = !((lParam >> 31) & 1); window_data->mod_keys = translate_mod(); @@ -113,8 +114,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_XBUTTONDBLCLK: { if (window_data) { - MouseButton button = MOUSE_BTN_0; - window_data->mod_keys = translate_mod(); + mfb_mouse_button button = MOUSE_BTN_0; + window_data->mod_keys = translate_mod(); int is_pressed = 0; switch(message) { case WM_LBUTTONDOWN: @@ -219,7 +220,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -struct Window *mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) { +struct mfb_window * +mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) { RECT rect = { 0 }; int x = 0, y = 0; @@ -357,18 +359,20 @@ struct Window *mfb_open_ex(const char *title, unsigned width, unsigned height, u window_data_win->hdc = GetDC(window_data_win->window); - mfb_set_keyboard_callback((struct Window *) window_data, keyboard_default); + mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default); - return (struct Window *) window_data; + return (struct mfb_window *) window_data; } -struct Window *mfb_open(const char *title, unsigned width, unsigned height) { +struct mfb_window * +mfb_open(const char *title, unsigned width, unsigned height) { return mfb_open_ex(title, width, height, 0); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -UpdateState mfb_update(struct Window *window, void *buffer) { +mfb_update_state +mfb_update(struct mfb_window *window, void *buffer) { MSG msg; if (window == 0x0) { @@ -401,7 +405,8 @@ UpdateState mfb_update(struct Window *window, void *buffer) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -UpdateState mfb_update_events(struct Window *window) { +mfb_update_state +mfb_update_events(struct mfb_window *window) { MSG msg; if (window == 0x0) { @@ -428,7 +433,8 @@ UpdateState mfb_update_events(struct Window *window) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void destroy_window_data(SWindowData *window_data) { +void +destroy_window_data(SWindowData *window_data) { if (window_data == 0x0) return; @@ -452,7 +458,8 @@ void destroy_window_data(SWindowData *window_data) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -uint32_t translate_mod() { +uint32_t +translate_mod() { uint32_t mods = 0; if (GetKeyState(VK_SHIFT) & 0x8000) @@ -475,7 +482,8 @@ uint32_t translate_mod() { extern short int g_keycodes[512]; -void init_keycodes() { +void +init_keycodes() { // Clear keys for (size_t i = 0; i < sizeof(g_keycodes) / sizeof(g_keycodes[0]); ++i) @@ -606,7 +614,8 @@ void init_keycodes() { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -Key translate_key(unsigned int wParam, unsigned long lParam) { +mfb_key +translate_key(unsigned int wParam, unsigned long lParam) { if (wParam == VK_CONTROL) { MSG next; DWORD time; @@ -626,12 +635,13 @@ Key translate_key(unsigned int wParam, unsigned long lParam) { if (wParam == VK_PROCESSKEY) return KB_KEY_UNKNOWN; - return (Key) g_keycodes[HIWORD(lParam) & 0x1FF]; + return (mfb_key) g_keycodes[HIWORD(lParam) & 0x1FF]; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { +bool +mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { SWindowData *window_data = (SWindowData *) window; if (offset_x + width > window_data->window_width) { diff --git a/src/x11/WindowData_X11.h b/src/x11/WindowData_X11.h index fb3490f..ccecd79 100644 --- a/src/x11/WindowData_X11.h +++ b/src/x11/WindowData_X11.h @@ -1,20 +1,20 @@ -#pragma once - -#include -#include -#include - - -typedef struct { - Window window; - - Display *display; - int screen; - GC gc; - XImage *image; - - void *image_buffer; - XImage *image_scaler; - uint32_t image_scaler_width; - uint32_t image_scaler_height; -} SWindowData_X11; +#pragma once + +#include +#include +#include + + +typedef struct { + Window window; + + Display *display; + int screen; + GC gc; + XImage *image; + + void *image_buffer; + XImage *image_scaler; + uint32_t image_scaler_width; + uint32_t image_scaler_height; +} SWindowData_X11; diff --git a/src/x11/X11MiniFB.c b/src/x11/X11MiniFB.c index 1463d7e..b797487 100644 --- a/src/x11/X11MiniFB.c +++ b/src/x11/X11MiniFB.c @@ -20,7 +20,7 @@ stretch_image(uint32_t *srcImage, uint32_t srcX, uint32_t srcY, uint32_t srcWidt /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -struct Window * +struct mfb_window * mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) { int depth, i, formatCount, convDepth = -1; XPixmapFormatValues* formats; @@ -185,14 +185,14 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) window_data_x11->image = XCreateImage(window_data_x11->display, CopyFromParent, depth, ZPixmap, 0, 0x0, width, height, 32, width * 4); - mfb_set_keyboard_callback((struct Window *) window_data, keyboard_default); + mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default); printf("Window created using X11 API\n"); - return (struct Window *) window_data; + return (struct mfb_window *) window_data; } -struct Window * +struct mfb_window * mfb_open(const char *title, unsigned width, unsigned height) { return mfb_open_ex(title, width, height, 0); } @@ -203,7 +203,8 @@ int translate_key(int scancode); int translate_mod(int state); int translate_mod_ex(int key, int state, int is_pressed); -static void processEvents(SWindowData *window_data) { +static void +processEvents(SWindowData *window_data) { XEvent event; SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; @@ -214,44 +215,44 @@ static void processEvents(SWindowData *window_data) { case KeyPress: case KeyRelease: { - Key key_code = (Key) translate_key(event.xkey.keycode); - int is_pressed = (event.type == KeyPress); + mfb_key key_code = (mfb_key) translate_key(event.xkey.keycode); + int is_pressed = (event.type == KeyPress); window_data->mod_keys = translate_mod_ex(key_code, event.xkey.state, is_pressed); window_data->key_status[key_code] = is_pressed; - kCall(keyboard_func, key_code, (KeyMod) window_data->mod_keys, is_pressed); + kCall(keyboard_func, key_code, (mfb_key_mod) window_data->mod_keys, is_pressed); } break; case ButtonPress: case ButtonRelease: { - MouseButton button = (MouseButton) event.xbutton.button; + mfb_mouse_button button = (mfb_mouse_button) event.xbutton.button; int is_pressed = (event.type == ButtonPress); - window_data->mod_keys = translate_mod(event.xkey.state); + window_data->mod_keys = translate_mod(event.xkey.state); switch (button) { case Button1: case Button2: case Button3: - kCall(mouse_btn_func, button, (KeyMod) window_data->mod_keys, is_pressed); + kCall(mouse_btn_func, button, (mfb_key_mod) window_data->mod_keys, is_pressed); break; case Button4: - kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, 0.0f, 1.0f); + kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 0.0f, 1.0f); break; case Button5: - kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, 0.0f, -1.0f); + kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 0.0f, -1.0f); break; case 6: - kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, 1.0f, 0.0f); + kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 1.0f, 0.0f); break; case 7: - kCall(mouse_wheel_func, (KeyMod) window_data->mod_keys, -1.0f, 0.0f); + kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, -1.0f, 0.0f); break; default: - kCall(mouse_btn_func, (MouseButton) (button - 4), (KeyMod) window_data->mod_keys, is_pressed); + kCall(mouse_btn_func, (mfb_mouse_button) (button - 4), (mfb_key_mod) window_data->mod_keys, is_pressed); break; } } @@ -303,7 +304,8 @@ static void processEvents(SWindowData *window_data) { void destroy(SWindowData *window_data); -UpdateState mfb_update(struct Window *window, void *buffer) { +mfb_update_state +mfb_update(struct mfb_window *window, void *buffer) { if (window == 0x0) { return STATE_INVALID_WINDOW; } @@ -358,7 +360,8 @@ UpdateState mfb_update(struct Window *window, void *buffer) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -UpdateState mfb_update_events(struct Window *window) { +mfb_update_state +mfb_update_events(struct mfb_window *window) { if (window == 0x0) { return STATE_INVALID_WINDOW; } @@ -378,7 +381,8 @@ UpdateState mfb_update_events(struct Window *window) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void destroy(SWindowData *window_data) { +void +destroy(SWindowData *window_data) { if (window_data != 0x0) { if (window_data->specific != 0x0) { SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; @@ -400,7 +404,8 @@ void destroy(SWindowData *window_data) { extern short int g_keycodes[512]; -static int translateKeyCodeB(int keySym) { +static int +translateKeyCodeB(int keySym) { switch (keySym) { @@ -563,7 +568,8 @@ static int translateKeyCodeA(int keySym) { return KB_KEY_UNKNOWN; } -void init_keycodes(SWindowData_X11 *window_data_x11) { +void +init_keycodes(SWindowData_X11 *window_data_x11) { size_t i; int keySym; @@ -585,7 +591,8 @@ void init_keycodes(SWindowData_X11 *window_data_x11) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int translate_key(int scancode) { +int +translate_key(int scancode) { if (scancode < 0 || scancode > 255) return KB_KEY_UNKNOWN; @@ -594,7 +601,8 @@ int translate_key(int scancode) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int translate_mod(int state) { +int +translate_mod(int state) { int mod_keys = 0; if (state & ShiftMask) @@ -615,7 +623,8 @@ int translate_mod(int state) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int translate_mod_ex(int key, int state, int is_pressed) { +int +translate_mod_ex(int key, int state, int is_pressed) { int mod_keys = 0; mod_keys = translate_mod(state); @@ -660,7 +669,8 @@ int translate_mod_ex(int key, int state, int is_pressed) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool mfb_set_viewport(struct Window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { +bool +mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { SWindowData *window_data = (SWindowData *) window; if (offset_x + width > window_data->window_width) { diff --git a/tests/input_events.c b/tests/input_events.c index b99fa2f..9657455 100644 --- a/tests/input_events.c +++ b/tests/input_events.c @@ -1,141 +1,149 @@ -#include -#include -#include - -#define kUnused(var) (void) var - -#define WIDTH 800 -#define HEIGHT 600 -static unsigned int g_buffer[WIDTH * HEIGHT]; -static bool g_active = true; - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void active(struct Window *window, bool isActive) { - const char *window_title = ""; - if(window) { - window_title = (const char *) mfb_get_user_data(window); - } - fprintf(stdout, "%s > active: %d\n", window_title, isActive); - g_active = isActive; -} - -void resize(struct Window *window, int width, int height) { - uint32_t x = 0; - uint32_t y = 0; - const char *window_title = ""; - if(window) { - window_title = (const char *) mfb_get_user_data(window); - } - - fprintf(stdout, "%s > resize: %d, %d\n", window_title, width, height); - if(width > WIDTH) { - x = (width - WIDTH) >> 1; - width = WIDTH; - } - if(height > HEIGHT) { - y = (height - HEIGHT) >> 1; - height = HEIGHT; - } - mfb_set_viewport(window, x, y, width, height); -} - -void keyboard(struct Window *window, Key key, KeyMod mod, bool isPressed) { - const char *window_title = ""; - if(window) { - window_title = (const char *) mfb_get_user_data(window); - } - fprintf(stdout, "%s > keyboard: key: %s (pressed: %d) [KeyMod: %x]\n", window_title, mfb_get_key_name(key), isPressed, mod); - if(key == KB_KEY_ESCAPE) { - mfb_close(window); - } -} - -void char_input(struct Window *window, unsigned int charCode) { - const char *window_title = ""; - if(window) { - window_title = (const char *) mfb_get_user_data(window); - } - fprintf(stdout, "%s > charCode: %d\n", window_title, charCode); -} - -void mouse_btn(struct Window *window, MouseButton button, KeyMod mod, bool isPressed) { - const char *window_title = ""; - if(window) { - window_title = (const char *) mfb_get_user_data(window); - } - fprintf(stdout, "%s > mouse_btn: button: %d (pressed: %d) [KeyMod: %x]\n", window_title, button, isPressed, mod); -} - -void mouse_move(struct Window *window, int x, int y) { - kUnused(window); - kUnused(x); - kUnused(y); - // const char *window_title = ""; - // if(window) { - // window_t(const char *) itle = mfb_get_user_data(window); - // } - //fprintf(stdout, "%s > mouse_move: %d, %d\n", window_title, x, y); -} - -void mouse_scroll(struct Window *window, KeyMod mod, float deltaX, float deltaY) { - const char *window_title = ""; - if(window) { - window_title = (const char *) mfb_get_user_data(window); - } - fprintf(stdout, "%s > mouse_scroll: x: %f, y: %f [KeyMod: %x]\n", window_title, deltaX, deltaY, mod); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int main() -{ - int noise, carry, seed = 0xbeef; - - struct Window *window = mfb_open_ex("Input Events Test", WIDTH, HEIGHT, WF_RESIZABLE); - if (!window) - return 0; - - mfb_set_active_callback(window, active); - mfb_set_resize_callback(window, resize); - mfb_set_keyboard_callback(window, keyboard); - mfb_set_char_input_callback(window, char_input); - mfb_set_mouse_button_callback(window, mouse_btn); - mfb_set_mouse_move_callback(window, mouse_move); - mfb_set_mouse_scroll_callback(window, mouse_scroll); - - mfb_set_user_data(window, (void *) "Input Events Test"); - - for (;;) - { - int i; - UpdateState state; - - if(g_active) - { - for (i = 0; i < WIDTH * HEIGHT; ++i) - { - noise = seed; - noise >>= 3; - noise ^= seed; - carry = noise & 1; - noise >>= 1; - seed >>= 1; - seed |= (carry << 30); - noise &= 0xFF; - g_buffer[i] = MFB_RGB(noise, noise, noise); - } - - state = mfb_update(window, g_buffer); - } - else { - state = mfb_update_events(window); - } - if (state != STATE_OK) { - window = 0x0; - break; - } - } - - return 0; -} +#include +#include +#include + +#define kUnused(var) (void) var + +#define WIDTH 800 +#define HEIGHT 600 +static unsigned int g_buffer[WIDTH * HEIGHT]; +static bool g_active = true; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void +active(struct mfb_window *window, bool isActive) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > active: %d\n", window_title, isActive); + g_active = isActive; +} + +void +resize(struct mfb_window *window, int width, int height) { + uint32_t x = 0; + uint32_t y = 0; + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + + fprintf(stdout, "%s > resize: %d, %d\n", window_title, width, height); + if(width > WIDTH) { + x = (width - WIDTH) >> 1; + width = WIDTH; + } + if(height > HEIGHT) { + y = (height - HEIGHT) >> 1; + height = HEIGHT; + } + mfb_set_viewport(window, x, y, width, height); +} + +void +keyboard(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > keyboard: key: %s (pressed: %d) [key_mod: %x]\n", window_title, mfb_get_key_name(key), isPressed, mod); + if(key == KB_KEY_ESCAPE) { + mfb_close(window); + } +} + +void +char_input(struct mfb_window *window, unsigned int charCode) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > charCode: %d\n", window_title, charCode); +} + +void +mouse_btn(struct mfb_window *window, mfb_mouse_button button, mfb_key_mod mod, bool isPressed) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > mouse_btn: button: %d (pressed: %d) [key_mod: %x]\n", window_title, button, isPressed, mod); +} + +void +mouse_move(struct mfb_window *window, int x, int y) { + kUnused(window); + kUnused(x); + kUnused(y); + // const char *window_title = ""; + // if(window) { + // window_t(const char *) itle = mfb_get_user_data(window); + // } + //fprintf(stdout, "%s > mouse_move: %d, %d\n", window_title, x, y); +} + +void +mouse_scroll(struct mfb_window *window, mfb_key_mod mod, float deltaX, float deltaY) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > mouse_scroll: x: %f, y: %f [key_mod: %x]\n", window_title, deltaX, deltaY, mod); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int +main() +{ + int noise, carry, seed = 0xbeef; + + struct mfb_window *window = mfb_open_ex("Input Events Test", WIDTH, HEIGHT, WF_RESIZABLE); + if (!window) + return 0; + + mfb_set_active_callback(window, active); + mfb_set_resize_callback(window, resize); + mfb_set_keyboard_callback(window, keyboard); + mfb_set_char_input_callback(window, char_input); + mfb_set_mouse_button_callback(window, mouse_btn); + mfb_set_mouse_move_callback(window, mouse_move); + mfb_set_mouse_scroll_callback(window, mouse_scroll); + + mfb_set_user_data(window, (void *) "Input Events Test"); + + for (;;) + { + int i; + mfb_update_state state; + + if(g_active) + { + for (i = 0; i < WIDTH * HEIGHT; ++i) + { + noise = seed; + noise >>= 3; + noise ^= seed; + carry = noise & 1; + noise >>= 1; + seed >>= 1; + seed |= (carry << 30); + noise &= 0xFF; + g_buffer[i] = MFB_RGB(noise, noise, noise); + } + + state = mfb_update(window, g_buffer); + } + else { + state = mfb_update_events(window); + } + if (state != STATE_OK) { + window = 0x0; + break; + } + } + + return 0; +} diff --git a/tests/input_events_cpp.cpp b/tests/input_events_cpp.cpp index 4429cda..13cfd22 100644 --- a/tests/input_events_cpp.cpp +++ b/tests/input_events_cpp.cpp @@ -1,138 +1,139 @@ -#include -#include -#include - -#define kUnused(var) (void) var; - -#define WIDTH 800 -#define HEIGHT 600 -static unsigned int g_buffer[WIDTH * HEIGHT]; - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -class Events { -public: - void active(struct Window *window, bool isActive) { - const char *window_title = ""; - if(window) { - window_title = (const char *) mfb_get_user_data(window); - } - fprintf(stdout, "%s > active: %d\n", window_title, isActive); - } - - void resize(struct Window *window, int width, int height) { - uint32_t x = 0; - uint32_t y = 0; - const char *window_title = ""; - if(window) { - window_title = (const char *) mfb_get_user_data(window); - } - - fprintf(stdout, "%s > resize: %d, %d\n", window_title, width, height); - if(width > WIDTH) { - x = (width - WIDTH) >> 1; - width = WIDTH; - } - if(height > HEIGHT) { - y = (height - HEIGHT) >> 1; - height = HEIGHT; - } - mfb_set_viewport(window, x, y, width, height); - } - - void keyboard(struct Window *window, Key key, KeyMod mod, bool isPressed) { - const char *window_title = ""; - if(window) { - window_title = (const char *) mfb_get_user_data(window); - } - fprintf(stdout, "%s > keyboard: key: %s (pressed: %d) [KeyMod: %x]\n", window_title, mfb_get_key_name(key), isPressed, mod); - if(key == KB_KEY_ESCAPE) { - mfb_close(window); - } - } - - void char_input(struct Window *window, unsigned int charCode) { - const char *window_title = ""; - if(window) { - window_title = (const char *) mfb_get_user_data(window); - } - fprintf(stdout, "%s > charCode: %d\n", window_title, charCode); - } - - void mouse_btn(struct Window *window, MouseButton button, KeyMod mod, bool isPressed) { - const char *window_title = ""; - if(window) { - window_title = (const char *) mfb_get_user_data(window); - } - fprintf(stdout, "%s > mouse_btn: button: %d (pressed: %d) [KeyMod: %x]\n", window_title, button, isPressed, mod); - } - - void mouse_move(struct Window *window, int x, int y) { - kUnused(window); - kUnused(x); - kUnused(y); - // const char *window_title = ""; - // if(window) { - // window_t(const char *) itle = mfb_get_user_data(window); - // } - //fprintf(stdout, "%s > mouse_move: %d, %d\n", window_title, x, y); - } - - void mouse_scroll(struct Window *window, KeyMod mod, float deltaX, float deltaY) { - const char *window_title = ""; - if(window) { - window_title = (const char *) mfb_get_user_data(window); - } - fprintf(stdout, "%s > mouse_scroll: x: %f, y: %f [KeyMod: %x]\n", window_title, deltaX, deltaY, mod); - } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int main() -{ - int noise, carry, seed = 0xbeef; - - struct Window *window = mfb_open_ex("Input Events CPP Test", WIDTH, HEIGHT, WF_RESIZABLE); - if (!window) - return 0; - - Events e; - - mfb_set_active_callback(window, &e, &Events::active); - mfb_set_resize_callback(window, &e, &Events::resize); - mfb_set_keyboard_callback(window, &e, &Events::keyboard); - mfb_set_char_input_callback(window, &e, &Events::char_input); - mfb_set_mouse_button_callback(window, &e, &Events::mouse_btn); - mfb_set_mouse_move_callback(window, &e, &Events::mouse_move); - mfb_set_mouse_scroll_callback(window, &e, &Events::mouse_scroll); - - mfb_set_user_data(window, (void *) "Input Events CPP Test"); - - for (;;) - { - int i; - UpdateState state; - - for (i = 0; i < WIDTH * HEIGHT; ++i) - { - noise = seed; - noise >>= 3; - noise ^= seed; - carry = noise & 1; - noise >>= 1; - seed >>= 1; - seed |= (carry << 30); - noise &= 0xFF; - g_buffer[i] = MFB_RGB(noise, noise, noise); - } - - state = mfb_update(window, g_buffer); - if (state != STATE_OK) { - window = 0x0; - break; - } - } - - return 0; -} +#include +#include +#include + +#define kUnused(var) (void) var; + +#define WIDTH 800 +#define HEIGHT 600 +static unsigned int g_buffer[WIDTH * HEIGHT]; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class Events { +public: + void active(struct mfb_window *window, bool isActive) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > active: %d\n", window_title, isActive); + } + + void resize(struct mfb_window *window, int width, int height) { + uint32_t x = 0; + uint32_t y = 0; + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + + fprintf(stdout, "%s > resize: %d, %d\n", window_title, width, height); + if(width > WIDTH) { + x = (width - WIDTH) >> 1; + width = WIDTH; + } + if(height > HEIGHT) { + y = (height - HEIGHT) >> 1; + height = HEIGHT; + } + mfb_set_viewport(window, x, y, width, height); + } + + void keyboard(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > keyboard: key: %s (pressed: %d) [key_mod: %x]\n", window_title, mfb_get_key_name(key), isPressed, mod); + if(key == KB_KEY_ESCAPE) { + mfb_close(window); + } + } + + void char_input(struct mfb_window *window, unsigned int charCode) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > charCode: %d\n", window_title, charCode); + } + + void mouse_btn(struct mfb_window *window, mfb_mouse_button button, mfb_key_mod mod, bool isPressed) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > mouse_btn: button: %d (pressed: %d) [key_mod: %x]\n", window_title, button, isPressed, mod); + } + + void mouse_move(struct mfb_window *window, int x, int y) { + kUnused(window); + kUnused(x); + kUnused(y); + // const char *window_title = ""; + // if(window) { + // window_t(const char *) itle = mfb_get_user_data(window); + // } + //fprintf(stdout, "%s > mouse_move: %d, %d\n", window_title, x, y); + } + + void mouse_scroll(struct mfb_window *window, mfb_key_mod mod, float deltaX, float deltaY) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > mouse_scroll: x: %f, y: %f [key_mod: %x]\n", window_title, deltaX, deltaY, mod); + } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int +main() +{ + int noise, carry, seed = 0xbeef; + + struct mfb_window *window = mfb_open_ex("Input Events CPP Test", WIDTH, HEIGHT, WF_RESIZABLE); + if (!window) + return 0; + + Events e; + + mfb_set_active_callback(window, &e, &Events::active); + mfb_set_resize_callback(window, &e, &Events::resize); + mfb_set_keyboard_callback(window, &e, &Events::keyboard); + mfb_set_char_input_callback(window, &e, &Events::char_input); + mfb_set_mouse_button_callback(window, &e, &Events::mouse_btn); + mfb_set_mouse_move_callback(window, &e, &Events::mouse_move); + mfb_set_mouse_scroll_callback(window, &e, &Events::mouse_scroll); + + mfb_set_user_data(window, (void *) "Input Events CPP Test"); + + for (;;) + { + int i; + mfb_update_state state; + + for (i = 0; i < WIDTH * HEIGHT; ++i) + { + noise = seed; + noise >>= 3; + noise ^= seed; + carry = noise & 1; + noise >>= 1; + seed >>= 1; + seed |= (carry << 30); + noise &= 0xFF; + g_buffer[i] = MFB_RGB(noise, noise, noise); + } + + state = mfb_update(window, g_buffer); + if (state != STATE_OK) { + window = 0x0; + break; + } + } + + return 0; +} diff --git a/tests/multiple_windows.c b/tests/multiple_windows.c index f8a3499..c45854b 100644 --- a/tests/multiple_windows.c +++ b/tests/multiple_windows.c @@ -1,188 +1,197 @@ -#include -#include -#include -#define _USE_MATH_DEFINES -#include - -#define kPI 3.14159265358979323846f -#define kUnused(var) (void) var; - -#define WIDTH_A 800 -#define HEIGHT_A 600 -static unsigned int g_buffer_a[WIDTH_A * HEIGHT_A]; - -#define WIDTH_B 320 -#define HEIGHT_B 240 -static unsigned int g_buffer_b[WIDTH_B * HEIGHT_B]; - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void active(struct Window *window, bool isActive) { - const char *window_title = ""; - if(window) { - window_title = (const char *) mfb_get_user_data(window); - } - fprintf(stdout, "%s > active: %d\n", window_title, isActive); -} - -void resize(struct Window *window, int width, int height) { - const char *window_title = ""; - if(window) { - window_title = (const char *) mfb_get_user_data(window); - } - - fprintf(stdout, "%s > resize: %d, %d\n", window_title, width, height); -} - -void keyboard(struct Window *window, Key key, KeyMod mod, bool isPressed) { - const char *window_title = ""; - if(window) { - window_title = (const char *) mfb_get_user_data(window); - } - fprintf(stdout, "%s > keyboard: key: %s (pressed: %d) [KeyMod: %x]\n", window_title, mfb_get_key_name(key), isPressed, mod); - if(key == KB_KEY_ESCAPE) { - mfb_close(window); - } -} - -void char_input(struct Window *window, unsigned int charCode) { - const char *window_title = ""; - if(window) { - window_title = (const char *) mfb_get_user_data(window); - } - fprintf(stdout, "%s > charCode: %d\n", window_title, charCode); -} - -void mouse_btn(struct Window *window, MouseButton button, KeyMod mod, bool isPressed) { - const char *window_title = ""; - if(window) { - window_title = (const char *) mfb_get_user_data(window); - } - fprintf(stdout, "%s > mouse_btn: button: %d (pressed: %d) [KeyMod: %x]\n", window_title, button, isPressed, mod); -} - -void mouse_move(struct Window *window, int x, int y) { - kUnused(window); - kUnused(x); - kUnused(y); - // const char *window_title = ""; - // if(window) { - // window_t(const char *) itle = mfb_get_user_data(window); - // } - //fprintf(stdout, "%s > mouse_move: %d, %d\n", window_title, x, y); -} - -void mouse_scroll(struct Window *window, KeyMod mod, float deltaX, float deltaY) { - const char *window_title = ""; - if(window) { - window_title = (const char *) mfb_get_user_data(window); - } - fprintf(stdout, "%s > mouse_scroll: x: %f, y: %f [KeyMod: %x]\n", window_title, deltaX, deltaY, mod); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int main() -{ - int noise, carry, seed = 0xbeef; - - struct Window *window_a = mfb_open_ex("Multiple Windows Test", WIDTH_A, HEIGHT_A, WF_RESIZABLE); - if (!window_a) - return 0; - - mfb_set_active_callback(window_a, active); - mfb_set_resize_callback(window_a, resize); - mfb_set_keyboard_callback(window_a, keyboard); - mfb_set_char_input_callback(window_a, char_input); - mfb_set_mouse_button_callback(window_a, mouse_btn); - mfb_set_mouse_move_callback(window_a, mouse_move); - mfb_set_mouse_scroll_callback(window_a, mouse_scroll); - - mfb_set_user_data(window_a, (void *) "Window A"); - - //-- - struct Window *window_b = mfb_open_ex("Secondary Window", WIDTH_B, HEIGHT_B, WF_RESIZABLE); - if (!window_b) - return 0; - - mfb_set_active_callback(window_b, active); - mfb_set_resize_callback(window_b, resize); - mfb_set_keyboard_callback(window_b, keyboard); - mfb_set_char_input_callback(window_b, char_input); - mfb_set_mouse_button_callback(window_b, mouse_btn); - mfb_set_mouse_move_callback(window_b, mouse_move); - mfb_set_mouse_scroll_callback(window_b, mouse_scroll); - - mfb_set_user_data(window_b, (void *) "Window B"); - - // Generate pallete for plasma effect - uint32_t pallete[512]; - float inc = 90.0f / 64.0f; - for(uint32_t c=0; c<64; ++c) { - int32_t col = (int32_t) ((255.0f * sinf(c * inc * kPI / 180.0f)) + 0.5f); - pallete[64*0 + c] = MFB_RGB(col, 0, 0); - pallete[64*1 + c] = MFB_RGB(255, col, 0); - pallete[64*2 + c] = MFB_RGB(255-col, 255, 0); - pallete[64*3 + c] = MFB_RGB(0, 255, col); - pallete[64*4 + c] = MFB_RGB(0, 255-col, 255); - pallete[64*5 + c] = MFB_RGB(col, 0, 255); - pallete[64*6 + c] = MFB_RGB(255, 0, 255-col); - pallete[64*7 + c] = MFB_RGB(255-col, 0, 0); - } - - //-- - float time = 0; - for (;;) - { - int i, x, y; - float dx, dy, time_x, time_y; - int index; - UpdateState state_a, state_b; - - for (i = 0; i < WIDTH_A * HEIGHT_A; ++i) - { - noise = seed; - noise >>= 3; - noise ^= seed; - carry = noise & 1; - noise >>= 1; - seed >>= 1; - seed |= (carry << 30); - noise &= 0xFF; - g_buffer_a[i] = MFB_RGB(noise, noise, noise); - } - - //-- - time_x = sinf(time * kPI / 180.0f); - time_y = cosf(time * kPI / 180.0f); - i = 0; - for(y=0; y +#include +#include +#define _USE_MATH_DEFINES +#include + +#define kPI 3.14159265358979323846f +#define kUnused(var) (void) var; + +#define WIDTH_A 800 +#define HEIGHT_A 600 +static unsigned int g_buffer_a[WIDTH_A * HEIGHT_A]; + +#define WIDTH_B 320 +#define HEIGHT_B 240 +static unsigned int g_buffer_b[WIDTH_B * HEIGHT_B]; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void +active(struct mfb_window *window, bool isActive) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > active: %d\n", window_title, isActive); +} + +void +resize(struct mfb_window *window, int width, int height) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + + fprintf(stdout, "%s > resize: %d, %d\n", window_title, width, height); +} + +void +keyboard(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > keyboard: key: %s (pressed: %d) [key_mod: %x]\n", window_title, mfb_get_key_name(key), isPressed, mod); + if(key == KB_KEY_ESCAPE) { + mfb_close(window); + } +} + +void +char_input(struct mfb_window *window, unsigned int charCode) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > charCode: %d\n", window_title, charCode); +} + +void +mouse_btn(struct mfb_window *window, mfb_mouse_button button, mfb_key_mod mod, bool isPressed) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > mouse_btn: button: %d (pressed: %d) [key_mod: %x]\n", window_title, button, isPressed, mod); +} + +void +mouse_move(struct mfb_window *window, int x, int y) { + kUnused(window); + kUnused(x); + kUnused(y); + // const char *window_title = ""; + // if(window) { + // window_t(const char *) itle = mfb_get_user_data(window); + // } + //fprintf(stdout, "%s > mouse_move: %d, %d\n", window_title, x, y); +} + +void +mouse_scroll(struct mfb_window *window, mfb_key_mod mod, float deltaX, float deltaY) { + const char *window_title = ""; + if(window) { + window_title = (const char *) mfb_get_user_data(window); + } + fprintf(stdout, "%s > mouse_scroll: x: %f, y: %f [key_mod: %x]\n", window_title, deltaX, deltaY, mod); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int +main() +{ + int noise, carry, seed = 0xbeef; + + struct mfb_window *window_a = mfb_open_ex("Multiple Windows Test", WIDTH_A, HEIGHT_A, WF_RESIZABLE); + if (!window_a) + return 0; + + mfb_set_active_callback(window_a, active); + mfb_set_resize_callback(window_a, resize); + mfb_set_keyboard_callback(window_a, keyboard); + mfb_set_char_input_callback(window_a, char_input); + mfb_set_mouse_button_callback(window_a, mouse_btn); + mfb_set_mouse_move_callback(window_a, mouse_move); + mfb_set_mouse_scroll_callback(window_a, mouse_scroll); + + mfb_set_user_data(window_a, (void *) "Window A"); + + //-- + struct mfb_window *window_b = mfb_open_ex("Secondary Window", WIDTH_B, HEIGHT_B, WF_RESIZABLE); + if (!window_b) + return 0; + + mfb_set_active_callback(window_b, active); + mfb_set_resize_callback(window_b, resize); + mfb_set_keyboard_callback(window_b, keyboard); + mfb_set_char_input_callback(window_b, char_input); + mfb_set_mouse_button_callback(window_b, mouse_btn); + mfb_set_mouse_move_callback(window_b, mouse_move); + mfb_set_mouse_scroll_callback(window_b, mouse_scroll); + + mfb_set_user_data(window_b, (void *) "Window B"); + + // Generate pallete for plasma effect + uint32_t pallete[512]; + float inc = 90.0f / 64.0f; + for(uint32_t c=0; c<64; ++c) { + int32_t col = (int32_t) ((255.0f * sinf(c * inc * kPI / 180.0f)) + 0.5f); + pallete[64*0 + c] = MFB_RGB(col, 0, 0); + pallete[64*1 + c] = MFB_RGB(255, col, 0); + pallete[64*2 + c] = MFB_RGB(255-col, 255, 0); + pallete[64*3 + c] = MFB_RGB(0, 255, col); + pallete[64*4 + c] = MFB_RGB(0, 255-col, 255); + pallete[64*5 + c] = MFB_RGB(col, 0, 255); + pallete[64*6 + c] = MFB_RGB(255, 0, 255-col); + pallete[64*7 + c] = MFB_RGB(255-col, 0, 0); + } + + //-- + float time = 0; + for (;;) + { + int i, x, y; + float dx, dy, time_x, time_y; + int index; + + mfb_update_state state_a, state_b; + + for (i = 0; i < WIDTH_A * HEIGHT_A; ++i) + { + noise = seed; + noise >>= 3; + noise ^= seed; + carry = noise & 1; + noise >>= 1; + seed >>= 1; + seed |= (carry << 30); + noise &= 0xFF; + g_buffer_a[i] = MFB_RGB(noise, noise, noise); + } + + //-- + time_x = sinf(time * kPI / 180.0f); + time_y = cosf(time * kPI / 180.0f); + i = 0; + for(y=0; y -#include -#include - -#define WIDTH 800 -#define HEIGHT 600 -static unsigned int g_buffer[WIDTH * HEIGHT]; - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int main() -{ - int noise, carry, seed = 0xbeef; - - struct Window *window = mfb_open_ex("Noise Test", WIDTH, HEIGHT, WF_RESIZABLE); - if (!window) - return 0; - - for (;;) - { - int i; - UpdateState state; - - for (i = 0; i < WIDTH * HEIGHT; ++i) - { - noise = seed; - noise >>= 3; - noise ^= seed; - carry = noise & 1; - noise >>= 1; - seed >>= 1; - seed |= (carry << 30); - noise &= 0xFF; - g_buffer[i] = MFB_RGB(noise, noise, noise); - } - - state = mfb_update(window, g_buffer); - if (state != STATE_OK) { - window = 0x0; - break; - } - } - - return 0; -} +#include +#include +#include + +#define WIDTH 800 +#define HEIGHT 600 +static unsigned int g_buffer[WIDTH * HEIGHT]; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int +main() +{ + int noise, carry, seed = 0xbeef; + + struct mfb_window *window = mfb_open_ex("Noise Test", WIDTH, HEIGHT, WF_RESIZABLE); + if (!window) + return 0; + + for (;;) + { + int i; + mfb_update_state state; + + for (i = 0; i < WIDTH * HEIGHT; ++i) + { + noise = seed; + noise >>= 3; + noise ^= seed; + carry = noise & 1; + noise >>= 1; + seed >>= 1; + seed |= (carry << 30); + noise &= 0xFF; + g_buffer[i] = MFB_RGB(noise, noise, noise); + } + + state = mfb_update(window, g_buffer); + if (state != STATE_OK) { + window = 0x0; + break; + } + } + + return 0; +} From 661092081c6654d0befac112af822fd84055ee9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Aragon=C3=A9s?= <9335325+Darky-Lucera@users.noreply.github.com> Date: Fri, 6 Mar 2020 07:51:57 +0100 Subject: [PATCH 12/14] Renamed typo scrool by scroll (#29) * update documentation * Fix typo * Added some examples * changed window names * Minor fix * Added mfb_update_events to all platforms. Checked on Windows, X11 and Wayland * simplify CMake * Upgrade to CMake 3.5, simplify script and generalize it Now the users only have to add_directory and link_libraries(minifb) in CMake * Renamed typo scrool by scroll Added some checks Removed some warnings * fix issue 32 Co-authored-by: Carlos Aragones <> Co-authored-by: caragones From 4175cec89e56eae8cf98c653ebc1bb44cc28136c Mon Sep 17 00:00:00 2001 From: Carlos Aragones Date: Sun, 19 Apr 2020 23:04:11 +0200 Subject: [PATCH 13/14] minor fix --- src/windows/WinMiniFB.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/windows/WinMiniFB.c b/src/windows/WinMiniFB.c index cca2c4d..1fb45b7 100644 --- a/src/windows/WinMiniFB.c +++ b/src/windows/WinMiniFB.c @@ -422,7 +422,7 @@ mfb_update_events(struct mfb_window *window) { SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific; while (window_data->close == false && PeekMessage(&msg, window_data_win->window, 0, 0, PM_REMOVE)) { if(msg.message == WM_PAINT) - return; + return STATE_OK; TranslateMessage(&msg); DispatchMessage(&msg); From 35b8439b26adffc7a4b07d5ad1b4a6380c6baf86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Aragon=C3=A9s?= <9335325+Darky-Lucera@users.noreply.github.com> Date: Wed, 22 Apr 2020 13:00:15 +0200 Subject: [PATCH 14/14] Add timers and ability to set a target fps for the application (#36) * working on windows * minor fix * working on macosx * Oops! I reversed resolution and frequency on macos * working on X11 * working on wayland * update the readme * format the readme Co-authored-by: Carlos Aragones <> --- CMakeLists.txt | 10 +- README.md | 267 +++++++++++++++++++++-------------- include/MiniFB.h | 11 ++ include/MiniFB_enums.h | 1 + src/MiniFB_internal.h | 7 + src/MiniFB_linux.c | 32 +++++ src/MiniFB_timer.c | 102 +++++++++++++ src/macosx/MacMiniFB.m | 96 ++++++++++++- src/macosx/WindowData_OSX.h | 4 +- src/wayland/WaylandMiniFB.c | 54 ++++++- src/wayland/WindowData_Way.h | 1 + src/windows/WinMiniFB.c | 84 ++++++++++- src/windows/WindowData_Win.h | 11 +- src/x11/WindowData_X11.h | 23 +-- src/x11/X11MiniFB.c | 241 +++++++++++++++++++------------ tests/input_events.c | 5 +- tests/input_events_cpp.cpp | 8 +- tests/multiple_windows.c | 8 ++ tests/noise.c | 8 +- 19 files changed, 734 insertions(+), 239 deletions(-) create mode 100644 src/MiniFB_linux.c create mode 100644 src/MiniFB_timer.c diff --git a/CMakeLists.txt b/CMakeLists.txt index ed7d20d..bee40ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ set(SrcLib src/MiniFB_cpp.cpp src/MiniFB_internal.c src/MiniFB_internal.h + src/MiniFB_timer.c src/WindowData.h ) @@ -34,11 +35,13 @@ set(SrcMacOSX set(SrcWayland src/wayland/WaylandMiniFB.c src/wayland/WindowData_Way.h + src/MiniFB_linux.c ) set(SrcX11 src/x11/X11MiniFB.c src/x11/WindowData_X11.h + src/MiniFB_linux.c ) # Avoid RelWithDebInfo and MinSizeRel @@ -52,6 +55,12 @@ if(NOT CMAKE_BUILD_TYPE) message(STATUS "Build type not specified: Use Release by default") endif(NOT CMAKE_BUILD_TYPE) +# Set features +#-------------------------------------- +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + # Set GCC/Clang flags #-------------------------------------- if (NOT MSVC) @@ -78,7 +87,6 @@ if (NOT MSVC) add_compile_options("$<$:-g>") add_compile_options("$,-O0,-O2>") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -pedantic -Wno-switch -Wno-unused-function -Wno-implicit-fallthrough") - set (CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11") set (CMAKE_OBJC_FLAGS "${CMAKE_C_FLAGS}") set (CMAKE_OBJCXX_FLAGS "${CMAKE_CXX_FLAGS}") endif() diff --git a/README.md b/README.md index 9cf7769..134e5eb 100644 --- a/README.md +++ b/README.md @@ -1,117 +1,173 @@ -MiniFB -====== +# MiniFB MiniFB (Mini FrameBuffer) is a small cross platform library that makes it easy to render (32-bit) pixels in a window. An example is the best way to show how it works: - struct mfb_window *window = mfb_open_ex("my display", 800, 600, WF_RESIZABLE); - if (!window) - return 0; +```c +struct mfb_window *window = mfb_open_ex("my display", 800, 600, WF_RESIZABLE); +if (!window) + return 0; - for (;;) - { - int state; +for (;;) +{ + int state; - // TODO: add some fancy rendering to the buffer of size 800 * 600 + // TODO: add some fancy rendering to the buffer of size 800 * 600 - state = mfb_update(buffer); + state = mfb_update(buffer); - if (state < 0) - break; - } + if (state < 0) + break; +} +``` -Furthermore, you can add callbacks to the windows: +Furthermore, you can _add callbacks to the windows_: - void active(struct mfb_window *window, bool isActive) { - ... - } - - void resize(struct mfb_window *window, int width, int height) { - ... - // Optionally you can also change the viewport size - mfb_set_viewport(window, x, y, width, height); - } - - void keyboard(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed) { - ... - // Remember to close the window in some way - if(key == KB_KEY_ESCAPE) { - mfb_close(window); - } - - fprintf(stdout, "%s > keyboard: key: %s (pressed: %d) [key_mod: %x]\n", window_title, mfb_get_key_name(key), isPressed, mod); - - } - - void char_input(struct mfb_window *window, unsigned int charCode) { - ... - } - - void mouse_btn(struct mfb_window *window, mfb_mouse_button button, mfb_key_mod mod, bool isPressed) { - ... - } - - // Use wisely this event. It can be sent too often - void mouse_move(struct mfb_window *window, int x, int y) { - ... - } - - // Mouse wheel - void mouse_scroll(struct mfb_window *window, mfb_key_mod mod, float deltaX, float deltaY) { - ... - } - - struct mfb_window *window = mfb_open_ex("my display", 800, 600, WF_RESIZABLE); - if (!window) - return 0; - - mfb_set_active_callback(window, active); - mfb_set_resize_callback(window, resize); - mfb_set_keyboard_callback(window, keyboard); - mfb_set_char_input_callback(window, char_input); - mfb_set_mouse_button_callback(window, mouse_btn); - mfb_set_mouse_move_callback(window, mouse_move); - mfb_set_mouse_scroll_callback(window, mouse_scroll); - - -Additionally you can set data per window and recover it - - mfb_set_user_data(window, (void *) myData); +```c +void active(struct mfb_window *window, bool isActive) { ... - myData = (someCast *) mfb_get_user_data(window); +} + +void resize(struct mfb_window *window, int width, int height) { + ... + // Optionally you can also change the viewport size + mfb_set_viewport(window, x, y, width, height); +} + +void keyboard(struct mfb_window *window, mfb_key key, mfb_key_mod mod, bool isPressed) { + ... + // Remember to close the window in some way + if(key == KB_KEY_ESCAPE) { + mfb_close(window); + } + + fprintf(stdout, "%s > keyboard: key: %s (pressed: %d) [key_mod: %x]\n", window_title, mfb_get_key_name(key), isPressed, mod); + +} + +void char_input(struct mfb_window *window, unsigned int charCode) { + ... +} + +void mouse_btn(struct mfb_window *window, mfb_mouse_button button, mfb_key_mod mod, bool isPressed) { + ... +} + +// Use wisely this event. It can be sent too often +void mouse_move(struct mfb_window *window, int x, int y) { + ... +} + +// Mouse wheel +void mouse_scroll(struct mfb_window *window, mfb_key_mod mod, float deltaX, float deltaY) { + ... +} + +struct mfb_window *window = mfb_open_ex("my display", 800, 600, WF_RESIZABLE); +if (!window) + return 0; + +mfb_set_active_callback(window, active); +mfb_set_resize_callback(window, resize); +mfb_set_keyboard_callback(window, keyboard); +mfb_set_char_input_callback(window, char_input); +mfb_set_mouse_button_callback(window, mouse_btn); +mfb_set_mouse_move_callback(window, mouse_move); +mfb_set_mouse_scroll_callback(window, mouse_scroll); +``` -Finally, you can get information about the events in the window directly: +Additionally you can _set data per window and recover it_: - bool mfb_is_window_active(struct mfb_window *window); - - unsigned mfb_get_window_width(struct mfb_window *window); - unsigned mfb_get_window_height(struct mfb_window *window); +```c +mfb_set_user_data(window, (void *) myData); +... +myData = (someCast *) mfb_get_user_data(window); +``` - int mfb_get_mouse_x(struct mfb_window *window); // Last mouse pos X - int mfb_get_mouse_y(struct mfb_window *window); // Last mouse pos Y - float mfb_get_mouse_scroll_x(struct mfb_window *window); // Mouse wheel X as a sum. When you call this function it resets. - float mfb_get_mouse_scroll_y(struct mfb_window *window); // Mouse wheel Y as a sum. When you call this function it resets. +Finally, you can _get information about the events in the window directly_: - 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) +```c +bool mfb_is_window_active(struct mfb_window *window); - const uint8_t * mfb_get_key_buffer(struct mfb_window *window); // One byte for every key. Press (1), Release 0. +unsigned mfb_get_window_width(struct mfb_window *window); +unsigned mfb_get_window_height(struct mfb_window *window); + +int mfb_get_mouse_x(struct mfb_window *window); // Last mouse pos X +int mfb_get_mouse_y(struct mfb_window *window); // Last mouse pos Y + +float mfb_get_mouse_scroll_x(struct mfb_window *window); // Mouse wheel X as a sum. When you call this function it resets. +float mfb_get_mouse_scroll_y(struct mfb_window *window); // Mouse wheel Y as a sum. When you call this function it resets. + +const uint8_t * mfb_get_mouse_button_buffer(struct mfb_window *window); // One byte for every button. Press (1), Release 0. (up to 8 buttons) + +const uint8_t * mfb_get_key_buffer(struct mfb_window *window); // One byte for every key. Press (1), Release 0. +``` First the code creates window with the mfb_open call that is used to display the data, next it's the applications responsibility to allocate a buffer (which has to be at least the size of the window and in 32-bit) Next when calling mfb_update function the buffer will be copied over to the window and displayed. Currently the mfb_update will return -1 if ESC key is pressed but later on it will support to return a key code for a pressed button. See https://github.com/emoon/minifb/blob/master/tests/noise.c for a complete example MiniFB has been tested on Windows, Mac OS X and Linux but may of course have trouble depending on your setup. Currently the code will not do any converting of data if not a proper 32-bit display can be created. -Build instructions ------------------- + +**Extra: Timers and target FPS** + +You can create timers for your own purposes. + +```c +struct mfb_timer * mfb_timer_create(); +void mfb_timer_destroy(struct mfb_timer *tmr); + +void mfb_timer_reset(struct mfb_timer *tmr); +double mfb_timer_now(struct mfb_timer *tmr); +double mfb_timer_delta(struct mfb_timer *tmr); + +double mfb_timer_get_frequency(); +double mfb_timer_get_resolution(); +``` + +Furthermore you can set a target fps for the application. The default is 60 frames per second. + +```c +void mfb_set_target_fps(uint32_t fps); +``` + +This avoid the problem of update too fast the window collapsing the redrawing in fast processors. + +To use this you need to call the function: + +```c +bool mfb_wait_sync(struct mfb_window *window); +``` + +_Example_: + +```c +do { + int i; + mfb_update_state state; + + // TODO: add some awesome rendering to the buffer + + state = mfb_update(window, g_buffer); + if (state != STATE_OK) { + window = 0x0; + break; + } +} while(mfb_wait_sync(window)); +``` + +Note that if you have several windows running on the same thread it makes no sense to wait them all... + + +## Build instructions MiniFB uses tundra https://github.com/deplinenoise/tundra as build system and is required to build the code as is but not many changes should be needed if you want to use it directly in your own code. You can also use CMake as build system. -Mac ---- +### Mac Cocoa and clang is assumed to be installed on the system (downloading latest XCode + installing the command line tools should do the trick) then to build run: tundra2 macosx-clang-debug and you should be able to run the noise example (t2-output/macosx-clang-debug-default/noise) @@ -120,44 +176,49 @@ To enable it just compile defining the preprocessor macro USE_METAL_API. If you use CMake just enable the flag: - mkdir build - cd build - cmake .. -DUSE_METAL_API=ON +``` +mkdir build +cd build +cmake .. -DUSE_METAL_API=ON +``` or if you don't want to use Metal API: - mkdir build - cd build - cmake .. -DUSE_METAL_API=OFF +``` +mkdir build +cd build +cmake .. -DUSE_METAL_API=OFF +``` -Windows -------- +### Windows Visual Studio (ver 2012 express has been tested) tools needed (using the vcvars32.bat (for 32-bit) will set up the enviroment) to build run: tundra2 win32-msvc-debug and you should be able to run noise in t2-output/win32-msvc-debug-default/noise.exe If you use CMake the Visual Studio project will be generated (2015, 2017 and 2019 have been tested). -x11 (FreeBSD, Linux, *nix) --------------------------- +### x11 (FreeBSD, Linux, *nix) gcc and x11-dev libs needs to be installed. To build the code run tundra2 x11-gcc-debug and you should be able to run t2-output/x11-gcc-debug-default/noise If you use CMake just disable the flag: - mkdir build - cd build - cmake .. -DUSE_WAYLAND_API=OFF +``` +mkdir build +cd build +cmake .. -DUSE_WAYLAND_API=OFF +``` -wayland (Linux) --------------------------- +### Wayland (Linux) Depends on gcc and wayland-client and wayland-cursor. Built using the wayland-gcc variants. If you use CMake just enable the flag: - mkdir build - cd build - cmake .. -DUSE_WAYLAND_API=ON +``` +mkdir build +cd build +cmake .. -DUSE_WAYLAND_API=ON +``` diff --git a/include/MiniFB.h b/include/MiniFB.h index c1a9763..a32c771 100644 --- a/include/MiniFB.h +++ b/include/MiniFB.h @@ -56,6 +56,17 @@ float mfb_get_mouse_scroll_y(struct mfb_window *window); // M const uint8_t * mfb_get_mouse_button_buffer(struct mfb_window *window); // One byte for every button. Press (1), Release 0. (up to 8 buttons) const uint8_t * mfb_get_key_buffer(struct mfb_window *window); // One byte for every key. Press (1), Release 0. +void mfb_set_target_fps(uint32_t fps); +bool mfb_wait_sync(struct mfb_window *window); + +struct mfb_timer * mfb_timer_create(); +void mfb_timer_destroy(struct mfb_timer *tmr); +void mfb_timer_reset(struct mfb_timer *tmr); +double mfb_timer_now(struct mfb_timer *tmr); +double mfb_timer_delta(struct mfb_timer *tmr); +double mfb_timer_get_frequency(); +double mfb_timer_get_resolution(); + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #ifdef __cplusplus diff --git a/include/MiniFB_enums.h b/include/MiniFB_enums.h index ea12eb5..d3dca1a 100755 --- a/include/MiniFB_enums.h +++ b/include/MiniFB_enums.h @@ -172,6 +172,7 @@ typedef enum { // Opaque pointer struct mfb_window; +struct mfb_timer; // Event callbacks typedef void(*mfb_active_func)(struct mfb_window *window, bool isActive); diff --git a/src/MiniFB_internal.h b/src/MiniFB_internal.h index 5a8b720..af30627 100755 --- a/src/MiniFB_internal.h +++ b/src/MiniFB_internal.h @@ -6,6 +6,13 @@ #define kCall(func, ...) if(window_data && window_data->func) window_data->func((struct mfb_window *) window_data, __VA_ARGS__); #define kUnused(var) (void) var; +typedef struct mfb_timer { + int64_t start_time; + int64_t delta_counter; + uint64_t time; +} mfb_timer; + + #if defined(__cplusplus) extern "C" { #endif diff --git a/src/MiniFB_linux.c b/src/MiniFB_linux.c new file mode 100644 index 0000000..9fa406c --- /dev/null +++ b/src/MiniFB_linux.c @@ -0,0 +1,32 @@ +#include +#include + +extern double g_timer_frequency; +extern double g_timer_resolution; + +#define kClock CLOCK_MONOTONIC +//#define kClock CLOCK_REALTIME + +uint64_t +mfb_timer_tick() { + struct timespec time; + + if (clock_gettime(kClock, &time) != 0) { + return 0.0; + } + + return time.tv_sec * 1e+9 + time.tv_nsec; +} + +void +mfb_timer_init() { + struct timespec res; + + if (clock_getres(kClock, &res) != 0) { + g_timer_frequency = 1e+9; + } + else { + g_timer_frequency = res.tv_sec + res.tv_nsec * 1e+9; + } + g_timer_resolution = 1.0 / g_timer_frequency; +} diff --git a/src/MiniFB_timer.c b/src/MiniFB_timer.c new file mode 100644 index 0000000..f1a9946 --- /dev/null +++ b/src/MiniFB_timer.c @@ -0,0 +1,102 @@ +#include "MiniFB.h" +#include "MiniFB_internal.h" +#include + +//------------------------------------- +double g_timer_frequency; +double g_timer_resolution; +double g_time_for_frame = 1.0 / 60.0; + +//------------------------------------- +extern uint64_t mfb_timer_tick(); +extern void mfb_timer_init(); + +//------------------------------------- +void +mfb_set_target_fps(uint32_t fps) { + if(fps == 0) { + g_time_for_frame = 0; + } + else { + g_time_for_frame = 1.0 / fps; + } +} + +//------------------------------------- +struct mfb_timer * +mfb_timer_create() { + static int once = 1; + mfb_timer *tmr; + + if(once) { + once = 0; + mfb_timer_init(); + } + + tmr = malloc(sizeof(mfb_timer)); + mfb_timer_reset(tmr); + + return tmr; +} + +//------------------------------------- +void +mfb_timer_destroy(struct mfb_timer *tmr) { + if(tmr != 0x0) { + free(tmr); + } +} + +//------------------------------------- +void +mfb_timer_reset(struct mfb_timer *tmr) { + if(tmr == 0x0) + return; + + tmr->start_time = mfb_timer_tick(); + tmr->delta_counter = tmr->start_time; + tmr->time = 0; +} + +//------------------------------------- +double +mfb_timer_now(struct mfb_timer *tmr) { + uint64_t counter; + + if(tmr == 0x0) + return 0.0; + + counter = mfb_timer_tick(); + tmr->time += (counter - tmr->start_time); + tmr->start_time = counter; + + return tmr->time * g_timer_resolution; +} + +//------------------------------------- +double +mfb_timer_delta(struct mfb_timer *tmr) { + int64_t counter; + uint64_t delta; + + if(tmr == 0x0) + return 0.0; + + counter = mfb_timer_tick(); + delta = (counter - tmr->delta_counter); + tmr->delta_counter = counter; + + return delta * g_timer_resolution; +} + +//------------------------------------- +double +mfb_timer_get_frequency() { + return g_timer_frequency; +} + +//------------------------------------- +double +mfb_timer_get_resolution() { + return g_timer_resolution; +} diff --git a/src/macosx/MacMiniFB.m b/src/macosx/MacMiniFB.m index e2c2992..4ae188a 100644 --- a/src/macosx/MacMiniFB.m +++ b/src/macosx/MacMiniFB.m @@ -10,6 +10,8 @@ #include #endif #include +#include +#include void init_keycodes(); @@ -250,6 +252,7 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) [window_data_osx->window setAcceptsMouseMovedEvents:YES]; [window_data_osx->window center]; + window_data_osx->timer = mfb_timer_create(); [NSApp activateIgnoringOtherApps:YES]; @@ -286,6 +289,8 @@ destroy_window_data(SWindowData *window_data) [window removeWindowData]; [window performClose:nil]; + mfb_timer_destroy(window_data_osx->timer); + memset(window_data_osx, 0, sizeof(SWindowData_OSX)); free(window_data_osx); } @@ -303,14 +308,12 @@ update_events(SWindowData *window_data) NSEvent* event; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - do - { + do { event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; if (event) { [NSApp sendEvent:event]; } - } - while ((window_data->close == false) && event); + } while ((window_data->close == false) && event); [pool release]; } @@ -375,6 +378,59 @@ mfb_update_events(struct mfb_window *window) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +extern double g_time_for_frame; + +bool +mfb_wait_sync(struct mfb_window *window) +{ + NSEvent* event; + + if(window == 0x0) { + return STATE_INVALID_WINDOW; + } + + SWindowData *window_data = (SWindowData *) window; + if(window_data->close) { + destroy_window_data(window_data); + return false; + } + + //NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific; + double current; + uint32_t millis = 1; + while(1) { + event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; + if (event) { + [NSApp sendEvent:event]; + } + + if(window_data->close) { + destroy_window_data(window_data); + return false; + } + + current = mfb_timer_now(window_data_osx->timer); + if (current >= g_time_for_frame) { + mfb_timer_reset(window_data_osx->timer); + return true; + } + else if(current >= g_time_for_frame * 0.8) { + millis = 0; + } + + usleep(millis * 1000); + //sched_yield(); + } + + //[pool release]; + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { @@ -540,3 +596,35 @@ init_keycodes() g_keycodes[0x43] = KB_KEY_KP_MULTIPLY; g_keycodes[0x4E] = KB_KEY_KP_SUBTRACT; } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +extern double g_timer_frequency; +extern double g_timer_resolution; + +uint64_t +mfb_timer_tick() { + static mach_timebase_info_data_t timebase = { 0 }; + + if (timebase.denom == 0) { + (void) mach_timebase_info(&timebase); + } + + uint64_t time = mach_absolute_time(); + + //return (time * s_timebase_info.numer) / s_timebase_info.denom; + + // Perform the arithmetic at 128-bit precision to avoid the overflow! + uint64_t high = (time >> 32) * timebase.numer; + uint64_t highRem = ((high % timebase.denom) << 32) / timebase.denom; + uint64_t low = (time & 0xFFFFFFFFull) * timebase.numer / timebase.denom; + high /= timebase.denom; + + return (high << 32) + highRem + low; +} + +void +mfb_timer_init() { + g_timer_frequency = 1e+9; + g_timer_resolution = 1.0 / g_timer_frequency; +} diff --git a/src/macosx/WindowData_OSX.h b/src/macosx/WindowData_OSX.h index a3d6903..efd0dfb 100644 --- a/src/macosx/WindowData_OSX.h +++ b/src/macosx/WindowData_OSX.h @@ -10,7 +10,9 @@ @class OSXWindow; typedef struct { - OSXWindow *window; + OSXWindow *window; + struct mfb_timer *timer; + #if defined(USE_METAL_API) struct { id command_queue; diff --git a/src/wayland/WaylandMiniFB.c b/src/wayland/WaylandMiniFB.c index 3b75bd2..71991f1 100644 --- a/src/wayland/WaylandMiniFB.c +++ b/src/wayland/WaylandMiniFB.c @@ -27,6 +27,7 @@ destroy_window_data(SWindowData *window_data) SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific; if(window_data_way != 0x0) { + mfb_timer_destroy(window_data_way->timer); memset(window_data_way, 0, sizeof(SWindowData_Way)); free(window_data_way); } @@ -596,8 +597,8 @@ mfb_open(const char *title, unsigned width, unsigned height) init_keycodes(); - if (wl_display_dispatch(window_data_way->display) == -1 || wl_display_roundtrip(window_data_way->display) == -1) - { + if (wl_display_dispatch(window_data_way->display) == -1 || + wl_display_roundtrip(window_data_way->display) == -1) { return 0x0; } @@ -667,6 +668,8 @@ mfb_open(const char *title, unsigned width, unsigned height) wl_surface_damage(window_data_way->surface, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height); wl_surface_commit(window_data_way->surface); + window_data_way->timer = mfb_timer_create(); + mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default); printf("Window created using Wayland API\n"); @@ -762,7 +765,7 @@ mfb_update_events(struct mfb_window *window) if (!window_data_way->display || wl_display_get_error(window_data_way->display) != 0) return STATE_INTERNAL_ERROR; - if (wl_display_dispatch(window_data_way->display) == -1 || wl_display_roundtrip(window_data_way->display) == -1) { + if (wl_display_dispatch_pending(window_data_way->display) == -1) { return STATE_INTERNAL_ERROR; } @@ -771,6 +774,51 @@ mfb_update_events(struct mfb_window *window) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +extern double g_time_for_frame; + +bool +mfb_wait_sync(struct mfb_window *window) { + if(window == 0x0) { + return false; + } + + SWindowData *window_data = (SWindowData *) window; + if(window_data->close) { + destroy(window_data); + return false; + } + + SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific; + double current; + uint32_t millis = 1; + while(1) { + if (wl_display_dispatch_pending(window_data_way->display) == -1) { + return false; + } + + if(window_data->close) { + destroy_window_data(window_data); + return false; + } + + current = mfb_timer_now(window_data_way->timer); + if (current >= g_time_for_frame) { + mfb_timer_reset(window_data_way->timer); + return true; + } + else if(current >= g_time_for_frame * 0.8) { + millis = 0; + } + + usleep(millis * 1000); + //sched_yield(); + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + extern short int g_keycodes[512]; void diff --git a/src/wayland/WindowData_Way.h b/src/wayland/WindowData_Way.h index 888c4d6..81c337c 100644 --- a/src/wayland/WindowData_Way.h +++ b/src/wayland/WindowData_Way.h @@ -53,5 +53,6 @@ typedef struct uint32_t buffer_stride; uint32_t mod_keys; + struct mfb_timer *timer; bool close; } SWindowData_Way; diff --git a/src/windows/WinMiniFB.c b/src/windows/WinMiniFB.c index 1fb45b7..3916da2 100644 --- a/src/windows/WinMiniFB.c +++ b/src/windows/WinMiniFB.c @@ -48,10 +48,8 @@ WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { StretchDIBits(window_data_win->hdc, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height, 0, 0, window_data->buffer_width, window_data->buffer_height, window_data->draw_buffer, window_data_win->bitmapInfo, DIB_RGB_COLORS, SRCCOPY); - - ValidateRect(hWnd, 0x0); } - + ValidateRect(hWnd, 0x0); break; } @@ -359,6 +357,8 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) window_data_win->hdc = GetDC(window_data_win->window); + window_data_win->timer = mfb_timer_create(); + mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default); return (struct mfb_window *) window_data; @@ -421,9 +421,8 @@ mfb_update_events(struct mfb_window *window) { SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific; while (window_data->close == false && PeekMessage(&msg, window_data_win->window, 0, 0, PM_REMOVE)) { - if(msg.message == WM_PAINT) - return STATE_OK; - + //if(msg.message == WM_PAINT) + // return STATE_OK; TranslateMessage(&msg); DispatchMessage(&msg); } @@ -433,6 +432,53 @@ mfb_update_events(struct mfb_window *window) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +extern double g_time_for_frame; + +bool +mfb_wait_sync(struct mfb_window *window) { + MSG msg; + + if (window == 0x0) { + return false; + } + + SWindowData *window_data = (SWindowData *)window; + if (window_data->close) { + destroy_window_data(window_data); + return false; + } + + SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific; + double current; + uint32_t millis = 1; + while (1) { + if(PeekMessage(&msg, window_data_win->window, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + if (window_data->close) { + destroy_window_data(window_data); + return false; + } + + current = mfb_timer_now(window_data_win->timer);; + if (current >= g_time_for_frame) { + mfb_timer_reset(window_data_win->timer); + return true; + } + else if(current >= g_time_for_frame * 0.8) { + millis = 0; + } + + Sleep(millis); + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void destroy_window_data(SWindowData *window_data) { if (window_data == 0x0) @@ -453,6 +499,8 @@ destroy_window_data(SWindowData *window_data) { window_data_win->window = 0; window_data_win->hdc = 0; window_data_win->bitmapInfo = 0x0; + mfb_timer_destroy(window_data_win->timer); + window_data_win->timer = 0x0; window_data->close = true; } @@ -659,3 +707,27 @@ mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y return true; } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +extern double g_timer_frequency; +extern double g_timer_resolution; + +uint64_t +mfb_timer_tick() { + int64_t counter; + + QueryPerformanceCounter((LARGE_INTEGER *) &counter); + + return counter; +} + +void +mfb_timer_init() { + uint64_t frequency; + + QueryPerformanceFrequency((LARGE_INTEGER *) &frequency); + + g_timer_frequency = (double) ((int64_t) frequency); + g_timer_resolution = 1.0 / g_timer_frequency; +} diff --git a/src/windows/WindowData_Win.h b/src/windows/WindowData_Win.h index fb8b8c1..5ccf068 100644 --- a/src/windows/WindowData_Win.h +++ b/src/windows/WindowData_Win.h @@ -7,9 +7,10 @@ typedef struct { - HWND window; - WNDCLASS wc; - HDC hdc; - BITMAPINFO *bitmapInfo; - bool mouse_inside; + HWND window; + WNDCLASS wc; + HDC hdc; + BITMAPINFO *bitmapInfo; + struct mfb_timer *timer; + bool mouse_inside; } SWindowData_Win; diff --git a/src/x11/WindowData_X11.h b/src/x11/WindowData_X11.h index ccecd79..6826020 100644 --- a/src/x11/WindowData_X11.h +++ b/src/x11/WindowData_X11.h @@ -6,15 +6,16 @@ typedef struct { - Window window; - - Display *display; - int screen; - GC gc; - XImage *image; - - void *image_buffer; - XImage *image_scaler; - uint32_t image_scaler_width; - uint32_t image_scaler_height; + Window window; + + Display *display; + int screen; + GC gc; + XImage *image; + + void *image_buffer; + XImage *image_scaler; + uint32_t image_scaler_width; + uint32_t image_scaler_height; + struct mfb_timer *timer; } SWindowData_X11; diff --git a/src/x11/X11MiniFB.c b/src/x11/X11MiniFB.c index b797487..b6e7117 100644 --- a/src/x11/X11MiniFB.c +++ b/src/x11/X11MiniFB.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include "WindowData.h" @@ -185,6 +186,8 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) window_data_x11->image = XCreateImage(window_data_x11->display, CopyFromParent, depth, ZPixmap, 0, 0x0, width, height, 32, width * 4); + window_data_x11->timer = mfb_timer_create(); + mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default); printf("Window created using X11 API\n"); @@ -203,106 +206,111 @@ int translate_key(int scancode); int translate_mod(int state); int translate_mod_ex(int key, int state, int is_pressed); +static void +processEvent(SWindowData *window_data, XEvent *event) { + switch (event->type) { + case KeyPress: + case KeyRelease: + { + mfb_key key_code = (mfb_key) translate_key(event->xkey.keycode); + int is_pressed = (event->type == KeyPress); + window_data->mod_keys = translate_mod_ex(key_code, event->xkey.state, is_pressed); + + window_data->key_status[key_code] = is_pressed; + kCall(keyboard_func, key_code, (mfb_key_mod) window_data->mod_keys, is_pressed); + } + break; + + case ButtonPress: + case ButtonRelease: + { + mfb_mouse_button button = (mfb_mouse_button) event->xbutton.button; + int is_pressed = (event->type == ButtonPress); + window_data->mod_keys = translate_mod(event->xkey.state); + switch (button) { + case Button1: + case Button2: + case Button3: + kCall(mouse_btn_func, button, (mfb_key_mod) window_data->mod_keys, is_pressed); + break; + + case Button4: + kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 0.0f, 1.0f); + break; + case Button5: + kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 0.0f, -1.0f); + break; + + case 6: + kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 1.0f, 0.0f); + break; + case 7: + kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, -1.0f, 0.0f); + break; + + default: + kCall(mouse_btn_func, (mfb_mouse_button) (button - 4), (mfb_key_mod) window_data->mod_keys, is_pressed); + break; + } + } + break; + + case MotionNotify: + window_data->mouse_pos_x = event->xmotion.x; + window_data->mouse_pos_y = event->xmotion.y; + kCall(mouse_move_func, event->xmotion.x, event->xmotion.y); + break; + + case ConfigureNotify: + { + window_data->window_width = event->xconfigure.width; + window_data->window_height = event->xconfigure.height; + window_data->dst_offset_x = 0; + window_data->dst_offset_y = 0; + window_data->dst_width = window_data->window_width; + window_data->dst_height = window_data->window_height; + + SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; + XClearWindow(window_data_x11->display, window_data_x11->window); + kCall(resize_func, window_data->window_width, window_data->window_height); + } + break; + + case EnterNotify: + case LeaveNotify: + break; + + case FocusIn: + window_data->is_active = true; + kCall(active_func, true); + break; + + case FocusOut: + window_data->is_active = false; + kCall(active_func, false); + break; + + case DestroyNotify: + window_data->close = true; + return; + break; + } +} + static void processEvents(SWindowData *window_data) { XEvent event; - SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; + SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; while ((window_data->close == false) && XPending(window_data_x11->display)) { XNextEvent(window_data_x11->display, &event); - - switch (event.type) { - case KeyPress: - case KeyRelease: - { - mfb_key key_code = (mfb_key) translate_key(event.xkey.keycode); - int is_pressed = (event.type == KeyPress); - window_data->mod_keys = translate_mod_ex(key_code, event.xkey.state, is_pressed); - - window_data->key_status[key_code] = is_pressed; - kCall(keyboard_func, key_code, (mfb_key_mod) window_data->mod_keys, is_pressed); - } - break; - - case ButtonPress: - case ButtonRelease: - { - mfb_mouse_button button = (mfb_mouse_button) event.xbutton.button; - int is_pressed = (event.type == ButtonPress); - window_data->mod_keys = translate_mod(event.xkey.state); - switch (button) { - case Button1: - case Button2: - case Button3: - kCall(mouse_btn_func, button, (mfb_key_mod) window_data->mod_keys, is_pressed); - break; - - case Button4: - kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 0.0f, 1.0f); - break; - case Button5: - kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 0.0f, -1.0f); - break; - - case 6: - kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 1.0f, 0.0f); - break; - case 7: - kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, -1.0f, 0.0f); - break; - - default: - kCall(mouse_btn_func, (mfb_mouse_button) (button - 4), (mfb_key_mod) window_data->mod_keys, is_pressed); - break; - } - } - break; - - case MotionNotify: - window_data->mouse_pos_x = event.xmotion.x; - window_data->mouse_pos_y = event.xmotion.y; - kCall(mouse_move_func, event.xmotion.x, event.xmotion.y); - break; - - case ConfigureNotify: - { - window_data->window_width = event.xconfigure.width; - window_data->window_height = event.xconfigure.height; - window_data->dst_offset_x = 0; - window_data->dst_offset_y = 0; - window_data->dst_width = window_data->window_width; - window_data->dst_height = window_data->window_height; - - XClearWindow(window_data_x11->display, window_data_x11->window); - kCall(resize_func, window_data->window_width, window_data->window_height); - } - break; - - case EnterNotify: - case LeaveNotify: - break; - - case FocusIn: - window_data->is_active = true; - kCall(active_func, true); - break; - - case FocusOut: - window_data->is_active = false; - kCall(active_func, false); - break; - - case DestroyNotify: - window_data->close = true; - return; - break; - } + processEvent(window_data, &event); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void destroy(SWindowData *window_data); +void destroy_window_data(SWindowData *window_data); mfb_update_state mfb_update(struct mfb_window *window, void *buffer) { @@ -312,7 +320,7 @@ mfb_update(struct mfb_window *window, void *buffer) { SWindowData *window_data = (SWindowData *) window; if (window_data->close) { - destroy(window_data); + destroy_window_data(window_data); return STATE_EXIT; } @@ -368,7 +376,7 @@ mfb_update_events(struct mfb_window *window) { SWindowData *window_data = (SWindowData *) window; if (window_data->close) { - destroy(window_data); + destroy_window_data(window_data); return STATE_EXIT; } @@ -381,8 +389,56 @@ mfb_update_events(struct mfb_window *window) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +extern double g_time_for_frame; + +bool +mfb_wait_sync(struct mfb_window *window) { + if (window == 0x0) { + return STATE_INVALID_WINDOW; + } + + SWindowData *window_data = (SWindowData *) window; + if (window_data->close) { + destroy_window_data(window_data); + return false; + } + + SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; + XFlush(window_data_x11->display); + XEvent event; + double current; + uint32_t millis = 1; + while(1) { + if(XEventsQueued(window_data_x11->display, QueuedAlready) > 0) { + XNextEvent(window_data_x11->display, &event); + processEvent(window_data, &event); + } + + if(window_data->close) { + destroy_window_data(window_data); + return false; + } + + current = mfb_timer_now(window_data_x11->timer); + if (current >= g_time_for_frame) { + mfb_timer_reset(window_data_x11->timer); + return true; + } + else if(current >= g_time_for_frame * 0.8) { + millis = 0; + } + + usleep(millis * 1000); + //sched_yield(); + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void -destroy(SWindowData *window_data) { +destroy_window_data(SWindowData *window_data) { if (window_data != 0x0) { if (window_data->specific != 0x0) { SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; @@ -392,6 +448,7 @@ destroy(SWindowData *window_data) { XDestroyWindow(window_data_x11->display, window_data_x11->window); XCloseDisplay(window_data_x11->display); } + mfb_timer_destroy(window_data_x11->timer); memset(window_data_x11, 0, sizeof(SWindowData_X11)); free(window_data_x11); } diff --git a/tests/input_events.c b/tests/input_events.c index 9657455..78092dc 100644 --- a/tests/input_events.c +++ b/tests/input_events.c @@ -114,8 +114,7 @@ main() mfb_set_user_data(window, (void *) "Input Events Test"); - for (;;) - { + do { int i; mfb_update_state state; @@ -143,7 +142,7 @@ main() window = 0x0; break; } - } + } while(mfb_wait_sync(window)); return 0; } diff --git a/tests/input_events_cpp.cpp b/tests/input_events_cpp.cpp index 13cfd22..4148ab3 100644 --- a/tests/input_events_cpp.cpp +++ b/tests/input_events_cpp.cpp @@ -110,13 +110,11 @@ main() mfb_set_user_data(window, (void *) "Input Events CPP Test"); - for (;;) - { + do { int i; mfb_update_state state; - for (i = 0; i < WIDTH * HEIGHT; ++i) - { + for (i = 0; i < WIDTH * HEIGHT; ++i) { noise = seed; noise >>= 3; noise ^= seed; @@ -133,7 +131,7 @@ main() window = 0x0; break; } - } + } while(mfb_wait_sync(window)); return 0; } diff --git a/tests/multiple_windows.c b/tests/multiple_windows.c index c45854b..9b8e5c9 100644 --- a/tests/multiple_windows.c +++ b/tests/multiple_windows.c @@ -138,6 +138,8 @@ main() pallete[64*7 + c] = MFB_RGB(255-col, 0, 0); } + mfb_set_target_fps(10); + //-- float time = 0; for (;;) @@ -191,6 +193,12 @@ main() if(window_a == 0x0 && window_b == 0x0) { break; } + + // Don't need to do this for both windows in the same thread + if(window_a != 0x0) + mfb_wait_sync(window_a); + else if(window_b != 0x0) + mfb_wait_sync(window_b); } return 0; diff --git a/tests/noise.c b/tests/noise.c index c278cd5..ff7d3fb 100644 --- a/tests/noise.c +++ b/tests/noise.c @@ -17,13 +17,11 @@ main() if (!window) return 0; - for (;;) - { + do { int i; mfb_update_state state; - for (i = 0; i < WIDTH * HEIGHT; ++i) - { + for (i = 0; i < WIDTH * HEIGHT; ++i) { noise = seed; noise >>= 3; noise ^= seed; @@ -40,7 +38,7 @@ main() window = 0x0; break; } - } + } while(mfb_wait_sync(window)); return 0; }