mirror of
https://github.com/dscyrescotti/Memola.git
synced 2026-04-25 01:58:52 +02:00
Merge pull request #51 from dscyrescotti/feature/general-optimization
Optimize in general
This commit is contained in:
@@ -19,7 +19,7 @@ final class Canvas: ObservableObject, Identifiable, @unchecked Sendable {
|
|||||||
let viewPortContext = ViewPortContext()
|
let viewPortContext = ViewPortContext()
|
||||||
|
|
||||||
let maximumZoomScale: CGFloat = 35
|
let maximumZoomScale: CGFloat = 35
|
||||||
let minimumZoomScale: CGFloat = 5
|
let minimumZoomScale: CGFloat = 8
|
||||||
let defaultZoomScale: CGFloat = 20
|
let defaultZoomScale: CGFloat = 20
|
||||||
|
|
||||||
var transform: simd_float4x4 = .init()
|
var transform: simd_float4x4 = .init()
|
||||||
|
|||||||
@@ -45,7 +45,11 @@ enum Element: Equatable, Comparable {
|
|||||||
switch self {
|
switch self {
|
||||||
case .stroke(let anyStroke):
|
case .stroke(let anyStroke):
|
||||||
switch anyStroke.value.style {
|
switch anyStroke.value.style {
|
||||||
case .marker: return .stroke
|
case .marker:
|
||||||
|
guard let penStroke = anyStroke.stroke(as: PenStroke.self) else {
|
||||||
|
return .stroke(penStyle: .marker, color: [0, 0, 0, 0])
|
||||||
|
}
|
||||||
|
return .stroke(penStyle: penStroke.penStyle, color: penStroke.color)
|
||||||
case .eraser: return .eraser
|
case .eraser: return .eraser
|
||||||
}
|
}
|
||||||
case .photo:
|
case .photo:
|
||||||
|
|||||||
@@ -28,15 +28,15 @@ class ElementGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getPenStyle() -> PenStyle? {
|
func getPenStyle() -> PenStyle? {
|
||||||
if let last = elements.last, case let .stroke(anyStroke) = last {
|
if case let .stroke(penStyle, _) = type {
|
||||||
return anyStroke.value.penStyle
|
return penStyle
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPenColor() -> [CGFloat]? {
|
func getPenColor() -> [CGFloat]? {
|
||||||
if let last = elements.last, case let .stroke(anyStroke) = last {
|
if case let .stroke(_, color) = type {
|
||||||
return anyStroke.value.color
|
return color
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,7 @@ class ElementGroup {
|
|||||||
|
|
||||||
extension ElementGroup {
|
extension ElementGroup {
|
||||||
enum ElementGroupType {
|
enum ElementGroupType {
|
||||||
case stroke
|
case stroke(penStyle: PenStyle, color: [CGFloat])
|
||||||
case eraser
|
case eraser
|
||||||
case photo
|
case photo
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
import MetalKit
|
import MetalKit
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
protocol Stroke: AnyObject, Drawable, Hashable, Equatable {
|
protocol Stroke: AnyObject, Hashable, Equatable {
|
||||||
var id: UUID { get set }
|
var id: UUID { get set }
|
||||||
var bounds: [CGFloat] { get set }
|
var bounds: [CGFloat] { get set }
|
||||||
var color: [CGFloat] { get set }
|
var color: [CGFloat] { get set }
|
||||||
@@ -80,31 +80,6 @@ extension Stroke {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Stroke {
|
|
||||||
func prepare(device: MTLDevice) {
|
|
||||||
guard texture == nil else { return }
|
|
||||||
if penStyle.textureName != nil {
|
|
||||||
texture = penStyle.loadTexture(on: device)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func draw(device: MTLDevice, renderEncoder: MTLRenderCommandEncoder) {
|
|
||||||
guard !isEmpty, let indexBuffer else { return }
|
|
||||||
prepare(device: device)
|
|
||||||
if penStyle.textureName != nil {
|
|
||||||
renderEncoder.setFragmentTexture(texture, index: 0)
|
|
||||||
}
|
|
||||||
renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
|
|
||||||
renderEncoder.drawIndexedPrimitives(
|
|
||||||
type: .triangle,
|
|
||||||
indexCount: quads.endIndex * 6,
|
|
||||||
indexType: .uint32,
|
|
||||||
indexBuffer: indexBuffer,
|
|
||||||
indexBufferOffset: 0
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Stroke {
|
extension Stroke {
|
||||||
static func == (lhs: Self, rhs: Self) -> Bool {
|
static func == (lhs: Self, rhs: Self) -> Bool {
|
||||||
lhs.id == rhs.id
|
lhs.id == rhs.id
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ struct SolidPointStrokeGenerator: StrokeGenerator {
|
|||||||
let factor: CGFloat
|
let factor: CGFloat
|
||||||
switch configuration.granularity {
|
switch configuration.granularity {
|
||||||
case .automatic:
|
case .automatic:
|
||||||
factor = min(5, 1 / (stroke.thickness * 1 / 50))
|
factor = min(10, 1 / (stroke.thickness * 1 / 50))
|
||||||
case .fixed:
|
case .fixed:
|
||||||
factor = 1 / (stroke.thickness * stroke.penStyle.stepRate)
|
factor = 1 / (stroke.thickness * stroke.penStyle.stepRate)
|
||||||
case .none:
|
case .none:
|
||||||
|
|||||||
@@ -152,20 +152,4 @@ final class PenStroke: Stroke, @unchecked Sendable {
|
|||||||
func getAllErasedQuads() -> [Quad] {
|
func getAllErasedQuads() -> [Quad] {
|
||||||
eraserStrokes.flatMap { $0.quads }
|
eraserStrokes.flatMap { $0.quads }
|
||||||
}
|
}
|
||||||
|
|
||||||
func erase(device: MTLDevice, renderEncoder: MTLRenderCommandEncoder) {
|
|
||||||
guard !isEmptyErasedQuads, let erasedIndexBuffer else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
prepare(device: device)
|
|
||||||
renderEncoder.setFragmentTexture(texture, index: 0)
|
|
||||||
renderEncoder.setVertexBuffer(erasedVertexBuffer, offset: 0, index: 0)
|
|
||||||
renderEncoder.drawIndexedPrimitives(
|
|
||||||
type: .triangle,
|
|
||||||
indexCount: erasedQuadCount * 6,
|
|
||||||
indexType: .uint32,
|
|
||||||
indexBuffer: erasedIndexBuffer,
|
|
||||||
indexBufferOffset: 0
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,10 +31,15 @@ public class Tool: NSObject, ObservableObject {
|
|||||||
|
|
||||||
init(object: ToolObject) {
|
init(object: ToolObject) {
|
||||||
self.object = object
|
self.object = object
|
||||||
|
selection = ToolSelection(rawValue: object.selection) ?? .hand
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectTool(_ selection: ToolSelection) {
|
func selectTool(_ selection: ToolSelection) {
|
||||||
self.selection = selection
|
self.selection = selection
|
||||||
|
withPersistence(\.viewContext) { [weak object] context in
|
||||||
|
object?.selection = selection.rawValue
|
||||||
|
try context.saveIfNeeded()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func load() {
|
func load() {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum ToolSelection: Equatable {
|
enum ToolSelection: Int16, Equatable {
|
||||||
case hand
|
case hand
|
||||||
case pen
|
case pen
|
||||||
case photo
|
case photo
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class DrawingView: UIView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateDrawableSize(with size: CGSize) {
|
func updateDrawableSize(with size: CGSize) {
|
||||||
renderView.drawableSize = size.multiply(by: 2.6)
|
renderView.drawableSize = size.multiply(by: 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ struct MemosView: View {
|
|||||||
canvasObject.height = 8_000
|
canvasObject.height = 8_000
|
||||||
|
|
||||||
let toolObject = ToolObject(\.viewContext)
|
let toolObject = ToolObject(\.viewContext)
|
||||||
|
toolObject.selection = 0
|
||||||
toolObject.pens = []
|
toolObject.pens = []
|
||||||
|
|
||||||
let eraserPenObject = PenObject.createObject(\.viewContext, penStyle: .eraser)
|
let eraserPenObject = PenObject.createObject(\.viewContext, penStyle: .eraser)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import Foundation
|
|||||||
|
|
||||||
@objc(ToolObject)
|
@objc(ToolObject)
|
||||||
class ToolObject: NSManagedObject {
|
class ToolObject: NSManagedObject {
|
||||||
|
@NSManaged var selection: Int16
|
||||||
@NSManaged var pens: NSMutableSet
|
@NSManaged var pens: NSMutableSet
|
||||||
@NSManaged var memo: MemoObject?
|
@NSManaged var memo: MemoObject?
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,7 @@
|
|||||||
<relationship name="quads" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="QuadObject" inverseName="stroke" inverseEntity="QuadObject"/>
|
<relationship name="quads" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="QuadObject" inverseName="stroke" inverseEntity="QuadObject"/>
|
||||||
</entity>
|
</entity>
|
||||||
<entity name="ToolObject" representedClassName="ToolObject" syncable="YES">
|
<entity name="ToolObject" representedClassName="ToolObject" syncable="YES">
|
||||||
|
<attribute name="selection" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
|
||||||
<relationship name="memo" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MemoObject" inverseName="tool" inverseEntity="MemoObject"/>
|
<relationship name="memo" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MemoObject" inverseName="tool" inverseEntity="MemoObject"/>
|
||||||
<relationship name="pens" toMany="YES" deletionRule="Cascade" destinationEntity="PenObject" inverseName="tool" inverseEntity="PenObject"/>
|
<relationship name="pens" toMany="YES" deletionRule="Cascade" destinationEntity="PenObject" inverseName="tool" inverseEntity="PenObject"/>
|
||||||
</entity>
|
</entity>
|
||||||
|
|||||||
Reference in New Issue
Block a user