Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added another example project #10

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions Example2/StarWars/Circular/AnimationDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// Copyright © 2014 Yalantis
// Licensed under the MIT license: http://opensource.org/licenses/MIT
//

import UIKit

open class AnimationDelegate: NSObject, CAAnimationDelegate {

fileprivate let completion: () -> Void

public init(completion: @escaping () -> Void) {
self.completion = completion
}

public func animationDidStop(_: CAAnimation, finished: Bool) {
completion()
}
}
68 changes: 68 additions & 0 deletions Example2/StarWars/Circular/CircularRevealAnimator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//
// Copyright © 2014 Yalantis
// Licensed under the MIT license: http://opensource.org/licenses/MIT
//

import QuartzCore

private func SquareAroundCircle(_ center: CGPoint, radius: CGFloat) -> CGRect {
assert(0 <= radius, "radius must be a positive value")
return CGRect(origin: center, size: CGSize.zero).insetBy(dx: -radius, dy: -radius)
}

open class CircularRevealAnimator {

public var completion: (() -> Void)?

fileprivate let layer: CALayer
fileprivate let mask: CAShapeLayer
fileprivate let animation: CABasicAnimation

public var duration: CFTimeInterval {
get { return animation.duration }
set(value) { animation.duration = value }
}

public var timingFunction: CAMediaTimingFunction! {
get { return animation.timingFunction }
set(value) { animation.timingFunction = value }
}

public init(layer: CALayer, center: CGPoint, startRadius: CGFloat, endRadius: CGFloat, invert: Bool = false) {
let startCirclePath = CGPath(ellipseIn: SquareAroundCircle(center, radius: startRadius), transform: nil)
let endCirclePath = CGPath(ellipseIn: SquareAroundCircle(center, radius: endRadius), transform: nil)

var startPath = startCirclePath, endPath = endCirclePath
if invert {
var path = CGMutablePath()
path.addRect(layer.bounds)
path.addPath(startCirclePath)
startPath = path
path = CGMutablePath()
path.addRect(layer.bounds)
path.addPath(endCirclePath)
endPath = path
}

self.layer = layer

mask = CAShapeLayer()
mask.path = endPath
mask.fillRule = kCAFillRuleEvenOdd

animation = CABasicAnimation(keyPath: "path")
animation.fromValue = startPath
animation.toValue = endPath
animation.delegate = AnimationDelegate {
layer.mask = nil
self.completion?()
self.animation.delegate = nil
}
}

public func start() {
layer.mask = mask
mask.frame = layer.bounds
mask.add(animation, forKey: "reveal")
}
}
38 changes: 38 additions & 0 deletions Example2/StarWars/Circular/UIView+CircularAnimation.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// UIView+CircularAnimation.swift
// StarWarsAnimations
//
// Created by Artem Sidorenko on 10/5/15.
// Copyright © 2015 Yalantis. All rights reserved.
//

import UIKit

extension UIView {

open func animateCircular(withDuration duration: TimeInterval, center: CGPoint, revert: Bool = false, animations: () -> Void, completion: ((Bool) -> Void)? = nil) {
let snapshot = snapshotView(afterScreenUpdates: false)!
snapshot.frame = bounds
self.addSubview(snapshot)

let center = convert(center, to: snapshot)
let radius: CGFloat = {
let x = frame.width
let y = frame.height
return sqrt(x * x + y * y)
}()
var animation : CircularRevealAnimator
if !revert {
animation = CircularRevealAnimator(layer: snapshot.layer, center: center, startRadius: 0, endRadius: radius, invert: true)
} else {
animation = CircularRevealAnimator(layer: snapshot.layer, center: center, startRadius: radius, endRadius: 0, invert: false)
}
animation.duration = duration
animation.completion = {
snapshot.removeFromSuperview()
completion?(true)
}
animation.start()
animations()
}
}
24 changes: 24 additions & 0 deletions Example2/StarWars/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
19 changes: 19 additions & 0 deletions Example2/StarWars/StarWars.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// StarWars.h
// StarWars
//
// Created by Isabel Lee on 02/05/2017.
// Copyright © 2017 isabeljlee. All rights reserved.
//

#import <UIKit/UIKit.h>

//! Project version number for StarWars.
FOUNDATION_EXPORT double StarWarsVersionNumber;

//! Project version string for StarWars.
FOUNDATION_EXPORT const unsigned char StarWarsVersionString[];

