Various improvements

This commit is contained in:
Ilya Laktyushin
2022-12-25 10:33:53 +04:00
parent 6ece02e998
commit a0f3cfef58
27 changed files with 779 additions and 1894 deletions

View File

@@ -2,7 +2,7 @@ import Foundation
import UIKit
import Display
final class MarkerTool: DrawingElement, Codable {
final class MarkerTool: DrawingElement {
let uuid: UUID
let drawingSize: CGSize
@@ -17,11 +17,31 @@ final class MarkerTool: DrawingElement, Codable {
weak var metalView: DrawingMetalView?
var isValid: Bool {
return !self.points.isEmpty
return self.points.count > 6
}
var bounds: CGRect {
return CGRect(origin: .zero, size: self.drawingSize)
var minX: CGFloat = .greatestFiniteMagnitude
var minY: CGFloat = .greatestFiniteMagnitude
var maxX: CGFloat = 0.0
var maxY: CGFloat = 0.0
for point in self.points {
if point.x < minX {
minX = point.x
}
if point.x > maxX {
maxX = point.x
}
if point.y < minY {
minY = point.y
}
if point.y > maxY {
maxY = point.y
}
}
return normalizeDrawingRect(CGRect(x: minX, y: minY, width: maxX - minX, height: maxY - minY).insetBy(dx: -80.0, dy: -80.0), drawingSize: self.drawingSize)
}
required init(drawingSize: CGSize, color: DrawingColor, lineWidth: CGFloat) {
@@ -35,33 +55,7 @@ final class MarkerTool: DrawingElement, Codable {
self.renderLineWidth = lineWidth
}
private enum CodingKeys: String, CodingKey {
case uuid
case drawingSize
case color
case renderLineWidth
case points
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.uuid = try container.decode(UUID.self, forKey: .uuid)
self.drawingSize = try container.decode(CGSize.self, forKey: .drawingSize)
self.color = try container.decode(DrawingColor.self, forKey: .color)
self.renderLineWidth = try container.decode(CGFloat.self, forKey: .renderLineWidth)
self.points = try container.decode([CGPoint].self, forKey: .points)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.uuid, forKey: .uuid)
try container.encode(self.drawingSize, forKey: .drawingSize)
try container.encode(self.color, forKey: .color)
try container.encode(self.renderLineWidth, forKey: .renderLineWidth)
try container.encode(self.points, forKey: .points)
}
func setupRenderView(screenSize: CGSize) -> DrawingRenderView? {
return nil
}
@@ -71,12 +65,11 @@ final class MarkerTool: DrawingElement, Codable {
}
private var didSetup = false
func updatePath(_ path: DrawingGesturePipeline.DrawingResult, state: DrawingGesturePipeline.DrawingGestureState) {
guard case let .location(point) = path else {
return
func updatePath(_ point: DrawingPoint, state: DrawingGesturePipeline.DrawingGestureState) {
if let lastPoint = self.points.last, lastPoint.isEqual(to: point.location, epsilon: 0.1) {
} else {
self.points.append(point.location)
}
self.points.append(point.location)
self.didSetup = true
self.metalView?.updated(point, state: state, brush: .marker, color: self.color, size: self.renderLineWidth)
@@ -90,203 +83,14 @@ final class MarkerTool: DrawingElement, Codable {
context.translateBy(x: self.translation.x, y: self.translation.y)
let didSetup = self.didSetup
if didSetup {
self.didSetup = false
} else {
self.metalView?.setup(self.points, brush: .marker, color: self.color, size: self.renderLineWidth)
}
self.metalView?.drawInContext(context)
if !didSetup {
self.metalView?.clear()
}
context.restoreGState()
}
}
final class NeonTool: DrawingElement, Codable {
class RenderLayer: SimpleLayer, DrawingRenderLayer {
var lineWidth: CGFloat = 0.0
let shadowLayer = SimpleShapeLayer()
let borderLayer = SimpleShapeLayer()
let fillLayer = SimpleShapeLayer()
func setup(size: CGSize, color: DrawingColor, lineWidth: CGFloat, strokeWidth: CGFloat, shadowRadius: CGFloat) {
self.contentsScale = 1.0
self.lineWidth = lineWidth
let bounds = CGRect(origin: .zero, size: size)
self.frame = bounds
self.shadowLayer.frame = bounds
self.shadowLayer.backgroundColor = UIColor.clear.cgColor
self.shadowLayer.contentsScale = 1.0
self.shadowLayer.lineWidth = strokeWidth * 0.5
self.shadowLayer.lineCap = .round
self.shadowLayer.lineJoin = .round
self.shadowLayer.fillColor = UIColor.white.cgColor
self.shadowLayer.strokeColor = UIColor.white.cgColor
self.shadowLayer.shadowColor = color.toCGColor()
self.shadowLayer.shadowRadius = shadowRadius
self.shadowLayer.shadowOpacity = 1.0
self.shadowLayer.shadowOffset = .zero
self.borderLayer.frame = bounds
self.borderLayer.contentsScale = 1.0
self.borderLayer.lineWidth = strokeWidth
self.borderLayer.lineCap = .round
self.borderLayer.lineJoin = .round
self.borderLayer.fillColor = UIColor.clear.cgColor
self.borderLayer.strokeColor = UIColor.white.mixedWith(color.toUIColor(), alpha: 0.25).cgColor
self.fillLayer.frame = bounds
self.fillLayer.contentsScale = 1.0
self.fillLayer.fillColor = UIColor.white.cgColor
self.addSublayer(self.shadowLayer)
self.addSublayer(self.borderLayer)
self.addSublayer(self.fillLayer)
}
func updatePath(_ path: CGPath) {
self.shadowLayer.path = path
self.borderLayer.path = path
self.fillLayer.path = path
}
}
let uuid: UUID
let drawingSize: CGSize
let color: DrawingColor
var renderPath: CGPath?
let renderStrokeWidth: CGFloat
let renderShadowRadius: CGFloat
let renderLineWidth: CGFloat
var translation = CGPoint()
private var currentRenderLayer: DrawingRenderLayer?
var isValid: Bool {
return self.renderPath != nil
}
var bounds: CGRect {
return CGRect(origin: .zero, size: self.drawingSize)
}
required init(drawingSize: CGSize, color: DrawingColor, lineWidth: CGFloat) {
self.uuid = UUID()
self.drawingSize = drawingSize
self.color = color
let strokeWidth = min(drawingSize.width, drawingSize.height) * 0.008
let shadowRadius = min(drawingSize.width, drawingSize.height) * 0.03
let minLineWidth = max(1.0, max(drawingSize.width, drawingSize.height) * 0.003)
let maxLineWidth = max(10.0, max(drawingSize.width, drawingSize.height) * 0.09)
let lineWidth = minLineWidth + (maxLineWidth - minLineWidth) * lineWidth
self.renderStrokeWidth = strokeWidth
self.renderShadowRadius = shadowRadius
self.renderLineWidth = lineWidth
}
private enum CodingKeys: String, CodingKey {
case uuid
case drawingSize
case color
case renderStrokeWidth
case renderShadowRadius
case renderLineWidth
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.uuid = try container.decode(UUID.self, forKey: .uuid)
self.drawingSize = try container.decode(CGSize.self, forKey: .drawingSize)
self.color = try container.decode(DrawingColor.self, forKey: .color)
self.renderStrokeWidth = try container.decode(CGFloat.self, forKey: .renderStrokeWidth)
self.renderShadowRadius = try container.decode(CGFloat.self, forKey: .renderShadowRadius)
self.renderLineWidth = try container.decode(CGFloat.self, forKey: .renderLineWidth)
// self.points = try container.decode([CGPoint].self, forKey: .points)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.uuid, forKey: .uuid)
try container.encode(self.drawingSize, forKey: .drawingSize)
try container.encode(self.color, forKey: .color)
try container.encode(self.renderStrokeWidth, forKey: .renderStrokeWidth)
try container.encode(self.renderShadowRadius, forKey: .renderShadowRadius)
try container.encode(self.renderLineWidth, forKey: .renderLineWidth)
// try container.encode(self.points, forKey: .points)
}
func setupRenderView(screenSize: CGSize) -> DrawingRenderView? {
return nil
}
func setupRenderLayer() -> DrawingRenderLayer? {
let layer = RenderLayer()
layer.setup(size: self.drawingSize, color: self.color, lineWidth: self.renderLineWidth, strokeWidth: self.renderStrokeWidth, shadowRadius: self.renderShadowRadius)
self.currentRenderLayer = layer
return layer
}
func updatePath(_ path: DrawingGesturePipeline.DrawingResult, state: DrawingGesturePipeline.DrawingGestureState) {
guard case let .smoothCurve(bezierPath) = path else {
return
}
let cgPath = bezierPath.path.cgPath.copy(strokingWithWidth: self.renderLineWidth, lineCap: .round, lineJoin: .round, miterLimit: 0.0)
self.renderPath = cgPath
if let currentRenderLayer = self.currentRenderLayer as? RenderLayer {
currentRenderLayer.updatePath(cgPath)
}
}
func draw(in context: CGContext, size: CGSize) {
guard let path = self.renderPath else {
return
}
context.saveGState()
context.translateBy(x: self.translation.x, y: self.translation.y)
context.setShouldAntialias(true)
context.setBlendMode(.normal)
context.addPath(path)
context.setFillColor(UIColor.white.cgColor)
context.setStrokeColor(UIColor.white.cgColor)
context.setLineWidth(self.renderStrokeWidth * 0.5)
context.setShadow(offset: .zero, blur: self.renderShadowRadius * 1.9, color: self.color.toCGColor())
context.drawPath(using: .fillStroke)
context.addPath(path)
context.setShadow(offset: .zero, blur: 0.0, color: UIColor.clear.cgColor)
context.setLineCap(.round)
context.setLineWidth(self.renderStrokeWidth)
context.setStrokeColor(UIColor.white.mixedWith(self.color.toUIColor(), alpha: 0.25).cgColor)
context.strokePath()
context.addPath(path)
context.setFillColor(UIColor.white.cgColor)
context.fillPath()
self.metalView?.clear()
context.restoreGState()
}
}
final class FillTool: DrawingElement, Codable {
final class FillTool: DrawingElement {
let uuid: UUID
let drawingSize: CGSize
@@ -311,30 +115,7 @@ final class FillTool: DrawingElement, Codable {
self.isBlur = blur
self.blurredImage = blurredImage
}
private enum CodingKeys: String, CodingKey {
case uuid
case drawingSize
case color
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.uuid = try container.decode(UUID.self, forKey: .uuid)
self.drawingSize = try container.decode(CGSize.self, forKey: .drawingSize)
self.color = try container.decode(DrawingColor.self, forKey: .color)
self.isBlur = false
// self.points = try container.decode([CGPoint].self, forKey: .points)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.uuid, forKey: .uuid)
try container.encode(self.drawingSize, forKey: .drawingSize)
try container.encode(self.color, forKey: .color)
// try container.encode(self.points, forKey: .points)
}
func setupRenderView(screenSize: CGSize) -> DrawingRenderView? {
return nil
}
@@ -343,7 +124,7 @@ final class FillTool: DrawingElement, Codable {
return nil
}
func updatePath(_ path: DrawingGesturePipeline.DrawingResult, state: DrawingGesturePipeline.DrawingGestureState) {
func updatePath(_ path: DrawingPoint, state: DrawingGesturePipeline.DrawingGestureState) {
}
func draw(in context: CGContext, size: CGSize) {
@@ -365,12 +146,4 @@ final class FillTool: DrawingElement, Codable {
context.setBlendMode(.normal)
}
func containsPoint(_ point: CGPoint) -> Bool {
return false
}
func hasPointsInsidePath(_ path: UIBezierPath) -> Bool {
return false
}
}