123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672 |
- //
- // SKTransitionController.m
- // Skim
- //
- // Created by Christiaan Hofman on 7/15/07.
- /*
- This software is Copyright (c) 2007-2018
- Christiaan Hofman. All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- - Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- - Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- - Neither the name of Christiaan Hofman nor the names of any
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
- /*
- This code is based partly on Apple's AnimatingTabView example code
- and Ankur Kothari's AnimatingTabsDemo application <http://dev.lipidity.com>
- */
- #import "SKTransitionController.h"
- #import "NSBitmapImageRep_SKExtensions.h"
- //#import "NSView_SKExtensions.h"
- #import <CoreFoundation/CoreFoundation.h>
- #import <Quartz/Quartz.h>
- #include <unistd.h>
- #import <OpenGL/OpenGL.h>
- #import <OpenGL/gl.h>
- #import <objc/runtime.h>
- NSString *SKStyleNameKey = @"styleName";
- NSString *SKDurationKey = @"duration";
- NSString *SKShouldRestrictKey = @"shouldRestrict";
- NSString *KMTransitionStyleName = @"transitionStyle";
- NSString *KMDurationName = @"duration";
- NSString *KMShouldRestrictName = @"shouldRestrict";
- NSString *KMPageTransitionsName = @"pageTransitions";
- NSString *KMOldValueName = @"oldValue";
- NSString *KMNewValueName = @"newValue";
- #define kCIInputBacksideImageKey @"inputBacksideImage"
- #define kCIInputRectangleKey @"inputRectangle"
- #define WEAK_NULL NULL
- #pragma mark Private Core Graphics types and functions
- typedef int CGSConnection;
- typedef int CGSWindow;
- typedef enum _CGSTransitionType {
- CGSNone,
- CGSFade,
- CGSZoom,
- CGSReveal,
- CGSSlide,
- CGSWarpFade,
- CGSSwap,
- CGSCube,
- CGSWarpSwitch,
- CGSFlip
- } CGSTransitionType;
- typedef enum _CGSTransitionOption {
- CGSDown,
- CGSLeft,
- CGSRight,
- CGSInRight,
- CGSBottomLeft = 5,
- CGSBottomRight,
- CGSDownTopRight,
- CGSUp,
- CGSTopLeft,
- CGSTopRight,
- CGSUpBottomRight,
- CGSInBottom,
- CGSLeftBottomRight,
- CGSRightBottomLeft,
- CGSInBottomRight,
- CGSInOut
- } CGSTransitionOption;
- typedef struct _CGSTransitionSpec {
- uint32_t unknown1;
- CGSTransitionType type;
- CGSTransitionOption option;
- CGSWindow wid; // Can be 0 for full-screen
- float *backColour; // Null for black otherwise pointer to 3 CGFloat array with RGB value
- } CGSTransitionSpec;
- extern CGSConnection _CGSDefaultConnection(void) __attribute__((weak_import));
- extern OSStatus CGSNewTransition(const CGSConnection cid, const CGSTransitionSpec* spec, int *pTransitionHandle) __attribute__((weak_import));
- extern OSStatus CGSInvokeTransition(const CGSConnection cid, int transitionHandle, float duration) __attribute__((weak_import));
- extern OSStatus CGSReleaseTransition(const CGSConnection cid, int transitionHandle) __attribute__((weak_import));
- #pragma mark Check whether the above functions are actually defined at run time
- static BOOL CoreGraphicsServicesTransitionsDefined() {
- return _CGSDefaultConnection != WEAK_NULL &&
- CGSNewTransition != WEAK_NULL &&
- CGSInvokeTransition != WEAK_NULL &&
- CGSReleaseTransition != WEAK_NULL;
- }
- #define SDK_BEFORE(_version) (!defined(MAC_OS_X_VERSION_ ## _version) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_ ## _version)
- #pragma mark -
- typedef void(^SKTransitionAnimationProgressHandler)(CGFloat);
- @interface SKTransitionAnimation : NSAnimation {
- SKTransitionAnimationProgressHandler progressHandler;
- }
- @property (nonatomic, copy) SKTransitionAnimationProgressHandler progressHandler;
- @end
- #pragma mark -
- #if SDK_BEFORE(10_7)
- @interface NSOpenGLView (SKLionDeclarations)
- - (BOOL)wantsBestResolutionOpenGLSurface;
- - (void)setWantsBestResolutionOpenGLSurface:(BOOL)flag;
- @end
- #endif
- @interface SKTransitionView : NSOpenGLView {
- CIImage *image;
- CGFloat imageScale;
- CIContext *context;
- BOOL needsReshape;
- }
- @property (nonatomic, retain) CIImage *image;
- @property (nonatomic) CGFloat imageScale;
- @end
- #pragma mark -
- @implementation SKTransitionController
- // transitionStyle duration shouldRestrict pageTransitions
- @synthesize view;
- @dynamic hasTransition;
- + (NSArray *)transitionNames {
- static NSArray *transitionNames = nil;
-
- if (transitionNames == nil) {
- transitionNames = [NSArray arrayWithObjects:
- @"",
- @"CoreGraphics SKTransitionFade",
- @"CoreGraphics SKTransitionZoom",
- @"CoreGraphics SKTransitionReveal",
- @"CoreGraphics SKTransitionSlide",
- @"CoreGraphics SKTransitionWarpFade",
- @"CoreGraphics SKTransitionSwap",
- @"CoreGraphics SKTransitionCube",
- @"CoreGraphics SKTransitionWarpSwitch",
- @"CoreGraphics SKTransitionWarpFlip", nil];
- // get all the transition filters
- [CIPlugIn loadAllPlugIns];
- transitionNames = [[transitionNames arrayByAddingObjectsFromArray:[CIFilter filterNamesInCategory:kCICategoryTransition]] copy];
- }
-
- return transitionNames;
- }
- + (NSString *)nameForStyle:(SKAnimationTransitionStyle)style {
- if (style > SKNoTransition && style < [[self transitionNames] count])
- return [[self transitionNames] objectAtIndex:style];
- else
- return nil;
- }
- + (SKAnimationTransitionStyle)styleForName:(NSString *)name {
- NSUInteger idx = [[self transitionNames] indexOfObject:name];
- return idx == NSNotFound ? SKNoTransition : idx;
- }
- + (NSString *)localizedNameForStyle:(SKAnimationTransitionStyle)style {
- switch (style) {
- case SKNoTransition: return NSLocalizedString(@"No Transition", @"Transition name");
- case SKTransitionFade: return NSLocalizedString(@"Fade", @"Transition name");
- case SKTransitionZoom: return NSLocalizedString(@"Zoom", @"Transition name");
- case SKTransitionReveal: return NSLocalizedString(@"Reveal", @"Transition name");
- case SKTransitionSlide: return NSLocalizedString(@"Slide", @"Transition name");
- case SKTransitionWarpFade: return NSLocalizedString(@"Warp Fade", @"Transition name");
- case SKTransitionSwap: return NSLocalizedString(@"Swap", @"Transition name");
- case SKTransitionCube: return NSLocalizedString(@"Cube", @"Transition name");
- case SKTransitionWarpSwitch: return NSLocalizedString(@"Warp Switch", @"Transition name");
- case SKTransitionWarpFlip: return NSLocalizedString(@"Flip", @"Transition name");
- default: return [CIFilter localizedNameForFilterName:[self nameForStyle:style]];
- };
- }
- - (id)initForView:(NSView *)aView {
- self = [super init];
- if (self) {
- self.view = aView; // don't retain as it may retain us
- imageRect = NSZeroRect;
-
- _transitionStyle = SKNoTransition;
- _duration = 1.0;
- _shouldRestrict = YES;
- currentTransitionStyle = SKNoTransition;
- currentDuration = 1.0;
- currentShouldRestrict = YES;
- currentForward = YES;
- }
- return self;
- }
- - (void)dealloc {
- self.view = nil;
- }
- - (NSRect)convertRectToScreen:(NSRect)rect view:(NSView *)view{
- rect = [view convertRect:rect toView:nil];
- rect.origin = [[view window] convertBaseToScreen:rect.origin];
- return rect;
- }
- - (BOOL)hasTransition {
- return self.transitionStyle != SKNoTransition || self.pageTransitions != nil;
- }
- static inline CGRect scaleRect(NSRect rect, CGFloat scale) {
- return CGRectMake(scale * NSMinX(rect), scale * NSMinY(rect), scale * NSWidth(rect), scale * NSHeight(rect));
- }
- // rect and bounds are in pixels
- - (CIFilter *)transitionFilterForRect:(CGRect)rect bounds:(CGRect)bounds forward:(BOOL)forward initialCIImage:(CIImage *)initialCIImage finalCIImage:(CIImage *)finalCIImage {
- NSString *filterName = [[self class] nameForStyle:currentTransitionStyle];
- CIFilter *transitionFilter = [CIFilter filterWithName:filterName];
-
- [transitionFilter setDefaults];
-
- for (NSString *key in [transitionFilter inputKeys]) {
- id value = nil;
- if ([key isEqualToString:kCIInputExtentKey]) {
- CGRect extent = currentShouldRestrict ? rect : bounds;
- value = [CIVector vectorWithX:CGRectGetMinX(extent) Y:CGRectGetMinY(extent) Z:CGRectGetWidth(extent) W:CGRectGetHeight(extent)];
- } else if ([key isEqualToString:kCIInputAngleKey]) {
- CGFloat angle = forward ? 0.0 : M_PI;
- if ([filterName isEqualToString:@"CIPageCurlTransition"] || [filterName isEqualToString:@"CIPageCurlWithShadowTransition"])
- angle = forward ? -M_PI_4 : -3.0 * M_PI_4;
- value = [NSNumber numberWithDouble:angle];
- } else if ([key isEqualToString:kCIInputCenterKey]) {
- value = [CIVector vectorWithX:CGRectGetMidX(rect) Y:CGRectGetMidY(rect)];
- } else if ([key isEqualToString:kCIInputImageKey]) {
- value = initialCIImage;
- if (CGRectEqualToRect(rect, bounds) == NO)
- value = [value imageByCroppingToRect:rect];
- } else if ([key isEqualToString:kCIInputTargetImageKey]) {
- value = finalCIImage;
- if (CGRectEqualToRect(rect, bounds) == NO)
- value = [value imageByCroppingToRect:rect];
- } else if ([key isEqualToString:kCIInputShadingImageKey]) {
- static CIImage *inputShadingImage = nil;
- if (inputShadingImage == nil)
- inputShadingImage = [[CIImage alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"TransitionShading" withExtension:@"tiff"]];
- value = inputShadingImage;
- } else if ([key isEqualToString:kCIInputBacksideImageKey]) {
- value = initialCIImage;
- if (CGRectEqualToRect(rect, bounds) == NO)
- value = [value imageByCroppingToRect:rect];
- } else if ([[[[transitionFilter attributes] objectForKey:key] objectForKey:kCIAttributeClass] isEqualToString:@"CIImage"]) {
- // Scale and translate our mask image to match the transition area size.
- static CIImage *inputMaskImage = nil;
- if (inputMaskImage == nil)
- inputMaskImage = [[CIImage alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"TransitionMask" withExtension:@"jpg"]];
- CGRect extent = [inputMaskImage extent];
- CGAffineTransform transform;
- if ((CGRectGetWidth(extent) < CGRectGetHeight(extent)) != (CGRectGetWidth(rect) < CGRectGetHeight(rect))) {
- transform = CGAffineTransformMake(0.0, 1.0, 1.0, 0.0, 0.0, 0.0);
- transform = CGAffineTransformTranslate(transform, CGRectGetMinY(rect) - CGRectGetMinY(bounds), CGRectGetMinX(rect) - CGRectGetMinX(bounds));
- transform = CGAffineTransformScale(transform, CGRectGetHeight(rect) / CGRectGetWidth(extent), CGRectGetWidth(rect) / CGRectGetHeight(extent));
- } else {
- transform = CGAffineTransformMakeTranslation(CGRectGetMinX(rect) - CGRectGetMinX(bounds), CGRectGetMinY(rect) - CGRectGetMinY(bounds));
- transform = CGAffineTransformScale(transform, CGRectGetWidth(rect) / CGRectGetWidth(extent), CGRectGetHeight(rect) / CGRectGetHeight(extent));
- }
- value = [inputMaskImage imageByApplyingTransform:transform];
- } else continue;
- [transitionFilter setValue:value forKey:key];
- }
-
- return transitionFilter;
- }
- - (CIImage *)newCurrentImage {
- NSRect bounds = [view bounds];
- NSBitmapImageRep *contentBitmap = [view bitmapImageRepForCachingDisplayInRect:bounds];
-
- [contentBitmap clear];
- [view cacheDisplayInRect:bounds toBitmapImageRep:contentBitmap];
-
- return [[CIImage alloc] initWithBitmapImageRep:contentBitmap];
- }
- - (SKTransitionView *)transitionViewForRect:(NSRect)rect image:(CIImage *)image scale:(CGFloat)imageScale {
- SKTransitionView *transitionView = nil;
-
- if (window == nil) {
- transitionView = [[SKTransitionView alloc] init];
- if ([transitionView respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)])
- [transitionView setWantsBestResolutionOpenGLSurface:YES];
- window = [[NSWindow alloc] initWithContentRect:NSZeroRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
- [window setReleasedWhenClosed:NO];
- [window setIgnoresMouseEvents:YES];
- [window setContentView:transitionView];
- } else {
- transitionView = (SKTransitionView *)[window contentView];
- }
-
- [transitionView setImageScale:imageScale];
- [transitionView setImage:image];
- [transitionView setNeedsDisplay:YES];
-
- [window setFrame:[self convertRectToScreen:rect view:view] display:NO];
- [window orderBack:nil];
- [[view window] addChildWindow:window ordered:NSWindowAbove];
-
- return transitionView;
- }
- - (void)prepareAnimationForRect:(NSRect)rect from:(NSUInteger)fromIndex to:(NSUInteger)toIndex {
- currentTransitionStyle = self.transitionStyle;
- currentDuration = self.duration;
- currentShouldRestrict = self.shouldRestrict;
- currentForward = (toIndex >= fromIndex);
-
- NSUInteger idx = MIN(fromIndex, toIndex);
- if (fromIndex != NSNotFound && toIndex != NSNotFound && idx < [self.pageTransitions count]) {
- NSDictionary *info = [self.pageTransitions objectAtIndex:idx];
- id value;
- if ((value = [info objectForKey:SKStyleNameKey]))
- currentTransitionStyle = [[self class] styleForName:value];
- if ((value = [info objectForKey:SKDurationKey]) && [value respondsToSelector:@selector(doubleValue)])
- currentDuration = [value doubleValue];
- if ((value = [info objectForKey:SKShouldRestrictKey]) && [value respondsToSelector:@selector(boolValue)])
- currentShouldRestrict = [value boolValue];
- }
-
- if (currentTransitionStyle >= SKCoreImageTransition) {
- initialImage = [self newCurrentImage];
- // We don't want the window to draw the next state before the animation is run
- [[view window] disableFlushWindow];
- } else if (currentTransitionStyle > SKNoTransition && CoreGraphicsServicesTransitionsDefined()) {
- if (currentShouldRestrict) {
- initialImage = [self newCurrentImage];
- }
- // We don't want the window to draw the next state before the animation is run
- [[view window] disableFlushWindow];
- }
- imageRect = rect;
- }
- - (void)animateUsingCoreGraphics {
- CIImage *finalImage = nil;
- NSWindow *viewWindow = [view window];
- SKTransitionView *transitionView = nil;
-
- if (currentShouldRestrict) {
- NSRect bounds = [view bounds];
- CGFloat imageScale = CGRectGetWidth([initialImage extent]) / NSWidth(bounds);
-
- finalImage = [self newCurrentImage];
-
- CGAffineTransform transform = CGAffineTransformMakeTranslation(-imageScale * NSMinX(imageRect), -imageScale * NSMinY(imageRect));
- initialImage = [initialImage imageByApplyingTransform:transform];
- finalImage = [finalImage imageByApplyingTransform:transform];
-
- transitionView = [self transitionViewForRect:imageRect image:initialImage scale:imageScale];
- initialImage = nil;
- }
-
- // declare our variables
- int handle = -1;
- CGSTransitionSpec spec;
- // specify our specifications
- spec.unknown1 = 0;
- spec.type = currentTransitionStyle;
- spec.option = currentForward ? CGSLeft : CGSRight;
- spec.backColour = NULL;
- spec.wid = [(currentShouldRestrict ? window : viewWindow) windowNumber];
-
- // Let's get a connection
- CGSConnection cgs = _CGSDefaultConnection();
-
- // Create a transition
- CGSNewTransition(cgs, &spec, &handle);
-
- if (currentShouldRestrict) {
- [transitionView setImage:finalImage];
- [transitionView display];
- }
-
- // Redraw the window
- [viewWindow display];
- // Remember we disabled flushing in the previous method, we need to balance that.
- [viewWindow enableFlushWindow];
- [viewWindow flushWindow];
-
- CGSInvokeTransition(cgs, handle, currentDuration);
- // We need to wait for the transition to finish before we get rid of it, otherwise we'll get all sorts of nasty errors... or maybe not.
- [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:currentDuration]];
-
- CGSReleaseTransition(cgs, handle);
- handle = 0;
-
- if (currentShouldRestrict) {
- [viewWindow removeChildWindow:window];
- [window orderOut:nil];
- [transitionView setImage:nil];
- }
- }
- - (void)animateUsingCoreImage {
- NSRect bounds = [view bounds];
- CGFloat imageScale = CGRectGetWidth([initialImage extent]) / NSWidth(bounds);
-
- CIImage *finalImage = [self newCurrentImage];
-
- CIFilter *transitionFilter = [self transitionFilterForRect:scaleRect(imageRect, imageScale) bounds:scaleRect(bounds, imageScale) forward:currentForward initialCIImage:initialImage finalCIImage:finalImage];
-
- SKTransitionView *transitionView = [self transitionViewForRect:bounds image:initialImage scale:imageScale];
-
- initialImage = nil;
-
- SKTransitionAnimation *animation = [[SKTransitionAnimation alloc] initWithDuration:currentDuration animationCurve:NSAnimationEaseInOut];
- [animation setProgressHandler:^(CGFloat value){
- [transitionFilter setValue:[NSNumber numberWithDouble:value] forKey:kCIInputTimeKey];
- [transitionView setImage:[transitionFilter valueForKey:kCIOutputImageKey]];
- [transitionView display];
- }];
- [animation startAnimation];
-
- // Update the view and its window, so it shows the correct state when it is shown.
- [view display];
- // Remember we disabled flushing in the previous method, we need to balance that.
- NSWindow *viewWindow = [view window];
- [viewWindow enableFlushWindow];
- [viewWindow flushWindow];
-
- [viewWindow removeChildWindow:window];
- [window orderOut:nil];
- [transitionView setImage:nil];
- }
- - (void)animateForRect:(NSRect)rect {
- if (NSEqualRects(imageRect, NSZeroRect))
- [self prepareAnimationForRect:rect from:NSNotFound to:NSNotFound];
- imageRect = NSIntegralRect(NSIntersectionRect(NSUnionRect(imageRect, rect), [view bounds]));
-
- if (currentTransitionStyle >= SKCoreImageTransition)
- [self animateUsingCoreImage];
- else if (currentTransitionStyle > SKNoTransition && CoreGraphicsServicesTransitionsDefined())
- [self animateUsingCoreGraphics];
-
- currentTransitionStyle = self.transitionStyle;
- currentDuration = self.duration;
- currentShouldRestrict = self.shouldRestrict;
- currentForward = YES;
-
- imageRect = NSZeroRect;
- }
- - (void)setTransitionStyle:(SKAnimationTransitionStyle)transitionStyle {
- SKAnimationTransitionStyle oldValue = _transitionStyle;
- _transitionStyle = transitionStyle;
-
- [self.delegate transitionController:self valueDidChanged:@{
- KMTransitionStyleName : @{
- KMOldValueName : @(oldValue),
- KMNewValueName : @(transitionStyle)
- }
- }];
- }
- - (void)setDuration:(CGFloat)duration {
- CGFloat oldValue = self.duration;
- _duration = duration;
-
- [self.delegate transitionController:self valueDidChanged:@{
- KMDurationName : @{
- KMOldValueName : @(oldValue),
- KMNewValueName : @(duration)
- }
- }];
- }
- - (void)setShouldRestrict:(BOOL)shouldRestrict {
- BOOL oldValue = self.shouldRestrict;
- _shouldRestrict = shouldRestrict;
-
- [self.delegate transitionController:self valueDidChanged:@{
- KMShouldRestrictName : @{
- KMOldValueName : @(oldValue),
- KMNewValueName : @(shouldRestrict)
- }
- }];
- }
- - (void)setPageTransitions:(NSArray *)pageTransitions {
- NSArray *oldValue = self.pageTransitions;
- _pageTransitions = pageTransitions;
-
- [self.delegate transitionController:self valueDidChanged:@{
- KMPageTransitionsName : @{
- KMOldValueName : oldValue ? oldValue : @[],
- KMNewValueName : pageTransitions ? pageTransitions : @[]
- }
- }];
- }
- @end
- #pragma mark -
- @implementation SKTransitionAnimation
- @synthesize progressHandler;
- - (void)dealloc {
- progressHandler = nil;
- }
- - (void)setCurrentProgress:(NSAnimationProgress)progress {
- [super setCurrentProgress:progress];
- if (progressHandler) progressHandler([self currentValue]);
- }
- @end
- #pragma mark -
- @implementation SKTransitionView
- @synthesize image, imageScale;
- + (NSOpenGLPixelFormat *)defaultPixelFormat {
- static NSOpenGLPixelFormat *pf;
- if (pf == nil) {
- NSOpenGLPixelFormatAttribute attr[] = {
- NSOpenGLPFAAccelerated,
- NSOpenGLPFANoRecovery,
- NSOpenGLPFAColorSize,
- 32,
- 0
- };
-
- pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
- }
- return pf;
- }
- - (void)dealloc {
-
- }
- - (void)reshape {
- needsReshape = YES;
- }
- - (void)prepareOpenGL {
- // Enable beam-synced updates.
- GLint parm = 1;
- [[self openGLContext] setValues:&parm forParameter:NSOpenGLCPSwapInterval];
-
- // Make sure that everything we don't need is disabled.
- // Some of these are enabled by default and can slow down rendering.
-
- glDisable(GL_ALPHA_TEST);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_SCISSOR_TEST);
- glDisable(GL_BLEND);
- glDisable(GL_DITHER);
- glDisable(GL_CULL_FACE);
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- glDepthMask(GL_FALSE);
- glStencilMask(0);
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- glHint(GL_TRANSFORM_HINT_APPLE, GL_FASTEST);
-
- needsReshape = YES;
- }
- - (CGFloat)backingScaleNew {
- if ([self respondsToSelector:@selector(convertSizeToBacking:)])
- return [self convertSizeToBacking:NSMakeSize(1.0, 1.0)].width;
- return 1.0;
- }
- - (void)updateMatrices {
- NSRect bounds = [self bounds];
- CGFloat scale = ([self respondsToSelector:@selector(wantsBestResolutionOpenGLSurface)] && [self wantsBestResolutionOpenGLSurface]) ? [self backingScaleNew] : 1.0;
-
- [[self openGLContext] update];
-
- glViewport(0, 0, scale * NSWidth(bounds), scale * NSHeight(bounds));
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(scale * NSMinX(bounds), scale * NSMaxX(bounds), scale * NSMinY(bounds), scale * NSMaxY(bounds), -1, 1);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
-
- needsReshape = NO;
- }
- - (void)drawRect:(NSRect)rect {
- [[self openGLContext] makeCurrentContext];
-
- if (needsReshape)
- [self updateMatrices];
-
- glClearColor(0.0, 0.0, 0.0, 1.0);
- glClear(GL_COLOR_BUFFER_BIT);
- if (image) {
- CGFloat scale = ([self respondsToSelector:@selector(wantsBestResolutionOpenGLSurface)] && [self wantsBestResolutionOpenGLSurface]) ? [self backingScaleNew] : 1.0;
- NSRect bounds = [self bounds];
- if (context == nil) {
- NSOpenGLPixelFormat *pf = [self pixelFormat] ?: [[self class] defaultPixelFormat];
- context = [CIContext contextWithCGLContext:CGLGetCurrentContext() pixelFormat:[pf CGLPixelFormatObj] colorSpace:nil options:nil];
- }
- [context drawImage:image inRect:scaleRect(bounds, scale) fromRect:scaleRect(bounds, imageScale)];
- }
-
- glFlush();
- }
- @end
- @implementation SKTransitionController (KMExtension)
- //- (void)setDelegate:(id<SKTransitionControllerDelegate>)delegate {
- // objc_setAssociatedObject(self, @selector(delegate), delegate, OBJC_ASSOCIATION_ASSIGN);
- //}
- //
- //- (id<SKTransitionControllerDelegate>)delegate {
- // return objc_getAssociatedObject(self, @selector(delegate));
- //}
- @end
|