// In this header, you should import all the public headers of your framework using statements like #import <StarWars/PublicHeader.h>


60 changes: 60 additions & 0 deletions Example2/StarWars/StarWarsGLAnimator/Sprite.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// Created by Artem Sidorenko on 10/8/15.
// Copyright © 2015 Yalantis. All rights reserved.
//
// Licensed under the MIT license: http://opensource.org/licenses/MIT
// Latest version can be found at https://github.com/Yalantis/StarWars.iOS
//

import GLKit

struct TexturedVertex {
var geometryVertex = Vector2()
var textureVertex = Vector2()
}

struct TexturedQuad {
var bl = TexturedVertex()
var br = TexturedVertex() { didSet { _br = br } }
var tl = TexturedVertex() { didSet { _tl = tl } }
var tr = TexturedVertex()

// openGL optimization. it uses triangles to draw.
// so we duplicate 2 vertex, so it have 6 vertex to draw two triangles
fileprivate var _br = TexturedVertex()
fileprivate var _tl = TexturedVertex()
}

struct Sprite {
var quad = TexturedQuad()
var moveVelocity = Vector2()

mutating func slice(_ rect: CGRect, textureSize: CGSize) {
quad.bl.geometryVertex = Vector2(x: 0, y: 0)
quad.br.geometryVertex = Vector2(x: rect.size.width, y: 0)
quad.tl.geometryVertex = Vector2(x: 0, y: rect.size.height)
quad.tr.geometryVertex = Vector2(x: rect.size.width, y: rect.size.height)

quad.bl.textureVertex = Vector2(x: rect.origin.x / textureSize.width, y: rect.origin.y / textureSize.height)
quad.br.textureVertex = Vector2(x: (rect.origin.x + rect.size.width) / textureSize.width, y: rect.origin.y / textureSize.height)
quad.tl.textureVertex = Vector2(x: rect.origin.x / textureSize.width, y: (rect.origin.y + rect.size.height) / textureSize.height)
quad.tr.textureVertex = Vector2(x: (rect.origin.x + rect.size.width) / textureSize.width, y: (rect.origin.y + rect.size.height) / textureSize.height)

position += Vector2(rect.origin)
}

var position = Vector2() {
didSet {
let diff = position - oldValue
quad.bl.geometryVertex += diff
quad.br.geometryVertex += diff
quad.tl.geometryVertex += diff
quad.tr.geometryVertex += diff
}
}

mutating func update(_ tick: TimeInterval) {
position += moveVelocity * Float32(tick)
}

}
41 changes: 41 additions & 0 deletions Example2/StarWars/StarWarsGLAnimator/SpriteRender.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// Created by Artem Sidorenko on 10/8/15.
// Copyright © 2015 Yalantis. All rights reserved.
//
// Licensed under the MIT license: http://opensource.org/licenses/MIT
// Latest version can be found at https://github.com/Yalantis/StarWars.iOS
//

import GLKit

class SpriteRender {

fileprivate let texture: ViewTexture
fileprivate let effect: GLKBaseEffect

init(texture: ViewTexture, effect: GLKBaseEffect) {
self.texture = texture
self.effect = effect
}

func render(_ sprites: [Sprite]) {
effect.texture2d0.name = self.texture.name
effect.texture2d0.enabled = 1

effect.prepareToDraw()

var vertex = sprites.map { $0.quad }

glEnableVertexAttribArray(GLuint(GLKVertexAttrib.position.rawValue))
glEnableVertexAttribArray(GLuint(GLKVertexAttrib.texCoord0.rawValue))

withUnsafePointer(to: &vertex[0].bl.geometryVertex) { offset in
glVertexAttribPointer(GLuint(GLKVertexAttrib.position.rawValue), 2, GLenum(GL_FLOAT), GLboolean(UInt8(GL_FALSE)), GLsizei(MemoryLayout<TexturedVertex>.size), offset)
}
withUnsafePointer(to: &vertex[0].bl.textureVertex) { offset in
glVertexAttribPointer(GLuint(GLKVertexAttrib.texCoord0.rawValue), 2, GLenum(GL_FLOAT), GLboolean(UInt8(GL_FALSE)), GLsizei(MemoryLayout<TexturedVertex>.size), offset)
}

glDrawArrays(GLenum(GL_TRIANGLES), 0, GLsizei(vertex.count * 6))
}
}
121 changes: 121 additions & 0 deletions Example2/StarWars/StarWarsGLAnimator/StarWarsGLAnimator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//
// Created by Artem Sidorenko on 9/14/15.
// Copyright © 2015 Yalantis. All rights reserved.
//
// Licensed under the MIT license: http://opensource.org/licenses/MIT
// Latest version can be found at https://github.com/Yalantis/StarWars.iOS
//

