mirror of
https://github.com/dscyrescotti/Memola.git
synced 2026-04-24 17:48:39 +02:00
feat: add grid option
This commit is contained in:
@@ -31,6 +31,9 @@
|
|||||||
EC7F6BEC2BE5E6E300A34A7B /* MemolaApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7F6BEB2BE5E6E300A34A7B /* MemolaApp.swift */; };
|
EC7F6BEC2BE5E6E300A34A7B /* MemolaApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7F6BEB2BE5E6E300A34A7B /* MemolaApp.swift */; };
|
||||||
EC7F6BF02BE5E6E400A34A7B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EC7F6BEF2BE5E6E400A34A7B /* Assets.xcassets */; };
|
EC7F6BF02BE5E6E400A34A7B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EC7F6BEF2BE5E6E400A34A7B /* Assets.xcassets */; };
|
||||||
EC7F6BF32BE5E6E400A34A7B /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EC7F6BF22BE5E6E400A34A7B /* Preview Assets.xcassets */; };
|
EC7F6BF32BE5E6E400A34A7B /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EC7F6BF22BE5E6E400A34A7B /* Preview Assets.xcassets */; };
|
||||||
|
EC8F54AC2C2ACDA8001C7C74 /* GridMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC8F54AB2C2ACDA8001C7C74 /* GridMode.swift */; };
|
||||||
|
EC8F54AE2C2AF5A4001C7C74 /* LineGridVertex.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC8F54AD2C2AF5A4001C7C74 /* LineGridVertex.swift */; };
|
||||||
|
EC8F54B02C2AF5E9001C7C74 /* LineGridContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC8F54AF2C2AF5E9001C7C74 /* LineGridContext.swift */; };
|
||||||
EC9AB09F2C1401A40076AF58 /* EraserObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC9AB09E2C1401A40076AF58 /* EraserObject.swift */; };
|
EC9AB09F2C1401A40076AF58 /* EraserObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC9AB09E2C1401A40076AF58 /* EraserObject.swift */; };
|
||||||
ECA7387A2BE5EF0400A4542E /* MemosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738792BE5EF0400A4542E /* MemosView.swift */; };
|
ECA7387A2BE5EF0400A4542E /* MemosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738792BE5EF0400A4542E /* MemosView.swift */; };
|
||||||
ECA7387D2BE5EF4B00A4542E /* MemoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA7387C2BE5EF4B00A4542E /* MemoView.swift */; };
|
ECA7387D2BE5EF4B00A4542E /* MemoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA7387C2BE5EF4B00A4542E /* MemoView.swift */; };
|
||||||
@@ -44,7 +47,7 @@
|
|||||||
ECA738932BE6011100A4542E /* Stroke.metal in Sources */ = {isa = PBXBuildFile; fileRef = ECA738922BE6011100A4542E /* Stroke.metal */; };
|
ECA738932BE6011100A4542E /* Stroke.metal in Sources */ = {isa = PBXBuildFile; fileRef = ECA738922BE6011100A4542E /* Stroke.metal */; };
|
||||||
ECA738952BE6012D00A4542E /* ViewPort.metal in Sources */ = {isa = PBXBuildFile; fileRef = ECA738942BE6012D00A4542E /* ViewPort.metal */; };
|
ECA738952BE6012D00A4542E /* ViewPort.metal in Sources */ = {isa = PBXBuildFile; fileRef = ECA738942BE6012D00A4542E /* ViewPort.metal */; };
|
||||||
ECA738972BE6014200A4542E /* Graphic.metal in Sources */ = {isa = PBXBuildFile; fileRef = ECA738962BE6014200A4542E /* Graphic.metal */; };
|
ECA738972BE6014200A4542E /* Graphic.metal in Sources */ = {isa = PBXBuildFile; fileRef = ECA738962BE6014200A4542E /* Graphic.metal */; };
|
||||||
ECA7389C2BE601AF00A4542E /* GridVertex.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA7389B2BE601AF00A4542E /* GridVertex.swift */; };
|
ECA7389C2BE601AF00A4542E /* PointGridVertex.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA7389B2BE601AF00A4542E /* PointGridVertex.swift */; };
|
||||||
ECA7389E2BE601CB00A4542E /* QuadVertex.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA7389D2BE601CB00A4542E /* QuadVertex.swift */; };
|
ECA7389E2BE601CB00A4542E /* QuadVertex.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA7389D2BE601CB00A4542E /* QuadVertex.swift */; };
|
||||||
ECA738A02BE601E400A4542E /* ViewPortVertex.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA7389F2BE601E400A4542E /* ViewPortVertex.swift */; };
|
ECA738A02BE601E400A4542E /* ViewPortVertex.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA7389F2BE601E400A4542E /* ViewPortVertex.swift */; };
|
||||||
ECA738A32BE6020A00A4542E /* CGFloat++.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738A22BE6020A00A4542E /* CGFloat++.swift */; };
|
ECA738A32BE6020A00A4542E /* CGFloat++.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738A22BE6020A00A4542E /* CGFloat++.swift */; };
|
||||||
@@ -64,7 +67,7 @@
|
|||||||
ECA738C62BE60E9D00A4542E /* EraserPenStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738C52BE60E9D00A4542E /* EraserPenStyle.swift */; };
|
ECA738C62BE60E9D00A4542E /* EraserPenStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738C52BE60E9D00A4542E /* EraserPenStyle.swift */; };
|
||||||
ECA738C92BE60EF700A4542E /* GraphicContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738C82BE60EF700A4542E /* GraphicContext.swift */; };
|
ECA738C92BE60EF700A4542E /* GraphicContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738C82BE60EF700A4542E /* GraphicContext.swift */; };
|
||||||
ECA738CB2BE60F1900A4542E /* ViewPortContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738CA2BE60F1900A4542E /* ViewPortContext.swift */; };
|
ECA738CB2BE60F1900A4542E /* ViewPortContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738CA2BE60F1900A4542E /* ViewPortContext.swift */; };
|
||||||
ECA738CD2BE60F2F00A4542E /* GridContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738CC2BE60F2F00A4542E /* GridContext.swift */; };
|
ECA738CD2BE60F2F00A4542E /* PointGridContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738CC2BE60F2F00A4542E /* PointGridContext.swift */; };
|
||||||
ECA738D22BE60F7B00A4542E /* PenStroke.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738D12BE60F7B00A4542E /* PenStroke.swift */; };
|
ECA738D22BE60F7B00A4542E /* PenStroke.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738D12BE60F7B00A4542E /* PenStroke.swift */; };
|
||||||
ECA738D42BE60F9100A4542E /* StrokeGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738D32BE60F9100A4542E /* StrokeGenerator.swift */; };
|
ECA738D42BE60F9100A4542E /* StrokeGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738D32BE60F9100A4542E /* StrokeGenerator.swift */; };
|
||||||
ECA738D72BE60FC100A4542E /* SolidPointStrokeGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738D62BE60FC100A4542E /* SolidPointStrokeGenerator.swift */; };
|
ECA738D72BE60FC100A4542E /* SolidPointStrokeGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738D62BE60FC100A4542E /* SolidPointStrokeGenerator.swift */; };
|
||||||
@@ -136,6 +139,9 @@
|
|||||||
EC7F6BEB2BE5E6E300A34A7B /* MemolaApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemolaApp.swift; sourceTree = "<group>"; };
|
EC7F6BEB2BE5E6E300A34A7B /* MemolaApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemolaApp.swift; sourceTree = "<group>"; };
|
||||||
EC7F6BEF2BE5E6E400A34A7B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
EC7F6BEF2BE5E6E400A34A7B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
EC7F6BF22BE5E6E400A34A7B /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
EC7F6BF22BE5E6E400A34A7B /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||||
|
EC8F54AB2C2ACDA8001C7C74 /* GridMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GridMode.swift; sourceTree = "<group>"; };
|
||||||
|
EC8F54AD2C2AF5A4001C7C74 /* LineGridVertex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineGridVertex.swift; sourceTree = "<group>"; };
|
||||||
|
EC8F54AF2C2AF5E9001C7C74 /* LineGridContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineGridContext.swift; sourceTree = "<group>"; };
|
||||||
EC9AB09E2C1401A40076AF58 /* EraserObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EraserObject.swift; sourceTree = "<group>"; };
|
EC9AB09E2C1401A40076AF58 /* EraserObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EraserObject.swift; sourceTree = "<group>"; };
|
||||||
ECA738792BE5EF0400A4542E /* MemosView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemosView.swift; sourceTree = "<group>"; };
|
ECA738792BE5EF0400A4542E /* MemosView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemosView.swift; sourceTree = "<group>"; };
|
||||||
ECA7387C2BE5EF4B00A4542E /* MemoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoView.swift; sourceTree = "<group>"; };
|
ECA7387C2BE5EF4B00A4542E /* MemoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoView.swift; sourceTree = "<group>"; };
|
||||||
@@ -149,7 +155,7 @@
|
|||||||
ECA738922BE6011100A4542E /* Stroke.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = Stroke.metal; sourceTree = "<group>"; };
|
ECA738922BE6011100A4542E /* Stroke.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = Stroke.metal; sourceTree = "<group>"; };
|
||||||
ECA738942BE6012D00A4542E /* ViewPort.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = ViewPort.metal; sourceTree = "<group>"; };
|
ECA738942BE6012D00A4542E /* ViewPort.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = ViewPort.metal; sourceTree = "<group>"; };
|
||||||
ECA738962BE6014200A4542E /* Graphic.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = Graphic.metal; sourceTree = "<group>"; };
|
ECA738962BE6014200A4542E /* Graphic.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = Graphic.metal; sourceTree = "<group>"; };
|
||||||
ECA7389B2BE601AF00A4542E /* GridVertex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GridVertex.swift; sourceTree = "<group>"; };
|
ECA7389B2BE601AF00A4542E /* PointGridVertex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PointGridVertex.swift; sourceTree = "<group>"; };
|
||||||
ECA7389D2BE601CB00A4542E /* QuadVertex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuadVertex.swift; sourceTree = "<group>"; };
|
ECA7389D2BE601CB00A4542E /* QuadVertex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuadVertex.swift; sourceTree = "<group>"; };
|
||||||
ECA7389F2BE601E400A4542E /* ViewPortVertex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewPortVertex.swift; sourceTree = "<group>"; };
|
ECA7389F2BE601E400A4542E /* ViewPortVertex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewPortVertex.swift; sourceTree = "<group>"; };
|
||||||
ECA738A22BE6020A00A4542E /* CGFloat++.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGFloat++.swift"; sourceTree = "<group>"; };
|
ECA738A22BE6020A00A4542E /* CGFloat++.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGFloat++.swift"; sourceTree = "<group>"; };
|
||||||
@@ -169,7 +175,7 @@
|
|||||||
ECA738C52BE60E9D00A4542E /* EraserPenStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EraserPenStyle.swift; sourceTree = "<group>"; };
|
ECA738C52BE60E9D00A4542E /* EraserPenStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EraserPenStyle.swift; sourceTree = "<group>"; };
|
||||||
ECA738C82BE60EF700A4542E /* GraphicContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphicContext.swift; sourceTree = "<group>"; };
|
ECA738C82BE60EF700A4542E /* GraphicContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphicContext.swift; sourceTree = "<group>"; };
|
||||||
ECA738CA2BE60F1900A4542E /* ViewPortContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewPortContext.swift; sourceTree = "<group>"; };
|
ECA738CA2BE60F1900A4542E /* ViewPortContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewPortContext.swift; sourceTree = "<group>"; };
|
||||||
ECA738CC2BE60F2F00A4542E /* GridContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GridContext.swift; sourceTree = "<group>"; };
|
ECA738CC2BE60F2F00A4542E /* PointGridContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PointGridContext.swift; sourceTree = "<group>"; };
|
||||||
ECA738D12BE60F7B00A4542E /* PenStroke.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenStroke.swift; sourceTree = "<group>"; };
|
ECA738D12BE60F7B00A4542E /* PenStroke.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenStroke.swift; sourceTree = "<group>"; };
|
||||||
ECA738D32BE60F9100A4542E /* StrokeGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StrokeGenerator.swift; sourceTree = "<group>"; };
|
ECA738D32BE60F9100A4542E /* StrokeGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StrokeGenerator.swift; sourceTree = "<group>"; };
|
||||||
ECA738D62BE60FC100A4542E /* SolidPointStrokeGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SolidPointStrokeGenerator.swift; sourceTree = "<group>"; };
|
ECA738D62BE60FC100A4542E /* SolidPointStrokeGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SolidPointStrokeGenerator.swift; sourceTree = "<group>"; };
|
||||||
@@ -376,6 +382,14 @@
|
|||||||
path = "Preview Content";
|
path = "Preview Content";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
EC8F54AA2C2ACD9D001C7C74 /* Grid */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
EC8F54AB2C2ACDA8001C7C74 /* GridMode.swift */,
|
||||||
|
);
|
||||||
|
path = Grid;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
ECA738762BE5EE4E00A4542E /* App */ = {
|
ECA738762BE5EE4E00A4542E /* App */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -415,6 +429,7 @@
|
|||||||
ECA7387E2BE5FE4200A4542E /* Canvas */ = {
|
ECA7387E2BE5FE4200A4542E /* Canvas */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
EC8F54AA2C2ACD9D001C7C74 /* Grid */,
|
||||||
ECD12A872C19EF8700B96E12 /* Elements */,
|
ECD12A872C19EF8700B96E12 /* Elements */,
|
||||||
EC2BEBF22C0F5FE1005DB0AF /* RTree */,
|
EC2BEBF22C0F5FE1005DB0AF /* RTree */,
|
||||||
ECA738812BE5FEEE00A4542E /* Abstracts */,
|
ECA738812BE5FEEE00A4542E /* Abstracts */,
|
||||||
@@ -494,10 +509,11 @@
|
|||||||
ECA7389A2BE6019700A4542E /* Vertices */ = {
|
ECA7389A2BE6019700A4542E /* Vertices */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
ECA7389B2BE601AF00A4542E /* GridVertex.swift */,
|
ECA7389B2BE601AF00A4542E /* PointGridVertex.swift */,
|
||||||
ECA7389D2BE601CB00A4542E /* QuadVertex.swift */,
|
ECA7389D2BE601CB00A4542E /* QuadVertex.swift */,
|
||||||
ECA7389F2BE601E400A4542E /* ViewPortVertex.swift */,
|
ECA7389F2BE601E400A4542E /* ViewPortVertex.swift */,
|
||||||
ECD12A942C1B1FA200B96E12 /* PhotoVertex.swift */,
|
ECD12A942C1B1FA200B96E12 /* PhotoVertex.swift */,
|
||||||
|
EC8F54AD2C2AF5A4001C7C74 /* LineGridVertex.swift */,
|
||||||
);
|
);
|
||||||
path = Vertices;
|
path = Vertices;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -595,7 +611,8 @@
|
|||||||
children = (
|
children = (
|
||||||
ECA738C82BE60EF700A4542E /* GraphicContext.swift */,
|
ECA738C82BE60EF700A4542E /* GraphicContext.swift */,
|
||||||
ECA738CA2BE60F1900A4542E /* ViewPortContext.swift */,
|
ECA738CA2BE60F1900A4542E /* ViewPortContext.swift */,
|
||||||
ECA738CC2BE60F2F00A4542E /* GridContext.swift */,
|
ECA738CC2BE60F2F00A4542E /* PointGridContext.swift */,
|
||||||
|
EC8F54AF2C2AF5E9001C7C74 /* LineGridContext.swift */,
|
||||||
);
|
);
|
||||||
path = Contexts;
|
path = Contexts;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -854,10 +871,12 @@
|
|||||||
ECA738AD2BE60CC600A4542E /* DrawingView.swift in Sources */,
|
ECA738AD2BE60CC600A4542E /* DrawingView.swift in Sources */,
|
||||||
EC1B783D2BFA0AC9005A34E2 /* Toolbar.swift in Sources */,
|
EC1B783D2BFA0AC9005A34E2 /* Toolbar.swift in Sources */,
|
||||||
ECA738E02BE610B900A4542E /* EraserRenderPass.swift in Sources */,
|
ECA738E02BE610B900A4542E /* EraserRenderPass.swift in Sources */,
|
||||||
|
EC8F54B02C2AF5E9001C7C74 /* LineGridContext.swift in Sources */,
|
||||||
EC35655A2BF060D900A4E0BF /* Quad.metal in Sources */,
|
EC35655A2BF060D900A4E0BF /* Quad.metal in Sources */,
|
||||||
ECA738912BE600F500A4542E /* Cache.metal in Sources */,
|
ECA738912BE600F500A4542E /* Cache.metal in Sources */,
|
||||||
ECA7389C2BE601AF00A4542E /* GridVertex.swift in Sources */,
|
ECA7389C2BE601AF00A4542E /* PointGridVertex.swift in Sources */,
|
||||||
ECA738A82BE6025900A4542E /* GraphicUniforms.swift in Sources */,
|
ECA738A82BE6025900A4542E /* GraphicUniforms.swift in Sources */,
|
||||||
|
EC8F54AE2C2AF5A4001C7C74 /* LineGridVertex.swift in Sources */,
|
||||||
ECA738E62BE611FD00A4542E /* CGRect++.swift in Sources */,
|
ECA738E62BE611FD00A4542E /* CGRect++.swift in Sources */,
|
||||||
EC5E83902BFDB69C00261D9C /* MovingAverage.swift in Sources */,
|
EC5E83902BFDB69C00261D9C /* MovingAverage.swift in Sources */,
|
||||||
ECFA15262BEF224900455818 /* StrokeObject.swift in Sources */,
|
ECFA15262BEF224900455818 /* StrokeObject.swift in Sources */,
|
||||||
@@ -870,7 +889,7 @@
|
|||||||
ECA738AA2BE6026D00A4542E /* Uniforms.swift in Sources */,
|
ECA738AA2BE6026D00A4542E /* Uniforms.swift in Sources */,
|
||||||
ECA7387D2BE5EF4B00A4542E /* MemoView.swift in Sources */,
|
ECA7387D2BE5EF4B00A4542E /* MemoView.swift in Sources */,
|
||||||
ECA738DA2BE60FF100A4542E /* CacheRenderPass.swift in Sources */,
|
ECA738DA2BE60FF100A4542E /* CacheRenderPass.swift in Sources */,
|
||||||
ECA738CD2BE60F2F00A4542E /* GridContext.swift in Sources */,
|
ECA738CD2BE60F2F00A4542E /* PointGridContext.swift in Sources */,
|
||||||
ECFA15202BEF21EF00455818 /* MemoObject.swift in Sources */,
|
ECFA15202BEF21EF00455818 /* MemoObject.swift in Sources */,
|
||||||
ECE883C12C00C9CB0045C53D /* StrokeStyle.swift in Sources */,
|
ECE883C12C00C9CB0045C53D /* StrokeStyle.swift in Sources */,
|
||||||
EC37FB122C1B2DD90008D976 /* ToolSelection.swift in Sources */,
|
EC37FB122C1B2DD90008D976 /* ToolSelection.swift in Sources */,
|
||||||
@@ -934,6 +953,7 @@
|
|||||||
ECA738C12BE60E5300A4542E /* PenStyle.swift in Sources */,
|
ECA738C12BE60E5300A4542E /* PenStyle.swift in Sources */,
|
||||||
ECBE52962C1D5900006BDB3D /* PhotoPreview.swift in Sources */,
|
ECBE52962C1D5900006BDB3D /* PhotoPreview.swift in Sources */,
|
||||||
ECA738DE2BE610A000A4542E /* ViewPortRenderPass.swift in Sources */,
|
ECA738DE2BE610A000A4542E /* ViewPortRenderPass.swift in Sources */,
|
||||||
|
EC8F54AC2C2ACDA8001C7C74 /* GridMode.swift in Sources */,
|
||||||
EC7F6BEC2BE5E6E300A34A7B /* MemolaApp.swift in Sources */,
|
EC7F6BEC2BE5E6E300A34A7B /* MemolaApp.swift in Sources */,
|
||||||
EC2BEBF82C0F601A005DB0AF /* Node.swift in Sources */,
|
EC2BEBF82C0F601A005DB0AF /* Node.swift in Sources */,
|
||||||
ECC995A52C1EB4CC00B2699A /* Data++.swift in Sources */,
|
ECC995A52C1EB4CC00B2699A /* Data++.swift in Sources */,
|
||||||
|
|||||||
13
Memola/Canvas/Buffers/Vertices/LineGridVertex.swift
Normal file
13
Memola/Canvas/Buffers/Vertices/LineGridVertex.swift
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// LineGridVertex.swift
|
||||||
|
// Memola
|
||||||
|
//
|
||||||
|
// Created by Dscyre Scotti on 6/25/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import MetalKit
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct LineGridVertex {
|
||||||
|
var position: vector_float4
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// GridVertex.swift
|
// PointGridVertex.swift
|
||||||
// Memola
|
// Memola
|
||||||
//
|
//
|
||||||
// Created by Dscyre Scotti on 5/4/24.
|
// Created by Dscyre Scotti on 5/4/24.
|
||||||
@@ -8,12 +8,12 @@
|
|||||||
import MetalKit
|
import MetalKit
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct GridVertex {
|
struct PointGridVertex {
|
||||||
var position: vector_float4
|
var position: vector_float4
|
||||||
var pointSize: Float = 10
|
var pointSize: Float = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
extension GridVertex {
|
extension PointGridVertex {
|
||||||
init(x: CGFloat, y: CGFloat) {
|
init(x: CGFloat, y: CGFloat) {
|
||||||
self.position = [x.float, y.float, 0, 1]
|
self.position = [x.float, y.float, 0, 1]
|
||||||
}
|
}
|
||||||
45
Memola/Canvas/Contexts/LineGridContext.swift
Normal file
45
Memola/Canvas/Contexts/LineGridContext.swift
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
//
|
||||||
|
// LineGridContext.swift
|
||||||
|
// Memola
|
||||||
|
//
|
||||||
|
// Created by Dscyre Scotti on 6/25/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import MetalKit
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class LineGridContext {
|
||||||
|
var vertices: [LineGridVertex] = []
|
||||||
|
var vertexCount: Int = 0
|
||||||
|
var vertexBuffer: MTLBuffer?
|
||||||
|
|
||||||
|
init() {
|
||||||
|
generateVertices()
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateVertices() {
|
||||||
|
let steps = stride(from: -10, through: 110, by: 0.25)
|
||||||
|
for y in steps {
|
||||||
|
vertices.append(LineGridVertex(position: [-10, Float(y), 0, 0]))
|
||||||
|
vertices.append(LineGridVertex(position: [110, Float(y), 0, 0]))
|
||||||
|
}
|
||||||
|
for x in steps {
|
||||||
|
vertices.append(LineGridVertex(position: [Float(x), -10, 0, 0]))
|
||||||
|
vertices.append(LineGridVertex(position: [Float(x), 110, 0, 0]))
|
||||||
|
}
|
||||||
|
vertexCount = vertices.count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension LineGridContext: Drawable {
|
||||||
|
func prepare(device: MTLDevice) {
|
||||||
|
vertexBuffer = device.makeBuffer(bytes: vertices, length: vertexCount * MemoryLayout<LineGridVertex>.stride, options: [])
|
||||||
|
}
|
||||||
|
|
||||||
|
func draw(device: MTLDevice, renderEncoder: MTLRenderCommandEncoder) {
|
||||||
|
guard vertexCount > .zero else { return }
|
||||||
|
prepare(device: device)
|
||||||
|
renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
|
||||||
|
renderEncoder.drawPrimitives(type: .line, vertexStart: 0, vertexCount: vertexCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// GridContext.swift
|
// PointGridContext.swift
|
||||||
// Memola
|
// Memola
|
||||||
//
|
//
|
||||||
// Created by Dscyre Scotti on 5/4/24.
|
// Created by Dscyre Scotti on 5/4/24.
|
||||||
@@ -8,8 +8,8 @@
|
|||||||
import MetalKit
|
import MetalKit
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class GridContext {
|
class PointGridContext {
|
||||||
var vertices: [GridVertex] = []
|
var vertices: [PointGridVertex] = []
|
||||||
var vertexCount: Int = 0
|
var vertexCount: Int = 0
|
||||||
var vertexBuffer: MTLBuffer?
|
var vertexBuffer: MTLBuffer?
|
||||||
|
|
||||||
@@ -21,16 +21,16 @@ class GridContext {
|
|||||||
let steps = stride(from: -10, through: 110, by: 0.25)
|
let steps = stride(from: -10, through: 110, by: 0.25)
|
||||||
for y in steps {
|
for y in steps {
|
||||||
for x in steps {
|
for x in steps {
|
||||||
vertices.append(GridVertex(x: CGFloat(x), y: CGFloat(y)))
|
vertices.append(PointGridVertex(x: CGFloat(x), y: CGFloat(y)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vertexCount = vertices.count
|
vertexCount = vertices.count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension GridContext: Drawable {
|
extension PointGridContext: Drawable {
|
||||||
func prepare(device: MTLDevice) {
|
func prepare(device: MTLDevice) {
|
||||||
vertexBuffer = device.makeBuffer(bytes: vertices, length: vertexCount * MemoryLayout<GridVertex>.stride, options: [])
|
vertexBuffer = device.makeBuffer(bytes: vertices, length: vertexCount * MemoryLayout<PointGridVertex>.stride, options: [])
|
||||||
}
|
}
|
||||||
|
|
||||||
func draw(device: MTLDevice, renderEncoder: MTLRenderCommandEncoder) {
|
func draw(device: MTLDevice, renderEncoder: MTLRenderCommandEncoder) {
|
||||||
@@ -13,8 +13,10 @@ import Foundation
|
|||||||
final class Canvas: ObservableObject, Identifiable, @unchecked Sendable {
|
final class Canvas: ObservableObject, Identifiable, @unchecked Sendable {
|
||||||
let size: CGSize
|
let size: CGSize
|
||||||
let canvasID: NSManagedObjectID
|
let canvasID: NSManagedObjectID
|
||||||
|
var object: CanvasObject?
|
||||||
|
|
||||||
let gridContext = GridContext()
|
let pointGridContext = PointGridContext()
|
||||||
|
let lineGridContext = LineGridContext()
|
||||||
var graphicContext = GraphicContext()
|
var graphicContext = GraphicContext()
|
||||||
let viewPortContext = ViewPortContext()
|
let viewPortContext = ViewPortContext()
|
||||||
|
|
||||||
@@ -31,11 +33,14 @@ final class Canvas: ObservableObject, Identifiable, @unchecked Sendable {
|
|||||||
@Published var zoomScale: CGFloat = .zero
|
@Published var zoomScale: CGFloat = .zero
|
||||||
@Published var locksCanvas: Bool = false
|
@Published var locksCanvas: Bool = false
|
||||||
|
|
||||||
|
@Published var gridMode: GridMode = .point
|
||||||
|
|
||||||
let zoomPublisher = PassthroughSubject<CGFloat, Never>()
|
let zoomPublisher = PassthroughSubject<CGFloat, Never>()
|
||||||
|
|
||||||
init(size: CGSize, canvasID: NSManagedObjectID) {
|
init(size: CGSize, canvasID: NSManagedObjectID, gridMode: Int16) {
|
||||||
self.size = size
|
self.size = size
|
||||||
self.canvasID = canvasID
|
self.canvasID = canvasID
|
||||||
|
self.gridMode = GridMode(rawValue: gridMode) ?? .point
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasValidStroke: Bool {
|
var hasValidStroke: Bool {
|
||||||
@@ -56,6 +61,7 @@ extension Canvas {
|
|||||||
guard let canvas = context.object(with: canvasID) as? CanvasObject else {
|
guard let canvas = context.object(with: canvasID) as? CanvasObject else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
self?.object = canvas
|
||||||
let graphicContext = canvas.graphicContext
|
let graphicContext = canvas.graphicContext
|
||||||
self?.graphicContext.object = graphicContext
|
self?.graphicContext.object = graphicContext
|
||||||
self?.graphicContext.loadStrokes(bounds)
|
self?.graphicContext.loadStrokes(bounds)
|
||||||
@@ -103,6 +109,18 @@ extension Canvas {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Grid Mode
|
||||||
|
extension Canvas {
|
||||||
|
func setGridMode(_ gridMode: GridMode) {
|
||||||
|
guard self.gridMode != gridMode else { return }
|
||||||
|
self.gridMode = gridMode
|
||||||
|
withPersistence(\.backgroundContext) { [weak object] context in
|
||||||
|
object?.gridMode = gridMode.rawValue
|
||||||
|
try context.saveIfNeeded()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Stroke
|
// MARK: - Stroke
|
||||||
extension Canvas {
|
extension Canvas {
|
||||||
func beginTouch(at point: CGPoint, pen: Pen) -> any Stroke {
|
func beginTouch(at point: CGPoint, pen: Pen) -> any Stroke {
|
||||||
@@ -135,7 +153,7 @@ extension Canvas {
|
|||||||
|
|
||||||
// MARK: - Rendering
|
// MARK: - Rendering
|
||||||
extension Canvas {
|
extension Canvas {
|
||||||
func renderGrid(device: MTLDevice, renderEncoder: MTLRenderCommandEncoder) {
|
func renderPointGrid(device: MTLDevice, renderEncoder: MTLRenderCommandEncoder) {
|
||||||
var uniforms = GridUniforms(
|
var uniforms = GridUniforms(
|
||||||
ratio: size.width.float / 100,
|
ratio: size.width.float / 100,
|
||||||
zoom: zoomScale.float,
|
zoom: zoomScale.float,
|
||||||
@@ -143,7 +161,18 @@ extension Canvas {
|
|||||||
)
|
)
|
||||||
uniformsBuffer = device.makeBuffer(bytes: &uniforms, length: MemoryLayout<GridUniforms>.size)
|
uniformsBuffer = device.makeBuffer(bytes: &uniforms, length: MemoryLayout<GridUniforms>.size)
|
||||||
renderEncoder.setVertexBuffer(uniformsBuffer, offset: 0, index: 11)
|
renderEncoder.setVertexBuffer(uniformsBuffer, offset: 0, index: 11)
|
||||||
gridContext.draw(device: device, renderEncoder: renderEncoder)
|
pointGridContext.draw(device: device, renderEncoder: renderEncoder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func renderLineGrid(device: MTLDevice, renderEncoder: MTLRenderCommandEncoder) {
|
||||||
|
var uniforms = GridUniforms(
|
||||||
|
ratio: size.width.float / 100,
|
||||||
|
zoom: zoomScale.float,
|
||||||
|
transform: transform
|
||||||
|
)
|
||||||
|
uniformsBuffer = device.makeBuffer(bytes: &uniforms, length: MemoryLayout<GridUniforms>.size)
|
||||||
|
renderEncoder.setVertexBuffer(uniformsBuffer, offset: 0, index: 11)
|
||||||
|
lineGridContext.draw(device: device, renderEncoder: renderEncoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderGraphic(device: MTLDevice, renderEncoder: MTLRenderCommandEncoder) {
|
func renderGraphic(device: MTLDevice, renderEncoder: MTLRenderCommandEncoder) {
|
||||||
|
|||||||
@@ -9,14 +9,35 @@ import MetalKit
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct PipelineStates {
|
struct PipelineStates {
|
||||||
static func createGridPipelineState(from renderer: Renderer, pixelFormat: MTLPixelFormat? = nil) -> MTLRenderPipelineState? {
|
static func createPointGridPipelineState(from renderer: Renderer, pixelFormat: MTLPixelFormat? = nil) -> MTLRenderPipelineState? {
|
||||||
let device = renderer.device
|
let device = renderer.device
|
||||||
let library = renderer.library
|
let library = renderer.library
|
||||||
let pipelineDescriptor = MTLRenderPipelineDescriptor()
|
let pipelineDescriptor = MTLRenderPipelineDescriptor()
|
||||||
pipelineDescriptor.vertexFunction = library.makeFunction(name: "vertex_grid")
|
pipelineDescriptor.vertexFunction = library.makeFunction(name: "vertex_point_grid")
|
||||||
pipelineDescriptor.fragmentFunction = library.makeFunction(name: "fragment_grid")
|
pipelineDescriptor.fragmentFunction = library.makeFunction(name: "fragment_point_grid")
|
||||||
pipelineDescriptor.colorAttachments[0].pixelFormat = pixelFormat ?? renderer.pixelFormat
|
pipelineDescriptor.colorAttachments[0].pixelFormat = pixelFormat ?? renderer.pixelFormat
|
||||||
pipelineDescriptor.label = "Grid Pipeline State"
|
pipelineDescriptor.label = "Point Grid Pipeline State"
|
||||||
|
|
||||||
|
let attachment = pipelineDescriptor.colorAttachments[0]
|
||||||
|
attachment?.isBlendingEnabled = true
|
||||||
|
attachment?.rgbBlendOperation = .add
|
||||||
|
attachment?.sourceRGBBlendFactor = .one
|
||||||
|
attachment?.destinationRGBBlendFactor = .oneMinusSourceAlpha
|
||||||
|
attachment?.alphaBlendOperation = .add
|
||||||
|
attachment?.sourceAlphaBlendFactor = .sourceAlpha
|
||||||
|
attachment?.destinationAlphaBlendFactor = .oneMinusSourceAlpha
|
||||||
|
|
||||||
|
return try? device.makeRenderPipelineState(descriptor: pipelineDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func createLineGridPipelineState(from renderer: Renderer, pixelFormat: MTLPixelFormat? = nil) -> MTLRenderPipelineState? {
|
||||||
|
let device = renderer.device
|
||||||
|
let library = renderer.library
|
||||||
|
let pipelineDescriptor = MTLRenderPipelineDescriptor()
|
||||||
|
pipelineDescriptor.vertexFunction = library.makeFunction(name: "vertex_line_grid")
|
||||||
|
pipelineDescriptor.fragmentFunction = library.makeFunction(name: "fragment_line_grid")
|
||||||
|
pipelineDescriptor.colorAttachments[0].pixelFormat = pixelFormat ?? renderer.pixelFormat
|
||||||
|
pipelineDescriptor.label = "Line Grid Pipeline State"
|
||||||
|
|
||||||
let attachment = pipelineDescriptor.colorAttachments[0]
|
let attachment = pipelineDescriptor.colorAttachments[0]
|
||||||
attachment?.isBlendingEnabled = true
|
attachment?.isBlendingEnabled = true
|
||||||
|
|||||||
38
Memola/Canvas/Grid/GridMode.swift
Normal file
38
Memola/Canvas/Grid/GridMode.swift
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// GridMode.swift
|
||||||
|
// Memola
|
||||||
|
//
|
||||||
|
// Created by Dscyre Scotti on 6/25/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum GridMode: Int16, Equatable {
|
||||||
|
case none
|
||||||
|
case point
|
||||||
|
case line
|
||||||
|
|
||||||
|
var title: String {
|
||||||
|
switch self {
|
||||||
|
case .none:
|
||||||
|
return "No Grid"
|
||||||
|
case .point:
|
||||||
|
return "Point Grid"
|
||||||
|
case .line:
|
||||||
|
return "Line Grid"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var icon: String {
|
||||||
|
switch self {
|
||||||
|
case .none:
|
||||||
|
return "square.slash"
|
||||||
|
case .point:
|
||||||
|
return "circle.grid.3x3.fill"
|
||||||
|
case .line:
|
||||||
|
return "squareshape.split.3x3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static let all: [GridMode] = [.none, .point, line]
|
||||||
|
}
|
||||||
@@ -12,7 +12,8 @@ class ViewPortRenderPass: RenderPass {
|
|||||||
var label: String { "View Port Render Pass"}
|
var label: String { "View Port Render Pass"}
|
||||||
var descriptor: MTLRenderPassDescriptor?
|
var descriptor: MTLRenderPassDescriptor?
|
||||||
|
|
||||||
var gridPipelineState: MTLRenderPipelineState?
|
var pointGridPipelineState: MTLRenderPipelineState?
|
||||||
|
var lineGridPipelineState: MTLRenderPipelineState?
|
||||||
var viewPortPipelineState: MTLRenderPipelineState?
|
var viewPortPipelineState: MTLRenderPipelineState?
|
||||||
var viewPortUpdatePipelineState: MTLRenderPipelineState?
|
var viewPortUpdatePipelineState: MTLRenderPipelineState?
|
||||||
|
|
||||||
@@ -22,7 +23,8 @@ class ViewPortRenderPass: RenderPass {
|
|||||||
weak var view: MTKView?
|
weak var view: MTKView?
|
||||||
|
|
||||||
init(renderer: Renderer) {
|
init(renderer: Renderer) {
|
||||||
gridPipelineState = PipelineStates.createGridPipelineState(from: renderer)
|
pointGridPipelineState = PipelineStates.createPointGridPipelineState(from: renderer)
|
||||||
|
lineGridPipelineState = PipelineStates.createLineGridPipelineState(from: renderer)
|
||||||
viewPortPipelineState = PipelineStates.createViewPortPipelineState(from: renderer)
|
viewPortPipelineState = PipelineStates.createViewPortPipelineState(from: renderer)
|
||||||
viewPortUpdatePipelineState = PipelineStates.createViewPortPipelineState(from: renderer, isUpdate: true)
|
viewPortUpdatePipelineState = PipelineStates.createViewPortPipelineState(from: renderer, isUpdate: true)
|
||||||
}
|
}
|
||||||
@@ -38,9 +40,18 @@ class ViewPortRenderPass: RenderPass {
|
|||||||
}
|
}
|
||||||
renderEncoder.label = "View Port Render Encoder"
|
renderEncoder.label = "View Port Render Encoder"
|
||||||
|
|
||||||
guard let gridPipelineState else { return }
|
switch canvas.gridMode {
|
||||||
renderEncoder.setRenderPipelineState(gridPipelineState)
|
case .none:
|
||||||
canvas.renderGrid(device: renderer.device, renderEncoder: renderEncoder)
|
break
|
||||||
|
case .point:
|
||||||
|
guard let pointGridPipelineState else { return }
|
||||||
|
renderEncoder.setRenderPipelineState(pointGridPipelineState)
|
||||||
|
canvas.renderPointGrid(device: renderer.device, renderEncoder: renderEncoder)
|
||||||
|
case .line:
|
||||||
|
guard let lineGridPipelineState else { return }
|
||||||
|
renderEncoder.setRenderPipelineState(lineGridPipelineState)
|
||||||
|
canvas.renderLineGrid(device: renderer.device, renderEncoder: renderEncoder)
|
||||||
|
}
|
||||||
|
|
||||||
if renderer.updatesViewPort {
|
if renderer.updatesViewPort {
|
||||||
guard let viewPortUpdatePipelineState else {
|
guard let viewPortUpdatePipelineState else {
|
||||||
|
|||||||
@@ -8,33 +8,37 @@
|
|||||||
#include <metal_stdlib>
|
#include <metal_stdlib>
|
||||||
using namespace metal;
|
using namespace metal;
|
||||||
|
|
||||||
struct Vertex {
|
struct PointVertex {
|
||||||
float4 position [[position]];
|
float4 position [[position]];
|
||||||
float pointSize [[point_size]];
|
float pointSize [[point_size]];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LineVertex {
|
||||||
|
float4 position [[position]];
|
||||||
|
};
|
||||||
|
|
||||||
struct Uniforms {
|
struct Uniforms {
|
||||||
float ratio;
|
float ratio;
|
||||||
float zoom;
|
float zoom;
|
||||||
float4x4 transform;
|
float4x4 transform;
|
||||||
};
|
};
|
||||||
|
|
||||||
vertex Vertex vertex_grid(
|
vertex PointVertex vertex_point_grid(
|
||||||
constant Vertex *vertices [[buffer(0)]],
|
constant PointVertex *vertices [[buffer(0)]],
|
||||||
constant Uniforms &uniforms [[buffer(11)]],
|
constant Uniforms &uniforms [[buffer(11)]],
|
||||||
uint vertexId [[vertex_id]]
|
uint vertexId [[vertex_id]]
|
||||||
) {
|
) {
|
||||||
Vertex _vertex = vertices[vertexId];
|
PointVertex _vertex = vertices[vertexId];
|
||||||
float x = _vertex.position.x * uniforms.ratio;
|
float x = _vertex.position.x * uniforms.ratio;
|
||||||
float y = _vertex.position.y * uniforms.ratio;
|
float y = _vertex.position.y * uniforms.ratio;
|
||||||
float4 position = float4(x, y, 0, 1);
|
float4 position = float4(x, y, 0, 1);
|
||||||
_vertex.position = uniforms.transform * position;
|
_vertex.position = uniforms.transform * position;
|
||||||
_vertex.pointSize = 10 * uniforms.zoom / 12;
|
_vertex.pointSize = 8 * uniforms.zoom / 12;
|
||||||
return _vertex;
|
return _vertex;
|
||||||
}
|
}
|
||||||
|
|
||||||
fragment float4 fragment_grid(
|
fragment float4 fragment_point_grid(
|
||||||
Vertex _vertex [[stage_in]],
|
PointVertex _vertex [[stage_in]],
|
||||||
float2 pointCoord [[point_coord]]
|
float2 pointCoord [[point_coord]]
|
||||||
) {
|
) {
|
||||||
float dist = length(pointCoord - float2(0.5));
|
float dist = length(pointCoord - float2(0.5));
|
||||||
@@ -42,3 +46,20 @@ fragment float4 fragment_grid(
|
|||||||
color.a = 1.0 - smoothstep(0.4, 0.5, dist);
|
color.a = 1.0 - smoothstep(0.4, 0.5, dist);
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vertex LineVertex vertex_line_grid(
|
||||||
|
constant LineVertex *vertices [[buffer(0)]],
|
||||||
|
constant Uniforms &uniforms [[buffer(11)]],
|
||||||
|
uint vertexId [[vertex_id]]
|
||||||
|
) {
|
||||||
|
LineVertex _vertex = vertices[vertexId];
|
||||||
|
float x = _vertex.position.x * uniforms.ratio;
|
||||||
|
float y = _vertex.position.y * uniforms.ratio;
|
||||||
|
float4 position = float4(x, y, 0, 1);
|
||||||
|
_vertex.position = uniforms.transform * position;
|
||||||
|
return _vertex;
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 fragment_line_grid() {
|
||||||
|
return float4(0.752, 0.752, 0.752, 1);
|
||||||
|
}
|
||||||
|
|||||||
@@ -161,18 +161,22 @@ extension CanvasViewController {
|
|||||||
self?.canvasStateChanged(state)
|
self?.canvasStateChanged(state)
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
canvas.zoomPublisher
|
canvas.zoomPublisher
|
||||||
.sink { [weak self] zoomScale in
|
.sink { [weak self] zoomScale in
|
||||||
self?.zoomChanged(zoomScale)
|
self?.zoomChanged(zoomScale)
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
canvas.$locksCanvas
|
canvas.$locksCanvas
|
||||||
.sink { [weak self] state in
|
.sink { [weak self] state in
|
||||||
self?.lockModeChanged(state)
|
self?.lockModeChanged(state)
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
canvas.$gridMode
|
||||||
|
.delay(for: .milliseconds(100), scheduler: DispatchQueue.main)
|
||||||
|
.sink { [weak self] mode in
|
||||||
|
self?.gridModeChanged(mode)
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
|
||||||
tool.$selectedPen
|
tool.$selectedPen
|
||||||
.sink { [weak self] pen in
|
.sink { [weak self] pen in
|
||||||
@@ -364,6 +368,13 @@ extension CanvasViewController {
|
|||||||
func lockModeChanged(_ state: Bool) {
|
func lockModeChanged(_ state: Bool) {
|
||||||
scrollView.pinchGestureRecognizer?.isEnabled = !state
|
scrollView.pinchGestureRecognizer?.isEnabled = !state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func gridModeChanged(_ mode: GridMode) {
|
||||||
|
drawingView.disableUserInteraction()
|
||||||
|
renderer.resize(on: renderView, to: renderView.drawableSize)
|
||||||
|
renderView.draw()
|
||||||
|
drawingView.enableUserInteraction()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension CanvasViewController {
|
extension CanvasViewController {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ struct MemoView: View {
|
|||||||
self.memo = memo
|
self.memo = memo
|
||||||
self.title = memo.title
|
self.title = memo.title
|
||||||
self._tool = StateObject(wrappedValue: Tool(object: memo.tool))
|
self._tool = StateObject(wrappedValue: Tool(object: memo.tool))
|
||||||
self._canvas = StateObject(wrappedValue: Canvas(size: memo.canvas.size, canvasID: memo.canvas.objectID))
|
self._canvas = StateObject(wrappedValue: Canvas(size: memo.canvas.size, canvasID: memo.canvas.objectID, gridMode: memo.canvas.gridMode))
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
|||||||
@@ -50,8 +50,9 @@ struct Toolbar: View {
|
|||||||
if !canvas.locksCanvas {
|
if !canvas.locksCanvas {
|
||||||
elementTool
|
elementTool
|
||||||
}
|
}
|
||||||
Group {
|
HStack(spacing: 5) {
|
||||||
if !canvas.locksCanvas {
|
if !canvas.locksCanvas {
|
||||||
|
gridModeControl
|
||||||
historyControl
|
historyControl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -263,6 +264,31 @@ struct Toolbar: View {
|
|||||||
.transition(.move(edge: .top).combined(with: .blurReplace))
|
.transition(.move(edge: .top).combined(with: .blurReplace))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var gridModeControl: some View {
|
||||||
|
Menu {
|
||||||
|
ForEach(GridMode.all, id: \.self) { mode in
|
||||||
|
Button {
|
||||||
|
canvas.setGridMode(mode)
|
||||||
|
} label: {
|
||||||
|
Label {
|
||||||
|
Text(mode.title)
|
||||||
|
} icon: {
|
||||||
|
Image(systemName: mode.icon)
|
||||||
|
}
|
||||||
|
.font(.headline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
Image(systemName: canvas.gridMode.icon)
|
||||||
|
.contentShape(.circle)
|
||||||
|
.frame(width: size, height: size)
|
||||||
|
.background(.regularMaterial)
|
||||||
|
.clipShape(.rect(cornerRadius: 8))
|
||||||
|
}
|
||||||
|
.hoverEffect(.lift)
|
||||||
|
.contentTransition(.symbolEffect(.replace))
|
||||||
|
}
|
||||||
|
|
||||||
func openCamera() {
|
func openCamera() {
|
||||||
let status = AVCaptureDevice.authorizationStatus(for: .video)
|
let status = AVCaptureDevice.authorizationStatus(for: .video)
|
||||||
switch status {
|
switch status {
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ struct MemosView: View {
|
|||||||
let canvasObject = CanvasObject(context: managedObjectContext)
|
let canvasObject = CanvasObject(context: managedObjectContext)
|
||||||
canvasObject.width = 8_000
|
canvasObject.width = 8_000
|
||||||
canvasObject.height = 8_000
|
canvasObject.height = 8_000
|
||||||
|
canvasObject.gridMode = 1
|
||||||
|
|
||||||
let toolObject = ToolObject(\.viewContext)
|
let toolObject = ToolObject(\.viewContext)
|
||||||
toolObject.selection = 0
|
toolObject.selection = 0
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import Foundation
|
|||||||
final class CanvasObject: NSManagedObject {
|
final class CanvasObject: NSManagedObject {
|
||||||
@NSManaged var width: CGFloat
|
@NSManaged var width: CGFloat
|
||||||
@NSManaged var height: CGFloat
|
@NSManaged var height: CGFloat
|
||||||
|
@NSManaged var gridMode: Int16
|
||||||
@NSManaged var memo: MemoObject?
|
@NSManaged var memo: MemoObject?
|
||||||
@NSManaged var graphicContext: GraphicContextObject
|
@NSManaged var graphicContext: GraphicContextObject
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="22757" systemVersion="23B74" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="22757" systemVersion="23B74" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||||
<entity name="CanvasObject" representedClassName="CanvasObject" syncable="YES">
|
<entity name="CanvasObject" representedClassName="CanvasObject" syncable="YES">
|
||||||
|
<attribute name="gridMode" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
|
||||||
<attribute name="height" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES" customClassName="CGFloat"/>
|
<attribute name="height" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES" customClassName="CGFloat"/>
|
||||||
<attribute name="width" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES" customClassName="CGFloat"/>
|
<attribute name="width" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES" customClassName="CGFloat"/>
|
||||||
<relationship name="graphicContext" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="GraphicContextObject" inverseName="canvas" inverseEntity="GraphicContextObject"/>
|
<relationship name="graphicContext" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="GraphicContextObject" inverseName="canvas" inverseEntity="GraphicContextObject"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user