pathfinder/examples/macos_app/Pathfinder Example/PathfinderView.m

153 lines
5.0 KiB
Objective-C

//
// PathfinderView.m
// Pathfinder Example
//
// Created by Patrick Walton on 6/21/19.
// Copyright © 2019 The Pathfinder Project Developers. All rights reserved.
//
#import <QuartzCore/QuartzCore.h>
#import "PathfinderView.h"
#import <Metal/Metal.h>
#include <math.h>
static CVReturn outputCallback(CVDisplayLinkRef displayLink,
const CVTimeStamp *now,
const CVTimeStamp *outputTime,
CVOptionFlags flagsIn,
CVOptionFlags *flagsOut,
void *userData) {
[(__bridge PathfinderView *)userData _render];
return kCVReturnSuccess;
}
@implementation PathfinderView
#define FONT_SIZE 256.0f
- (void)_render {
[mRenderLock lock];
CGSize size = mLayerSize;
PFCanvasRef canvas = PFCanvasCreate(mFontContext, &(PFVector2F){size.width, size.height});
PFFillStyleRef fillStyle =
PFFillStyleCreateColor(&(PFColorU){0, 0, 0, 255});
float scaleX = cosf((float)mFrameNumber * 0.02);
PFTransform2F textTransform;
textTransform.matrix = (PFMatrix2x2F){scaleX, 0.0, 0.0, 1.0};
textTransform.vector = (PFVector2F){size.width * 0.5, size.height * 0.5};
PFCanvasSetTransform(canvas, &textTransform);
PFCanvasSetFillStyle(canvas, fillStyle);
PFCanvasSetFontSize(canvas, FONT_SIZE);
PFCanvasSetTextAlign(canvas, PF_TEXT_ALIGN_CENTER);
PFCanvasFillText(canvas, "Pathfinder", 0, &(PFVector2F){0.0, FONT_SIZE * 0.5});
PFFillStyleDestroy(fillStyle);
PFSceneRef scene = PFCanvasCreateScene(canvas);
PFSceneProxyRef sceneProxy =
PFSceneProxyCreateFromSceneAndRayonExecutor(scene, PF_RENDERER_LEVEL_D3D11);
PFTransform2F pfTransform;
pfTransform.matrix.m00 = 1.0;
pfTransform.matrix.m01 = 0.0;
pfTransform.matrix.m10 = 0.0;
pfTransform.matrix.m11 = 1.0;
pfTransform.vector.x = 0.0;
pfTransform.vector.y = 0.0;
PFBuildOptionsRef buildOptions = PFBuildOptionsCreate();
PFRenderTransformRef renderTransform = PFRenderTransformCreate2D(&pfTransform);
PFBuildOptionsSetTransform(buildOptions, renderTransform);
PFSceneProxyBuildAndRenderMetal(sceneProxy, mRenderer, buildOptions);
PFMetalDeviceRef pfMetalDevice = PFMetalRendererGetDevice(mRenderer);
PFMetalDevicePresentDrawable(pfMetalDevice, mCurrentDrawable);
mCurrentDrawable = [mLayer nextDrawable];
PFMetalDeviceSwapDrawable(pfMetalDevice, mCurrentDrawable);
mFrameNumber++;
[mRenderLock unlock];
}
- (void)_checkCVResult:(CVReturn)result {
if (result != kCVReturnSuccess) {
@throw [NSException exceptionWithName:@"CoreVideoCallFailed"
reason:@"Core Video call failed"
userInfo:nil];
}
}
- (void)_initializeIfNecessary:(CAMetalLayer *)layer {
if (mDevice != nil)
return;
mFrameNumber = 0;
mDevice = MTLCreateSystemDefaultDevice();
[layer setDevice:mDevice];
[layer setContentsScale:[[self window] backingScaleFactor]];
mRenderLock = [[NSLock alloc] init];
mLayerSize = [self convertSizeToBacking:[layer bounds].size];
mCurrentDrawable = [layer nextDrawable];
mLayer = layer;
PFMetalDeviceRef device = PFMetalDeviceCreateWithDrawable(mDevice, mCurrentDrawable);
PFResourceLoaderRef resourceLoader = PFFilesystemResourceLoaderLocate();
PFMetalDestFramebufferRef destFramebuffer =
PFMetalDestFramebufferCreateFullWindow(&(PFVector2I){mLayerSize.width, mLayerSize.height});
PFRendererMode rendererMode;
rendererMode.level = PF_RENDERER_LEVEL_D3D11;
PFRendererOptions rendererOptions;
rendererOptions.background_color = (PFColorF){1.0, 1.0, 1.0, 1.0};
rendererOptions.flags = PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR;
rendererOptions.dest = destFramebuffer;
mRenderer = PFMetalRendererCreate(device,
resourceLoader,
&rendererMode,
&rendererOptions);
mFontContext = PFCanvasFontContextCreateWithSystemSource();
mBuildOptions = PFBuildOptionsCreate();
[self _checkCVResult:CVDisplayLinkCreateWithActiveCGDisplays(&mDisplayLink)];
[self _checkCVResult:CVDisplayLinkSetOutputCallback(mDisplayLink,
outputCallback,
(__bridge void *_Nullable)(self))];
[self _checkCVResult:CVDisplayLinkStart(mDisplayLink)];
}
- (CALayer *)makeBackingLayer {
return [[CAMetalLayer alloc] init];
}
- (BOOL)wantsLayer {
return YES;
}
- (BOOL)wantsUpdateLayer {
return YES;
}
- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy {
return NSViewLayerContentsRedrawOnSetNeedsDisplay;
}
- (void)drawRect:(NSRect)dirtyRect {
[self _initializeIfNecessary:(CAMetalLayer *)[self layer]];
}
- (void)displayLayer:(CALayer *)layer {
[self _initializeIfNecessary:(CAMetalLayer *)layer];
}
- (void)awakeFromNib {
[self _initializeIfNecessary:(CAMetalLayer *)[self layer]];
}
@end