import UIKit
import GLKit

open class StarWarsGLAnimator: NSObject, UIViewControllerAnimatedTransitioning {

open var duration: TimeInterval = 2
open var spriteWidth: CGFloat = 8

fileprivate var sprites: [Sprite] = []
fileprivate var glContext: EAGLContext!
fileprivate var effect: GLKBaseEffect!
fileprivate var glView: GLKView!
fileprivate var displayLink: CADisplayLink!
fileprivate var lastUpdateTime: TimeInterval?
fileprivate var startTransitionTime: TimeInterval!
fileprivate var transitionContext: UIViewControllerContextTransitioning!
fileprivate var render: SpriteRender!

open func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return duration
}

open func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView
let fromView = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!.view
let toView = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!.view

containerView.addSubview(toView!)
containerView.sendSubview(toBack: toView!)

func randomFloatBetween(_ smallNumber: CGFloat, and bigNumber: CGFloat) -> Float {
let diff = bigNumber - smallNumber
return Float((CGFloat(arc4random()) / 100.0).truncatingRemainder(dividingBy: diff) + smallNumber)
}

self.glContext = EAGLContext(api: .openGLES2)
EAGLContext.setCurrent(glContext)

glView = GLKView(frame: (fromView?.frame)!, context: glContext)
glView.enableSetNeedsDisplay = true
glView.delegate = self
glView.isOpaque = false
containerView.addSubview(glView)

let texture = ViewTexture()
texture.setupOpenGL()
texture.render(view: fromView!)

effect = GLKBaseEffect()
let projectionMatrix = GLKMatrix4MakeOrtho(0, Float(texture.width), 0, Float(texture.height), -1, 1)
effect.transform.projectionMatrix = projectionMatrix

render = SpriteRender(texture: texture, effect: effect)

let size = CGSize(width: CGFloat(texture.width), height: CGFloat(texture.height))

let scale = UIScreen.main.scale
let width = spriteWidth * scale
let height = width

for x in stride(from: CGFloat(0), through: size.width, by: width) {
for y in stride(from: CGFloat(0), through: size.height, by: height) {
let region = CGRect(x: x, y: y, width: width, height: height)
var sprite = Sprite()
sprite.slice(region, textureSize: size)
sprite.moveVelocity = Vector2(x: randomFloatBetween(-100, and: 100), y: randomFloatBetween(-CGFloat(texture.height)*1.3/CGFloat(duration), and: -CGFloat(texture.height)/CGFloat(duration)))

sprites.append(sprite)
}
}
fromView?.removeFromSuperview()
self.transitionContext = transitionContext

displayLink = CADisplayLink(target: self, selector: #selector(StarWarsGLAnimator.displayLinkTick(_:)))
displayLink.isPaused = false
displayLink.add(to: RunLoop.main, forMode: RunLoopMode.commonModes)

self.startTransitionTime = Date.timeIntervalSinceReferenceDate
}

open func animationEnded(_ transitionCompleted: Bool) {
displayLink.invalidate()
displayLink = nil
}

func displayLinkTick(_ displayLink: CADisplayLink) {
if let lastUpdateTime = lastUpdateTime {
let timeSinceLastUpdate = Date.timeIntervalSinceReferenceDate - lastUpdateTime
self.lastUpdateTime = Date.timeIntervalSinceReferenceDate
for index in 0..<sprites.count {
sprites[index].update(timeSinceLastUpdate)
}
} else {
lastUpdateTime = Date.timeIntervalSinceReferenceDate
}
glView.setNeedsDisplay()
if Date.timeIntervalSinceReferenceDate - startTransitionTime > duration {
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
}
}
}

extension StarWarsGLAnimator: GLKViewDelegate {

public func glkView(_ view: GLKView, drawIn rect: CGRect) {
glClearColor(0, 0, 0, 0)
glClear(UInt32(GL_COLOR_BUFFER_BIT))
glBlendFunc(GLenum(GL_SRC_ALPHA), GLenum(GL_ONE_MINUS_SRC_ALPHA))
glEnable(GLenum(GL_BLEND))

render.render(self.sprites)
}
}
Loading