diff --git a/CMakeLists.txt b/CMakeLists.txt index 1717bb0..b0d38d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,8 +6,11 @@ project(${PROJECT_NAME}) message("Processing " ${PROJECT_NAME}) if(NOT DEFINED IOS) - if(TOLOWER CMAKE_SYSTEM_NAME STREQUAL "ios") - set(IOS true) + if(DEFINED CMAKE_SYSTEM_NAME) + string(TOLOWER CMAKE_SYSTEM_NAME CMAKE_SYSTEM_NAME_LOWER) + if(CMAKE_SYSTEM_NAME_LOWER STREQUAL "ios") + set(IOS true) + endif() endif() endif() @@ -132,22 +135,12 @@ 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() @@ -161,18 +154,30 @@ add_library(minifb STATIC #-------------------------------------- if (APPLE) if(IOS) + target_link_libraries(minifb + "-framework UIKit" + "-framework QuartzCore" + "-framework Metal" + "-framework MetalKit" + ) else() - target_link_libraries(minifb "-framework Cocoa") - target_link_libraries(minifb "-framework QuartzCore") - target_link_libraries(minifb "-framework Metal") - target_link_libraries(minifb "-framework MetalKit") + target_link_libraries(minifb + "-framework Cocoa" + "-framework QuartzCore" + "-framework Metal" + "-framework MetalKit" + ) endif() elseif (UNIX) if(USE_WAYLAND_API) - target_link_libraries(minifb "-lwayland-client") - target_link_libraries(minifb "-lwayland-cursor") + target_link_libraries(minifb + "-lwayland-client" + "-lwayland-cursor" + ) else() - target_link_libraries(minifb "-lX11") + target_link_libraries(minifb + "-lX11" + ) endif() endif() @@ -186,6 +191,7 @@ link_libraries(minifb) # Examples #-------------------------------------- if(NOT IOS) + add_executable(noise tests/noise.c ) @@ -201,7 +207,9 @@ if(NOT IOS) add_executable(multiple_windows tests/multiple_windows.c ) + else() + add_executable(noise tests/ios/main.m tests/ios/AppDelegate.h @@ -210,14 +218,11 @@ else() set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING "Set CMake deployment target" ${FORCE_CACHE}) - target_include_directories(minifb PRIVATE src) + target_include_directories(noise PRIVATE src) + target_include_directories(noise PRIVATE src/ios) add_definitions(-DTVOS_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}) - target_include_directories(noise PRIVATE src/ios) - - target_link_libraries(noise "-framework UIKit") - target_link_libraries(noise "-framework Metal") endif() message("Done " ${PROJECT_NAME}) diff --git a/src/macosx/MacMiniFB.m b/src/macosx/MacMiniFB.m index d3cfea1..41234c4 100644 --- a/src/macosx/MacMiniFB.m +++ b/src/macosx/MacMiniFB.m @@ -200,14 +200,11 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) // Create the texture from the device by using the descriptor for (size_t i = 0; i < MaxBuffersInFlight; ++i) { - viewController->m_texture_buffers[i] = [g_metal_device newTextureWithDescriptor:td]; + viewController->texture_buffers[i] = [g_metal_device newTextureWithDescriptor:td]; } // 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; + viewController->semaphore = dispatch_semaphore_create(MaxBuffersInFlight); MTKView* view = [[MTKView alloc] initWithFrame:rectangle]; view.device = g_metal_device; @@ -313,11 +310,14 @@ mfb_update(struct mfb_window *window, void *buffer) { #endif 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]; + if(window_data->close) { + destroy_window_data(window_data); + return STATE_EXIT; } + SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific; + [[window_data_osx->window contentView] setNeedsDisplay:YES]; + return STATE_OK; } @@ -336,11 +336,14 @@ mfb_update_events(struct mfb_window *window) { } 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]; + if(window_data->close) { + destroy_window_data(window_data); + return STATE_EXIT; } + SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific; + [[window_data_osx->window contentView] setNeedsDisplay:YES]; + return STATE_OK; } @@ -365,6 +368,10 @@ mfb_wait_sync(struct mfb_window *window) { //NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific; + if(window_data_osx == 0x0) { + return false; + } + double current; uint32_t millis = 1; while(1) { @@ -400,6 +407,10 @@ mfb_wait_sync(struct mfb_window *window) { bool mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { + if(window == 0x0) { + return false; + } + SWindowData *window_data = (SWindowData *) window; if(offset_x + width > window_data->window_width) { diff --git a/src/macosx/OSXWindow.h b/src/macosx/OSXWindow.h index 4dd0ba7..4f77ac7 100644 --- a/src/macosx/OSXWindow.h +++ b/src/macosx/OSXWindow.h @@ -1,6 +1,5 @@ #import #include -// @class OSXWindowFrameView; @interface OSXWindow : NSWindow { diff --git a/src/macosx/OSXWindow.m b/src/macosx/OSXWindow.m index 17fe84f..a8f0add 100644 --- a/src/macosx/OSXWindow.m +++ b/src/macosx/OSXWindow.m @@ -72,6 +72,9 @@ - (void)flagsChanged:(NSEvent *)event { + if(window_data == 0x0) + return; + const uint32_t flags = [event modifierFlags]; uint32_t mod_keys = 0, mod_keys_aux = 0; @@ -135,42 +138,48 @@ - (void)keyDown:(NSEvent *)event { - 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); + if(window_data != 0x0) { + 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 key_code = g_keycodes[[event keyCode] & 0x1ff]; - window_data->key_status[key_code] = false; - kCall(keyboard_func, key_code, window_data->mod_keys, false); + if(window_data != 0x0) { + 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); + } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - (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; + if(window_data != 0x0) { + NSString *characters; + NSUInteger length; - length = [characters length]; - for (NSUInteger i = 0; i < length; i++) - { - const unichar code = [characters characterAtIndex:i]; - if ((code & 0xff00) == 0xf700) - continue; + if ([string isKindOfClass:[NSAttributedString class]]) + characters = [string string]; + else + characters = (NSString*) string; - kCall(char_input_func, code); + length = [characters length]; + for (NSUInteger i = 0; i < length; i++) + { + const unichar code = [characters characterAtIndex:i]; + if ((code & 0xff00) == 0xf700) + continue; + + kCall(char_input_func, code); + } } } @@ -180,9 +189,11 @@ { kUnused(notification); - if(window_data->is_active == true) { - window_data->is_active = false; - kCall(active_func, false); + if(window_data != 0x0) { + if(window_data->is_active == true) { + window_data->is_active = false; + kCall(active_func, false); + } } } @@ -190,10 +201,10 @@ - (void)setContentView:(NSView *)aView { - if ([childContentView isEqualTo:aView]) - { + if ([childContentView isEqualTo:aView]) { return; } + NSRect bounds = [self frame]; bounds.origin = NSZeroPoint; @@ -232,15 +243,19 @@ - (void)windowDidBecomeKey:(NSNotification *)notification { kUnused(notification); - window_data->is_active = true; - kCall(active_func, true); + if(window_data != 0x0) { + window_data->is_active = true; + kCall(active_func, true); + } } - (void)windowDidResignKey:(NSNotification *)notification { kUnused(notification); - window_data->is_active = false; - kCall(active_func, false); + if(window_data) { + window_data->is_active = false; + kCall(active_func, false); + } } - (void)windowWillClose:(NSNotification *)notification { @@ -277,19 +292,23 @@ - (void)willClose { - window_data->close = true; + if(window_data != 0x0) { + window_data->close = true; + } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - (void)windowDidResize:(NSNotification *)notification { kUnused(notification); - CGSize size = [self contentRectForFrameRect:[self frame]].size; + if(window_data != 0x0) { + CGSize size = [self contentRectForFrameRect:[self frame]].size; - window_data->window_width = size.width; - window_data->window_height = size.height; + window_data->window_width = size.width; + window_data->window_height = size.height; - kCall(resize_func, size.width, size.height); + kCall(resize_func, size.width, size.height); + } } @end diff --git a/src/macosx/OSXWindowFrameView.h b/src/macosx/OSXWindowFrameView.h index 0356dfe..ad3b308 100644 --- a/src/macosx/OSXWindowFrameView.h +++ b/src/macosx/OSXWindowFrameView.h @@ -16,12 +16,9 @@ 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; - @public dispatch_semaphore_t m_semaphore; // Used for syncing with CPU/GPU + @public id texture_buffers[MaxBuffersInFlight]; + @public int current_buffer; + @public dispatch_semaphore_t semaphore; // Used for syncing with CPU/GPU } @end @@ -31,9 +28,9 @@ enum { MaxBuffersInFlight = 3 }; @interface OSXWindowFrameView : NSView { - @public SWindowData *window_data; + @public SWindowData *window_data; #if defined(USE_METAL_API) - @private NSTrackingArea* trackingArea; + @private NSTrackingArea *tracking_area; #endif } diff --git a/src/macosx/OSXWindowFrameView.m b/src/macosx/OSXWindowFrameView.m index d451aae..1f5764a 100644 --- a/src/macosx/OSXWindowFrameView.m +++ b/src/macosx/OSXWindowFrameView.m @@ -20,24 +20,24 @@ extern Vertex g_vertices[4]; } - (void) drawInMTKView:(nonnull MTKView *)view { - OSXWindow *window = (OSXWindow *) view.window; - if(window->window_data == 0x0) { + OSXWindow *window = (OSXWindow *) view.window; + SWindowData *window_data = window->window_data; + if(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); + dispatch_semaphore_wait(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; + current_buffer = (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 } }; + MTLRegion region = { { 0, 0, 0 }, { window_data->buffer_width, window_data->buffer_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]; + [texture_buffers[current_buffer] replaceRegion:region mipmapLevel:0 withBytes:window_data->draw_buffer bytesPerRow:window_data->buffer_stride]; // Create a new command buffer for each render pass to the current drawable SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window->window_data->specific; @@ -49,7 +49,7 @@ extern Vertex g_vertices[4]; // 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; + __block dispatch_semaphore_t block_sema = semaphore; [commandBuffer addCompletedHandler:^(id buffer) { (void)buffer; @@ -65,13 +65,13 @@ extern Vertex g_vertices[4]; renderEncoder.label = @"minifb_command_encoder"; // Set render command encoder state - OSXWindow *window = (OSXWindow *) view.window; + 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:g_vertices length:sizeof(g_vertices) atIndex:0]; - [renderEncoder setFragmentTexture:m_texture_buffers[m_current_buffer] atIndex:0]; + [renderEncoder setFragmentTexture:texture_buffers[current_buffer] atIndex:0]; // Draw the vertices of our quads [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4]; @@ -97,17 +97,17 @@ extern Vertex g_vertices[4]; - (void)updateTrackingAreas { - if(trackingArea != nil) { - [self removeTrackingArea:trackingArea]; - [trackingArea release]; + if(tracking_area != nil) { + [self removeTrackingArea:tracking_area]; + [tracking_area release]; } int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways); - trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds] - options:opts - owner:self - userInfo:nil]; - [self addTrackingArea:trackingArea]; + tracking_area = [[NSTrackingArea alloc] initWithRect:[self bounds] + options:opts + owner:self + userInfo:nil]; + [self addTrackingArea:tracking_area]; } #else @@ -136,7 +136,7 @@ extern Vertex g_vertices[4]; { (void)rect; - if(!window_data) + if(window_data == 0x0) return; SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific; @@ -181,7 +181,9 @@ extern Vertex g_vertices[4]; - (void)mouseDown:(NSEvent*)event { (void)event; - kCall(mouse_btn_func, MOUSE_BTN_1, window_data->mod_keys, true); + if(window_data != 0x0) { + kCall(mouse_btn_func, MOUSE_BTN_1, window_data->mod_keys, true); + } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -189,7 +191,9 @@ extern Vertex g_vertices[4]; - (void)mouseUp:(NSEvent*)event { (void)event; - kCall(mouse_btn_func, MOUSE_BTN_1, window_data->mod_keys, false); + if(window_data != 0x0) { + kCall(mouse_btn_func, MOUSE_BTN_1, window_data->mod_keys, false); + } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -197,7 +201,9 @@ extern Vertex g_vertices[4]; - (void)rightMouseDown:(NSEvent*)event { (void)event; - kCall(mouse_btn_func, MOUSE_BTN_2, window_data->mod_keys, true); + if(window_data != 0x0) { + kCall(mouse_btn_func, MOUSE_BTN_2, window_data->mod_keys, true); + } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -205,7 +211,9 @@ extern Vertex g_vertices[4]; - (void)rightMouseUp:(NSEvent*)event { (void)event; - kCall(mouse_btn_func, MOUSE_BTN_1, window_data->mod_keys, false); + if(window_data != 0x0) { + kCall(mouse_btn_func, MOUSE_BTN_1, window_data->mod_keys, false); + } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -213,7 +221,9 @@ extern Vertex g_vertices[4]; - (void)otherMouseDown:(NSEvent *)event { (void)event; - kCall(mouse_btn_func, [event buttonNumber], window_data->mod_keys, true); + if(window_data != 0x0) { + kCall(mouse_btn_func, [event buttonNumber], window_data->mod_keys, true); + } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -221,14 +231,18 @@ extern Vertex g_vertices[4]; - (void)otherMouseUp:(NSEvent *)event { (void)event; - kCall(mouse_btn_func, [event buttonNumber], window_data->mod_keys, false); + if(window_data != 0x0) { + kCall(mouse_btn_func, [event buttonNumber], window_data->mod_keys, false); + } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - (void)scrollWheel:(NSEvent *)event { - kCall(mouse_wheel_func, window_data->mod_keys, [event deltaX], [event deltaY]); + if(window_data != 0x0) { + kCall(mouse_wheel_func, window_data->mod_keys, [event deltaX], [event deltaY]); + } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -250,11 +264,13 @@ extern Vertex g_vertices[4]; - (void)mouseMoved:(NSEvent *)event { - 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); + if(window_data != 0x0) { + 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 efd0dfb..ec8bd5f 100644 --- a/src/macosx/WindowData_OSX.h +++ b/src/macosx/WindowData_OSX.h @@ -4,7 +4,7 @@ #include #if defined(USE_METAL_API) -#include + #include #endif @class OSXWindow; @@ -14,9 +14,9 @@ typedef struct { struct mfb_timer *timer; #if defined(USE_METAL_API) - struct { - id command_queue; - id pipeline_state; - } metal; + struct { + id command_queue; + id pipeline_state; + } metal; #endif } SWindowData_OSX; diff --git a/tests/multiple_windows.c b/tests/multiple_windows.c index 9b8e5c9..da391da 100644 --- a/tests/multiple_windows.c +++ b/tests/multiple_windows.c @@ -107,6 +107,7 @@ main() mfb_set_mouse_scroll_callback(window_a, mouse_scroll); mfb_set_user_data(window_a, (void *) "Window A"); + mfb_set_viewport(window_a, 25, 25, WIDTH_A-25, HEIGHT_A-25); //-- struct mfb_window *window_b = mfb_open_ex("Secondary Window", WIDTH_B, HEIGHT_B, WF_RESIZABLE); @@ -150,44 +151,48 @@ main() 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); - } + if(window_a != 0x0) { + 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