From 3fe7b0b29c64a2d0342e2fd26a57d45d357fdedc Mon Sep 17 00:00:00 2001 From: assiduous Date: Thu, 26 Nov 2020 16:56:08 -0800 Subject: Mac/iOS app sources: removed '-x objective-c++' flag and using mm extension instead --- NativeApp/Apple/Source/Classes/OSX/GLView.m | 218 --------------------- NativeApp/Apple/Source/Classes/OSX/GLView.mm | 218 +++++++++++++++++++++ NativeApp/Apple/Source/Classes/OSX/MVKView.m | 50 ----- NativeApp/Apple/Source/Classes/OSX/MVKView.mm | 50 +++++ NativeApp/Apple/Source/Classes/OSX/MetalView.m | 160 --------------- NativeApp/Apple/Source/Classes/OSX/MetalView.mm | 160 +++++++++++++++ NativeApp/Apple/Source/Classes/OSX/ViewBase.m | 147 -------------- NativeApp/Apple/Source/Classes/OSX/ViewBase.mm | 147 ++++++++++++++ .../Apple/Source/Classes/OSX/WindowController.m | 181 ----------------- .../Apple/Source/Classes/OSX/WindowController.mm | 181 +++++++++++++++++ NativeApp/Apple/Source/Classes/iOS/AppViewBase.m | 160 --------------- NativeApp/Apple/Source/Classes/iOS/AppViewBase.mm | 160 +++++++++++++++ NativeApp/Apple/Source/Classes/iOS/BaseView.m | 21 -- NativeApp/Apple/Source/Classes/iOS/BaseView.mm | 21 ++ NativeApp/Apple/Source/Classes/iOS/EAGLView.m | 76 ------- NativeApp/Apple/Source/Classes/iOS/EAGLView.mm | 76 +++++++ NativeApp/Apple/Source/Classes/iOS/MVKView.m | 41 ---- NativeApp/Apple/Source/Classes/iOS/MVKView.mm | 41 ++++ NativeApp/Apple/Source/Classes/iOS/MetalView.m | 41 ---- NativeApp/Apple/Source/Classes/iOS/MetalView.mm | 41 ++++ NativeApp/CMakeLists.txt | 27 +-- 21 files changed, 1105 insertions(+), 1112 deletions(-) delete mode 100644 NativeApp/Apple/Source/Classes/OSX/GLView.m create mode 100644 NativeApp/Apple/Source/Classes/OSX/GLView.mm delete mode 100644 NativeApp/Apple/Source/Classes/OSX/MVKView.m create mode 100644 NativeApp/Apple/Source/Classes/OSX/MVKView.mm delete mode 100644 NativeApp/Apple/Source/Classes/OSX/MetalView.m create mode 100644 NativeApp/Apple/Source/Classes/OSX/MetalView.mm delete mode 100644 NativeApp/Apple/Source/Classes/OSX/ViewBase.m create mode 100644 NativeApp/Apple/Source/Classes/OSX/ViewBase.mm delete mode 100644 NativeApp/Apple/Source/Classes/OSX/WindowController.m create mode 100644 NativeApp/Apple/Source/Classes/OSX/WindowController.mm delete mode 100644 NativeApp/Apple/Source/Classes/iOS/AppViewBase.m create mode 100644 NativeApp/Apple/Source/Classes/iOS/AppViewBase.mm delete mode 100644 NativeApp/Apple/Source/Classes/iOS/BaseView.m create mode 100644 NativeApp/Apple/Source/Classes/iOS/BaseView.mm delete mode 100644 NativeApp/Apple/Source/Classes/iOS/EAGLView.m create mode 100644 NativeApp/Apple/Source/Classes/iOS/EAGLView.mm delete mode 100644 NativeApp/Apple/Source/Classes/iOS/MVKView.m create mode 100644 NativeApp/Apple/Source/Classes/iOS/MVKView.mm delete mode 100644 NativeApp/Apple/Source/Classes/iOS/MetalView.m create mode 100644 NativeApp/Apple/Source/Classes/iOS/MetalView.mm (limited to 'NativeApp') diff --git a/NativeApp/Apple/Source/Classes/OSX/GLView.m b/NativeApp/Apple/Source/Classes/OSX/GLView.m deleted file mode 100644 index d4aef78..0000000 --- a/NativeApp/Apple/Source/Classes/OSX/GLView.m +++ /dev/null @@ -1,218 +0,0 @@ -/* - Copyright (C) 2015 Apple Inc. All Rights Reserved. - See LICENSE.txt for this sample’s licensing information - - Abstract: - OpenGL view subclass. - */ - -#include - -#import "GLView.h" - -@interface GLView () -{ - NSRect _viewRectPixels; -} -@end - -@implementation GLView - -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -- (CVReturn) getFrameForTime:(const CVTimeStamp*)outputTime -{ - // There is no autorelease pool when this method is called - // because it will be called from a background thread. - // It's important to create one or app can leak objects. - @autoreleasepool { - [self drawView]; - } - return kCVReturnSuccess; -} - -// This is the renderer output callback function -static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, - const CVTimeStamp* now, - const CVTimeStamp* outputTime, - CVOptionFlags flagsIn, - CVOptionFlags* flagsOut, - void* displayLinkContext) -{ - CVReturn result = [(__bridge GLView*)displayLinkContext getFrameForTime:outputTime]; - return result; -} - -// Prepares the receiver for service after it has been loaded -// from an Interface Builder archive, or nib file. -- (void) awakeFromNib -{ - [super awakeFromNib]; - - self.renderMode = Diligent::MacOSAppBase::RenderMode::OpenGL; - - NSOpenGLPixelFormatAttribute attrs[] = - { - NSOpenGLPFADoubleBuffer, - NSOpenGLPFADepthSize, 24, - NSOpenGLPFAOpenGLProfile, - NSOpenGLProfileVersion4_1Core, - 0 - }; - - NSOpenGLPixelFormat *pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; - - if (!pf) - { - NSLog(@"No OpenGL pixel format"); - } - - NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:pf shareContext:nil]; - -#if defined(DEBUG) - // When we're using a CoreProfile context, crash if we call a legacy OpenGL function - // This will make it much more obvious where and when such a function call is made so - // that we can remove such calls. - // Without this we'd simply get GL_INVALID_OPERATION error for calling legacy functions - // but it would be more difficult to see where that function was called. - CGLEnable([context CGLContextObj], kCGLCECrashOnRemovedFunctions); -#endif - - [self setPixelFormat:pf]; - - [self setOpenGLContext:context]; - - // Opt-In to Retina resolution - [self setWantsBestResolutionOpenGLSurface:YES]; -} - -- (void) prepareOpenGL -{ - [super prepareOpenGL]; - - // Application must be initialized befor display link is started - [self initGL]; - - CVDisplayLinkRef displayLink; - // Create a display link capable of being used with all active displays - CVDisplayLinkCreateWithActiveCGDisplays(&displayLink); - [self setDisplayLink:displayLink]; - - // Set the renderer output callback function - CVDisplayLinkSetOutputCallback(displayLink, &MyDisplayLinkCallback, (__bridge void*)self); - - // Set the display link for the current renderer - CGLContextObj cglContext = [[self openGLContext] CGLContextObj]; - CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj]; - CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat); - - // Activate the display link - CVDisplayLinkStart(displayLink); -} - -- (void) initGL -{ - // The reshape function may have changed the thread to which our OpenGL - // context is attached before prepareOpenGL and initGL are called. So call - // makeCurrentContext to ensure that our OpenGL context current to this - // thread (i.e. makeCurrentContext directs all OpenGL calls on this thread - // to [self openGLContext]) - [[self openGLContext] makeCurrentContext]; - - // Synchronize buffer swaps with vertical refresh rate - GLint swapInt = 1; - [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLContextParameterSwapInterval]; - - // Init the application. - [self initApp:nil]; -} - -- (void)reshape -{ - [super reshape]; - - auto* glContext = [self openGLContext]; - - // We draw on a secondary thread through the display link. However, when - // resizing the view, -drawRect is called on the main thread. - // Add a mutex around to avoid the threads accessing the context - // simultaneously when resizing. - CGLLockContext([glContext CGLContextObj]); - - [glContext makeCurrentContext]; - - // Get the view size in Points - NSRect viewRectPoints = [self bounds]; - - // Rendering at retina resolutions will reduce aliasing, but at the potential - // cost of framerate and battery life due to the GPU needing to render more - // pixels. - - // Any calculations the renderer does which use pixel dimentions, must be - // in "retina" space. [NSView convertRectToBacking] converts point sizes - // to pixel sizes. Thus the renderer gets the size in pixels, not points, - // so that it can set it's viewport and perform and other pixel based - // calculations appropriately. - // viewRectPixels will be larger than viewRectPoints for retina displays. - // viewRectPixels will be the same as viewRectPoints for non-retina displays - _viewRectPixels = [self convertRectToBacking:viewRectPoints]; - - // Set the new dimensions in our renderer - auto* theApp = [self lockApp]; - if(theApp) - { - theApp->WindowResize(_viewRectPixels.size.width, _viewRectPixels.size.height); - } - [self unlockApp]; - - CGLUnlockContext([glContext CGLContextObj]); -} - - -- (void)renewGState -{ - // Called whenever graphics state updated (such as window resize) - - // OpenGL rendering is not synchronous with other rendering on the OSX. - // Therefore, call disableScreenUpdatesUntilFlush so the window server - // doesn't render non-OpenGL content in the window asynchronously from - // OpenGL content, which could cause flickering. (non-OpenGL content - // includes the title bar and drawing done by the app with other APIs) - [[self window] disableScreenUpdatesUntilFlush]; - - [super renewGState]; -} - -- (void) drawRect: (NSRect) theRect -{ - // Called during resize operations - - // Avoid flickering during resize by drawing - [self drawView]; -} - -- (void) drawView -{ - auto* glContext = [self openGLContext]; - - // We draw on a secondary thread through the display link - // When resizing the view, -reshape is called automatically on the main - // thread. Add a mutex around to avoid the threads accessing the context - // simultaneously when resizing - CGLLockContext([glContext CGLContextObj]); - - [glContext makeCurrentContext]; - - auto* theApp = [self lockApp]; - if(theApp) - { - theApp->Update(); - theApp->Render(); - } - [self unlockApp]; - - CGLFlushDrawable([glContext CGLContextObj]); - CGLUnlockContext([glContext CGLContextObj]); -} - -@end diff --git a/NativeApp/Apple/Source/Classes/OSX/GLView.mm b/NativeApp/Apple/Source/Classes/OSX/GLView.mm new file mode 100644 index 0000000..d4aef78 --- /dev/null +++ b/NativeApp/Apple/Source/Classes/OSX/GLView.mm @@ -0,0 +1,218 @@ +/* + Copyright (C) 2015 Apple Inc. All Rights Reserved. + See LICENSE.txt for this sample’s licensing information + + Abstract: + OpenGL view subclass. + */ + +#include + +#import "GLView.h" + +@interface GLView () +{ + NSRect _viewRectPixels; +} +@end + +@implementation GLView + +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +- (CVReturn) getFrameForTime:(const CVTimeStamp*)outputTime +{ + // There is no autorelease pool when this method is called + // because it will be called from a background thread. + // It's important to create one or app can leak objects. + @autoreleasepool { + [self drawView]; + } + return kCVReturnSuccess; +} + +// This is the renderer output callback function +static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, + const CVTimeStamp* now, + const CVTimeStamp* outputTime, + CVOptionFlags flagsIn, + CVOptionFlags* flagsOut, + void* displayLinkContext) +{ + CVReturn result = [(__bridge GLView*)displayLinkContext getFrameForTime:outputTime]; + return result; +} + +// Prepares the receiver for service after it has been loaded +// from an Interface Builder archive, or nib file. +- (void) awakeFromNib +{ + [super awakeFromNib]; + + self.renderMode = Diligent::MacOSAppBase::RenderMode::OpenGL; + + NSOpenGLPixelFormatAttribute attrs[] = + { + NSOpenGLPFADoubleBuffer, + NSOpenGLPFADepthSize, 24, + NSOpenGLPFAOpenGLProfile, + NSOpenGLProfileVersion4_1Core, + 0 + }; + + NSOpenGLPixelFormat *pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; + + if (!pf) + { + NSLog(@"No OpenGL pixel format"); + } + + NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:pf shareContext:nil]; + +#if defined(DEBUG) + // When we're using a CoreProfile context, crash if we call a legacy OpenGL function + // This will make it much more obvious where and when such a function call is made so + // that we can remove such calls. + // Without this we'd simply get GL_INVALID_OPERATION error for calling legacy functions + // but it would be more difficult to see where that function was called. + CGLEnable([context CGLContextObj], kCGLCECrashOnRemovedFunctions); +#endif + + [self setPixelFormat:pf]; + + [self setOpenGLContext:context]; + + // Opt-In to Retina resolution + [self setWantsBestResolutionOpenGLSurface:YES]; +} + +- (void) prepareOpenGL +{ + [super prepareOpenGL]; + + // Application must be initialized befor display link is started + [self initGL]; + + CVDisplayLinkRef displayLink; + // Create a display link capable of being used with all active displays + CVDisplayLinkCreateWithActiveCGDisplays(&displayLink); + [self setDisplayLink:displayLink]; + + // Set the renderer output callback function + CVDisplayLinkSetOutputCallback(displayLink, &MyDisplayLinkCallback, (__bridge void*)self); + + // Set the display link for the current renderer + CGLContextObj cglContext = [[self openGLContext] CGLContextObj]; + CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj]; + CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat); + + // Activate the display link + CVDisplayLinkStart(displayLink); +} + +- (void) initGL +{ + // The reshape function may have changed the thread to which our OpenGL + // context is attached before prepareOpenGL and initGL are called. So call + // makeCurrentContext to ensure that our OpenGL context current to this + // thread (i.e. makeCurrentContext directs all OpenGL calls on this thread + // to [self openGLContext]) + [[self openGLContext] makeCurrentContext]; + + // Synchronize buffer swaps with vertical refresh rate + GLint swapInt = 1; + [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLContextParameterSwapInterval]; + + // Init the application. + [self initApp:nil]; +} + +- (void)reshape +{ + [super reshape]; + + auto* glContext = [self openGLContext]; + + // We draw on a secondary thread through the display link. However, when + // resizing the view, -drawRect is called on the main thread. + // Add a mutex around to avoid the threads accessing the context + // simultaneously when resizing. + CGLLockContext([glContext CGLContextObj]); + + [glContext makeCurrentContext]; + + // Get the view size in Points + NSRect viewRectPoints = [self bounds]; + + // Rendering at retina resolutions will reduce aliasing, but at the potential + // cost of framerate and battery life due to the GPU needing to render more + // pixels. + + // Any calculations the renderer does which use pixel dimentions, must be + // in "retina" space. [NSView convertRectToBacking] converts point sizes + // to pixel sizes. Thus the renderer gets the size in pixels, not points, + // so that it can set it's viewport and perform and other pixel based + // calculations appropriately. + // viewRectPixels will be larger than viewRectPoints for retina displays. + // viewRectPixels will be the same as viewRectPoints for non-retina displays + _viewRectPixels = [self convertRectToBacking:viewRectPoints]; + + // Set the new dimensions in our renderer + auto* theApp = [self lockApp]; + if(theApp) + { + theApp->WindowResize(_viewRectPixels.size.width, _viewRectPixels.size.height); + } + [self unlockApp]; + + CGLUnlockContext([glContext CGLContextObj]); +} + + +- (void)renewGState +{ + // Called whenever graphics state updated (such as window resize) + + // OpenGL rendering is not synchronous with other rendering on the OSX. + // Therefore, call disableScreenUpdatesUntilFlush so the window server + // doesn't render non-OpenGL content in the window asynchronously from + // OpenGL content, which could cause flickering. (non-OpenGL content + // includes the title bar and drawing done by the app with other APIs) + [[self window] disableScreenUpdatesUntilFlush]; + + [super renewGState]; +} + +- (void) drawRect: (NSRect) theRect +{ + // Called during resize operations + + // Avoid flickering during resize by drawing + [self drawView]; +} + +- (void) drawView +{ + auto* glContext = [self openGLContext]; + + // We draw on a secondary thread through the display link + // When resizing the view, -reshape is called automatically on the main + // thread. Add a mutex around to avoid the threads accessing the context + // simultaneously when resizing + CGLLockContext([glContext CGLContextObj]); + + [glContext makeCurrentContext]; + + auto* theApp = [self lockApp]; + if(theApp) + { + theApp->Update(); + theApp->Render(); + } + [self unlockApp]; + + CGLFlushDrawable([glContext CGLContextObj]); + CGLUnlockContext([glContext CGLContextObj]); +} + +@end diff --git a/NativeApp/Apple/Source/Classes/OSX/MVKView.m b/NativeApp/Apple/Source/Classes/OSX/MVKView.m deleted file mode 100644 index 06353e4..0000000 --- a/NativeApp/Apple/Source/Classes/OSX/MVKView.m +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright 2015-2019 Egor Yusov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -#import "MVKView.h" - -@implementation MVKView -{ -} - -- (id)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self) - { - self.renderMode = Diligent::MacOSAppBase::RenderMode::MoltenVK; - } - return self; -} - -- (id)initWithCoder:(NSCoder*)coder -{ - self = [super initWithCoder:coder]; - if (self) - { - self.renderMode = Diligent::MacOSAppBase::RenderMode::MoltenVK; - } - return self; -} - -@end diff --git a/NativeApp/Apple/Source/Classes/OSX/MVKView.mm b/NativeApp/Apple/Source/Classes/OSX/MVKView.mm new file mode 100644 index 0000000..06353e4 --- /dev/null +++ b/NativeApp/Apple/Source/Classes/OSX/MVKView.mm @@ -0,0 +1,50 @@ +/* Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#import "MVKView.h" + +@implementation MVKView +{ +} + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) + { + self.renderMode = Diligent::MacOSAppBase::RenderMode::MoltenVK; + } + return self; +} + +- (id)initWithCoder:(NSCoder*)coder +{ + self = [super initWithCoder:coder]; + if (self) + { + self.renderMode = Diligent::MacOSAppBase::RenderMode::MoltenVK; + } + return self; +} + +@end diff --git a/NativeApp/Apple/Source/Classes/OSX/MetalView.m b/NativeApp/Apple/Source/Classes/OSX/MetalView.m deleted file mode 100644 index 05de9b1..0000000 --- a/NativeApp/Apple/Source/Classes/OSX/MetalView.m +++ /dev/null @@ -1,160 +0,0 @@ -/* Copyright 2015-2019 Egor Yusov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -#import -#import "MetalView.h" - -@implementation MetalView -{ -} - -- (id)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self) - { - self.renderMode = Diligent::MacOSAppBase::RenderMode::Metal; - } - return self; -} - -- (id)initWithCoder:(NSCoder*)coder -{ - self = [super initWithCoder:coder]; - if (self) - { - self.renderMode = Diligent::MacOSAppBase::RenderMode::Metal; - } - return self; -} - - -- (void) awakeFromNib -{ - [super awakeFromNib]; - - // Back the view with a layer created by the makeBackingLayer method. - self.wantsLayer = YES; - - [self initApp:self]; - - CVDisplayLinkRef displayLink; - CVDisplayLinkCreateWithActiveCGDisplays(&displayLink); - [self setDisplayLink:displayLink]; - CVDisplayLinkSetOutputCallback(displayLink, &DisplayLinkCallback, (__bridge void*)self); - CVDisplayLinkStart(displayLink); - - [self setPostsBoundsChangedNotifications:YES]; - [self setPostsFrameChangedNotifications:YES]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(boundsDidChange:) name:NSViewBoundsDidChangeNotification object:self]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(boundsDidChange:) name:NSViewFrameDidChangeNotification object:self]; -} - -// Indicates that the view wants to draw using the backing -// layer instead of using drawRect:. --(BOOL) wantsUpdateLayer -{ - return YES; -} - -// Returns a Metal-compatible layer. -+(Class) layerClass -{ - return [CAMetalLayer class]; -} - -// If the wantsLayer property is set to YES, this method will -// be invoked to return a layer instance. --(CALayer*) makeBackingLayer -{ - CALayer* layer = [self.class.layerClass layer]; - CGSize viewScale = [self convertSizeToBacking: CGSizeMake(1.0, 1.0)]; - layer.contentsScale = MIN(viewScale.width, viewScale.height); - return layer; -} - --(void)render -{ - auto* theApp = [self lockApp]; - if (theApp) - { - theApp->Update(); - theApp->Render(); - theApp->Present(); - } - [self unlockApp]; -} - - -- (CVReturn) getFrameForTime:(const CVTimeStamp*)outputTime -{ - // There is no autorelease pool when this method is called - // because it will be called from a background thread. - // It's important to create one or app can leak objects. - @autoreleasepool { - [self render]; - } - return kCVReturnSuccess; -} - -// Rendering loop callback function for use with a CVDisplayLink. -static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, - const CVTimeStamp* now, - const CVTimeStamp* outputTime, - CVOptionFlags flagsIn, - CVOptionFlags* flagsOut, - void* target) -{ - MetalView* view = (__bridge MetalView*)target; - CVReturn result = [view getFrameForTime:outputTime]; - return result; -} - --(void)boundsDidChange:(NSNotification *)notification -{ - // It is not clear what the proper way to handle window resize is. - // Cube demo from MoltenVK ignores any window resize notifications and - // recreates the swap chain if Present or AcquireNextImage fails, causing - // jagged transitions. - - // According to this thread, there is no solution for flickering during - // resize in Metal: - // https://forums.developer.apple.com/thread/77901 - - // Calling WindowResize() causes flickering. - // Even if [self render] is called ater WindowResize() - // Similar results when using Metal kit view - // Calling [self render] alone produces jagged transitions but no flickering. - // Calling nothing causes the app to crash during resize. - - NSRect viewRectPoints = [self bounds]; - NSRect viewRectPixels = [self convertRectToBacking:viewRectPoints]; - auto* theApp = [self lockApp]; - if (theApp) - { - theApp->WindowResize(viewRectPixels.size.width, viewRectPixels.size.height); - } - [self unlockApp]; -} - -@end diff --git a/NativeApp/Apple/Source/Classes/OSX/MetalView.mm b/NativeApp/Apple/Source/Classes/OSX/MetalView.mm new file mode 100644 index 0000000..05de9b1 --- /dev/null +++ b/NativeApp/Apple/Source/Classes/OSX/MetalView.mm @@ -0,0 +1,160 @@ +/* Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#import +#import "MetalView.h" + +@implementation MetalView +{ +} + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) + { + self.renderMode = Diligent::MacOSAppBase::RenderMode::Metal; + } + return self; +} + +- (id)initWithCoder:(NSCoder*)coder +{ + self = [super initWithCoder:coder]; + if (self) + { + self.renderMode = Diligent::MacOSAppBase::RenderMode::Metal; + } + return self; +} + + +- (void) awakeFromNib +{ + [super awakeFromNib]; + + // Back the view with a layer created by the makeBackingLayer method. + self.wantsLayer = YES; + + [self initApp:self]; + + CVDisplayLinkRef displayLink; + CVDisplayLinkCreateWithActiveCGDisplays(&displayLink); + [self setDisplayLink:displayLink]; + CVDisplayLinkSetOutputCallback(displayLink, &DisplayLinkCallback, (__bridge void*)self); + CVDisplayLinkStart(displayLink); + + [self setPostsBoundsChangedNotifications:YES]; + [self setPostsFrameChangedNotifications:YES]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(boundsDidChange:) name:NSViewBoundsDidChangeNotification object:self]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(boundsDidChange:) name:NSViewFrameDidChangeNotification object:self]; +} + +// Indicates that the view wants to draw using the backing +// layer instead of using drawRect:. +-(BOOL) wantsUpdateLayer +{ + return YES; +} + +// Returns a Metal-compatible layer. ++(Class) layerClass +{ + return [CAMetalLayer class]; +} + +// If the wantsLayer property is set to YES, this method will +// be invoked to return a layer instance. +-(CALayer*) makeBackingLayer +{ + CALayer* layer = [self.class.layerClass layer]; + CGSize viewScale = [self convertSizeToBacking: CGSizeMake(1.0, 1.0)]; + layer.contentsScale = MIN(viewScale.width, viewScale.height); + return layer; +} + +-(void)render +{ + auto* theApp = [self lockApp]; + if (theApp) + { + theApp->Update(); + theApp->Render(); + theApp->Present(); + } + [self unlockApp]; +} + + +- (CVReturn) getFrameForTime:(const CVTimeStamp*)outputTime +{ + // There is no autorelease pool when this method is called + // because it will be called from a background thread. + // It's important to create one or app can leak objects. + @autoreleasepool { + [self render]; + } + return kCVReturnSuccess; +} + +// Rendering loop callback function for use with a CVDisplayLink. +static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, + const CVTimeStamp* now, + const CVTimeStamp* outputTime, + CVOptionFlags flagsIn, + CVOptionFlags* flagsOut, + void* target) +{ + MetalView* view = (__bridge MetalView*)target; + CVReturn result = [view getFrameForTime:outputTime]; + return result; +} + +-(void)boundsDidChange:(NSNotification *)notification +{ + // It is not clear what the proper way to handle window resize is. + // Cube demo from MoltenVK ignores any window resize notifications and + // recreates the swap chain if Present or AcquireNextImage fails, causing + // jagged transitions. + + // According to this thread, there is no solution for flickering during + // resize in Metal: + // https://forums.developer.apple.com/thread/77901 + + // Calling WindowResize() causes flickering. + // Even if [self render] is called ater WindowResize() + // Similar results when using Metal kit view + // Calling [self render] alone produces jagged transitions but no flickering. + // Calling nothing causes the app to crash during resize. + + NSRect viewRectPoints = [self bounds]; + NSRect viewRectPixels = [self convertRectToBacking:viewRectPoints]; + auto* theApp = [self lockApp]; + if (theApp) + { + theApp->WindowResize(viewRectPixels.size.width, viewRectPixels.size.height); + } + [self unlockApp]; +} + +@end diff --git a/NativeApp/Apple/Source/Classes/OSX/ViewBase.m b/NativeApp/Apple/Source/Classes/OSX/ViewBase.m deleted file mode 100644 index bbc5cbb..0000000 --- a/NativeApp/Apple/Source/Classes/OSX/ViewBase.m +++ /dev/null @@ -1,147 +0,0 @@ -/* Copyright 2015-2019 Egor Yusov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -#include -#include - -#import "ViewBase.h" - -@implementation ViewBase -{ - std::unique_ptr _theApp; - std::string _error; - NSRecursiveLock* appLock; -} - -@synthesize displayLink; - -// Prepares the receiver for service after it has been loaded -// from an Interface Builder archive, or nib file. -- (void) awakeFromNib -{ - [super awakeFromNib]; - - _theApp.reset(Diligent::CreateApplication()); - - // [self window] is nil here - auto* mainWindow = [[NSApplication sharedApplication] mainWindow]; - // Register to be notified when the main window closes so we can stop the displaylink - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(windowWillClose:) - name:NSWindowWillCloseNotification - object:mainWindow]; - mainWindow.minSize = NSSize{320, 240}; -} - --(void)initApp:(NSView*) view -{ - // Init the application. - try - { - _theApp->Initialize((__bridge void*)view, self.renderMode); - } - catch(std::runtime_error &err) - { - _error = err.what(); - _theApp.reset(); - } -} - --(Diligent::NativeAppBase*)lockApp -{ - [appLock lock]; - return _theApp.get(); -} - --(void)unlockApp -{ - [appLock unlock]; -} - -- (BOOL)acceptsFirstResponder -{ - return YES; // To make keyboard events work -} - --(void)destroyApp -{ - // Stop the display link BEFORE releasing anything in the view - // otherwise the display link thread may call into the view and crash - // when it encounters something that has been released - if (displayLink) - { - CVDisplayLinkStop(displayLink); - } - - [appLock lock]; - _theApp.reset(); - [appLock unlock]; -} - --(void) dealloc -{ - [self destroyApp]; - - CVDisplayLinkRelease(displayLink); - - [appLock release]; - - [super dealloc]; -} - --(NSString*)getError -{ - return _error.empty() ? nil : [NSString stringWithFormat:@"%s", _error.c_str()]; -} - - -- (void)stopDisplayLink -{ - if (displayLink) - { - CVDisplayLinkStop(displayLink); - } -} - -- (void)startDisplayLink -{ - if (displayLink) - { - CVDisplayLinkStart(displayLink); - } -} - -- (void) windowWillClose:(NSNotification*)notification -{ - [self destroyApp]; -} - --(NSString*)getAppName -{ - auto* theApp = [self lockApp]; - auto Title = [NSString stringWithFormat:@"%s", theApp ? theApp->GetAppTitle() : ""]; - [self unlockApp]; - return Title; -} - -@end diff --git a/NativeApp/Apple/Source/Classes/OSX/ViewBase.mm b/NativeApp/Apple/Source/Classes/OSX/ViewBase.mm new file mode 100644 index 0000000..bbc5cbb --- /dev/null +++ b/NativeApp/Apple/Source/Classes/OSX/ViewBase.mm @@ -0,0 +1,147 @@ +/* Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include +#include + +#import "ViewBase.h" + +@implementation ViewBase +{ + std::unique_ptr _theApp; + std::string _error; + NSRecursiveLock* appLock; +} + +@synthesize displayLink; + +// Prepares the receiver for service after it has been loaded +// from an Interface Builder archive, or nib file. +- (void) awakeFromNib +{ + [super awakeFromNib]; + + _theApp.reset(Diligent::CreateApplication()); + + // [self window] is nil here + auto* mainWindow = [[NSApplication sharedApplication] mainWindow]; + // Register to be notified when the main window closes so we can stop the displaylink + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(windowWillClose:) + name:NSWindowWillCloseNotification + object:mainWindow]; + mainWindow.minSize = NSSize{320, 240}; +} + +-(void)initApp:(NSView*) view +{ + // Init the application. + try + { + _theApp->Initialize((__bridge void*)view, self.renderMode); + } + catch(std::runtime_error &err) + { + _error = err.what(); + _theApp.reset(); + } +} + +-(Diligent::NativeAppBase*)lockApp +{ + [appLock lock]; + return _theApp.get(); +} + +-(void)unlockApp +{ + [appLock unlock]; +} + +- (BOOL)acceptsFirstResponder +{ + return YES; // To make keyboard events work +} + +-(void)destroyApp +{ + // Stop the display link BEFORE releasing anything in the view + // otherwise the display link thread may call into the view and crash + // when it encounters something that has been released + if (displayLink) + { + CVDisplayLinkStop(displayLink); + } + + [appLock lock]; + _theApp.reset(); + [appLock unlock]; +} + +-(void) dealloc +{ + [self destroyApp]; + + CVDisplayLinkRelease(displayLink); + + [appLock release]; + + [super dealloc]; +} + +-(NSString*)getError +{ + return _error.empty() ? nil : [NSString stringWithFormat:@"%s", _error.c_str()]; +} + + +- (void)stopDisplayLink +{ + if (displayLink) + { + CVDisplayLinkStop(displayLink); + } +} + +- (void)startDisplayLink +{ + if (displayLink) + { + CVDisplayLinkStart(displayLink); + } +} + +- (void) windowWillClose:(NSNotification*)notification +{ + [self destroyApp]; +} + +-(NSString*)getAppName +{ + auto* theApp = [self lockApp]; + auto Title = [NSString stringWithFormat:@"%s", theApp ? theApp->GetAppTitle() : ""]; + [self unlockApp]; + return Title; +} + +@end diff --git a/NativeApp/Apple/Source/Classes/OSX/WindowController.m b/NativeApp/Apple/Source/Classes/OSX/WindowController.m deleted file mode 100644 index e3f7923..0000000 --- a/NativeApp/Apple/Source/Classes/OSX/WindowController.m +++ /dev/null @@ -1,181 +0,0 @@ -/* - Copyright (C) 2015 Apple Inc. All Rights Reserved. - See LICENSE.txt for this sample’s licensing information - - Abstract: - Window controller subclass. - */ - -#import "WindowController.h" -#import "FullscreenWindow.h" -#import "ViewBase.h" - -@interface WindowController () - -// Fullscreen window -@property(strong) FullscreenWindow *fullscreenWindow; - -// Non-Fullscreen window (also the initial window) -@property(strong) NSWindow* standardWindow; - -@end - -@implementation WindowController -{ - bool CommandKeyPressed; -} - -- (instancetype)initWithWindow:(NSWindow *)window -{ - self = [super initWithWindow:window]; - - if (self) - { - // Initialize to nil since it indicates app is not fullscreen - _fullscreenWindow = nil; - } - - CommandKeyPressed = false; - - return self; -} - -- (void) goFullscreen -{ - // If app is already fullscreen... - if([self fullscreenWindow]) - { - //...don't do anything - return; - } - - ViewBase* view = (ViewBase*)self.window.contentView; - - // We must stop the display link while - // switching the windows to make sure - // that render commands are not issued - // from another thread - [view stopDisplayLink]; - - // Allocate a new fullscreen window - [self setFullscreenWindow: [[FullscreenWindow alloc] init]]; - - [[self fullscreenWindow] setAcceptsMouseMovedEvents:YES]; - - // Resize the view to screensize - NSRect viewRect = [[self fullscreenWindow] frame]; - - // Set the view to the size of the fullscreen window - [self.window.contentView setFrameSize: viewRect.size]; - - // Set the view in the fullscreen window - [[self fullscreenWindow] setContentView:self.window.contentView]; - - [self setStandardWindow:[self window]]; - - // Hide non-fullscreen window so it doesn't show up when switching out - // of this app (i.e. with CMD-TAB) - [[self standardWindow] orderOut:self]; - - // Set controller to the fullscreen window so that all input will go to - // this controller (self) - [self setWindow:[self fullscreenWindow]]; - - // Show the window and make it the key window for input - [[self fullscreenWindow] makeKeyAndOrderFront:self]; - - // Restore display link - [view startDisplayLink]; -} - -- (void) goWindow -{ - // If controller doesn't have a full screen window... - if([self fullscreenWindow] == nil) - { - //...app is already windowed so don't do anything - return; - } - - ViewBase* view = (ViewBase*)self.window.contentView; - - // We must stop the display link while - // switching the windows to make sure - // that render commands are not issued - // from another thread - [view stopDisplayLink]; - - // Get the rectangle of the original window - NSRect viewRect = [[self standardWindow] frame]; - - // Set the view rect to the new size - [self.window.contentView setFrame:viewRect]; - - // Hide fullscreen window - [[self fullscreenWindow] orderOut:self]; - - // Set controller to the standard window so that all input will go to - // this controller (self) - [self setWindow:[self standardWindow]]; - - // Set the content of the orginal window to the view - [[self window] setContentView: [self fullscreenWindow].contentView]; - - // Show the window and make it the key window for input - [[self window] makeKeyAndOrderFront:self]; - - // Ensure we set fullscreen Window to nil so our checks for - // windowed vs. fullscreen mode elsewhere are correct - [self setFullscreenWindow: nil]; - - // Restore display link - [view startDisplayLink]; -} - - -- (void) keyDown:(NSEvent *)event -{ - unichar c = [[event charactersIgnoringModifiers] characterAtIndex:0]; - - switch (c) - { - // Handle [ESC] key - case 27: - if([self fullscreenWindow] != nil) - { - [self goWindow]; - } - return; - - // Have Command+f or Command+Enter toggle fullscreen - case 13: - case 'f': - if (CommandKeyPressed) - { - if([self fullscreenWindow] == nil) - { - [self goFullscreen]; - } - else - { - [self goWindow]; - } - } - return; - } - - // Allow other character to be handled (or not and beep) - //[super keyDown:event]; -} - -// Informs the receiver that the user has pressed or released a -// modifier key (Shift, Control, and so on) -- (void)flagsChanged:(NSEvent *)event -{ - auto modifierFlags = [event modifierFlags]; - CommandKeyPressed = modifierFlags & NSEventModifierFlagCommand; - - [super flagsChanged:event]; -} - -@end diff --git a/NativeApp/Apple/Source/Classes/OSX/WindowController.mm b/NativeApp/Apple/Source/Classes/OSX/WindowController.mm new file mode 100644 index 0000000..e3f7923 --- /dev/null +++ b/NativeApp/Apple/Source/Classes/OSX/WindowController.mm @@ -0,0 +1,181 @@ +/* + Copyright (C) 2015 Apple Inc. All Rights Reserved. + See LICENSE.txt for this sample’s licensing information + + Abstract: + Window controller subclass. + */ + +#import "WindowController.h" +#import "FullscreenWindow.h" +#import "ViewBase.h" + +@interface WindowController () + +// Fullscreen window +@property(strong) FullscreenWindow *fullscreenWindow; + +// Non-Fullscreen window (also the initial window) +@property(strong) NSWindow* standardWindow; + +@end + +@implementation WindowController +{ + bool CommandKeyPressed; +} + +- (instancetype)initWithWindow:(NSWindow *)window +{ + self = [super initWithWindow:window]; + + if (self) + { + // Initialize to nil since it indicates app is not fullscreen + _fullscreenWindow = nil; + } + + CommandKeyPressed = false; + + return self; +} + +- (void) goFullscreen +{ + // If app is already fullscreen... + if([self fullscreenWindow]) + { + //...don't do anything + return; + } + + ViewBase* view = (ViewBase*)self.window.contentView; + + // We must stop the display link while + // switching the windows to make sure + // that render commands are not issued + // from another thread + [view stopDisplayLink]; + + // Allocate a new fullscreen window + [self setFullscreenWindow: [[FullscreenWindow alloc] init]]; + + [[self fullscreenWindow] setAcceptsMouseMovedEvents:YES]; + + // Resize the view to screensize + NSRect viewRect = [[self fullscreenWindow] frame]; + + // Set the view to the size of the fullscreen window + [self.window.contentView setFrameSize: viewRect.size]; + + // Set the view in the fullscreen window + [[self fullscreenWindow] setContentView:self.window.contentView]; + + [self setStandardWindow:[self window]]; + + // Hide non-fullscreen window so it doesn't show up when switching out + // of this app (i.e. with CMD-TAB) + [[self standardWindow] orderOut:self]; + + // Set controller to the fullscreen window so that all input will go to + // this controller (self) + [self setWindow:[self fullscreenWindow]]; + + // Show the window and make it the key window for input + [[self fullscreenWindow] makeKeyAndOrderFront:self]; + + // Restore display link + [view startDisplayLink]; +} + +- (void) goWindow +{ + // If controller doesn't have a full screen window... + if([self fullscreenWindow] == nil) + { + //...app is already windowed so don't do anything + return; + } + + ViewBase* view = (ViewBase*)self.window.contentView; + + // We must stop the display link while + // switching the windows to make sure + // that render commands are not issued + // from another thread + [view stopDisplayLink]; + + // Get the rectangle of the original window + NSRect viewRect = [[self standardWindow] frame]; + + // Set the view rect to the new size + [self.window.contentView setFrame:viewRect]; + + // Hide fullscreen window + [[self fullscreenWindow] orderOut:self]; + + // Set controller to the standard window so that all input will go to + // this controller (self) + [self setWindow:[self standardWindow]]; + + // Set the content of the orginal window to the view + [[self window] setContentView: [self fullscreenWindow].contentView]; + + // Show the window and make it the key window for input + [[self window] makeKeyAndOrderFront:self]; + + // Ensure we set fullscreen Window to nil so our checks for + // windowed vs. fullscreen mode elsewhere are correct + [self setFullscreenWindow: nil]; + + // Restore display link + [view startDisplayLink]; +} + + +- (void) keyDown:(NSEvent *)event +{ + unichar c = [[event charactersIgnoringModifiers] characterAtIndex:0]; + + switch (c) + { + // Handle [ESC] key + case 27: + if([self fullscreenWindow] != nil) + { + [self goWindow]; + } + return; + + // Have Command+f or Command+Enter toggle fullscreen + case 13: + case 'f': + if (CommandKeyPressed) + { + if([self fullscreenWindow] == nil) + { + [self goFullscreen]; + } + else + { + [self goWindow]; + } + } + return; + } + + // Allow other character to be handled (or not and beep) + //[super keyDown:event]; +} + +// Informs the receiver that the user has pressed or released a +// modifier key (Shift, Control, and so on) +- (void)flagsChanged:(NSEvent *)event +{ + auto modifierFlags = [event modifierFlags]; + CommandKeyPressed = modifierFlags & NSEventModifierFlagCommand; + + [super flagsChanged:event]; +} + +@end diff --git a/NativeApp/Apple/Source/Classes/iOS/AppViewBase.m b/NativeApp/Apple/Source/Classes/iOS/AppViewBase.m deleted file mode 100644 index 84d1b01..0000000 --- a/NativeApp/Apple/Source/Classes/iOS/AppViewBase.m +++ /dev/null @@ -1,160 +0,0 @@ - -#import "AppViewBase.h" - -#include "NativeAppBase.hpp" -#include -#include - -@interface AppViewBase () -{ - std::unique_ptr _theApp; - NSInteger _preferredFramesPerSecond; - CADisplayLink* _displayLink; - std::string _error; -} -@end - -@implementation AppViewBase - -- (void) initApp:(int)deviceType; -{ - try - { - _theApp.reset(Diligent::CreateApplication()); - // Init our renderer. - _theApp->Initialize(deviceType, (__bridge void*)self.layer); - } - catch(std::runtime_error &err) - { - _error = err.what(); - _theApp.reset(); - } - - [super stopAnimation]; - _preferredFramesPerSecond = 60; - _displayLink = nil; -} - -- (void) render -{ - if(_theApp) - { - _theApp->Update(); - _theApp->Render(); - _theApp->Present(); - } -} - -- (void) layoutSubviews -{ - auto bounds = [self.layer bounds]; - auto scale = [self.layer contentsScale]; - - if(_theApp) - { - _theApp->WindowResize(bounds.size.width * scale, bounds.size.height * scale); - } -} - -- (NSInteger) preferredFramesPerSecond -{ - return _preferredFramesPerSecond; -} - -- (void) setPreferredFramesPerSecond:(NSInteger)preferredFPS -{ - if (preferredFPS >= 1) - { - _preferredFramesPerSecond = preferredFPS; - - if (self.animating) - { - [self stopAnimation]; - [self startAnimation]; - } - } -} - -- (void) startAnimation -{ - if (!self.animating) - { - // Create the display link and set the callback to our drawView method - _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawView:)]; - - // Set it to our _animationFrameInterval - [_displayLink setPreferredFramesPerSecond:_preferredFramesPerSecond]; - - // Have the display link run on the default runn loop (and the main thread) - [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; - - [super startAnimation]; - } -} - -- (void)stopAnimation -{ - if (self.animating) - { - [_displayLink invalidate]; - _displayLink = nil; - [super stopAnimation]; - } -} - -- (void)terminate -{ - _theApp.reset(); - [super terminate]; -} - -- (NSString*)getError -{ - return _error.empty() ? nil : [NSString stringWithFormat:@"%s", _error.c_str()]; -} - -- (void)touchesBegan:(NSSet *)touches - withEvent:(UIEvent *)event; -{ - UITouch *firstTouch = touches.allObjects[0]; - CGPoint location = [firstTouch locationInView:self]; - if(_theApp) - { - _theApp->OnTouchBegan(location.x, location.y); - } -} - -- (void)touchesMoved:(NSSet *)touches - withEvent:(UIEvent *)event; -{ - UITouch *firstTouch = touches.allObjects[0]; - CGPoint location = [firstTouch locationInView:self]; - if(_theApp) - { - _theApp->OnTouchMoved(location.x, location.y); - } -} - -- (void)touchesEnded:(NSSet *)touches - withEvent:(UIEvent *)event; -{ - UITouch *firstTouch = touches.allObjects[0]; - CGPoint location = [firstTouch locationInView:self]; - if(_theApp) - { - _theApp->OnTouchEnded(location.x, location.y); - } -} - -- (void)touchesCancelled:(NSSet *)touches - withEvent:(UIEvent *)event; -{ - UITouch *firstTouch = touches.allObjects[0]; - CGPoint location = [firstTouch locationInView:self]; - if(_theApp) - { - _theApp->OnTouchEnded(location.x, location.y); - } -} - -@end diff --git a/NativeApp/Apple/Source/Classes/iOS/AppViewBase.mm b/NativeApp/Apple/Source/Classes/iOS/AppViewBase.mm new file mode 100644 index 0000000..84d1b01 --- /dev/null +++ b/NativeApp/Apple/Source/Classes/iOS/AppViewBase.mm @@ -0,0 +1,160 @@ + +#import "AppViewBase.h" + +#include "NativeAppBase.hpp" +#include +#include + +@interface AppViewBase () +{ + std::unique_ptr _theApp; + NSInteger _preferredFramesPerSecond; + CADisplayLink* _displayLink; + std::string _error; +} +@end + +@implementation AppViewBase + +- (void) initApp:(int)deviceType; +{ + try + { + _theApp.reset(Diligent::CreateApplication()); + // Init our renderer. + _theApp->Initialize(deviceType, (__bridge void*)self.layer); + } + catch(std::runtime_error &err) + { + _error = err.what(); + _theApp.reset(); + } + + [super stopAnimation]; + _preferredFramesPerSecond = 60; + _displayLink = nil; +} + +- (void) render +{ + if(_theApp) + { + _theApp->Update(); + _theApp->Render(); + _theApp->Present(); + } +} + +- (void) layoutSubviews +{ + auto bounds = [self.layer bounds]; + auto scale = [self.layer contentsScale]; + + if(_theApp) + { + _theApp->WindowResize(bounds.size.width * scale, bounds.size.height * scale); + } +} + +- (NSInteger) preferredFramesPerSecond +{ + return _preferredFramesPerSecond; +} + +- (void) setPreferredFramesPerSecond:(NSInteger)preferredFPS +{ + if (preferredFPS >= 1) + { + _preferredFramesPerSecond = preferredFPS; + + if (self.animating) + { + [self stopAnimation]; + [self startAnimation]; + } + } +} + +- (void) startAnimation +{ + if (!self.animating) + { + // Create the display link and set the callback to our drawView method + _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawView:)]; + + // Set it to our _animationFrameInterval + [_displayLink setPreferredFramesPerSecond:_preferredFramesPerSecond]; + + // Have the display link run on the default runn loop (and the main thread) + [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + + [super startAnimation]; + } +} + +- (void)stopAnimation +{ + if (self.animating) + { + [_displayLink invalidate]; + _displayLink = nil; + [super stopAnimation]; + } +} + +- (void)terminate +{ + _theApp.reset(); + [super terminate]; +} + +- (NSString*)getError +{ + return _error.empty() ? nil : [NSString stringWithFormat:@"%s", _error.c_str()]; +} + +- (void)touchesBegan:(NSSet *)touches + withEvent:(UIEvent *)event; +{ + UITouch *firstTouch = touches.allObjects[0]; + CGPoint location = [firstTouch locationInView:self]; + if(_theApp) + { + _theApp->OnTouchBegan(location.x, location.y); + } +} + +- (void)touchesMoved:(NSSet *)touches + withEvent:(UIEvent *)event; +{ + UITouch *firstTouch = touches.allObjects[0]; + CGPoint location = [firstTouch locationInView:self]; + if(_theApp) + { + _theApp->OnTouchMoved(location.x, location.y); + } +} + +- (void)touchesEnded:(NSSet *)touches + withEvent:(UIEvent *)event; +{ + UITouch *firstTouch = touches.allObjects[0]; + CGPoint location = [firstTouch locationInView:self]; + if(_theApp) + { + _theApp->OnTouchEnded(location.x, location.y); + } +} + +- (void)touchesCancelled:(NSSet *)touches + withEvent:(UIEvent *)event; +{ + UITouch *firstTouch = touches.allObjects[0]; + CGPoint location = [firstTouch locationInView:self]; + if(_theApp) + { + _theApp->OnTouchEnded(location.x, location.y); + } +} + +@end diff --git a/NativeApp/Apple/Source/Classes/iOS/BaseView.m b/NativeApp/Apple/Source/Classes/iOS/BaseView.m deleted file mode 100644 index c87e5cd..0000000 --- a/NativeApp/Apple/Source/Classes/iOS/BaseView.m +++ /dev/null @@ -1,21 +0,0 @@ - -#import "BaseView.h" - -@implementation BaseView - -- (void) startAnimation -{ - _animating = TRUE; -} - -- (void)stopAnimation -{ - _animating = FALSE; -} - -- (void) terminate -{ - -} - -@end diff --git a/NativeApp/Apple/Source/Classes/iOS/BaseView.mm b/NativeApp/Apple/Source/Classes/iOS/BaseView.mm new file mode 100644 index 0000000..c87e5cd --- /dev/null +++ b/NativeApp/Apple/Source/Classes/iOS/BaseView.mm @@ -0,0 +1,21 @@ + +#import "BaseView.h" + +@implementation BaseView + +- (void) startAnimation +{ + _animating = TRUE; +} + +- (void)stopAnimation +{ + _animating = FALSE; +} + +- (void) terminate +{ + +} + +@end diff --git a/NativeApp/Apple/Source/Classes/iOS/EAGLView.m b/NativeApp/Apple/Source/Classes/iOS/EAGLView.m deleted file mode 100644 index 5980493..0000000 --- a/NativeApp/Apple/Source/Classes/iOS/EAGLView.m +++ /dev/null @@ -1,76 +0,0 @@ -/* - Copyright (C) 2015 Apple Inc. All Rights Reserved. - See LICENSE.txt for this sample’s licensing information - - Abstract: - The EAGLView class is a UIView subclass that renders OpenGL scene. -*/ - -#import "EAGLView.h" - -#include "GraphicsTypes.h" - -@interface EAGLView () -{ - EAGLContext* _context; -} -@end - -@implementation EAGLView - -// Must return the CAEAGLLayer class so that CA allocates an EAGLLayer backing for this view -+ (Class) layerClass -{ - return [CAEAGLLayer class]; -} - -// The GL view is stored in the storyboard file. When it's unarchived it's sent -initWithCoder: -- (instancetype) initWithCoder:(NSCoder*)coder -{ - if ((self = [super initWithCoder:coder])) - { - // Get the layer - CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; - - eaglLayer.opaque = TRUE; - eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]; - - _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; - - if (!_context || ![EAGLContext setCurrentContext:_context]) - { - return nil; - } - - [self initApp:(int)Diligent::RENDER_DEVICE_TYPE_GLES]; - } - - return self; -} - -- (void) drawView:(id)sender -{ - [EAGLContext setCurrentContext:_context]; - - // There is no autorelease pool when this method is called - // because it will be called from a background thread. - // It's important to create one or app can leak objects. - @autoreleasepool - { - [self render]; - } -} - -- (void) dealloc -{ - [self terminate]; - - // tear down context - if ([EAGLContext currentContext] == _context) - [EAGLContext setCurrentContext:nil]; - - [super dealloc]; -} - -@end diff --git a/NativeApp/Apple/Source/Classes/iOS/EAGLView.mm b/NativeApp/Apple/Source/Classes/iOS/EAGLView.mm new file mode 100644 index 0000000..5980493 --- /dev/null +++ b/NativeApp/Apple/Source/Classes/iOS/EAGLView.mm @@ -0,0 +1,76 @@ +/* + Copyright (C) 2015 Apple Inc. All Rights Reserved. + See LICENSE.txt for this sample’s licensing information + + Abstract: + The EAGLView class is a UIView subclass that renders OpenGL scene. +*/ + +#import "EAGLView.h" + +#include "GraphicsTypes.h" + +@interface EAGLView () +{ + EAGLContext* _context; +} +@end + +@implementation EAGLView + +// Must return the CAEAGLLayer class so that CA allocates an EAGLLayer backing for this view ++ (Class) layerClass +{ + return [CAEAGLLayer class]; +} + +// The GL view is stored in the storyboard file. When it's unarchived it's sent -initWithCoder: +- (instancetype) initWithCoder:(NSCoder*)coder +{ + if ((self = [super initWithCoder:coder])) + { + // Get the layer + CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; + + eaglLayer.opaque = TRUE; + eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]; + + _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; + + if (!_context || ![EAGLContext setCurrentContext:_context]) + { + return nil; + } + + [self initApp:(int)Diligent::RENDER_DEVICE_TYPE_GLES]; + } + + return self; +} + +- (void) drawView:(id)sender +{ + [EAGLContext setCurrentContext:_context]; + + // There is no autorelease pool when this method is called + // because it will be called from a background thread. + // It's important to create one or app can leak objects. + @autoreleasepool + { + [self render]; + } +} + +- (void) dealloc +{ + [self terminate]; + + // tear down context + if ([EAGLContext currentContext] == _context) + [EAGLContext setCurrentContext:nil]; + + [super dealloc]; +} + +@end diff --git a/NativeApp/Apple/Source/Classes/iOS/MVKView.m b/NativeApp/Apple/Source/Classes/iOS/MVKView.m deleted file mode 100644 index 6f3a11e..0000000 --- a/NativeApp/Apple/Source/Classes/iOS/MVKView.m +++ /dev/null @@ -1,41 +0,0 @@ -#import "MVKView.h" - -#import - -#include "GraphicsTypes.h" - -@implementation MVKView - -+ (Class) layerClass -{ - return [CAMetalLayer class]; -} - -- (instancetype) initWithCoder:(NSCoder*)coder -{ - if ((self = [super initWithCoder:coder])) - { - [self initApp:(int)Diligent::RENDER_DEVICE_TYPE_VULKAN]; - } - - return self; -} - -- (void) drawView:(id)sender -{ - // There is no autorelease pool when this method is called - // because it will be called from a background thread. - // It's important to create one or app can leak objects. - @autoreleasepool - { - [self render]; - } -} - -- (void) dealloc -{ - [self terminate]; - [super dealloc]; -} - -@end diff --git a/NativeApp/Apple/Source/Classes/iOS/MVKView.mm b/NativeApp/Apple/Source/Classes/iOS/MVKView.mm new file mode 100644 index 0000000..6f3a11e --- /dev/null +++ b/NativeApp/Apple/Source/Classes/iOS/MVKView.mm @@ -0,0 +1,41 @@ +#import "MVKView.h" + +#import + +#include "GraphicsTypes.h" + +@implementation MVKView + ++ (Class) layerClass +{ + return [CAMetalLayer class]; +} + +- (instancetype) initWithCoder:(NSCoder*)coder +{ + if ((self = [super initWithCoder:coder])) + { + [self initApp:(int)Diligent::RENDER_DEVICE_TYPE_VULKAN]; + } + + return self; +} + +- (void) drawView:(id)sender +{ + // There is no autorelease pool when this method is called + // because it will be called from a background thread. + // It's important to create one or app can leak objects. + @autoreleasepool + { + [self render]; + } +} + +- (void) dealloc +{ + [self terminate]; + [super dealloc]; +} + +@end diff --git a/NativeApp/Apple/Source/Classes/iOS/MetalView.m b/NativeApp/Apple/Source/Classes/iOS/MetalView.m deleted file mode 100644 index c56049f..0000000 --- a/NativeApp/Apple/Source/Classes/iOS/MetalView.m +++ /dev/null @@ -1,41 +0,0 @@ -#import "MetalView.h" - -#import - -#include "GraphicsTypes.h" - -@implementation MetalView - -+ (Class) layerClass -{ - return [CAMetalLayer class]; -} - -- (instancetype) initWithCoder:(NSCoder*)coder -{ - if ((self = [super initWithCoder:coder])) - { - [self initApp:(int)Diligent::RENDER_DEVICE_TYPE_METAL]; - } - - return self; -} - -- (void) drawView:(id)sender -{ - // There is no autorelease pool when this method is called - // because it will be called from a background thread. - // It's important to create one or app can leak objects. - @autoreleasepool - { - [self render]; - } -} - -- (void) dealloc -{ - [self terminate]; - [super dealloc]; -} - -@end diff --git a/NativeApp/Apple/Source/Classes/iOS/MetalView.mm b/NativeApp/Apple/Source/Classes/iOS/MetalView.mm new file mode 100644 index 0000000..c56049f --- /dev/null +++ b/NativeApp/Apple/Source/Classes/iOS/MetalView.mm @@ -0,0 +1,41 @@ +#import "MetalView.h" + +#import + +#include "GraphicsTypes.h" + +@implementation MetalView + ++ (Class) layerClass +{ + return [CAMetalLayer class]; +} + +- (instancetype) initWithCoder:(NSCoder*)coder +{ + if ((self = [super initWithCoder:coder])) + { + [self initApp:(int)Diligent::RENDER_DEVICE_TYPE_METAL]; + } + + return self; +} + +- (void) drawView:(id)sender +{ + // There is no autorelease pool when this method is called + // because it will be called from a background thread. + // It's important to create one or app can leak objects. + @autoreleasepool + { + [self render]; + } +} + +- (void) dealloc +{ + [self terminate]; + [super dealloc]; +} + +@end diff --git a/NativeApp/CMakeLists.txt b/NativeApp/CMakeLists.txt index 2f9904d..eb55573 100644 --- a/NativeApp/CMakeLists.txt +++ b/NativeApp/CMakeLists.txt @@ -151,19 +151,16 @@ elseif(PLATFORM_MACOS) set(APPLE_SOURCE ${NATIVE_APP_SOURCE_DIR}/Apple/Source/main.m - ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/OSX/WindowController.m + ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/OSX/WindowController.mm ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/OSX/AppDelegate.m ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/OSX/FullscreenWindow.m - ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/OSX/GLView.m - ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/OSX/MetalView.m - ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/OSX/MVKView.m - ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/OSX/ViewBase.m + ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/OSX/GLView.mm + ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/OSX/MetalView.mm + ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/OSX/MVKView.mm + ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/OSX/ViewBase.mm ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/OSX/ViewController.mm ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/OSX/ModeSelectionViewController.mm ) - set_source_files_properties(${APPLE_SOURCE} PROPERTIES - COMPILE_FLAGS "-x objective-c++" - ) set(APPLE_INCLUDE ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/OSX/WindowController.h @@ -244,16 +241,12 @@ elseif(PLATFORM_IOS) set(APPLE_SOURCE ${NATIVE_APP_SOURCE_DIR}/Apple/Source/main.m ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/iOS/AppDelegate.m - ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/iOS/BaseView.m - ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/iOS/EAGLView.m - ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/iOS/AppViewBase.m + ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/iOS/BaseView.mm + ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/iOS/EAGLView.mm + ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/iOS/AppViewBase.mm ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/iOS/ModeSelectionViewController.mm - ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/iOS/MetalView.m - ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/iOS/MVKView.m - ) - - set_source_files_properties(${APPLE_SOURCE} PROPERTIES - COMPILE_FLAGS "-x objective-c++" + ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/iOS/MetalView.mm + ${NATIVE_APP_SOURCE_DIR}/Apple/Source/Classes/iOS/MVKView.mm ) set(APPLE_INCLUDE -- cgit v1.2.3