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

Fix render glitches and support Spritekit, SceneKit and GLKit #46

Merged
merged 3 commits into from
Mar 19, 2018
Merged
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
32 changes: 30 additions & 2 deletions Snap/Core/Infrastructure/Extension/UIView/UIView+Render.swift
Original file line number Diff line number Diff line change
@@ -1,16 +1,45 @@
import UIKit
import SpriteKit
import SceneKit

/**
Adds a static image view on top of all SCNViews, GLKViews and SKViews for the given view hierarchy so these can be captured. Returns the created views.
*/
func addImagesForRenderedViews(_ view: UIView) -> [UIView] {

func add(_ image: UIImage) -> [UIView] {
let imageView = UIImageView(image: image)
imageView.frame = view.bounds
view.addSubview(imageView)
return [imageView]
}

if let scnview = view as? SCNView {
return add(scnview.snapshot())
} else if let glview = view as? GLKView {
return add(glview.snapshot)
} else if let skview = view as? SKView {
return add(UIImage(cgImage: skview.texture(from: skview.scene!)!.cgImage()))
} else {
return view.subviews.flatMap(addImagesForRenderedViews)
}
}

extension UIView {
/// Extract image data with the whole hierarchy from `UIView`
func render() -> UIImage? {

// SpriteKit refuses to draw its hierarchy: render an image of the spritekit view and add it to the view to be able to capture it
let addedViews = addImagesForRenderedViews(self)
defer { addedViews.forEach { $0.removeFromSuperview() } }

if #available(iOS 10.0, *) {
let imageRendererFormat = UIGraphicsImageRendererFormat.default()
imageRendererFormat.opaque = true
let renderer = UIGraphicsImageRenderer(
bounds: bounds
)
return renderer.image { context in
drawHierarchy(in: bounds, afterScreenUpdates: true)
layer.render(in: context.cgContext)
}
}
Expand All @@ -21,7 +50,6 @@ extension UIView {
UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0.0)

let context = UIGraphicsGetCurrentContext()!
drawHierarchy(in: bounds, afterScreenUpdates: true)
layer.render(in: context)
return UIGraphicsGetImageFromCurrentImageContext()
}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
53 changes: 51 additions & 2 deletions SnapTests/SnapTests.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import XCTest
import UIKit
import SpriteKit
import SceneKit

private final class SnapTests: XCTestCase {

Expand Down Expand Up @@ -34,8 +36,8 @@ private final class SnapTests: XCTestCase {
UIColor.white.cgColor
]
layer.locations = [0.0, 1.0]
layer.startPoint = CGPoint(x: 0.0, y: 1.0)
layer.endPoint = CGPoint(x: 0.0, y: 1.0)
layer.startPoint = CGPoint(x: 0.0, y: 0.0)
layer.endPoint = CGPoint(x: 1.0, y: 0.0)

expect(layer).toMatchSnapshot()
}
Expand Down Expand Up @@ -67,4 +69,51 @@ private final class SnapTests: XCTestCase {

expect(view).toMatchSnapshot(for: .iPadDevices)
}

func test_spritekit_view() {
let scene = SKScene(size: CGSize(width: 100, height: 100))
scene.backgroundColor = .yellow

let rect = SKShapeNode(rectOf: CGSize(width: 10, height: 10))
rect.fillColor = .red
rect.strokeColor = .clear
rect.position = CGPoint(x: 50, y: 50)
scene.addChild(rect)

let view = SKView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
view.presentScene(scene)

expect(view).toMatchSnapshot()
}

func test_scenekit_view() {
let scene = SCNScene()

// light
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = .omni
lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
scene.rootNode.addChildNode(lightNode)

// cube
let cubeGeometry = SCNBox(width: 5, height: 5, length: 5, chamferRadius: 0)
cubeGeometry.firstMaterial!.diffuse.contents = UIColor.red
let cubeNode = SCNNode(geometry: cubeGeometry)
scene.rootNode.addChildNode(cubeNode)

// camera
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
cameraNode.position = SCNVector3(x: 10, y: 10, z: 10)
cameraNode.constraints = [SCNLookAtConstraint(target: cubeNode)]

let view = SCNView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
view.backgroundColor = .yellow
view.scene = scene

expect(view).toMatchSnapshot()
}

}