├── .github
├── FUNDING.yml
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── custom.md
│ ├── feature_request.md
│ └── new_feature.md
├── .gitignore
├── CHANGELOG.md
├── CHANGELOG.md.meta
├── Editor.meta
├── Editor
├── FontImporter.cs
├── FontImporter.cs.meta
├── SVGImporter.cs
├── SVGImporter.cs.meta
├── VX.GPUVectorGraphics.Editor.asmdef
└── VX.GPUVectorGraphics.Editor.asmdef.meta
├── Gizmos.meta
├── Gizmos
├── FontIcon.png
└── FontIcon.png.meta
├── LICENSE
├── Pictures~
└── simple_bezier_curve.png
├── README.md
├── README.md.meta
├── Runtime.meta
├── Runtime
├── BezierProperties.cs
├── BezierProperties.cs.meta
├── CDT.meta
├── CDT
│ ├── CDT.Constrain.cs
│ ├── CDT.Constrain.cs.meta
│ ├── CDT.ConstraintUtil.cs
│ ├── CDT.ConstraintUtil.cs.meta
│ ├── CDT.Primitive.cs
│ ├── CDT.Primitive.cs.meta
│ ├── CDT.QuadraticInsert.cs
│ ├── CDT.QuadraticInsert.cs.meta
│ ├── CDT.Triangulate.cs
│ ├── CDT.Triangulate.cs.meta
│ ├── CDT.TriangulationUtil.cs
│ ├── CDT.TriangulationUtil.cs.meta
│ ├── CDT.Util.cs
│ ├── CDT.Util.cs.meta
│ ├── CDT.cs
│ └── CDT.cs.meta
├── CubicBezier.meta
├── CubicBezier
│ ├── CubicBezier.CurveType.cs
│ ├── CubicBezier.CurveType.cs.meta
│ ├── CubicBezier.Geometry.cs
│ ├── CubicBezier.Geometry.cs.meta
│ ├── CubicBezier.Triangulate.cs
│ └── CubicBezier.Triangulate.cs.meta
├── Font.meta
├── Font
│ ├── FontCurve.cs
│ ├── FontCurve.cs.meta
│ ├── Glyph.cs
│ ├── Glyph.cs.meta
│ ├── Reader.meta
│ ├── Reader
│ │ ├── FontReader.cs
│ │ ├── FontReader.cs.meta
│ │ ├── FontReaderFile.cs
│ │ └── FontReaderFile.cs.meta
│ ├── Tables.meta
│ ├── Tables
│ │ ├── CMap.cs
│ │ ├── CMap.cs.meta
│ │ ├── Glyf.cs
│ │ ├── Glyf.cs.meta
│ │ ├── Head.cs
│ │ ├── Head.cs.meta
│ │ ├── Loca.cs
│ │ ├── Loca.cs.meta
│ │ ├── MaxP.cs
│ │ ├── MaxP.cs.meta
│ │ ├── Table.cs
│ │ └── Table.cs.meta
│ ├── TypeFace.cs
│ └── TypeFace.cs.meta
├── QuadraticBezier.meta
├── VGMath.cs
├── VGMath.cs.meta
├── VX.GPUVectorGraphics.Runtime.asmdef
└── VX.GPUVectorGraphics.Runtime.asmdef.meta
├── Shader.meta
├── Shader
├── CubicBezier.shadersubgraph
├── CubicBezier.shadersubgraph.meta
├── CubicBezierCurve.shader
├── CubicBezierCurve.shader.meta
├── QuadraticBezier.shadersubgraph
├── QuadraticBezier.shadersubgraph.meta
├── QuadraticBezierCurve.shader
├── QuadraticBezierCurve.shader.meta
├── SimpleLitQuadraticBezier.shadergraph
└── SimpleLitQuadraticBezier.shadergraph.meta
├── package.json
└── package.json.meta
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: voxelltech
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: ["paypal.me/voxelltechnologies"]
13 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/custom.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Custom issue template
3 | about: Describe this issue template's purpose here.
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/new_feature.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: New Feature
3 | about: Creating a new feature for this project.
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Summary**
11 |
12 | A quick intro or summary on the feature you want to create.
13 |
14 | **Intended Outcome**
15 |
16 | - What is the use case of this?
17 | - How will it affect/benefit the project?
18 |
19 | **How will it work?**
20 |
21 | - How to use this feature?
22 |
23 | *finally, please assign yourself to this issue if you intend to work on this new feature thanks!*
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode/
2 | __pycache__/
3 | checkpoints/
4 | inference/
5 | env/
6 | temp/
7 |
8 | # This .gitignore file should be placed at the root of your Unity project directory
9 | #
10 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore
11 | #
12 | /[Ll]ibrary/
13 | /[Tt]emp/
14 | /[Oo]bj/
15 | /[Bb]uild/
16 | /[Bb]uilds/
17 | /[Ll]ogs/
18 | /[Uu]ser[Ss]ettings/
19 | /[Rr]ecordings/
20 | /[Rr]eleases/
21 | /[Rr]elease/
22 |
23 |
24 | # MemoryCaptures can get excessive in size.
25 | # They also could contain extremely sensitive data
26 | /[Mm]emoryCaptures/
27 |
28 | # Asset meta data should only be ignored when the corresponding asset is also ignored
29 | !/[Aa]ssets/**/*.meta
30 |
31 | # Uncomment this line if you wish to ignore the asset store tools plugin
32 | # /[Aa]ssets/AssetStoreTools*
33 |
34 | # Autogenerated Jetbrains Rider plugin
35 | /[Aa]ssets/Plugins/Editor/JetBrains*
36 |
37 | # Visual Studio cache directory
38 | .vs/
39 |
40 | # Gradle cache directory
41 | .gradle/
42 |
43 | # Autogenerated VS/MD/Consulo solution and project files
44 | ExportedObj/
45 | .consulo/
46 | *.csproj
47 | *.unityproj
48 | *.sln
49 | *.suo
50 | *.tmp
51 | *.user
52 | *.userprefs
53 | *.pidb
54 | *.booproj
55 | *.svd
56 | *.pdb
57 | *.mdb
58 | *.opendb
59 | *.VC.db
60 |
61 | # Unity3D generated meta files
62 | *.pidb.meta
63 | *.pdb.meta
64 | *.mdb.meta
65 |
66 | # Unity3D generated file on crash reports
67 | sysinfo.txt
68 |
69 | # Builds
70 | *.apk
71 | *.aab
72 | *.unitypackage
73 | *.unitypackage.meta
74 | *.exe
75 |
76 | # Crashlytics generated file
77 | crashlytics-build.properties
78 |
79 | # Packed Addressables
80 | /[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin*
81 |
82 | # Temporary auto-generated Android Assets
83 | /[Aa]ssets/[Ss]treamingAssets/aa.meta
84 | /[Aa]ssets/[Ss]treamingAssets/aa/*
85 |
86 | # Tensorflow trained checkpoints and weights
87 | *.h5
88 | *.h5.meta
89 | *.pbmm
90 | *.pbmm.meta
91 | *.tflite
92 | *.tflite.meta
93 |
94 | # API keys
95 | *.apikey
96 |
97 | # pycaches
98 | *.pyc
99 |
100 | # audio files
101 | AudioClips/
102 | *.mp3
103 | *.wav
104 | *.audio
105 |
106 | # license
107 | LICENSE.meta
108 |
109 | # large libraries
110 | native/
111 | tensorflow.dll
112 | tensorflow.dll.meta
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [0.3.3]
2 |
3 | ### New Features
4 |
5 | - `FontCurve` stores an array of precomputed meshes on import.
6 | - Implementation of binary search to search for character's glyph/mesh index.
7 |
8 | ### Changes
9 |
10 | - Burst Compile uses high precision float and strict float mode.
11 | - Reduced `MARGIN` from 10.0f to 1.0f.
12 | - Renamed `Circumcenter` to `Circumcircle`.
13 | - Renamed `GenerateMeshDataFromGlyph` to `ExtractGlyphData`.
14 | - Increased `FontImporter` verion from 2 to 3.
15 | - Instead of `charMaps`, `FontCurve` now stores 2 separate arrays:
16 | - `charCodes`: an array of supported characters.
17 | - `glyphIndices`: an array of glyph indices corresponding to the supported character codes.
18 | - Uses "super-triangle" instead of "rect-triangles" as there is an elegant way to create a huge triangle that encapsulates all points inside.
19 | 1. Calculate bounding-box (min/max rect) of the points.
20 | 2. Place the bounding-box on a line.
21 | ```
22 | __
23 | |__|
24 | ----
25 | ```
26 | 3. Place 2 more of the same box at the top and bottom of the current box.
27 | ```
28 | __
29 | |__|
30 | __
31 | |__|
32 | __
33 | |__|
34 | ----
35 | ```
36 | 4. Place another 2 more of the same box at the left and right of the bottom most box.
37 | ```
38 | __
39 | |__|
40 | __
41 | |__|
42 | __ __ __
43 | |__| |__| |__|
44 | --------------
45 | ```
46 | 5. Now, connect the "left-bottom most" point, "right-bottom most" point, and the "middle-top-most" point together.
47 | ```
48 | __ /\
49 | |__| /__\
50 | __ / __ \
51 | |__| / |__| \
52 | __ __ __ _/ __ \_
53 | |__| |__| |__| |/_| |__| |_\|
54 | ----------------------------------
55 | ```
56 | 6. And now you get a "super-triangle" that encapsulates all the points in the middle box! (of course, you can add some kind of margin to the box itself to enlarge the "super-triangle" just to make sure!)
57 | - Added "alpha" to package version.
58 |
59 | ### Bug Fixes
60 |
61 | - `PointInTriangle` method in `VGMath` is much more accurate (to handle edge cases) and computationally cheap.
62 | - Removed addition of `EPSILON` to `div` in `Cirumcircle` to prevent numerical inaccuracy.
63 | - `TriEdgeIntersect` method now checks for similarity based on point position rather than index as there might be duplicated points that have a different index.
64 |
65 | ## [0.3.2]
66 |
67 | ### Changes
68 |
69 | - Major code refactoring for CDT triangulation and constraint:
70 | - Generalize procedures into static function calls.
71 | - Create functions to prevent repetitive code.
72 | - CDT utility functions are now separated into 3 files:
73 | - `CDT.Util` for general utility purposes.
74 | - `CDT.TriangulationUtil` for delaunay triangulation utility purposes.
75 | - `CDT.ConstraintUtil` for constrained delaunay triangulation utility purposes.
76 |
77 | ### Bug Fixes
78 |
79 | - Removed `Debug.Log` calls from a static function that is being called in a burst compiled code.
80 |
81 | ## [0.3.1]
82 |
83 | ### New Features
84 |
85 | - Removal of triangles that are outside the constraint contour.
86 |
87 | ### Changes
88 |
89 | - Uses "rect-triangles" instead of "super-triangles" for stability. This can prevent some points from being excluded when the min and max rect is large.
90 |
91 | ## [0.3.0]
92 |
93 | ### New Features
94 |
95 | - Implementation of constrained delaunay triangulation.
96 |
97 | ### Changes
98 |
99 | - Removed `Voxell.GPUVectorGraphics.Delaunay` namespace.
100 |
101 | ## [0.2.0]
102 |
103 | ### New Features
104 |
105 | - Bezier Properties for describing a shape made up of bezier curves.
106 | - Open Font lightweight importer:
107 | - Native support.
108 | - Store data as glyphs. Each glyph will have a glyph contour containing a sequence of points in the order of p0-ctrl0-p1-ctrl1.
109 | - Character maps that maps each character to a glyph index.
110 |
111 | ### Bug Fixes
112 |
113 | - Fixes uvw coordinate when being flipped.
114 | - Prevent extra triangulation when encountering loop artifacts.
115 |
116 | ## [0.1.0]
117 |
118 | - Initial release.
--------------------------------------------------------------------------------
/CHANGELOG.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 144cf53156b805e4ea68518bd4c7528e
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: fa7bb127083dcdc4bb6fc95551ad49fd
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/FontImporter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.IO;
3 | using UnityEngine;
4 | using UnityEditor.AssetImporters;
5 | using Unity.Mathematics;
6 | using Unity.Collections;
7 | using Unity.Jobs;
8 |
9 | namespace Voxell.GPUVectorGraphics.Font
10 | {
11 | using Inspector;
12 |
13 | [ScriptedImporter(3, new[] { "ttfvector", "otfVector" }, new[] { "ttf", "otf" })]
14 | public class FontImporter : ScriptedImporter
15 | {
16 | /// Format of the font.
17 | public enum FontFormat
18 | {
19 | /// True type format.
20 | TTF,
21 | /// Open type format.
22 | OTF
23 | }
24 |
25 | public const int FormatTrueType = 0x00010000;
26 | public const int FormatOTF = 0x4F54544F;
27 |
28 | [Tooltip("Format of the font."), InspectOnly]
29 | public FontFormat fontFormat;
30 | [Tooltip("0x00010000 (TTF) or 0x4F54544F (OTF)."), InspectOnly]
31 | public uint sfntVersion;
32 | [Tooltip("Number of tables."), InspectOnly]
33 | public ushort numTables;
34 |
35 | private Dictionary _tableMap;
36 |
37 | // we convert the integer into a float for easier division operation purposes
38 | // we want a float division instead of a integer division (which looses all the floating point data)
39 | [Tooltip("The *integer value for a unit distance in the font."), InspectOnly]
40 | public float unitsPerEm = 0;
41 | [Tooltip("Offset width, relevant when certain peices of data in the file."), InspectOnly]
42 | public int offsetByteWidth = 0;
43 | [Tooltip("The number of glyphs in the font file."), InspectOnly]
44 | public int glyphCount;
45 |
46 | [Tooltip("Name of the type face."), InspectOnly]
47 | public string fontName;
48 |
49 | public override void OnImportAsset(AssetImportContext ctx)
50 | {
51 | string filePath = FileUtilx.GetAssetFilePath(ctx.assetPath);
52 | FontReaderFile fontReader = new FontReaderFile(filePath);
53 | fontReader.SetPosition(0);
54 | fontReader.ReadInt(out sfntVersion);
55 |
56 |
57 | if (sfntVersion != FormatTrueType && sfntVersion != FormatOTF)
58 | {
59 | Debug.LogWarning("Font type not supported!");
60 | return;
61 | }
62 |
63 | fontFormat = sfntVersion == FormatTrueType ? FontFormat.TTF : FontFormat.OTF;
64 | fontReader.ReadInt(out numTables);
65 | fontReader.SetPosition(6, SeekOrigin.Current);
66 |
67 | Table table;
68 | _tableMap = new Dictionary();
69 | for (int t=0; t < numTables; ++t)
70 | {
71 | table = new Table();
72 | table.Read(fontReader);
73 | _tableMap.Add(table.tag, table);
74 | }
75 |
76 | // head will tell us all table offset information
77 | ////////////////////////////////////////////////////////////////////////////////
78 | #region Head
79 | if (!_tableMap.TryGetValue(Head.TagName, out table))
80 | {
81 | Debug.LogError("Font file does not have a header!");
82 | return;
83 | }
84 |
85 | fontReader.SetPosition(table.offset);
86 | Head head = new Head();
87 | head.Read(fontReader);
88 | unitsPerEm = (float)head.unitsPerEm;
89 | offsetByteWidth = head.OffsetByteWidth;
90 | #endregion
91 |
92 | // maxp will tell us how many glyphs there are in the file
93 | ////////////////////////////////////////////////////////////////////////////////
94 | #region Maxp
95 | if (!_tableMap.TryGetValue(Maxp.TagName, out table))
96 | {
97 | Debug.LogError("Font file does not have maxp data!");
98 | return;
99 | }
100 |
101 | fontReader.SetPosition(table.offset);
102 | Maxp maxP = new Maxp();
103 | maxP.Read(fontReader);
104 | glyphCount = maxP.numGlyphs;
105 | #endregion
106 |
107 | // loca knows offsets of glyphs in the glyf table
108 | ////////////////////////////////////////////////////////////////////////////////
109 | #region Loca
110 | if (!_tableMap.TryGetValue(Loca.TagName, out table))
111 | {
112 | Debug.LogError("Font file does not have loca data!");
113 | return;
114 | }
115 |
116 | fontReader.SetPosition(table.offset);
117 | Loca loca = new Loca();
118 | loca.Read(fontReader, glyphCount, offsetByteWidth == 4);
119 | #endregion
120 |
121 | // glyf provides contour data
122 | ////////////////////////////////////////////////////////////////////////////////
123 | #region Glyf
124 | if (!_tableMap.TryGetValue(Glyf.TagName, out table))
125 | {
126 | Debug.LogError("Font file does not have glyf data!");
127 | return;
128 | }
129 |
130 | Glyph[] glyphs = new Glyph[glyphCount];
131 | fontName = FileUtilx.GetFilename(filePath).Split('.')[0];
132 | for (int g=0; g < glyphCount; g++)
133 | {
134 | uint glyphOffset = loca.GetGlyphOffset(table, g);
135 | uint glyphSize = loca.GetGlyphSize(g);
136 | // possibly a blank space or character does not exsit in this font
137 | // usually we treat it as a blank box
138 | if (glyphSize == 0) continue;
139 |
140 | fontReader.SetPosition(glyphOffset);
141 | Glyf glyf = new Glyf();
142 | glyf.Read(fontReader);
143 | int contourCount = glyf.numberOfContours;
144 |
145 | if (glyf.IsComplex)
146 | {
147 | // complex
148 | int compositeCount = glyf.compositeEntries.Count;
149 | glyphs[g].compositeReferences = new Glyph.CompositeReference[compositeCount];
150 | for (int c=0; c < compositeCount; c++)
151 | {
152 | Glyf.CompositeEntry ce = glyf.compositeEntries[c];
153 | Glyph.CompositeReference cref = new Font.Glyph.CompositeReference();
154 | cref.xAxis = new float2(ce.xscale, ce.scale01);
155 | cref.yAxis = new float2(ce.scale10, ce.yscale);
156 | cref.offset = new float2(ce.argument1, ce.argument2) / unitsPerEm;
157 | cref.glyphRef = ce.glyphIndex;
158 |
159 | glyphs[g].compositeReferences[c] = cref;
160 | }
161 | glyphs[g].isComplex = true;
162 | } else
163 | {
164 | // simple
165 | glyphs[g].contours = new QuadraticContour[contourCount];
166 | int pointIdx = 0;
167 |
168 | for (int c=0; c < contourCount; c++)
169 | {
170 | int endPoint = glyf.endPtsOfCountours[c]+1;
171 | int pointCount = endPoint - pointIdx;
172 |
173 | // initialize with the minimum capacity needed (if there are no consecutive points)
174 | List points = new List(pointCount);
175 | List isControls = new List(pointCount);
176 |
177 | // populate lists with original data
178 | for (; pointIdx < endPoint; pointIdx++)
179 | {
180 | isControls.Add((glyf.simpflags[pointIdx] & Glyf.ON_CURVE_POINT) == 0);
181 | float2 point = new float2(
182 | (float)glyf.xCoordinates[pointIdx], (float)glyf.yCoordinates[pointIdx]
183 | ) / unitsPerEm;
184 |
185 | points.Add(point);
186 | }
187 |
188 | // insert missing vertex points and control points
189 | for (int p=0; p < points.Count; p++)
190 | {
191 | // reverts back to 0 when we reach the end of the array
192 | int nextIdx = (p + 1) % points.Count;
193 |
194 | if (isControls[p] && isControls[nextIdx])
195 | {
196 | // If 2 control points are next to each other, there's an implied
197 | // point in between them at their average.
198 | // We add them explicitly for better parallelization in the future.
199 |
200 | // average vector between previous point and current point
201 | float2 avgPoint = (points[p] + points[nextIdx]) * 0.5f;
202 | points.Insert(nextIdx, avgPoint);
203 | isControls.Insert(nextIdx, false);
204 | } else if (!isControls[p] && !isControls[nextIdx])
205 | {
206 | // If 2 vertex points are next to each other, it represents that
207 | // the segment is a line instead of a curve.
208 | // We add a dummy control point which has the exact same location
209 | // as the current vertex point to indicate that it is a line.
210 |
211 | points.Insert(nextIdx, points[p]);
212 | isControls.Insert(nextIdx, true);
213 | }
214 | }
215 |
216 | // convert point list into segment array
217 | int segmentCount = points.Count/2;
218 | QuadraticPathSegment[] segments = new QuadraticPathSegment[segmentCount];
219 | for (int s=0; s < segmentCount; s++)
220 | {
221 | int segmentIdx = s*2;
222 | segments[s].p0 = points[segmentIdx];
223 | segments[s].p1 = points[segmentIdx+1];
224 | }
225 |
226 | // store to glyph struct
227 | glyphs[g].contours[c].segments = segments;
228 | glyphs[g].contours[c].closed = true;
229 | glyphs[g].maxRect = new float2(glyf.xMax, glyf.yMax)/unitsPerEm;
230 | glyphs[g].minRect = new float2(glyf.xMin, glyf.yMin)/unitsPerEm;
231 | }
232 | glyphs[g].isComplex = false;
233 | }
234 | }
235 | #endregion
236 |
237 | // cmap tells us the mapping between
238 | // character codes and glyph indices used throughout the font file
239 | ////////////////////////////////////////////////////////////////////////////////
240 | #region cmap
241 | if (!_tableMap.TryGetValue(CMap.TagName, out table))
242 | {
243 | Debug.LogError("Font file does not have cmap data!");
244 | return;
245 | }
246 |
247 | fontReader.SetPosition(table.offset);
248 | CMap cMap = new CMap();
249 | cMap.Read(fontReader, table.offset);
250 |
251 | Dictionary characterRemap = null;
252 | foreach (CMap.CharacterConversionMap ccm in cMap.EnumCharacterMaps())
253 | {
254 | Dictionary potentialMap = ccm.MapCodeToIndex(fontReader);
255 | if (characterRemap == null || potentialMap.Count > characterRemap.Count)
256 | characterRemap = potentialMap;
257 | }
258 |
259 | List charCodesList = new List();
260 | charCodesList.Add(0);
261 | List glyphIndicesList = new List();
262 | glyphIndicesList.Add(0);
263 |
264 | foreach (KeyValuePair kvp in characterRemap)
265 | {
266 | int key = (int) kvp.Key;
267 | int value = (int) kvp.Value;
268 |
269 | if (value == 0 || value >= glyphCount) continue;
270 | charCodesList.Add(key);
271 | glyphIndicesList.Add(value);
272 | }
273 |
274 | int[] charCodes = charCodesList.ToArray();
275 | int[] glyphIndices = glyphIndicesList.ToArray();
276 |
277 | System.Array.Sort(charCodes, glyphIndices);
278 | // sort character codes
279 | #endregion
280 |
281 | _tableMap.Clear();
282 | fontReader.Close();
283 |
284 | FontCurve fontCurve = ScriptableObject.CreateInstance();
285 | ctx.AddObjectToAsset("FontCurve", fontCurve);
286 |
287 | // create mesh for each char
288 | ////////////////////////////////////////////////////////////////////////////////
289 | int keyCount = charCodes.Length;
290 | Mesh[] meshes = new Mesh[keyCount];
291 | NativeArray jobHandles = new NativeArray(keyCount, Allocator.Temp);
292 |
293 | NativeArray[] na_points_array =
294 | new NativeArray[keyCount];
295 | NativeList[] na_triangles_array =
296 | new NativeList[keyCount];
297 | NativeArray[] na_contours_array =
298 | new NativeArray[keyCount];
299 |
300 | for (int k=0; k < keyCount; k++)
301 | {
302 | Glyph glyph = glyphs[glyphIndices[k]];
303 | if (glyph.contours == null) continue;
304 | int contourCount = glyph.contours.Length;
305 | if (contourCount == 0) continue;
306 |
307 | float2[] points;
308 | CDT.ContourPoint[] contours;
309 | FontCurve.ExtractGlyphData(in glyph, out points, out contours);
310 |
311 | float2 maxRect = glyph.maxRect;
312 | float2 minRect = glyph.minRect;
313 | jobHandles[k] = CDT.ConstraintTriangulate(
314 | minRect, maxRect, in points, in contours,
315 | out na_points_array[k],
316 | out na_triangles_array[k],
317 | out na_contours_array[k]
318 | );
319 |
320 | Debug.Log(glyphIndices[k]);
321 | Debug.Log((char)charCodes[k]);
322 | jobHandles[k].Complete();
323 | }
324 |
325 | // make sure that all the scheduled jobs are completed
326 | // JobHandle.CompleteAll(jobHandles);
327 |
328 | for (int k=0; k < keyCount; k++)
329 | {
330 | if (!na_points_array[k].IsCreated) continue;
331 | Glyph glyph = glyphs[glyphIndices[k]];
332 |
333 | string name = ((char)charCodes[k]).ToString();
334 | Mesh mesh = new Mesh();
335 | mesh.name = name;
336 | mesh.SetVertices(FontCurve.PointsToVertices(in na_points_array[k]));
337 | mesh.SetIndices(na_triangles_array[k], MeshTopology.Triangles, 0);
338 | mesh.RecalculateNormals();
339 | mesh.RecalculateTangents();
340 |
341 | float3 maxRect = new float3(glyph.maxRect, 0.0f);
342 | float3 minRect = new float3(glyph.minRect, 0.0f);
343 | float3 size = maxRect - minRect;
344 | float3 center = minRect + size*0.5f;
345 | mesh.bounds = new Bounds(center, size);
346 |
347 | meshes[k] = mesh;
348 | ctx.AddObjectToAsset(name, mesh);
349 | }
350 |
351 | fontCurve.Initialize(glyphs, charCodes, glyphIndices, meshes);
352 |
353 | // dispose all allocated arrays
354 | jobHandles.Dispose();
355 | for (int k=0; k < keyCount; k++)
356 | {
357 | if(na_points_array[k].IsCreated)
358 | na_points_array[k].Dispose();
359 | if(na_triangles_array[k].IsCreated)
360 | na_triangles_array[k].Dispose();
361 | if(na_contours_array[k].IsCreated)
362 | na_contours_array[k].Dispose();
363 | }
364 | }
365 | }
366 | }
--------------------------------------------------------------------------------
/Editor/FontImporter.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 629c9a55b73b7db4087275fa513e57b4
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/SVGImporter.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using UnityEditor;
3 | using UnityEditor.AssetImporters;
4 |
5 | namespace Voxell.GPUVectorGraphics.Editor
6 | {
7 | [ScriptedImporter(0, "svg")]
8 | public class SVGImporter : ScriptedImporter
9 | {
10 | public override void OnImportAsset(AssetImportContext ctx)
11 | {
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/Editor/SVGImporter.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 7da1bf49bbe64584f9c109c30646df2e
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/VX.GPUVectorGraphics.Editor.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "VX.GPUVectorGraphics.Editor",
3 | "rootNamespace": "",
4 | "references": [
5 | "GUID:da829e25e5d77364984881df942d9735",
6 | "GUID:b23efe0d0bd83184681bd63517e3c327",
7 | "GUID:d8b63aba1907145bea998dd612889d6b",
8 | "GUID:e0cd26848372d4e5c891c569017e11f1",
9 | "GUID:8a2eafa29b15f444eb6d74f94a930e1d"
10 | ],
11 | "includePlatforms": [
12 | "Editor"
13 | ],
14 | "excludePlatforms": [],
15 | "allowUnsafeCode": false,
16 | "overrideReferences": false,
17 | "precompiledReferences": [],
18 | "autoReferenced": true,
19 | "defineConstraints": [],
20 | "versionDefines": [],
21 | "noEngineReferences": false
22 | }
--------------------------------------------------------------------------------
/Editor/VX.GPUVectorGraphics.Editor.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f896bb4f5ed8a3742b1e02b52b203edf
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Gizmos.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 192563b8914f43f4494627e7bfb423c6
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Gizmos/FontIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nixon-voxell/UnityGPUVectorGraphics/85a4b4282a83856a3edd92572c0e44d8ef89c893/Gizmos/FontIcon.png
--------------------------------------------------------------------------------
/Gizmos/FontIcon.png.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f04b41271e371d047854280baa7d3658
3 | TextureImporter:
4 | internalIDToNameTable: []
5 | externalObjects: {}
6 | serializedVersion: 11
7 | mipmaps:
8 | mipMapMode: 0
9 | enableMipMap: 0
10 | sRGBTexture: 1
11 | linearTexture: 0
12 | fadeOut: 0
13 | borderMipMap: 0
14 | mipMapsPreserveCoverage: 0
15 | alphaTestReferenceValue: 0.5
16 | mipMapFadeDistanceStart: 1
17 | mipMapFadeDistanceEnd: 3
18 | bumpmap:
19 | convertToNormalMap: 0
20 | externalNormalMap: 0
21 | heightScale: 0.25
22 | normalMapFilter: 0
23 | isReadable: 1
24 | streamingMipmaps: 0
25 | streamingMipmapsPriority: 0
26 | vTOnly: 0
27 | ignoreMasterTextureLimit: 0
28 | grayScaleToAlpha: 0
29 | generateCubemap: 6
30 | cubemapConvolution: 0
31 | seamlessCubemap: 0
32 | textureFormat: 1
33 | maxTextureSize: 2048
34 | textureSettings:
35 | serializedVersion: 2
36 | filterMode: 1
37 | aniso: 1
38 | mipBias: 0
39 | wrapU: 1
40 | wrapV: 1
41 | wrapW: 0
42 | nPOTScale: 0
43 | lightmap: 0
44 | compressionQuality: 50
45 | spriteMode: 1
46 | spriteExtrude: 1
47 | spriteMeshType: 1
48 | alignment: 0
49 | spritePivot: {x: 0.5, y: 0.5}
50 | spritePixelsToUnits: 100
51 | spriteBorder: {x: 0, y: 0, z: 0, w: 0}
52 | spriteGenerateFallbackPhysicsShape: 1
53 | alphaUsage: 1
54 | alphaIsTransparency: 1
55 | spriteTessellationDetail: -1
56 | textureType: 2
57 | textureShape: 1
58 | singleChannelComponent: 0
59 | flipbookRows: 1
60 | flipbookColumns: 1
61 | maxTextureSizeSet: 0
62 | compressionQualitySet: 0
63 | textureFormatSet: 0
64 | ignorePngGamma: 0
65 | applyGammaDecoding: 0
66 | platformSettings:
67 | - serializedVersion: 3
68 | buildTarget: DefaultTexturePlatform
69 | maxTextureSize: 1024
70 | resizeAlgorithm: 0
71 | textureFormat: -1
72 | textureCompression: 1
73 | compressionQuality: 50
74 | crunchedCompression: 0
75 | allowsAlphaSplitting: 0
76 | overridden: 0
77 | androidETC2FallbackOverride: 0
78 | forceMaximumCompressionQuality_BC6H_BC7: 0
79 | - serializedVersion: 3
80 | buildTarget: Standalone
81 | maxTextureSize: 64
82 | resizeAlgorithm: 0
83 | textureFormat: -1
84 | textureCompression: 1
85 | compressionQuality: 50
86 | crunchedCompression: 0
87 | allowsAlphaSplitting: 0
88 | overridden: 0
89 | androidETC2FallbackOverride: 0
90 | forceMaximumCompressionQuality_BC6H_BC7: 0
91 | - serializedVersion: 3
92 | buildTarget: iPhone
93 | maxTextureSize: 8192
94 | resizeAlgorithm: 0
95 | textureFormat: -1
96 | textureCompression: 1
97 | compressionQuality: 50
98 | crunchedCompression: 0
99 | allowsAlphaSplitting: 0
100 | overridden: 0
101 | androidETC2FallbackOverride: 0
102 | forceMaximumCompressionQuality_BC6H_BC7: 0
103 | - serializedVersion: 3
104 | buildTarget: Android
105 | maxTextureSize: 8192
106 | resizeAlgorithm: 0
107 | textureFormat: -1
108 | textureCompression: 1
109 | compressionQuality: 50
110 | crunchedCompression: 0
111 | allowsAlphaSplitting: 0
112 | overridden: 0
113 | androidETC2FallbackOverride: 0
114 | forceMaximumCompressionQuality_BC6H_BC7: 0
115 | - serializedVersion: 3
116 | buildTarget: Windows Store Apps
117 | maxTextureSize: 8192
118 | resizeAlgorithm: 0
119 | textureFormat: -1
120 | textureCompression: 1
121 | compressionQuality: 50
122 | crunchedCompression: 0
123 | allowsAlphaSplitting: 0
124 | overridden: 0
125 | androidETC2FallbackOverride: 0
126 | forceMaximumCompressionQuality_BC6H_BC7: 0
127 | - serializedVersion: 3
128 | buildTarget: Server
129 | maxTextureSize: 64
130 | resizeAlgorithm: 0
131 | textureFormat: -1
132 | textureCompression: 1
133 | compressionQuality: 50
134 | crunchedCompression: 0
135 | allowsAlphaSplitting: 0
136 | overridden: 0
137 | androidETC2FallbackOverride: 0
138 | forceMaximumCompressionQuality_BC6H_BC7: 0
139 | spriteSheet:
140 | serializedVersion: 2
141 | sprites: []
142 | outline: []
143 | physicsShape: []
144 | bones: []
145 | spriteID: 5e97eb03825dee720800000000000000
146 | internalID: 0
147 | vertices: []
148 | indices:
149 | edges: []
150 | weights: []
151 | secondaryTextures: []
152 | nameFileIdTable: {}
153 | spritePackingTag:
154 | pSDRemoveMatte: 0
155 | pSDShowRemoveMatteOption: 0
156 | userData:
157 | assetBundleName:
158 | assetBundleVariant:
159 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2021 Voxell Technologies
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/Pictures~/simple_bezier_curve.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nixon-voxell/UnityGPUVectorGraphics/85a4b4282a83856a3edd92572c0e44d8ef89c893/Pictures~/simple_bezier_curve.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Unity GPU Vector Graphics
2 |
3 | 
4 |
5 | This is a GPU accelerated vector graphics library built specifially for the Unity3D engine.
6 |
7 | You can find the example repository [here](https://github.com/nixon-voxell/UnityGPUVectorGraphicsExamples).
8 |
9 | - [Unity GPU Vector Graphics](#unity-gpu-vector-graphics)
10 | - [Installation](#installation)
11 | - [Support the project!](#support-the-project)
12 | - [Join the community!](#join-the-community)
13 | - [License](#license)
14 | - [References](#references)
15 |
16 | ## Installation
17 |
18 | External dependencies:
19 |
20 | - voxell.util ([UnityUtil](https://github.com/voxell-tech/UnityUtil))
21 |
22 | 1. Clone the [UnityUtil](https://github.com/voxell-tech/UnityUtil) repository into your `Packages` folder.
23 | 2. Clone this repository into your `Packages` folder.
24 | 3. And you are ready to go!
25 |
26 | ## Support the project!
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | ## Join the community!
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | ## License
48 |
49 | This repository as a whole is licensed under the Apache License 2.0. Individual files may have a different, but compatible license.
50 |
51 | See [license file](./LICENSE) for details.
52 |
53 | ## References
54 |
55 | 1. [Gliss (GitHub)](https://github.com/mdk/gliss)
56 | 2. [GPU Curve Rendering (GitHub)](https://github.com/azer89/GPU_Curve_Rendering)
57 | 3. [Beny_Core (GitHub)](https://github.com/Reavenk/Berny_Core)
58 | 4. [Resolution Independent Curve Rendering using Programmable Grpahics Hardware](https://www.microsoft.com/en-us/research/wp-content/uploads/2005/01/p1000-loop.pdf)
59 | 5. [NVIDIA GPU Gem 3 - Rendering Vector Art on the GPU](https://developer.nvidia.com/gpugems/gpugems3/part-iv-image-effects/chapter-25-rendering-vector-art-gpu)
60 | 6. [Delaunay Voronoi (GitHub)](https://github.com/RafaelKuebler/DelaunayVoronoi)
--------------------------------------------------------------------------------
/README.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: cfaca45a4f7847b4099d16da0be55f1a
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Runtime.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 6b5b0b8411bfea946a9f8a5299b49ac8
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/BezierProperties.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 | using Unity.Mathematics;
4 |
5 | namespace Voxell.GPUVectorGraphics
6 | {
7 | ///
8 | /// The various ways corners in an SVG file can be formed.
9 | ///
10 | public enum Corner
11 | {
12 | /// A half circle to round the end.
13 | Round,
14 |
15 | /// A flat connection.
16 | Bevel,
17 |
18 | /// Extrapolate sides with straight lines to where they collide.
19 | Miter,
20 |
21 | /// Extrapolate sides continuing their curve to where they collide.
22 | Arc
23 | }
24 |
25 | /// The style of an unconnected edge's end.
26 | public enum Cap
27 | {
28 | /// Stop instantly.
29 | Butt,
30 |
31 | /// Round it out with a half circle.
32 | Round,
33 |
34 | /// Add an additional half square, based off the width of the edge.
35 | Square
36 | }
37 |
38 | [Serializable]
39 | public struct CubicSegment
40 | {
41 | /// Origin point of the segment.
42 | public float2 p0;
43 |
44 | /// First control point of the segment.
45 | public float2 p1;
46 |
47 | /// Second control point of the segment.
48 | public float2 p2;
49 |
50 | /// Ending point of the segment.
51 | public float2 p3;
52 |
53 | public CubicSegment(float2 p0, float2 p1, float2 p2, float2 p3)
54 | {
55 | this.p0 = p0;
56 | this.p1 = p1;
57 | this.p2 = p2;
58 | this.p3 = p3;
59 | }
60 | }
61 |
62 | [Serializable]
63 | public struct QuadraticSegment
64 | {
65 | /// Origin point of the segment.
66 | public float2 p0;
67 |
68 | /// First control point of the segment.
69 | public float2 p1;
70 |
71 | /// Ending point of the segment.
72 | public float2 p2;
73 |
74 | public QuadraticSegment(float2 p0, float2 p1, float2 p2)
75 | {
76 | this.p0 = p0;
77 | this.p1 = p1;
78 | this.p2 = p2;
79 | }
80 | }
81 |
82 | [Serializable]
83 | public struct CubicPathSegment
84 | {
85 | /// Origin point of the segment.
86 | public float2 p0;
87 |
88 | /// First control point of the segment.
89 | public float2 p1;
90 |
91 | /// Second control point of the segment.
92 | public float2 p2;
93 |
94 | public CubicPathSegment(float2 p0, float2 p1, float2 p2)
95 | {
96 | this.p0 = p0;
97 | this.p1 = p1;
98 | this.p2 = p2;
99 | }
100 | }
101 |
102 | [Serializable]
103 | public struct QuadraticPathSegment
104 | {
105 | /// Origin point of the segment.
106 | public float2 p0;
107 |
108 | /// First control point of the segment.
109 | public float2 p1;
110 |
111 | public QuadraticPathSegment(float2 p0, float2 p1)
112 | {
113 | this.p0 = p0;
114 | this.p1 = p1;
115 | }
116 | }
117 |
118 | [Serializable]
119 | public struct CubicContour
120 | {
121 | /// An array of every cubic path segments on the contour.
122 | public CubicPathSegment[] segments;
123 |
124 | /// A closed loop contour.
125 | public bool closed;
126 | }
127 |
128 | [Serializable]
129 | public struct QuadraticContour
130 | {
131 | /// An array of every quadratic path segments on the contour.
132 | public QuadraticPathSegment[] segments;
133 |
134 | /// A closed loop contour.
135 | public bool closed;
136 | }
137 |
138 | [Serializable]
139 | public struct PathProperties
140 | {
141 | /// How the beginning of the path should be displayed.
142 | public Cap head;
143 |
144 | /// How the end of the path should be displayed.
145 | public Cap tail;
146 |
147 | /// How the corners of the path should be displayed.
148 | public Corner corner;
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/Runtime/BezierProperties.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 1c5f56c2c2ca25c4087b78a6ffe6d979
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/CDT.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: bddd1811271257b4fb17783336df7620
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/CDT/CDT.Constrain.cs:
--------------------------------------------------------------------------------
1 | using Unity.Mathematics;
2 | using Unity.Collections;
3 | using Unity.Jobs;
4 | using Unity.Burst;
5 |
6 | namespace Voxell.GPUVectorGraphics
7 | {
8 | using Mathx;
9 |
10 | public partial class CDT
11 | {
12 | [BurstCompile(FloatPrecision.High, FloatMode.Strict)]
13 | private struct ConstrainJob : IJob
14 | {
15 | public NativeArray na_contours;
16 | public NativeArray na_points;
17 | public NativeList na_triangles;
18 |
19 | public ConstrainJob(
20 | ref NativeArray na_contours,
21 | ref NativeArray na_points, ref NativeList na_triangles
22 | )
23 | {
24 | this.na_contours = na_contours;
25 | this.na_points = na_points;
26 | this.na_triangles = na_triangles;
27 | }
28 |
29 | public void Execute()
30 | {
31 | // create a list of all initial edges from the delaunay triangulation
32 | NativeList na_edges = new NativeList(Allocator.Temp);
33 | for (int t=0, triangleCount=na_triangles.Length/3; t < triangleCount; t++)
34 | {
35 | int t0, t1, t2;
36 | GetTriangleIndices(in na_triangles, t, out t0, out t1, out t2);
37 | Edge edge0 = new Edge(t0, t1);
38 | Edge edge1 = new Edge(t1, t2);
39 | Edge edge2 = new Edge(t2, t0);
40 |
41 | // make sure no duplicate edges are added
42 | if (!na_edges.Contains(edge0)) na_edges.Add(edge0);
43 | if (!na_edges.Contains(edge1)) na_edges.Add(edge1);
44 | if (!na_edges.Contains(edge2)) na_edges.Add(edge2);
45 | }
46 |
47 | NativeList na_insideIndices = new NativeList(2, Allocator.Temp);
48 | NativeList na_outsideIndices = new NativeList(2, Allocator.Temp);
49 | NativeList na_blackListedTris = new NativeList(Allocator.Temp);
50 |
51 | NativeList na_repairEdges = new NativeList(Allocator.Temp);
52 | NativeList na_blackListedRepairEdges = new NativeList(Allocator.Temp);
53 | NativeList na_repairTriangles = new NativeList(Allocator.Temp);
54 | NativeList na_repairCircumcenters = new NativeList(Allocator.Temp);
55 |
56 | int segmentCount = na_contours.Length - 1;
57 | for (int s=0; s < segmentCount; s++)
58 | {
59 | na_insideIndices.Clear();
60 | na_outsideIndices.Clear();
61 | na_blackListedTris.Clear();
62 |
63 | ContourPoint c0 = na_contours[s];
64 | ContourPoint c1 = na_contours[s + 1];
65 | // only check for intersection if both points are in the same contour
66 | if (c0.contourIdx != c1.contourIdx) continue;
67 |
68 | int e0 = c0.pointIdx;
69 | int e1 = c1.pointIdx;
70 |
71 | // if edge already exist, continue to the next contour segment
72 | Edge edge = new Edge(e0, e1);
73 | if (na_edges.Contains(edge)) continue;
74 |
75 | // initialize point list with edge points
76 | na_insideIndices.Add(e0); na_insideIndices.Add(e1);
77 | na_outsideIndices.Add(e0); na_outsideIndices.Add(e1);
78 | // initialize min and max point with edge points
79 | float2x2 ePoints = new float2x2(na_points[e0], na_points[e1]);
80 | float2 minRect = math.min(ePoints[0], ePoints[1]);
81 | float2 maxRect = math.max(ePoints[0], ePoints[1]);
82 | // remove all blocking triangles
83 | for (int t=0, triangleCount=na_triangles.Length/3; t < triangleCount; t++)
84 | {
85 | int3 tIdx;
86 | GetTriangleIndices(in na_triangles, t, out tIdx.x, out tIdx.y, out tIdx.z);
87 |
88 | bool3 diff_t;
89 | float2x3 tPoints;
90 | if (TriEdgeIntersect(in na_points, in tIdx, in edge, in ePoints, out diff_t, out tPoints))
91 | {
92 | // black list triangle to be removed later
93 | na_blackListedTris.Add(t);
94 |
95 | // sort points into outside and inside regions
96 | float2 n = math.normalize(float2x.perpendicular(ePoints[1] - ePoints[0]));
97 | for (int i=0; i < 3; i++)
98 | {
99 | if (diff_t[i])
100 | {
101 | minRect = math.min(minRect, na_points[tIdx[i]]);
102 | maxRect = math.max(maxRect, na_points[tIdx[i]]);
103 | if (math.dot(n, tPoints[i] - ePoints[0]) < 0.0f) na_insideIndices.Add(tIdx[i]);
104 | else na_outsideIndices.Add(tIdx[i]);
105 | }
106 | }
107 | }
108 | }
109 |
110 | // remove all black listed triangles
111 | RemoveBlacklistedTriangles(in na_blackListedTris, ref na_triangles);
112 |
113 | // retriangulate inside points
114 | if (na_insideIndices.Length > 2)
115 | {
116 | TriangulatePoints(
117 | in minRect, in maxRect, in na_insideIndices,
118 | ref na_repairEdges, ref na_repairTriangles, ref na_repairCircumcenters,
119 | ref na_blackListedRepairEdges, ref na_blackListedTris
120 | );
121 | }
122 |
123 | // retriangulate outside points
124 | if (na_outsideIndices.Length > 2)
125 | {
126 | TriangulatePoints(
127 | in minRect, in maxRect, in na_outsideIndices,
128 | ref na_repairEdges, ref na_repairTriangles, ref na_repairCircumcenters,
129 | ref na_blackListedRepairEdges, ref na_blackListedTris
130 | );
131 | }
132 | }
133 |
134 | // remove triangles connected to a contour edge and is outside the contour
135 | ////////////////////////////////////////////////////////////////////////////////
136 | NativeMultiHashMap na_pointTriMap = new NativeMultiHashMap(
137 | na_points.Length, Allocator.Temp
138 | );
139 |
140 | // create point idx to related triangles map
141 | for (int t=0, triangleCount=na_triangles.Length/3; t < triangleCount; t++)
142 | {
143 | int t0, t1, t2;
144 | GetTriangleIndices(in na_triangles, t, out t0, out t1, out t2);
145 |
146 | na_pointTriMap.Add(t0, t);
147 | na_pointTriMap.Add(t1, t);
148 | na_pointTriMap.Add(t2, t);
149 | }
150 |
151 | na_blackListedTris.Clear();
152 | for (int s=0; s < segmentCount; s++)
153 | {
154 | ContourPoint c0 = na_contours[s];
155 | ContourPoint c1 = na_contours[s + 1];
156 | // only check for edge triangles if both points are in the same contour
157 | if (c0.contourIdx != c1.contourIdx) continue;
158 |
159 | int e0 = c0.pointIdx;
160 | int e1 = c1.pointIdx;
161 |
162 | Edge edge = new Edge(e0, e1);
163 |
164 | NativeMultiHashMap.Enumerator enumerator = na_pointTriMap.GetValuesForKey(e0);
165 | int2 tris, extraPoints;
166 | FindEdgeTriangleAndExtraPoint(in enumerator, in na_triangles, in edge, out tris, out extraPoints);
167 |
168 | // if there are 2 related triangles we remove the one that has an extra point that is outside the edge
169 | // we might encounter edges that has only 1 related triangle as it might
170 | // be removed during the constraint process above
171 | if (tris[1] != -1)
172 | {
173 | float2 n = math.normalize(float2x.perpendicular(na_points[edge.e1] - na_points[edge.e0]));
174 |
175 | for (int t=0; t < 2; t++)
176 | {
177 | if (math.dot(n, na_points[extraPoints[t]] - na_points[edge.e1]) > 0.0f)
178 | {
179 | if (!na_blackListedTris.Contains(tris[t]))
180 | na_blackListedTris.Add(tris[t]);
181 | // only 1 of the triangles are going to be removed
182 | break;
183 | }
184 | }
185 | }
186 | }
187 |
188 | // remove triangles that are not connected to
189 | // any contour edge and is outside the contour
190 | ////////////////////////////////////////////////////////////////////////////////
191 | NativeArray na_contourEdges = new NativeArray(na_contours.Length, Allocator.Temp);
192 |
193 | for (int s=0; s < segmentCount; s++)
194 | na_contourEdges[s] = new Edge(na_contours[s].pointIdx, na_contours[s+1].pointIdx);
195 |
196 | na_contourEdges[segmentCount] = new Edge(
197 | na_contours[segmentCount].pointIdx, na_contours[0].pointIdx
198 | );
199 |
200 | {
201 | int removeCount = 0;
202 | for (int t=0, triangleCount=na_triangles.Length/3; t < triangleCount; t++)
203 | {
204 | int t0, t1, t2;
205 | GetTriangleIndices(in na_triangles, t-removeCount, out t0, out t1, out t2);
206 |
207 | Edge edge0 = new Edge(t0, t1);
208 | Edge edge1 = new Edge(t1, t2);
209 | Edge edge2 = new Edge(t2, t0);
210 |
211 | NativeMultiHashMap.Enumerator enum0 = na_pointTriMap.GetValuesForKey(t0);
212 | NativeMultiHashMap.Enumerator enum1 = na_pointTriMap.GetValuesForKey(t1);
213 | NativeMultiHashMap.Enumerator enum2 = na_pointTriMap.GetValuesForKey(t2);
214 | int2 tris0, tris1, tris2;
215 | FindEdgeTriangles(in enum0, in na_triangles, in edge0, out tris0);
216 | FindEdgeTriangles(in enum1, in na_triangles, in edge1, out tris1);
217 | FindEdgeTriangles(in enum2, in na_triangles, in edge2, out tris2);
218 |
219 | // triangles that are not connected to any contour
220 | if (
221 | !na_contourEdges.Contains(edge0) &&
222 | !na_contourEdges.Contains(edge1) &&
223 | !na_contourEdges.Contains(edge2)
224 | )
225 | {
226 | if (
227 | na_blackListedTris.Contains(tris0[0]) || na_blackListedTris.Contains(tris0[1]) ||
228 | na_blackListedTris.Contains(tris1[0]) || na_blackListedTris.Contains(tris1[1]) ||
229 | na_blackListedTris.Contains(tris2[0]) || na_blackListedTris.Contains(tris2[1])
230 | ) na_blackListedTris.Add(t);
231 | }
232 | }
233 | }
234 |
235 | // sort indices so that we remove the triangles with the lowest indices first
236 | na_blackListedTris.Sort();
237 | // remove all black listed triangles
238 | {
239 | int removeCount = 0;
240 | for (int t=0, blackListedTriCount=na_blackListedTris.Length; t < blackListedTriCount; t++)
241 | RemoveTriangle(ref na_triangles, na_blackListedTris[t]-removeCount++);
242 | }
243 |
244 | // disposing all temp allocations
245 | ////////////////////////////////////////////////////////////////////////////////
246 | na_edges.Dispose();
247 |
248 | na_insideIndices.Dispose();
249 | na_blackListedTris.Dispose();
250 |
251 | na_repairEdges.Dispose();
252 | na_blackListedRepairEdges.Dispose();
253 | na_repairTriangles.Dispose();
254 | na_repairCircumcenters.Dispose();
255 |
256 | na_pointTriMap.Dispose();
257 | }
258 |
259 | /// Delaunay triangulate a portion of points defined by an indices array.
260 | /// min AABB point
261 | /// max AABB point
262 | /// indices array indicating the portion of points to be triangulated
263 | private void TriangulatePoints(
264 | in float2 minRect, in float2 maxRect, in NativeList na_indices,
265 | ref NativeList na_repairEdges,
266 | ref NativeList na_repairTriangles,
267 | ref NativeList na_repairCircumcenters,
268 | ref NativeList na_blackListedRepairEdges,
269 | ref NativeList na_blackListedTris
270 | )
271 | {
272 | na_repairTriangles.Clear();
273 | na_repairCircumcenters.Clear();
274 | na_blackListedTris.Clear();
275 | int idxCount = na_indices.Length;
276 |
277 | // create rect-triangle
278 | // CreateRectTriangle(in minRect, in maxRect, ref na_points, ref na_repairTriangles, ref na_repairCircumcenters);
279 | // create super-triangle
280 | CreateSuperTriangle(in minRect, in maxRect, ref na_points, ref na_repairTriangles, ref na_repairCircumcenters);
281 |
282 | for (int i=0; i < idxCount; i++)
283 | {
284 | na_repairEdges.Clear();
285 | na_blackListedRepairEdges.Clear();
286 |
287 | int pIdx = na_indices[i];
288 | float2 point = na_points[pIdx];
289 |
290 | // remove triangles that contains the current point in its circumcenter
291 | int removeCount = 0;
292 | for (int c=0, circumCount=na_repairCircumcenters.Length; c < circumCount; c++)
293 | {
294 | int cIdx = c-removeCount;
295 | Cirumcircle circumcenter = na_repairCircumcenters[cIdx];
296 | if (circumcenter.ContainsPoint(point))
297 | {
298 | int t0, t1, t2;
299 | GetTriangleIndices(in na_repairTriangles, cIdx, out t0, out t1, out t2);
300 |
301 | Edge edge = new Edge(t0, t1);
302 | AddEdgesOfRemovedTriangle(in edge, ref na_repairEdges, ref na_blackListedRepairEdges);
303 |
304 | edge.SetEdge(t1, t2);
305 | AddEdgesOfRemovedTriangle(in edge, ref na_repairEdges, ref na_blackListedRepairEdges);
306 |
307 | edge.SetEdge(t2, t0);
308 | AddEdgesOfRemovedTriangle(in edge, ref na_repairEdges, ref na_blackListedRepairEdges);
309 |
310 | RemoveTriAndCircum(ref na_repairCircumcenters, ref na_repairTriangles, cIdx);
311 | removeCount++;
312 | }
313 | }
314 |
315 | // sort black listed edge indices in ascending order and remove them
316 | na_blackListedRepairEdges.Sort();
317 | RemoveBlacklistedEdges(in na_blackListedRepairEdges, ref na_repairEdges);
318 |
319 | // create new triangles out of it by connecting
320 | // each new edges to the current point
321 | CreateTrianglesForNewPoint(
322 | in pIdx, in point, in na_repairEdges, in na_points,
323 | ref na_repairTriangles, ref na_repairCircumcenters
324 | );
325 | }
326 |
327 | // remove rect-triangle
328 | // RemoveRectTriangle(na_points.Length, ref na_repairTriangles);
329 | // remove super-triangle
330 | RemoveSuperTriangle(na_points.Length, ref na_repairTriangles);
331 |
332 | // remove triangles that are overlapping other existing triangles
333 | int repairTriCount=na_repairTriangles.Length/3;
334 | for (int rt=0; rt < repairTriCount; rt++)
335 | {
336 | int t0, t1, t2;
337 | GetTriangleIndices(in na_repairTriangles, rt, out t0, out t1, out t2);
338 | float2 triMidPoint = (na_points[t0] + na_points[t1] + na_points[t2]) * mathx.ONE_THIRD;
339 |
340 | for (int t=0, triangleCount=na_triangles.Length/3; t < triangleCount; t++)
341 | {
342 | GetTriangleIndices(in na_triangles, t, out t0, out t1, out t2);
343 | if (VGMath.PointInTriangle(triMidPoint, na_points[t0], na_points[t1], na_points[t2]))
344 | {
345 | na_blackListedTris.Add(rt);
346 | break;
347 | }
348 | }
349 | }
350 |
351 | // remove black listed triangles
352 | RemoveBlacklistedTriangles(in na_blackListedTris, ref na_repairTriangles);
353 |
354 | // add remaining triangles to the main triangle pool
355 | na_triangles.AddRange(na_repairTriangles);
356 | }
357 | }
358 | }
359 | }
--------------------------------------------------------------------------------
/Runtime/CDT/CDT.Constrain.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f4ec1eea220e2bf4290ddd1f06b68780
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/CDT/CDT.ConstraintUtil.cs:
--------------------------------------------------------------------------------
1 | using Unity.Mathematics;
2 | using Unity.Collections;
3 |
4 | namespace Voxell.GPUVectorGraphics
5 | {
6 | public partial class CDT
7 | {
8 | ///
9 | /// Find the other triangle that is connected to this edge by looking up
10 | /// at a hash map from any of the point related to the edge.
11 | ///
12 | private static void FindEdgeTriangleAndExtraPoint(
13 | in NativeMultiHashMap.Enumerator enumerator,
14 | in NativeList na_triangles,
15 | in Edge edge, out int2 tris, out int2 extraPoints)
16 | {
17 | int foundCount = 0;
18 | tris = new int2(-1, -1);
19 | extraPoints = new int2(-1, -1);
20 |
21 | // UnityEngine.Debug.Log($"edge: {edge.e0}:{edge.e1}");
22 | int t0, t1, t2;
23 | foreach (int t in enumerator)
24 | {
25 | GetTriangleIndices(in na_triangles, t, out t0, out t1, out t2);
26 | Edge edge0 = new Edge(t0, t1);
27 | Edge edge1 = new Edge(t1, t2);
28 | Edge edge2 = new Edge(t2, t0);
29 |
30 | if (edge.Equals(edge0) || edge.Equals(edge1) || edge.Equals(edge2))
31 | {
32 | if (foundCount == 2)
33 | {
34 | UnityEngine.Debug.Log($"{foundCount}: {t0}, {t1}, {t2}");
35 | UnityEngine.Debug.Log($"edge: {edge.e0}:{edge.e1}");
36 | }
37 | tris[foundCount] = t;
38 |
39 | // find the odd one out (the point that is not related to the given edge)
40 | if (t0 != edge.e0 && t0 != edge.e1) extraPoints[foundCount] = t0;
41 | else if (t1 != edge.e0 && t1 != edge.e1) extraPoints[foundCount] = t1;
42 | else extraPoints[foundCount] = t2;
43 |
44 | foundCount++;
45 | }
46 | }
47 | }
48 |
49 | ///
50 | /// Find the other triangle that is connected to this edge by looking up
51 | /// at a hash map from any of the point related to the edge.
52 | ///
53 | private static void FindEdgeTriangles(
54 | in NativeMultiHashMap.Enumerator enumerator,
55 | in NativeList na_triangles,
56 | in Edge edge, out int2 tris)
57 | {
58 | int foundCount = 0;
59 | tris = new int2(-1, -1);
60 |
61 | // UnityEngine.Debug.Log($"edge: {edge.e0}:{edge.e1}");
62 | int t0, t1, t2;
63 | foreach (int t in enumerator)
64 | {
65 | GetTriangleIndices(in na_triangles, t, out t0, out t1, out t2);
66 | Edge edge0 = new Edge(t0, t1);
67 | Edge edge1 = new Edge(t1, t2);
68 | Edge edge2 = new Edge(t2, t0);
69 |
70 | if (edge.Equals(edge0) || edge.Equals(edge1) || edge.Equals(edge2))
71 | {
72 | if (foundCount == 2)
73 | {
74 | UnityEngine.Debug.Log($"{foundCount}: {t0}, {t1}, {t2}");
75 | UnityEngine.Debug.Log($"edge: {edge.e0}:{edge.e1}");
76 | }
77 | tris[foundCount++] = t;
78 | }
79 | }
80 | }
81 |
82 | /// Checks if an edge intersects a triangle.
83 | /// point pool
84 | /// triangle index
85 | /// edge indices
86 | /// 2 points that makes up the edge
87 | /// if triangle point is part of the edge
88 | /// triangle points
89 | private static bool TriEdgeIntersect(
90 | in NativeArray na_points,
91 | in int3 tIdx, in Edge edge, in float2x2 ePoints,
92 | out bool3 diff_t, out float2x3 tPoints
93 | )
94 | {
95 | diff_t = new bool3();
96 | tPoints = new float2x3();
97 | for (int i=0; i < 3; i++)
98 | {
99 | tPoints[i] = na_points[tIdx[i]];
100 | // compare point position rather than index
101 | // as there might be duplicated points with different index
102 | bool same = (tPoints[i].Equals(ePoints[0]) || tPoints[i].Equals(ePoints[1]));
103 | diff_t[i] = !same;
104 | }
105 |
106 | // only check for edge intersection when both edge are not connected
107 | // return a true, if either one of it intersects
108 | for (int i=0; i < 3; i++)
109 | {
110 | int nextIdx = (i + 1) % 3;
111 | if (diff_t[i] && diff_t[nextIdx])
112 | if (VGMath.LinesIntersect(tPoints[i], tPoints[nextIdx], ePoints[0], ePoints[1]))
113 | return true;
114 | }
115 |
116 | return false;
117 | }
118 | }
119 | }
--------------------------------------------------------------------------------
/Runtime/CDT/CDT.ConstraintUtil.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 9297d0a6e1c40384db1eb8b5d0f9244c
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/CDT/CDT.Primitive.cs:
--------------------------------------------------------------------------------
1 | using Unity.Mathematics;
2 |
3 | namespace Voxell.GPUVectorGraphics
4 | {
5 | public partial class CDT
6 | {
7 | private struct Edge : System.IEquatable
8 | {
9 | public int e0, e1;
10 |
11 | public Edge(int e0, int e1)
12 | {
13 | this.e0 = e0;
14 | this.e1 = e1;
15 | }
16 |
17 | public void SetEdge(int e0, int e1)
18 | {
19 | this.e0 = e0;
20 | this.e1 = e1;
21 | }
22 |
23 | public bool Equals(Edge other)
24 | => (this.e0 == other.e0 && this.e1 == other.e1) ||
25 | (this.e0 == other.e1 && this.e1 == other.e0);
26 | }
27 |
28 | private struct Cirumcircle
29 | {
30 | public float2 center;
31 | public float sqradius;
32 |
33 | public Cirumcircle(float2 p0, float2 p1, float2 p2)
34 | {
35 | float dA = p0.x * p0.x + p0.y * p0.y;
36 | float dB = p1.x * p1.x + p1.y * p1.y;
37 | float dC = p2.x * p2.x + p2.y * p2.y;
38 |
39 | float aux1 = dA * (p2.y - p1.y) + dB * (p0.y - p2.y) + dC * (p1.y - p0.y);
40 | float aux2 = -(dA * (p2.x - p1.x) + dB * (p0.x - p2.x) + dC * (p1.x - p0.x));
41 | float div = 2.0f * (p0.x * (p2.y - p1.y) + p1.x * (p0.y - p2.y) + p2.x * (p1.y - p0.y));
42 | div = 1.0f / div;
43 |
44 | center = new float2(aux1, aux2) * div;
45 | sqradius = math.lengthsq(center - p0);
46 | }
47 |
48 | public bool ContainsPoint(float2 p)
49 | {
50 | float sqlength = math.lengthsq(center - p);
51 | return sqlength < (sqradius + math.EPSILON*2.0f);
52 | }
53 | }
54 |
55 | public struct ContourPoint
56 | {
57 | public int pointIdx;
58 | public int contourIdx;
59 |
60 | public ContourPoint(int pointIdx, int contourIdx)
61 | {
62 | this.pointIdx = pointIdx;
63 | this.contourIdx = contourIdx;
64 | }
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/Runtime/CDT/CDT.Primitive.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f31b2987533090a44a05f2c845a75777
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/CDT/CDT.QuadraticInsert.cs:
--------------------------------------------------------------------------------
1 | using Unity.Mathematics;
2 | using Unity.Collections;
3 | using Unity.Jobs;
4 | using Unity.Burst;
5 |
6 | namespace Voxell.GPUVectorGraphics
7 | {
8 | using Mathx;
9 |
10 | public partial class CDT
11 | {
12 | // inserting quadratic control points from the contour
13 | [BurstCompile]
14 | private struct QuadraticInsertJob : IJob
15 | {
16 | public NativeArray na_points;
17 | public NativeArray na_controlPoints;
18 | public NativeList na_triangles;
19 |
20 | public void Execute()
21 | {
22 | NativeMultiHashMap na_pointTriMap = new NativeMultiHashMap(
23 | na_points.Length, Allocator.Temp
24 | );
25 |
26 | // create point idx to related triangles map
27 | for (int t=0, triangleCount=na_triangles.Length/3; t < triangleCount; t++)
28 | {
29 | int t0, t1, t2;
30 | GetTriangleIndices(in na_triangles, t, out t0, out t1, out t2);
31 |
32 | na_pointTriMap.Add(t0, t);
33 | na_pointTriMap.Add(t1, t);
34 | na_pointTriMap.Add(t2, t);
35 | }
36 |
37 | for (int p=0, pointCount=na_controlPoints.Length; p < pointCount; p++)
38 | {
39 | float2 controlPoint = na_controlPoints[p];
40 | // ignore if control point location is exactly same as the triangulation point
41 | if (na_points[p].Equals(controlPoint)) continue;
42 |
43 | // contour edge
44 | int nextP = (p + 1) % pointCount;
45 | Edge edge = new Edge(p, nextP);
46 | float2 p0 = na_points[edge.e0];
47 | float2 p1 = na_points[edge.e1];
48 | float2 n = math.normalize(float2x.perpendicular(p1 - p0));
49 |
50 | // if point is outside the contour, directly triangulate it as it will not overlap any triangles
51 | if (math.dot(controlPoint - p0, n) > 0.0f)
52 | {
53 | //
54 | } else
55 | // if point is inside the contour, check for triangle intersections
56 | // remove them and then retriangulate them
57 | {
58 | NativeMultiHashMap.Enumerator enumerator0 = na_pointTriMap.GetValuesForKey(edge.e0);
59 | NativeMultiHashMap.Enumerator enumerator1 = na_pointTriMap.GetValuesForKey(edge.e1);
60 |
61 | // line 0: p0, controlPoint
62 | // line 1: p1, controlPoint
63 |
64 | NativeList na_intersectedTriangles = new NativeList(Allocator.Temp);
65 |
66 | foreach (int t in enumerator0)
67 | {
68 | int t0, t1, t2;
69 | GetTriangleIndices(in na_triangles, t, out t0, out t1, out t2);
70 | }
71 | }
72 | }
73 | }
74 | }
75 | }
76 | }
--------------------------------------------------------------------------------
/Runtime/CDT/CDT.QuadraticInsert.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4a8c90f035c57fd4688a89fd0365efd7
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/CDT/CDT.Triangulate.cs:
--------------------------------------------------------------------------------
1 | using Unity.Mathematics;
2 | using Unity.Collections;
3 | using Unity.Jobs;
4 | using Unity.Burst;
5 |
6 | namespace Voxell.GPUVectorGraphics
7 | {
8 | public partial class CDT
9 | {
10 | /// Bowyer-Watson delaunay triangulation.
11 | [BurstCompile(FloatPrecision.High, FloatMode.Strict)]
12 | private struct TriangulateJob : IJob
13 | {
14 | public float2 minRect;
15 | public float2 maxRect;
16 |
17 | public NativeArray na_points;
18 | public NativeList na_triangles;
19 |
20 | public TriangulateJob(
21 | float2 minRect, float2 maxRect,
22 | ref NativeArray na_points,
23 | ref NativeList na_triangles
24 | )
25 | {
26 | this.minRect = minRect;
27 | this.maxRect = maxRect;
28 |
29 | this.na_points = na_points;
30 | this.na_triangles = na_triangles;
31 | }
32 |
33 | public void Execute()
34 | {
35 | // create temp arrays
36 | NativeList na_edges = new NativeList(Allocator.Temp);
37 | NativeList na_blackListedEdges = new NativeList(Allocator.Temp);
38 | NativeList na_cirumcircles = new NativeList(Allocator.Temp);
39 |
40 | // create rect-triangle
41 | // CreateRectTriangle(in minRect, in maxRect, ref na_points, ref na_triangles, ref na_cirumcircles);
42 | // create super-triangle
43 | CreateSuperTriangle(in minRect, in maxRect, ref na_points, ref na_triangles, ref na_cirumcircles);
44 |
45 | for (int p=0, pointCount=na_points.Length-3; p < pointCount; p++)
46 | {
47 | na_edges.Clear();
48 | na_blackListedEdges.Clear();
49 |
50 | float2 point = na_points[p];
51 |
52 | // prevent duplicated points (only triangulate the first point found)
53 | int tempIdx = na_points.IndexOf(point);
54 | if (tempIdx != p) continue;
55 |
56 | // remove triangles that contains the current point in its circumcenter
57 | int removeCount = 0;
58 | for (int c=0, circumCount=na_cirumcircles.Length; c < circumCount; c++)
59 | {
60 | int idx = c - removeCount;
61 | Cirumcircle circumcenter = na_cirumcircles[idx];
62 | if (circumcenter.ContainsPoint(point))
63 | {
64 | int t0, t1, t2;
65 | GetTriangleIndices(in na_triangles, idx, out t0, out t1, out t2);
66 |
67 | Edge edge = new Edge(t0, t1);
68 | AddEdgesOfRemovedTriangle(in edge, ref na_edges, ref na_blackListedEdges);
69 |
70 | edge.SetEdge(t1, t2);
71 | AddEdgesOfRemovedTriangle(in edge, ref na_edges, ref na_blackListedEdges);
72 |
73 | edge.SetEdge(t2, t0);
74 | AddEdgesOfRemovedTriangle(in edge, ref na_edges, ref na_blackListedEdges);
75 |
76 | RemoveTriAndCircum(ref na_cirumcircles, ref na_triangles, idx);
77 | removeCount++;
78 | }
79 | }
80 |
81 | // sort black listed edge indices in ascending order and remove them
82 | na_blackListedEdges.Sort();
83 | RemoveBlacklistedEdges(in na_blackListedEdges, ref na_edges);
84 |
85 | // create new triangles out of the current point
86 | // by connecting each new edges to the current point
87 | CreateTrianglesForNewPoint(
88 | in p, in point, in na_edges, in na_points,
89 | ref na_triangles, ref na_cirumcircles
90 | );
91 | }
92 |
93 | // remove all triangles associated with the rect-triangle
94 | // RemoveRectTriangle(na_points.Length, ref na_triangles);
95 | // remove all triangles associated with the super-triangle
96 | RemoveSuperTriangle(na_points.Length, ref na_triangles);
97 |
98 | // dispose all temp allocations
99 | na_edges.Dispose();
100 | na_blackListedEdges.Dispose();
101 | na_cirumcircles.Dispose();
102 | }
103 | }
104 | }
105 | }
--------------------------------------------------------------------------------
/Runtime/CDT/CDT.Triangulate.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: a7faf8ce4d8f7fd4a829934019be4df1
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/CDT/CDT.TriangulationUtil.cs:
--------------------------------------------------------------------------------
1 | using Unity.Mathematics;
2 | using Unity.Collections;
3 |
4 | namespace Voxell.GPUVectorGraphics
5 | {
6 | public partial class CDT
7 | {
8 | /// Create super-triangle using the last 3 elements of the point array.
9 | private static void CreateSuperTriangle(
10 | in float2 minRect, in float2 maxRect,
11 | ref NativeArray na_points,
12 | ref NativeList na_triangles,
13 | ref NativeList na_cirumcircles
14 | )
15 | {
16 | /// __ . /\
17 | /// |__| . /__\
18 | /// __ . / __ \
19 | /// |__| . / |__| \
20 | /// __ __ __ . _/ __ \_
21 | /// |__| |__| |__| . |/_| |__| |_\|
22 | int pointCount = na_points.Length;
23 | float width = maxRect.x - minRect.x;
24 | float height = maxRect.y - minRect.y;
25 | float marginedWidth = width + MARGIN;
26 | float marginedHeight = height + MARGIN;
27 |
28 | int r0 = pointCount-3;
29 | int r1 = pointCount-2;
30 | int r2 = pointCount-1;
31 |
32 | // left bottom
33 | na_points[r0] = new float2(minRect.x - marginedWidth, minRect.y - marginedHeight);
34 | // right bottom
35 | na_points[r1] = new float2(maxRect.x + marginedWidth, minRect.y - marginedHeight);
36 | // top
37 | na_points[r2] = new float2(minRect.x + width*0.5f, maxRect.y + marginedHeight);
38 |
39 | AddTriAndCircum(in na_points, ref na_triangles, ref na_cirumcircles, r0, r1, r2);
40 | }
41 |
42 | /// Remove all triangles associated with the super-triangle.
43 | private static void RemoveSuperTriangle(in int pointCount, ref NativeList na_triangles)
44 | {
45 | for (int p=pointCount-3; p < pointCount; p++)
46 | {
47 | int triangleCount = na_triangles.Length/3;
48 | int removeCount = 0;
49 | for (int t=0; t < triangleCount; t++)
50 | {
51 | int idx = t - removeCount;
52 | int t0, t1, t2;
53 | GetTriangleIndices(in na_triangles, idx, out t0, out t1, out t2);
54 |
55 | if (t0 == p || t1 == p || t2 == p)
56 | {
57 | RemoveTriangle(ref na_triangles, idx);
58 | removeCount++;
59 | }
60 | }
61 | }
62 | }
63 |
64 | /// Create new triangles out of a new point by connecting each new edges to it.
65 | /// index of the point
66 | /// point location
67 | private static void CreateTrianglesForNewPoint(
68 | in int pointIdx, in float2 point,
69 | in NativeList na_edges, in NativeArray na_points,
70 | ref NativeList na_triangles, ref NativeList na_cirumcircles
71 | )
72 | {
73 | int edgeCount = na_edges.Length;
74 | for (int e=0; e < edgeCount; e++)
75 | {
76 | Edge edge = na_edges[e];
77 | if (edge.e0 == pointIdx || edge.e1 == pointIdx) continue;
78 | float2 p0 = na_points[edge.e0];
79 | float2 p1 = na_points[edge.e1];
80 |
81 | if (VGMath.IsClockwise(in point, in p0, in p1))
82 | AddTriAndCircum(in na_points, ref na_triangles, ref na_cirumcircles, pointIdx, edge.e0, edge.e1);
83 | else
84 | AddTriAndCircum(in na_points, ref na_triangles, ref na_cirumcircles, pointIdx, edge.e1, edge.e0);
85 | }
86 | }
87 |
88 | ///
89 | /// Add edges obtained from a triangle that is going to be removed
90 | /// because its circumcircle contains a point.
91 | ///
92 | /// a list of all added edges
93 | ///
94 | /// a list of indices of duplicated edges to be removed
95 | ///
96 | private static void AddEdgesOfRemovedTriangle(
97 | in Edge edge, ref NativeList na_edges,
98 | ref NativeList na_blackListedEdges
99 | )
100 | {
101 | if (na_edges.Contains(edge))
102 | {
103 | int edgeIdx = na_edges.IndexOf(edge);
104 | if (!na_blackListedEdges.Contains(edgeIdx))
105 | na_blackListedEdges.Add(edgeIdx);
106 | } else na_edges.Add(edge);
107 | }
108 |
109 | /// Remove black listed triangles.
110 | /// black listed triangle indices in ascending order
111 | private static void RemoveBlacklistedTriangles(
112 | in NativeList na_blackListedTris, ref NativeList na_triangles
113 | )
114 | {
115 | int blacklistedTriCount = na_blackListedTris.Length;
116 | int removeCount = 0;
117 |
118 | for (int t=0; t < blacklistedTriCount; t++)
119 | RemoveTriangle(ref na_triangles, na_blackListedTris[t]-removeCount++);
120 | }
121 |
122 | /// Remove black listed edges.
123 | /// black listed edge indices in ascending order
124 | private static void RemoveBlacklistedEdges(
125 | in NativeList na_blackListedEdges, ref NativeList na_edges
126 | )
127 | {
128 | int blackListedEdgeCount = na_blackListedEdges.Length;
129 | int removeCount = 0;
130 |
131 | for (int b=0; b < blackListedEdgeCount; b++)
132 | na_edges.RemoveAt(na_blackListedEdges[b]-removeCount++);
133 | }
134 | }
135 | }
--------------------------------------------------------------------------------
/Runtime/CDT/CDT.TriangulationUtil.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 1e6c3fc851b45b6458b4081d474c02de
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/CDT/CDT.Util.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 | using Unity.Mathematics;
3 | using Unity.Collections;
4 |
5 | namespace Voxell.GPUVectorGraphics
6 | {
7 | public partial class CDT
8 | {
9 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
10 | private static void GetTriangleIndices(
11 | in NativeList na_triangles,
12 | int idx, out int t0, out int t1, out int t2
13 | )
14 | {
15 | int tIdx = idx*3;
16 | t0 = na_triangles[tIdx];
17 | t1 = na_triangles[tIdx + 1];
18 | t2 = na_triangles[tIdx + 2];
19 | }
20 |
21 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
22 | private static void AddTriangle(ref NativeList na_triangles, int t0, int t1, int t2)
23 | {
24 | na_triangles.Add(t0);
25 | na_triangles.Add(t1);
26 | na_triangles.Add(t2);
27 | }
28 |
29 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
30 | private static void RemoveTriangle(ref NativeList na_triangles, int idx)
31 | {
32 | int tIdx = idx*3;
33 | na_triangles.RemoveRange(tIdx, 3);
34 | }
35 |
36 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
37 | private static void AddTriAndCircum(
38 | in NativeArray na_points, ref NativeList na_triangles,
39 | ref NativeList na_cirumcircles,
40 | int t0, int t1, int t2
41 | )
42 | {
43 | AddTriangle(ref na_triangles, t0, t1, t2);
44 | float2 p0 = na_points[t0];
45 | float2 p1 = na_points[t1];
46 | float2 p2 = na_points[t2];
47 | na_cirumcircles.Add(new Cirumcircle(p0, p1, p2));
48 | }
49 |
50 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
51 | private static void RemoveTriAndCircum(
52 | ref NativeList na_cirumcircles, ref NativeList na_triangles, int idx
53 | )
54 | {
55 | RemoveTriangle(ref na_triangles, idx);
56 | na_cirumcircles.RemoveAt(idx);
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/Runtime/CDT/CDT.Util.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 1bf56708509871c4fa99cc92ad2e5fe0
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/CDT/CDT.cs:
--------------------------------------------------------------------------------
1 | using Unity.Mathematics;
2 | using Unity.Collections;
3 | using Unity.Jobs;
4 |
5 | namespace Voxell.GPUVectorGraphics
6 | {
7 | public static partial class CDT
8 | {
9 | private const float MARGIN = 1.0f;
10 |
11 | /// Constraint delaunay triangulation based on a contour.
12 | /// minimum point of the point set
13 | /// maximum point of the point set
14 | /// points to be triangulated
15 | /// contour defining the polygon boundary
16 | /// a copy of the input point array
17 | /// output of the final triangle list
18 | /// a copy of the input contour array
19 | ///
20 | public static JobHandle ConstraintTriangulate(
21 | float2 minRect, float2 maxRect, in float2[] points, in ContourPoint[] contours,
22 | out NativeArray na_points, out NativeList na_triangles,
23 | out NativeArray na_contours
24 | )
25 | {
26 | na_contours = new NativeArray(contours, Allocator.TempJob);
27 | JobHandle jobHandle = Triangulate(minRect, maxRect, in points, out na_points, out na_triangles);
28 | ConstrainJob job_constrain = new ConstrainJob(ref na_contours, ref na_points, ref na_triangles);
29 | return job_constrain.Schedule(jobHandle);
30 | }
31 |
32 | /// Performs a delaunay triangulation on a set of points.
33 | /// minimum point of the point set
34 | /// maximum point of the point set
35 | /// points to be triangulated
36 | /// a copy of the input point array
37 | /// output of the final triangle list
38 | /// A JobHandle the is being scheduled for delaunay triangulation.
39 | public static JobHandle Triangulate(
40 | float2 minRect, float2 maxRect, in float2[] points,
41 | out NativeArray na_points, out NativeList na_triangles
42 | )
43 | {
44 | // last 3 points are for the super-triangle (will be used throughout the CDT process too)
45 | na_points = new NativeArray(points.Length + 3, Allocator.TempJob);
46 | na_triangles = new NativeList(Allocator.TempJob);
47 |
48 | NativeSlice na_points_slice = na_points.Slice(0, points.Length);
49 | na_points_slice.CopyFrom(points);
50 |
51 | TriangulateJob job_triangulate = new TriangulateJob(
52 | minRect, maxRect, ref na_points, ref na_triangles
53 | );
54 | return job_triangulate.Schedule();
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/Runtime/CDT/CDT.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e524ea11db66751449adb2d2816022a7
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/CubicBezier.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d720627e5a79e7a489db23b1818e84b1
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/CubicBezier/CubicBezier.CurveType.cs:
--------------------------------------------------------------------------------
1 | using Unity.Mathematics;
2 |
3 | namespace Voxell.GPUVectorGraphics
4 | {
5 | public static partial class CubicBezier
6 | {
7 | internal static readonly float SQRT3 = math.sqrt(3.0f);
8 | internal static readonly float DET_SQRT3 = 1/SQRT3;
9 |
10 | internal const float ONE_THIRD = 1.0f/3.0f;
11 | internal const float TWO_THIRDS = 2.0f/3.0f;
12 |
13 | internal enum CurveType
14 | {
15 | UNKNOWN = 0,
16 | SERPENTINE = 1,
17 | LOOP = 2,
18 | CUSP = 3,
19 | QUADRATIC = 4,
20 | LINE = 5
21 | }
22 |
23 | internal static CurveType ClassifyCurve(
24 | float2 p0, float2 p1, float2 p2, float2 p3,
25 | out float d0, out float d1, out float d2, out float d3
26 | )
27 | {
28 | float3 b0 = new float3(p0, 1.0f);
29 | float3 b1 = new float3(p1, 1.0f);
30 | float3 b2 = new float3(p2, 1.0f);
31 | float3 b3 = new float3(p3, 1.0f);
32 |
33 | float a1 = math.dot(b0, math.cross(b3, b2));
34 | float a2 = math.dot(b1, math.cross(b0, b3));
35 | float a3 = math.dot(b2, math.cross(b1, b0));
36 |
37 | d0 = 0.0f;
38 | d1 = a1 - 2.0f * a2 + 3.0f * a3;
39 | d2 = -a2 + 3.0f * a3;
40 | d3 = 3.0f * a3;
41 |
42 | float D = 3.0f * d2 * d2 - 4.0f * d1 * d3;
43 | float disc = d1 * d1 * D;
44 |
45 | if (disc == 0.0f)
46 | {
47 | if (d1 == 0.0f && d2 == 0.0f)
48 | {
49 | if (d3 == 0.0f) return CurveType.LINE;
50 | return CurveType.QUADRATIC;
51 | }
52 |
53 | if (d1 != 0.0f) return CurveType.CUSP;
54 | if (D < 0.0f) return CurveType.LOOP;
55 |
56 | return CurveType.SERPENTINE;
57 | }
58 |
59 | if (disc > 0.0f) return CurveType.SERPENTINE;
60 | else return CurveType.LOOP;
61 | }
62 |
63 | public static float3x4 Serpentine(float d1, float d2, float d3, ref bool flip)
64 | {
65 | float t1 = math.sqrt(9.0f * d2 * d2 - 12 * d1 * d3);
66 | float ls = 3.0f * d2 - t1;
67 | float lt = 6.0f * d1;
68 | float ms = 3.0f * d2 + t1;
69 | float mt = lt;
70 | float ltMinusLs = lt - ls;
71 | float mtMinusMs = mt - ms;
72 |
73 | float3x4 coords = new float3x4();
74 | coords.c0.x = ls * ms;
75 | coords.c0.y = ls * ls * ls;
76 | coords.c0.z = ms * ms * ms;
77 |
78 | coords.c1.x = ONE_THIRD * (3.0f * ls * ms - ls * mt - lt * ms);
79 | coords.c1.y = ls * ls * (ls - lt);
80 | coords.c1.z = ms * ms * (ms - mt);
81 |
82 | coords.c2.x = ONE_THIRD * (lt * (mt - 2.0f * ms) + ls * (3.0f * ms - 2.0f * mt));
83 | coords.c2.y = ltMinusLs * ltMinusLs * ls;
84 | coords.c2.z = mtMinusMs * mtMinusMs * ms;
85 |
86 | coords.c3.x = ltMinusLs * mtMinusMs;
87 | coords.c3.y = -(ltMinusLs * ltMinusLs * ltMinusLs);
88 | coords.c3.z = -(mtMinusMs * mtMinusMs * mtMinusMs);
89 |
90 | flip = d1 < 0.0f;
91 | return coords;
92 | }
93 |
94 | public static float3x4 Loop(
95 | float d1, float d2, float d3, ref bool flip,
96 | ref int loopArtifact, ref float splitParam, int recursiveType
97 | )
98 | {
99 | float t1 = math.sqrt(4.0f * d1 * d3 - 3.0f * d2 * d2);
100 | float ls = d2 - t1;
101 | float lt = 2.0f * d1;
102 | float ms = d2 + t1;
103 | float mt = lt;
104 |
105 | // Figure out whether there is a rendering artifact requiring
106 | // the curve to be subdivided by the caller.
107 | float ql = ls / lt;
108 | float qm = ms / mt;
109 | if (0.0f < ql && ql < 1.0f)
110 | {
111 | loopArtifact = 1;
112 | splitParam = ql;
113 | }
114 |
115 | if (0.0f < qm && qm < 1.0f)
116 | {
117 | loopArtifact = 2;
118 | splitParam = qm;
119 | }
120 |
121 | float ltMinusLs = lt - ls;
122 | float mtMinusMs = mt - ms;
123 |
124 | float3x4 coords = new float3x4();
125 | coords.c0.x = ls * ms;
126 | coords.c0.y = ls * ls * ms;
127 | coords.c0.z = ls * ms * ms;
128 |
129 | coords.c1.x = ONE_THIRD * (-ls * mt - lt * ms + 3.0f * ls * ms);
130 | coords.c1.y = -ONE_THIRD * ls * (ls * (mt - 3.0f * ms) + 2.0f * lt * ms);
131 | coords.c1.z = -ONE_THIRD * ms * (ls * (2.0f * mt - 3.0f * ms) + lt * ms);
132 |
133 | coords.c2.x = ONE_THIRD * (lt * (mt - 2.0f * ms) + ls * (3.0f * ms - 2.0f * mt));
134 | coords.c2.y = ONE_THIRD * (lt - ls) * (ls * (2.0f * mt - 3.0f * ms) + lt * ms);
135 | coords.c2.z = ONE_THIRD * (mt - ms) * (ls * (mt - 3.0f * ms) + 2.0f * lt * ms);
136 |
137 | coords.c3.x = ltMinusLs * mtMinusMs;
138 | coords.c3.y = -(ltMinusLs * ltMinusLs) * mtMinusMs;
139 | coords.c3.z = -ltMinusLs * mtMinusMs * mtMinusMs;
140 |
141 | if (recursiveType == -1)
142 | flip = (d1 > 0.0f && coords.c0.x < 0.0f) || (d1 < 0.0f && coords.c0.x > 0.0f);
143 | return coords;
144 | }
145 |
146 | public static float3x4 Cusp(float d1, float d2, float d3)
147 | {
148 | float ls = d3;
149 | float lt = 3.0f * d2;
150 | float lsMinusLt = ls - lt;
151 |
152 | float3x4 coords = new float3x4();
153 | coords.c0.x = ls;
154 | coords.c0.y = ls * ls * ls;
155 | coords.c0.z = 1.0f;
156 |
157 | coords.c1.x = ls - TWO_THIRDS * lt;
158 | coords.c1.y = ls * ls * lsMinusLt;
159 | coords.c1.z = 1.0f;
160 |
161 | coords.c2.x = ls - TWO_THIRDS * lt;
162 | coords.c2.y = lsMinusLt * lsMinusLt * ls;
163 | coords.c2.z = 1.0f;
164 |
165 | coords.c3.x = lsMinusLt;
166 | coords.c3.y = lsMinusLt * lsMinusLt * lsMinusLt;
167 | coords.c3.z = 1.0f;
168 |
169 | return coords;
170 | }
171 |
172 | public static float3x4 Quadratic(float d3, ref bool flip)
173 | {
174 | float3x4 coords = new float3x4(
175 | 0.0f, 0.0f, 0.0f,
176 | ONE_THIRD, 0.0f, ONE_THIRD,
177 | TWO_THIRDS, ONE_THIRD, TWO_THIRDS,
178 | 1.0f, 1.0f, 1.0f
179 | );
180 |
181 | flip = d3 < 0.0f;
182 | return coords;
183 | }
184 | }
185 | }
--------------------------------------------------------------------------------
/Runtime/CubicBezier/CubicBezier.CurveType.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: bd1759239d76c1049bbfd046ea357200
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/CubicBezier/CubicBezier.Geometry.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using Unity.Mathematics;
3 | using Unity.Collections;
4 |
5 | namespace Voxell.GPUVectorGraphics
6 | {
7 | public static partial class CubicBezier
8 | {
9 | public static void ComputeCubic(
10 | float2 p0, float2 p1, float2 p2, float2 p3,
11 | ref int vertexStart, ref NativeSlice vertexSlice,
12 | ref int coordsStart, ref NativeSlice coordsSlice,
13 | int recursiveType = -1
14 | )
15 | {
16 | float d0, d1, d2, d3;
17 | float3x4 coords = new float3x4();
18 | bool flip = false;
19 | // artifact on loop
20 | int loopArtifact = -1;
21 | float splitParam = 0.0f;
22 | CurveType curveType = ClassifyCurve(p0, p1, p2, p3, out d0, out d1, out d2, out d3);
23 |
24 | switch (curveType)
25 | {
26 | case CurveType.SERPENTINE:
27 | coords = Serpentine(d1, d2, d3, ref flip);
28 | break;
29 |
30 | case CurveType.LOOP:
31 | coords = Loop(d1, d2, d3, ref flip, ref loopArtifact, ref splitParam, recursiveType);
32 | break;
33 |
34 | case CurveType.CUSP:
35 | coords = Cusp(d1, d2, d3);
36 | break;
37 |
38 | case CurveType.QUADRATIC:
39 | coords = Quadratic(d3, ref flip);
40 | break;
41 |
42 | default: return;
43 | }
44 |
45 | // recursive computation
46 | if (loopArtifact != -1 && recursiveType == -1)
47 | {
48 | float2 p01 = (p1 - p0) * splitParam + p0;
49 | float2 p12 = (p2 - p1) * splitParam + p1;
50 | float2 p23 = (p3 - p2) * splitParam + p2;
51 |
52 | float2 p012 = (p12 - p01) * splitParam + p01;
53 | float2 p123 = (p23 - p12) * splitParam + p12;
54 |
55 | float2 p0123 = (p123 - p012) * splitParam + p012;
56 |
57 | if (loopArtifact == 1) // flip second
58 | {
59 | ComputeCubic(p0, p01, p012, p0123, ref vertexStart, ref vertexSlice, ref coordsStart, ref coordsSlice, 0);
60 | ComputeCubic(p0123, p123, p23, p3, ref vertexStart, ref vertexSlice, ref coordsStart, ref coordsSlice, 1);
61 | } else if (loopArtifact == 2) // flip first
62 | {
63 | ComputeCubic(p0, p01, p012, p0123, ref vertexStart, ref vertexSlice, ref coordsStart, ref coordsSlice, 1);
64 | ComputeCubic(p0123, p123, p23, p3, ref vertexStart, ref vertexSlice, ref coordsStart, ref coordsSlice, 0);
65 | }
66 | return;
67 | }
68 |
69 | if (recursiveType == 1) flip = !flip;
70 | if (flip)
71 | {
72 | coords[0].xy = -coords[0].xy;
73 | coords[1].xy = -coords[1].xy;
74 | coords[2].xy = -coords[2].xy;
75 | coords[3].xy = -coords[3].xy;
76 | }
77 |
78 | // triangulate
79 | Triangulate(
80 | new float2x4(p0, p1, p2, p3), coords,
81 | ref vertexStart, ref vertexSlice,
82 | ref coordsStart, ref coordsSlice
83 | );
84 | }
85 | }
86 | }
--------------------------------------------------------------------------------
/Runtime/CubicBezier/CubicBezier.Geometry.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 2087e6dd157341347b88ad643983422b
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/CubicBezier/CubicBezier.Triangulate.cs:
--------------------------------------------------------------------------------
1 | using Unity.Mathematics;
2 | using Unity.Collections;
3 |
4 | namespace Voxell.GPUVectorGraphics
5 | {
6 | public static partial class CubicBezier
7 | {
8 | internal static void Triangulate(
9 | float2x4 points, float3x4 coords,
10 | ref int vertexStart, ref NativeSlice vertexSlice,
11 | ref int coordsStart, ref NativeSlice coordsSlice
12 | )
13 | {
14 | // test for degenerate cases.
15 | for (int i=0; i < 4; i++)
16 | {
17 | for (int j=i + 1; j < 4; j++)
18 | {
19 | if (math.distance(points[i], points[j]) == 0.0f)
20 | {
21 | // Two of the points are coincident, so we can eliminate at
22 | // least one triangle. We might be able to eliminate the other
23 | // as well, but this seems sufficient to avoid degenerate triangulations.
24 |
25 | NativeArray indices = new NativeArray(3, Allocator.Temp);
26 | int index = 0;
27 | for (int k=0; k < 4; ++k)
28 | if (k != j) indices[index++] = k;
29 |
30 | CreateTriangleIndices(
31 | ref vertexStart, ref vertexSlice,
32 | ref coordsStart, ref coordsSlice,
33 | indices[0], indices[1], indices[2],
34 | points, coords
35 | );
36 |
37 | indices.Dispose();
38 | return;
39 | }
40 | }
41 | }
42 |
43 | // see whether any of the points are fully contained in the
44 | // triangle defined by the other three.
45 | for (int i=0; i < 4; ++i)
46 | {
47 | NativeArray indices = new NativeArray(3, Allocator.Temp);
48 | int index = 0;
49 | for (int j=0; j < 4; ++j)
50 | if (i != j) indices[index++] = j;
51 |
52 | if (VGMath.PointInTriangle(points[i], points[indices[0]], points[indices[1]], points[indices[2]]))
53 | {
54 | // produce three triangles surrounding this interior vertex.
55 | for (int j=0; j < 3; ++j)
56 | {
57 | CreateTriangleIndices(
58 | ref vertexStart, ref vertexSlice,
59 | ref coordsStart, ref coordsSlice,
60 | indices[j % 3], indices[(j + 1) % 3], i,
61 | points, coords
62 | );
63 | }
64 |
65 | indices.Dispose();
66 | return;
67 | }
68 | }
69 |
70 | // There are only a few permutations of the points, ignoring
71 | // rotations, which are irrelevant:
72 |
73 | // 0--3 0--2 0--3 0--1 0--2 0--1
74 | // | | | | | | | | | | | |
75 | // | | | | | | | | | | | |
76 | // 1--2 1--3 2--1 2--3 3--1 3--2
77 |
78 | // Note that three of these are reflections of each other.
79 | // Therefore there are only three possible triangulations:
80 |
81 | // 0--3 0--2 0--3
82 | // |\ | |\ | |\ |
83 | // | \| | \| | \|
84 | // 1--2 1--3 2--1
85 |
86 | // From which we can choose by seeing which of the potential
87 | // diagonals intersect. Note that we choose the shortest diagonal
88 | // to split the quad.
89 | if (VGMath.LinesIntersect(points[0], points[2], points[1], points[3]))
90 | {
91 | if (math.lengthsq(points[2] - points[0]) < math.lengthsq(points[3] - points[1]))
92 | {
93 | CreateTriangleIndices(
94 | ref vertexStart, ref vertexSlice,
95 | ref coordsStart, ref coordsSlice,
96 | 0, 1, 2, points, coords
97 | );
98 | CreateTriangleIndices(
99 | ref vertexStart, ref vertexSlice,
100 | ref coordsStart, ref coordsSlice,
101 | 0, 2, 3, points, coords
102 | );
103 | } else
104 | {
105 | CreateTriangleIndices(
106 | ref vertexStart, ref vertexSlice,
107 | ref coordsStart, ref coordsSlice,
108 | 0, 1, 3, points, coords
109 | );
110 | CreateTriangleIndices(
111 | ref vertexStart, ref vertexSlice,
112 | ref coordsStart, ref coordsSlice,
113 | 1, 2, 3, points, coords
114 | );
115 | }
116 | } else if (VGMath.LinesIntersect(points[0], points[3], points[1], points[2]))
117 | {
118 | if (math.lengthsq(points[3] - points[0]) < math.lengthsq(points[2] - points[1]))
119 | {
120 | CreateTriangleIndices(
121 | ref vertexStart, ref vertexSlice,
122 | ref coordsStart, ref coordsSlice,
123 | 0, 1, 3, points, coords
124 | );
125 | CreateTriangleIndices(
126 | ref vertexStart, ref vertexSlice,
127 | ref coordsStart, ref coordsSlice,
128 | 0, 3, 2, points, coords
129 | );
130 | } else
131 | {
132 | CreateTriangleIndices(
133 | ref vertexStart, ref vertexSlice,
134 | ref coordsStart, ref coordsSlice,
135 | 0, 1, 2, points, coords
136 | );
137 | CreateTriangleIndices(
138 | ref vertexStart, ref vertexSlice,
139 | ref coordsStart, ref coordsSlice,
140 | 2, 1, 3, points, coords
141 | );
142 | }
143 | } else
144 | {
145 | // Lines (0->1), (2->3) intersect -- or should, modulo numerical
146 | // precision issues
147 | if (math.lengthsq(points[1] - points[0]) < math.lengthsq(points[3] - points[2]))
148 | {
149 | CreateTriangleIndices(
150 | ref vertexStart, ref vertexSlice,
151 | ref coordsStart, ref coordsSlice,
152 | 0, 2, 1, points, coords
153 | );
154 | CreateTriangleIndices(
155 | ref vertexStart, ref vertexSlice,
156 | ref coordsStart, ref coordsSlice,
157 | 0, 1, 3, points, coords
158 | );
159 | } else
160 | {
161 | CreateTriangleIndices(
162 | ref vertexStart, ref vertexSlice,
163 | ref coordsStart, ref coordsSlice,
164 | 0, 2, 3, points, coords
165 | );
166 | CreateTriangleIndices(
167 | ref vertexStart, ref vertexSlice,
168 | ref coordsStart, ref coordsSlice,
169 | 3, 2, 1, points, coords
170 | );
171 | }
172 | }
173 | }
174 |
175 | private static void CreateTriangleIndices(
176 | ref int vertexStart, ref NativeSlice vertexSlice,
177 | ref int coordsStart, ref NativeSlice coordsSlice,
178 | int idx0, int idx1, int idx2, float2x4 points, float3x4 coords
179 | )
180 | {
181 | vertexSlice[vertexStart] = points[idx0];
182 | coordsSlice[vertexStart++] = coords[idx0];
183 |
184 | vertexSlice[vertexStart] = points[idx1];
185 | coordsSlice[vertexStart++] = coords[idx1];
186 |
187 | vertexSlice[vertexStart] = points[idx2];
188 | coordsSlice[vertexStart++] = coords[idx2];
189 | }
190 | }
191 | }
--------------------------------------------------------------------------------
/Runtime/CubicBezier/CubicBezier.Triangulate.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b7056eed21ef0c8409c1cac2840735cc
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Font.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 618e75c1f854d6f439e60d8e4fc1af82
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/Font/FontCurve.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Unity.Mathematics;
5 | using Unity.Collections;
6 |
7 | namespace Voxell.GPUVectorGraphics.Font
8 | {
9 | public class FontCurve : ScriptableObject
10 | {
11 | public Glyph[] Glyphs => _glyphs;
12 | public int[] CharCodes => _charCodes;
13 | public int[] GlyphIndices => _glyphIndices;
14 |
15 | /// Bezier contour for each character.
16 | [SerializeField, NonReorderable] private Glyph[] _glyphs;
17 |
18 | /// Supported character codes.
19 | [SerializeField, NonReorderable] private int[] _charCodes;
20 | /// Glyph indices of the corresponding character codes.
21 | [SerializeField, NonReorderable] private int[] _glyphIndices;
22 | /// Meshes of the corresponding character glyph indices.
23 | [SerializeField, NonReorderable] private Mesh[] _meshes;
24 |
25 | public void Initialize(Glyph[] glyphs, int[] charCodes, int[] glyphIndices, Mesh[] meshes)
26 | {
27 | _glyphs = glyphs;
28 | _charCodes = charCodes;
29 | _glyphIndices = glyphIndices;
30 | _meshes = meshes;
31 | }
32 |
33 | /// Search for the glyph index of a certain character through binary search.
34 | /// 0 if character does not exsists, else index of the character's glyph.
35 | public int SearchGlyhIndex(char character)
36 | {
37 | int __len = _charCodes.Length;
38 | int __first = 0;
39 | int __half;
40 | int __middle;
41 |
42 | // binary search
43 | while (__len > 0)
44 | {
45 | __half = __len >> 1;
46 | __middle = __first + __half;
47 |
48 | int midCode = _charCodes[__middle];
49 | if (character == midCode) return _glyphIndices[__middle];
50 |
51 | // search first half if it is lower than the mid point
52 | if (character < midCode)
53 | __len = __half;
54 | // search second half if it is higher than the mid point
55 | else
56 | {
57 | __first = __middle + 1;
58 | __len = __len - __half - 1;
59 | }
60 | }
61 |
62 | // index of "square" glyph (a glyph repersenting that the character is not supported)
63 | return 0;
64 | }
65 |
66 | /// Get character glyph through binary search.
67 | ///
68 | /// First glyph if character is not supported,
69 | /// else the glyph representing the shape of the character
70 | ///
71 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
72 | public Glyph GetCharacterGlyph(char character) => _glyphs[SearchGlyhIndex(character)];
73 |
74 | /// Get character mesh through binary search.
75 | ///
76 | /// First mesh if character is not supported,
77 | /// else the mesh representing the shape of the character
78 | ///
79 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
80 | public Mesh GetCharacterMesh(char character) => _meshes[SearchGlyhIndex(character)];
81 |
82 | /// Convert glyphs into points and contours.
83 | public static void ExtractGlyphData(
84 | in Glyph glyph, out float2[] points, out CDT.ContourPoint[] contours
85 | )
86 | {
87 | int contourCount = glyph.contours.Length;
88 | List pointList = new List();
89 | List contourList = new List();
90 |
91 | int contourStart = 0;
92 | for (int c=0; c < contourCount; c++)
93 | {
94 | QuadraticContour glyphContour = glyph.contours[c];
95 | int segmentCount = glyphContour.segments.Length;
96 |
97 | for (int s=0; s < segmentCount; s++)
98 | {
99 | pointList.Add(glyphContour.segments[s].p0);
100 | contourList.Add(new CDT.ContourPoint(contourStart+s, c));
101 | }
102 | contourList.Add(new CDT.ContourPoint(contourStart, c));
103 | contourStart += segmentCount;
104 | }
105 |
106 | points = pointList.ToArray();
107 | contours = contourList.ToArray();
108 | }
109 |
110 | public static Vector3[] PointsToVertices(in NativeArray points)
111 | {
112 | Vector3[] vertices = new Vector3[points.Length];
113 | for (int p=0; p < points.Length; p++)
114 | {
115 | float2 point = points[p];
116 | vertices[p] = new Vector3(point.x, point.y, 0.0f);
117 | }
118 |
119 | return vertices;
120 | }
121 | }
122 | }
--------------------------------------------------------------------------------
/Runtime/Font/FontCurve.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 6d1f28eba00cd7a4dbce389f3b22feb8
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {fileID: 2800000, guid: f04b41271e371d047854280baa7d3658, type: 3}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Font/Glyph.cs:
--------------------------------------------------------------------------------
1 | using Unity.Mathematics;
2 |
3 | namespace Voxell.GPUVectorGraphics.Font
4 | {
5 | [System.Serializable]
6 | public struct Glyph
7 | {
8 | [System.Serializable]
9 | public struct CompositeReference
10 | {
11 | /// The offset for the referenced glyph.
12 | public float2 offset;
13 |
14 | /// The X axis for the referenced glyph.
15 | public float2 xAxis;
16 |
17 | /// The Y axis for the referenced glyph.
18 | public float2 yAxis;
19 |
20 | /// The index of the glyph being referenced.
21 | public int glyphRef;
22 | }
23 |
24 | /// All contours in the glyph.
25 | public QuadraticContour[] contours;
26 |
27 | /// Composition of referenes of other glyphs.
28 | public CompositeReference[] compositeReferences;
29 |
30 | /// Determines if this glyph is made up of other glyph or a glyph on its own.
31 | public bool isComplex;
32 |
33 | /// Bottom left of the glyph's bounding box.
34 | public float2 minRect;
35 | /// Top right of the glyph's bounding box.
36 | public float2 maxRect;
37 | }
38 | }
--------------------------------------------------------------------------------
/Runtime/Font/Glyph.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 68f867a8c7225ec46aac96abc5290e1f
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Font/Reader.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b5ab9495e477c5145b04e7586cbbbac0
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/Font/Reader/FontReader.cs:
--------------------------------------------------------------------------------
1 | // MIT License
2 | //
3 | // Copyright (c) 2020 Pixel Precision LLC
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | using System.IO;
24 |
25 | namespace Voxell.GPUVectorGraphics.Font
26 | {
27 | ///
28 | /// Utility class used by Berny to read a TrueType Font file and other
29 | /// related files and data streams.
30 | ///
31 | public abstract class FontReader
32 | {
33 | /// Returning access and resources back to the system.
34 | /// True if the reader was successfully closed. Else, false.
35 | /// May not be relevant on all platforms and implementations of TTFReader, but
36 | /// best practice is to call Close() at the proper time, regardless of the implementation
37 | /// or usecase. The only exception is explicit use to TTFReaderBytes.
38 | public abstract bool Close();
39 |
40 | ///
41 | /// Read a 1 byte un signed integer from the read position.
42 | ///
43 | /// The read integer value.
44 | public abstract sbyte ReadInt8();
45 |
46 | ///
47 | /// Read a 1 byte signed integer from the read position.
48 | ///
49 | /// The read integer value.
50 | public abstract byte ReadUInt8();
51 |
52 | ///
53 | /// Returns the read position.
54 | ///
55 | /// The read position.
56 | public abstract long GetPosition();
57 |
58 | ///
59 | /// Set the read position of the reader.
60 | ///
61 | /// The new read position.
62 | /// If true, the read position was successfully set. Else, false.
63 | public abstract bool SetPosition(long pos, SeekOrigin seekOrigin = SeekOrigin.Begin);
64 |
65 | ///
66 | /// Read an array of bytes, starting from the read position.
67 | ///
68 | /// The number of bytes to read.
69 | /// The read bytes.
70 | public abstract byte[] ReadBytes(int length);
71 |
72 | public sbyte[] ReadSBytes(int length)
73 | {
74 | // Reading SBytes is far less-used than ReadBytes, so we just do
75 | // our own implementation instead of forcing the implemenenters
76 | // to make their own.
77 | sbyte [] ret = new sbyte[length];
78 |
79 | for(int i = 0; i < length; ++i)
80 | ret[i] = this.ReadInt8();
81 |
82 | return ret;
83 | }
84 |
85 | ///
86 | /// If true, the read position is past the readable area of the data stream.
87 | /// Else, false.
88 | ///
89 | /// If false, there is still data that can be read from where the read position is.
90 | public abstract bool AtEnd();
91 |
92 | ///
93 | /// Read a signed 16 int from the current read position.
94 | ///
95 | /// The read integer value.
96 | /// Current implementation is hard coded for little endian platforms.
97 | public ushort ReadUInt16()
98 | {
99 | return (ushort)(this.ReadUInt8() << 8 | this.ReadUInt8());
100 | }
101 |
102 | ///
103 | /// Read a 24 bit unsigned value from the current read position.
104 | ///
105 | /// The read integer value.
106 | /// Current implementation is hard coded for little endian platforms.
107 | public uint ReadUInt24()
108 | {
109 | return (uint)((this.ReadUInt8() << 16) | (this.ReadUInt8() << 8) | (this.ReadUInt8() << 0));
110 | }
111 |
112 | ///
113 | /// Read a 32 bit unsigned value from the current read position.
114 | ///
115 | /// Current implementation is hard coded for little endian platforms.
116 | public uint ReadUInt32()
117 | {
118 | return (uint)((this.ReadUInt8() << 24) | (this.ReadUInt8() << 16) | (this.ReadUInt8() << 8) | (this.ReadUInt8() << 0));
119 | }
120 |
121 | public long ReadUInt64()
122 | {
123 | return (
124 | ((long)this.ReadUInt8() << 56) |
125 | ((long)this.ReadUInt8() << 48) |
126 | ((long)this.ReadUInt8() << 40) |
127 | ((long)this.ReadUInt8() << 32) |
128 | ((long)this.ReadUInt8() << 24) |
129 | ((long)this.ReadUInt8() << 16) |
130 | ((long)this.ReadUInt8() << 8) |
131 | ((long)this.ReadUInt8() << 0));
132 | }
133 |
134 | ///
135 | /// Read a 16 bit signed value from the current read position.
136 | ///
137 | ///
138 | /// Current implementation is hard coded for little endian platforms.
139 | public short ReadInt16()
140 | {
141 | return (short)(this.ReadUInt8() << 8 | this.ReadUInt8());
142 | }
143 |
144 | ///
145 | /// Read a 32 bit signed value from the current read position.
146 | ///
147 | ///
148 | /// Current implementation is hard coded for little endian platforms.
149 | public int ReadInt32()
150 | {
151 | return (int)((this.ReadUInt8() << 24) | (this.ReadUInt8() << 16) | (this.ReadUInt8() << 8) | (this.ReadUInt8() << 0));
152 | }
153 |
154 | ///
155 | /// Read a TTF FWord from the current read position.
156 | ///
157 | /// The value read from the data stream.
158 | public short ReadFWord()
159 | {
160 | return this.ReadInt16();
161 | }
162 |
163 | ///
164 | /// Read a TTF UFWord from the current read position.
165 | ///
166 | /// The value read from the data stream.
167 | public ushort ReadUFWord()
168 | {
169 | return this.ReadUInt16();
170 | }
171 |
172 | ///
173 | /// Read a TTF Offset16 value from the current read position.
174 | ///
175 | /// The value read from the data stream.
176 | public ushort ReadOffset16()
177 | {
178 | return this.ReadUInt16();
179 | }
180 |
181 | ///
182 | /// Read a TTF Offset32 value from the current read position.
183 | ///
184 | /// The value read from the data stream.
185 | public int ReadOffset32()
186 | {
187 | return this.ReadOffset32();
188 | }
189 |
190 | ///
191 | /// Reads a TTF FDot14 value from the current read position.
192 | ///
193 | /// The number value read from the data stream and converted to a float.
194 | public float ReadFDot14()
195 | {
196 | return (float)this.ReadInt16() / (float)(1 << 14);
197 | }
198 |
199 | ///
200 | /// Reads a TTF Fixed value from the current read position.
201 | ///
202 | /// the number value read from the data stream and converted to a float.
203 | public float ReadFixed()
204 | {
205 | return (float)this.ReadInt32() / (float)(1 << 16);
206 | }
207 |
208 | ///
209 | /// Read an ASCII string of a known length from file.
210 | ///
211 | /// The length of the string.
212 | /// The string read from the data stream.
213 | public string ReadString(int length)
214 | {
215 | byte[] rbStr = this.ReadBytes(length);
216 | return System.Text.ASCIIEncoding.ASCII.GetString(rbStr);
217 | }
218 |
219 | ///
220 | /// Read a record string from file. A record string is a pascal
221 | /// string with a 2 byte length.
222 | ///
223 | /// The string read from the data stream.
224 | public string ReadNameRecord()
225 | {
226 | ushort len = this.ReadUInt16();
227 | return this.ReadString(len);
228 | }
229 |
230 | ///
231 | /// Read a string from file in pascal format - where the first byte
232 | /// defines the length of the string, directly followed by the ASCII
233 | /// data.
234 | ///
235 | /// The string read from the datastream.
236 | public string ReadPascalString()
237 | {
238 | byte c = this.ReadUInt8();
239 | return this.ReadString(c);
240 | }
241 |
242 | // A strategy used in reading is to create file member variables
243 | // of the correct byte width and "signed-ness", and just use
244 | // ReadInt(out * i) and let the overloading resolve figure out
245 | // the proper Read*() function.
246 |
247 | ///
248 | /// Overload of ReadInt() for 1 byte unsigned int.
249 | ///
250 | /// The output variable.
251 | public void ReadInt(out sbyte i)
252 | {
253 | i = this.ReadInt8();
254 | }
255 |
256 | ///
257 | /// Overload of ReadInt() for 1 byte signed int.
258 | ///
259 | /// The output variable.
260 | public void ReadInt(out byte i)
261 | {
262 | i = this.ReadUInt8();
263 | }
264 |
265 | ///
266 | /// Overload of ReadInt() for 2 byte signed int.
267 | ///
268 | /// The output variable.
269 | public void ReadInt(out short i)
270 | {
271 | i = this.ReadInt16();
272 | }
273 |
274 | ///
275 | /// Overload of ReadInt() for 2 byte unsigned int.
276 | ///
277 | /// The output variable.
278 | public void ReadInt(out ushort i)
279 | {
280 | i = this.ReadUInt16();
281 | }
282 |
283 | ///
284 | /// Overload of ReadInt() for 4 byte signed int.
285 | ///
286 | /// The output variable.
287 | public void ReadInt(out int i)
288 | {
289 | i = this.ReadInt32();
290 | }
291 |
292 | ///
293 | /// Overload of ReadInt() for 4 byte unsigned int.
294 | ///
295 | /// The output variable.
296 | public void ReadInt(out uint i)
297 | {
298 | i = this.ReadUInt32();
299 | }
300 |
301 | ///
302 | /// Reads a date time from the TTF file.
303 | ///
304 | /// The datetime at the current read position.
305 | public System.DateTime ReadDate()
306 | {
307 | System.DateTime dt = new System.DateTime(1904, 1, 1);
308 | dt = dt.AddSeconds(this.ReadUInt64());
309 |
310 | return dt;
311 | }
312 | }
313 | }
--------------------------------------------------------------------------------
/Runtime/Font/Reader/FontReader.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 3d55171f2b5c96a4896e5d563ace868b
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Font/Reader/FontReaderFile.cs:
--------------------------------------------------------------------------------
1 | // MIT License
2 | //
3 | // Copyright (c) 2020 Pixel Precision LLC
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | using System.IO;
24 |
25 | namespace Voxell.GPUVectorGraphics.Font
26 | {
27 | ///
28 | /// An implementation of the TTFReader that pulls data from a file.
29 | ///
30 | public class FontReaderFile : FontReader
31 | {
32 | /// The file reader.
33 | BinaryReader reader = null;
34 |
35 | /// The file stream used by the binary reader.
36 | FileStream filestream = null;
37 |
38 | /// File path constructor.
39 | /// The file path to open.
40 | public FontReaderFile(string path)
41 | {
42 | if (this.Open(path) == false)
43 | throw new System.Exception("Could not open file");
44 | }
45 |
46 | /// Opens a file.
47 | /// The file path to open.
48 | /// If true, the file was successfully opened. Else, false.
49 | public bool Open(string path)
50 | {
51 | this.Close();
52 |
53 | this.filestream = System.IO.File.Open(path, System.IO.FileMode.Open);
54 | reader = new System.IO.BinaryReader(this.filestream);
55 | return true;
56 | }
57 |
58 | public override bool Close()
59 | {
60 | if (this.filestream != null)
61 | {
62 | this.filestream.Close();
63 | this.filestream = null;
64 | this.reader = null;
65 |
66 | return true;
67 | }
68 | return false;
69 | }
70 |
71 | public override bool AtEnd() => this.filestream.Position < this.filestream.Length;
72 |
73 | public override sbyte ReadInt8() => this.reader.ReadSByte();
74 |
75 | public override byte ReadUInt8() => this.reader.ReadByte();
76 |
77 | public override long GetPosition() => this.filestream.Position;
78 |
79 | public override bool SetPosition(long pos, SeekOrigin seekOrigin = SeekOrigin.Begin)
80 | {
81 | if (this.filestream == null) return false;
82 | return this.filestream.Seek(pos, seekOrigin) == pos;
83 | }
84 |
85 | public override byte [] ReadBytes(int length) => this.reader.ReadBytes(length);
86 | }
87 | }
--------------------------------------------------------------------------------
/Runtime/Font/Reader/FontReaderFile.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b679b744158d7894d8ca27c68580a66c
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Font/Tables.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: a1282eea054fbbe4d83f5fdb47cdb7ef
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/Font/Tables/CMap.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 3d165bd8a8f261a49b5578629b889b9e
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Font/Tables/Glyf.cs:
--------------------------------------------------------------------------------
1 | // MIT License
2 | //
3 | // Copyright (c) 2020 Pixel Precision LLC
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | using System.Collections.Generic;
24 | using UnityEngine;
25 |
26 | namespace Voxell.GPUVectorGraphics.Font
27 | {
28 | public struct Glyf
29 | {
30 | public struct CompositeEntry
31 | {
32 | public ushort flags; // composite flag
33 | public ushort glyphIndex; // glyph index of component
34 | public int argument1; // x-offset for component or point number; type depends on bits 0 and 1 in component flags
35 | public int argument2; // y-offset for component or point number; type depends on bits 0 and 1 in component flags
36 |
37 | public float scale;
38 | public float xscale;
39 | public float scale01;
40 | public float scale10;
41 | public float yscale;
42 |
43 | public bool Read(FontReader r)
44 | {
45 | // Set defaults in case we don't read them
46 | // because it's filtered out from the flags.
47 | this.argument1 = 0;
48 | this.argument2 = 0;
49 | this.scale = 1.0f;
50 | this.xscale = 1.0f;
51 | this.yscale = 1.0f;
52 | this.scale01 = 0.0f;
53 | this.scale10 = 0.0f;
54 |
55 | r.ReadInt(out this.flags);
56 | r.ReadInt(out this.glyphIndex);
57 |
58 | if ((this.flags & ARG_1_AND_2_ARE_WORDS) != 0)
59 | {
60 | short a1 = r.ReadInt16();
61 | short a2 = r.ReadInt16();
62 |
63 | if ((this.flags & ARGS_ARE_XY_VALUES) != 0)
64 | {
65 | this.argument1 = a1;
66 | this.argument2 = a2;
67 | }
68 | else
69 | {
70 | this.argument1 = (ushort)a1;
71 | this.argument2 = (ushort)a2;
72 | }
73 | }
74 | else
75 | {
76 | sbyte a1 = r.ReadInt8();
77 | sbyte a2 = r.ReadInt8();
78 |
79 | if ((this.flags & ARGS_ARE_XY_VALUES) != 0)
80 | {
81 | this.argument1 = a1;
82 | this.argument2 = a2;
83 | }
84 | else
85 | {
86 | this.argument1 = (byte)a1;
87 | this.argument2 = (byte)a2;
88 | }
89 | }
90 | if ((this.flags & WE_HAVE_A_SCALE) != 0)
91 | {
92 | this.scale = r.ReadFDot14();
93 | }
94 | else if ((this.flags & WE_HAVE_AN_X_AND_Y_SCALE) != 0)
95 | {
96 | this.xscale = r.ReadFDot14(); // Format 2.14
97 | this.yscale = r.ReadFDot14(); // Format 2.14
98 | }
99 | else if ((this.flags & WE_HAVE_A_TWO_BY_TWO) != 0)
100 | {
101 | this.xscale = r.ReadFDot14(); // Format 2.14
102 | this.scale01 = r.ReadFDot14(); // Format 2.14
103 | this.scale10 = r.ReadFDot14(); // Format 2.14
104 | this.yscale = r.ReadFDot14(); // Format 2.14
105 | }
106 |
107 | return (this.flags & MORE_COMPONENTS) != 0;
108 | }
109 | }
110 |
111 | // Simple Glyph Flags
112 | public const byte ON_CURVE_POINT = 0x01; // Bit 0: If set, the point is on the curve; otherwise, it is off the curve.
113 | public const byte X_SHORT_VECTOR = 0x02; // Bit 1: If set, the corresponding x-coordinate is 1 byte long. If not set, it is two bytes long. For the sign of this value, see the description of the X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR flag.
114 | public const byte Y_SHORT_VECTOR = 0x04; // Bit 2: If set, the corresponding y-coordinate is 1 byte long. If not set, it is two bytes long. For the sign of this value, see the description of the Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR flag.
115 | public const byte REPEAT_FLAG = 0x08; // Bit 3: If set, the next byte (read as unsigned) specifies the number of additional times this flag byte is to be repeated in the logical flags array — that is, the number of additional logical flag entries inserted after this entry. (In the expanded logical array, this bit is ignored.) In this way, the number of flags listed can be smaller than the number of points in the glyph description.
116 | public const byte X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR = 0x10; // Bit 4: This flag has two meanings, depending on how the X_SHORT_VECTOR flag is set. If X_SHORT_VECTOR is set, this bit describes the sign of the value, with 1 equaling positive and 0 negative.If X_SHORT_VECTOR is not set and this bit is set, then the current x-coordinate is the same as the previous x-coordinate.If X_SHORT_VECTOR is not set and this bit is also not set, the current x - coordinate is a signed 16 - bit delta vector.
117 | public const byte Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR = 0x20; // Bit 5: This flag has two meanings, depending on how the Y_SHORT_VECTOR flag is set.If Y_SHORT_VECTOR is set, this bit describes the sign of the value, with 1 equaling positive and 0 negative.If Y_SHORT_VECTOR is not set and this bit is set, then the current y-coordinate is the same as the previous y-coordinate.If Y_SHORT_VECTOR is not set and this bit is also not set, the current y - coordinate is a signed 16 - bit delta vector.
118 | public const byte OVERLAP_SIMPLE = 0x40; // Bit 6: If set, contours in the glyph description may overlap.Use of this flag is not required in OpenType — that is, it is valid to have contours overlap without having this flag set. It may affect behaviors in some platforms, however. (See the discussion of “Overlapping contours” in Apple’s specification for details regarding behavior in Apple platforms.) When used, it must be set on the first flag byte for the glyph. See additional details below.
119 | public const byte SIMPLE_RESERVED = 0x80; // Bit 7 is reserved: set to zero.
120 |
121 | //Composite Glyph Flags
122 | public const ushort ARG_1_AND_2_ARE_WORDS = 0x0001; // Bit 0: If this is set, the arguments are 16 - bit(uint16 or int16); otherwise, they are bytes(uint8 or int8).
123 | public const ushort ARGS_ARE_XY_VALUES = 0x0002; // Bit 1: If this is set, the arguments are signed xy values; otherwise, they are unsigned point numbers.
124 | public const ushort ROUND_XY_TO_GRID = 0x0004; // Bit 2: For the xy values if the preceding is true.
125 | public const ushort WE_HAVE_A_SCALE = 0x0008; // Bit 3: This indicates that there is a simple scale for the component. Otherwise, scale = 1.0.
126 | public const ushort MORE_COMPONENTS = 0x0020; // Bit 5: Indicates at least one more glyph after this one.
127 | public const ushort WE_HAVE_AN_X_AND_Y_SCALE = 0x0040; // Bit 6: The x direction will use a different scale from the y direction.
128 | public const ushort WE_HAVE_A_TWO_BY_TWO = 0x0080; // Bit 7: There is a 2 by 2 transformation that will be used to scale the component.
129 | public const ushort WE_HAVE_INSTRUCTIONS = 0x0100; // Bit 8: Following the last component are instructions for the composite character.
130 | public const ushort USE_MY_METRICS = 0x0200; // Bit 9: If set, this forces the aw and lsb(and rsb) for the composite to be equal to those from this original glyph.This works for hinted and unhinted characters.
131 | public const ushort OVERLAP_COMPOUND = 0x0400; // Bit 10: If set, the components of the compound glyph overlap.Use of this flag is not required in OpenType — that is, it is valid to have components overlap without having this flag set.It may affect behaviors in some platforms, however. (See Apple’s specification for details regarding behavior in Apple platforms.) When used, it must be set on the flag word for the first component.See additional remarks, above, for the similar OVERLAP_SIMPLE flag used in simple - glyph descriptions.
132 | public const ushort SCALED_COMPONENT_OFFSET = 0x0800; // Bit 11: The composite is designed to have the component offset scaled.
133 | public const ushort UNSCALED_COMPONENT_OFFSET = 0x1000; // Bit 12: The composite is designed not to have the component offset scaled.
134 | public const ushort COMPOSITE_RESERVED = 0xE010; // Bits 4, 13, 14 and 15 are reserved: set to 0.
135 |
136 | public const string TagName = "glyf";
137 |
138 | public short numberOfContours; // If the number of contours is greater than or equal to zero, this is a simple glyph. If negative, this is a composite glyph — the value -1 should be used for composite glyphs.
139 | public short xMin; // Minimum x for coordinate data.
140 | public short yMin; // Minimum y for coordinate data.
141 | public short xMax; // Maximum x for coordinate data.
142 | public short yMax; // Maximum y for coordinate data.
143 |
144 | // Simple Glyph
145 | public List endPtsOfCountours; // Array of point indices for the last point of each contour, in increasing numeric order.
146 | public ushort instructionLength; // Total number of bytes for instructions. If instructionLength is zero, no instructions are present for this glyph, and this field is followed directly by the flags field.
147 | public List instructions; // Array of instruction byte code for the glyph.
148 | public List simpflags; // Array of flag elements. See below for details regarding the number of flag array elements.
149 | public List xCoordinates; // Contour point x-coordinates. See below for details regarding the number of coordinate array elements. Coordinate for the first point is relative to (0,0); others are relative to previous point.
150 | public List yCoordinates; // Contour point y-coordinates. See below for details regarding the number of coordinate array elements. Coordinate for the first point is relative to (0,0); others are relative to previous point.
151 |
152 | public bool IsComplex { get => this.numberOfContours < 0; } // In general, values are complex; Ideally negative values should be -1
153 |
154 | public List compositeEntries;
155 | public ushort numInstr;
156 | public List instr;
157 |
158 | public void Read(FontReader r)
159 | {
160 | r.ReadInt(out this.numberOfContours);
161 | r.ReadInt(out this.xMin);
162 | r.ReadInt(out this.yMin);
163 | r.ReadInt(out this.xMax);
164 | r.ReadInt(out this.yMax);
165 |
166 | if (this.IsComplex == false)
167 | {
168 | // Simple
169 |
170 | this.endPtsOfCountours = new List();
171 | for(int i = 0; i < this.numberOfContours; ++i)
172 | this.endPtsOfCountours.Add( r.ReadUInt16() );
173 |
174 | r.ReadInt(out this.instructionLength);
175 | this.instructions = new List();
176 | for(int i = 0; i < this.instructionLength; ++i)
177 | this.instructions.Add(r.ReadUInt8());
178 |
179 | int numPoints = 0;
180 | // http://stevehanov.ca/blog/?id=143
181 | foreach(ushort us in this.endPtsOfCountours)
182 | numPoints = Mathf.Max(numPoints, us);
183 | numPoints += 1;
184 |
185 | this.simpflags = new List();
186 | this.xCoordinates = new List();
187 | this.yCoordinates = new List();
188 | for (int i = 0; i < numPoints; ++i)
189 | {
190 | byte flag = r.ReadUInt8();
191 | this.simpflags.Add(flag);
192 |
193 | if ((flag & REPEAT_FLAG) != 0)
194 | {
195 | byte repeatCount = r.ReadUInt8();
196 | i += repeatCount;
197 |
198 | for (int j = 0; j < repeatCount; ++j)
199 | this.simpflags.Add(flag);
200 |
201 | }
202 | }
203 |
204 | int val = 0;
205 | for (int i = 0; i < numPoints; ++i)
206 | {
207 | byte flag = this.simpflags[i];
208 | if ((flag & X_SHORT_VECTOR) != 0)
209 | {
210 | if ((flag & X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) != 0)
211 | val += r.ReadUInt8();
212 | else
213 | val -= r.ReadUInt8();
214 | }
215 | else if ((~flag & X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) != 0)
216 | val += r.ReadInt16();
217 |
218 | this.xCoordinates.Add(val);
219 | }
220 |
221 | val = 0;
222 | for (int i = 0; i < numPoints; ++i)
223 | {
224 | byte flag = this.simpflags[i];
225 | if ((flag & Y_SHORT_VECTOR) != 0)
226 | {
227 | if ((flag & Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) != 0)
228 | val += r.ReadUInt8();
229 | else
230 | val -= r.ReadUInt8();
231 | }
232 | else if ((~flag & Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) != 0)
233 | val += r.ReadInt16();
234 | else
235 | { } // Value is unchanged
236 |
237 | this.yCoordinates.Add(val);
238 | }
239 | }
240 | else
241 | {
242 | // Composite
243 | this.compositeEntries = new List();
244 |
245 | bool moreComps = true;
246 | while(moreComps == true)
247 | {
248 | CompositeEntry compE = new CompositeEntry();
249 | moreComps = compE.Read(r);
250 |
251 | this.compositeEntries.Add(compE);
252 | }
253 |
254 | CompositeEntry ceLast = this.compositeEntries[compositeEntries.Count - 1];
255 | if ((ceLast.flags & WE_HAVE_INSTRUCTIONS) != 0)
256 | {
257 | r.ReadInt(out this.numInstr);
258 |
259 | this.instr = new List();
260 | for (int i = 0; i < this.instr.Count; ++i)
261 | this.instr.Add(r.ReadUInt8());
262 |
263 | }
264 | }
265 | }
266 | }
267 | }
268 |
--------------------------------------------------------------------------------
/Runtime/Font/Tables/Glyf.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4a02f35bf11c8244ba8687a804c8ca52
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Font/Tables/Head.cs:
--------------------------------------------------------------------------------
1 | // MIT License
2 | //
3 | // Copyright (c) 2020 Pixel Precision LLC
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | namespace Voxell.GPUVectorGraphics.Font
24 | {
25 | ///
26 | /// head — Font Header Table
27 | /// https://docs.microsoft.com/en-us/typography/opentype/spec/head
28 | ///
29 | /// This table gives global information about the font. The bounding box values
30 | /// should be computed using only glyphs that have contours. Glyphs with no
31 | /// contours should be ignored for the purposes of these calculations.
32 | ///
33 | public struct Head
34 | {
35 | // A different style than the rest of the flags, but if they don't
36 | // give me text to explicitly copy, it's going to be a flag enum
37 | // with matching style.
38 | [System.Flags]
39 | public enum Flags
40 | {
41 | Baseline = (1 << 0),
42 | LeftSidebearing = (1 << 1),
43 | InstrDepOnPtSz = (1 << 2),
44 | ForcePPEMIntForScalar = (1 << 3),
45 | InstrMayAlterAdvWd = (1 << 4),
46 | Unused = (1 << 5),
47 | Lossless = (1 << 11),
48 | Converted = (1 << 12),
49 | Optimized = (1 << 13),
50 | LastResort = (1 << 14),
51 | }
52 |
53 | [System.Flags]
54 | public enum MacStyle
55 | {
56 | Bold = (1 << 0),
57 | Italic = (1 << 1),
58 | Underline = (1 << 2),
59 | Outline = (1 << 3),
60 | Shadow = (1 << 4),
61 | Condensed = (1 << 5),
62 | Extended = (1 << 6)
63 | }
64 |
65 | public const string TagName = "head";
66 |
67 | // See member head.magicNumber.
68 | public const int ExpectedMagicNumber = 0x5F0F3CF5;
69 |
70 | public ushort majorVersion; // Major version number of the font header table — set to 1.
71 | public ushort minorVersion; // Minor version number of the font header table — set to 0.
72 | public float fontRevision; // Set by font manufacturer.
73 | public uint checksumAdjustment; // To compute: set it to 0, sum the entire font as uint32, then store 0xB1B0AFBA - sum. If the font is used as a component in a font collection file, the value of this field will be invalidated by changes to the file structure and font table directory, and must be ignored.
74 | public uint magicNumber; // Set to 0x5F0F3CF5.
75 | public ushort flags;
76 | public ushort unitsPerEm; // Set to a value from 16 to 16384. Any value in this range is valid. In fonts that have TrueType outlines, a power of 2 is recommended as this allows performance optimizations in some rasterizers.
77 | public System.DateTime created; // Number of seconds since 12:00 midnight that started January 1st 1904 in GMT/UTC time zone.
78 | public System.DateTime modified; // Number of seconds since 12:00 midnight that started January 1st 1904 in GMT/UTC time zone.
79 | public short xMin; // For all glyph bounding boxes. (Glyphs without contours are ignored.)
80 | public short yMin; // For all glyph bounding boxes. (Glyphs without contours are ignored.)
81 | public short xMax; // For all glyph bounding boxes. (Glyphs without contours are ignored.)
82 | public short yMax; // For all glyph bounding boxes. (Glyphs without contours are ignored.)
83 | public ushort macStyle; //
84 | public ushort lowestRecPPEM; // Smallest readable size in pixels.
85 | public ushort fontDirectionHint; //
86 | public short indexToLocFormat; // 0 for short offsets (Offset16), 1 for long (Offset32).
87 | public short glyphDataFormat; // 0 for current format.
88 |
89 | public int OffsetByteWidth
90 | {
91 | get
92 | {
93 | switch (this.indexToLocFormat)
94 | {
95 | case 0:
96 | return 2; // Offset16 / uint16
97 | case 1:
98 | return 4; // Offset32 / uint32
99 | }
100 |
101 | return 0;
102 | }
103 |
104 | }
105 |
106 | public void Read(FontReader r)
107 | {
108 | r.ReadInt(out this.majorVersion);
109 | r.ReadInt(out this.minorVersion);
110 | this.fontRevision = r.ReadFixed();
111 | r.ReadInt(out this.checksumAdjustment);
112 | r.ReadInt(out this.magicNumber);
113 | r.ReadInt(out this.flags);
114 | r.ReadInt(out this.unitsPerEm);
115 | this.created = r.ReadDate();
116 | this.modified = r.ReadDate();
117 | r.ReadInt(out this.xMin);
118 | r.ReadInt(out this.yMin);
119 | r.ReadInt(out this.xMax);
120 | r.ReadInt(out this.yMax);
121 | r.ReadInt(out this.macStyle);
122 | r.ReadInt(out this.lowestRecPPEM);
123 | r.ReadInt(out this.fontDirectionHint);
124 | r.ReadInt(out this.indexToLocFormat);
125 | r.ReadInt(out this.glyphDataFormat);
126 | }
127 | }
128 | }
--------------------------------------------------------------------------------
/Runtime/Font/Tables/Head.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f9fca748297479c4d8ced97c8d5abf19
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Font/Tables/Loca.cs:
--------------------------------------------------------------------------------
1 | // MIT License
2 | //
3 | // Copyright (c) 2020 Pixel Precision LLC
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | using System.Collections.Generic;
24 |
25 | namespace Voxell.GPUVectorGraphics.Font
26 | {
27 | ///
28 | /// loca — Index to Location
29 | /// https://docs.microsoft.com/en-us/typography/opentype/spec/loca
30 | ///
31 | /// The indexToLoc table stores the offsets to the locations of the glyphs
32 | /// in the font, relative to the beginning of the glyphData table. In order
33 | /// to compute the length of the last glyph element, there is an extra entry
34 | /// after the last valid index.
35 | ///
36 | public struct Loca
37 | {
38 | public const string TagName = "loca";
39 |
40 | // If int16:
41 | // The actual local offset divided by 2 is stored. The value of n
42 | // is numGlyphs + 1. The value for numGlyphs is found in the 'maxp' table.
43 | // If Int32:
44 | // The actual local offset is stored. The value of n is numGlyphs + 1.
45 | // The value for numGlyphs is found in the 'maxp' table.
46 | public List offset;
47 |
48 | public void Read(FontReader r, int numGlyphs, bool longVer)
49 | {
50 | int readCt = numGlyphs + 1;
51 | this.offset = new List();
52 |
53 | if (longVer == false)
54 | {
55 | for (int i = 0; i < readCt; ++i)
56 | this.offset.Add( (uint)(r.ReadUInt16() * 2));
57 | }
58 | else
59 | {
60 | for (int i = 0; i < readCt; ++i)
61 | this.offset.Add( r.ReadUInt32());
62 | }
63 | }
64 |
65 | public int GetGlyphCount() => this.offset.Count - 1;
66 |
67 | public uint GetGlyphSize(int idx) => this.offset[idx + 1] - this.offset[idx];
68 |
69 | public uint GetGlyphOffset(Table tableGlyf, int idx) => tableGlyf.offset + this.offset[idx];
70 | }
71 | }
--------------------------------------------------------------------------------
/Runtime/Font/Tables/Loca.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 653f7c03ac620c349887a162580fb1ef
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Font/Tables/MaxP.cs:
--------------------------------------------------------------------------------
1 | // MIT License
2 | //
3 | // Copyright (c) 2020 Pixel Precision LLC
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | using System.Collections;
24 | using System.Collections.Generic;
25 | using UnityEngine;
26 |
27 | namespace Voxell.GPUVectorGraphics.Font
28 | {
29 | ///
30 | /// maxp — Maximum Profile
31 | /// https://docs.microsoft.com/en-us/typography/opentype/spec/maxp
32 | ///
33 | /// This table establishes the memory requirements for this font. Fonts with CFF
34 | /// data must use Version 0.5 of this table, specifying only the numGlyphs field.
35 | /// Fonts with TrueType outlines must use Version 1.0 of this table, where all
36 | /// data is required.
37 | ///
38 | public struct Maxp
39 | {
40 | public const string TagName = "maxp";
41 |
42 | public ushort majorVersion;
43 | public ushort minorVersion;
44 | public ushort numGlyphs;
45 |
46 | public ushort maxPoints;
47 | public ushort maxCountours;
48 | public ushort maxCompositePoints;
49 | public ushort maxCompositeContours;
50 | public ushort maxZones;
51 | public ushort maxTwilightPoints;
52 | public ushort maxStorage;
53 | public ushort maxFunctionDefs;
54 | public ushort maxIInstructionDefs;
55 | public ushort maxStackElements;
56 | public ushort maxSizeOfInstructions;
57 | public ushort maxComponentElements;
58 | public ushort maxComponentDepth;
59 |
60 | public void Read(FontReader r)
61 | {
62 | r.ReadInt(out this.majorVersion);
63 | r.ReadInt(out this.minorVersion);
64 | r.ReadInt(out this.numGlyphs);
65 |
66 | if (majorVersion == 0) return;
67 |
68 | r.ReadInt(out this.maxPoints);
69 | r.ReadInt(out this.maxCountours);
70 | r.ReadInt(out this.maxCompositePoints);
71 | r.ReadInt(out this.maxCompositeContours);
72 | r.ReadInt(out this.maxTwilightPoints);
73 | r.ReadInt(out this.maxStorage);
74 | r.ReadInt(out this.maxFunctionDefs);
75 | r.ReadInt(out this.maxIInstructionDefs);
76 | r.ReadInt(out this.maxStackElements);
77 | r.ReadInt(out this.maxSizeOfInstructions);
78 | r.ReadInt(out this.maxComponentElements);
79 | r.ReadInt(out this.maxComponentDepth);
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Runtime/Font/Tables/MaxP.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d83af5dedf599eb41ade6f24b6e3549d
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Font/Tables/Table.cs:
--------------------------------------------------------------------------------
1 | namespace Voxell.GPUVectorGraphics.Font
2 | {
3 | [System.Serializable]
4 | public struct Table
5 | {
6 | /// The 4 byte identifier.
7 | public string tag;
8 |
9 | /// The error detection checksum.
10 | public uint checksum;
11 |
12 | /// The offset from the start of the file, where the actual data payload is.
13 | public uint offset;
14 |
15 | /// The size, in bytes, of the data payload.
16 | public uint length;
17 |
18 | /// Read the table from a TTFReader.
19 | /// The reader.
20 | public void Read(FontReader r)
21 | {
22 | this.tag = r.ReadString(4);
23 | r.ReadInt(out this.checksum);
24 | r.ReadInt(out this.offset);
25 | r.ReadInt(out this.length);
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/Runtime/Font/Tables/Table.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d678988eb016f7f49a5ea2a941a6af27
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Font/TypeFace.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace Voxell.GPUVectorGraphics.Font
4 | {
5 | [System.Serializable]
6 | public struct TypeFace
7 | {
8 | [Tooltip("Name of the type face.")]
9 | public string name;
10 |
11 | [Tooltip("Bezier contour for each character.")]
12 | public Glyph[] glyphs;
13 | }
14 | }
--------------------------------------------------------------------------------
/Runtime/Font/TypeFace.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f2a57febe1efbd94ab8798c1990cef28
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/QuadraticBezier.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: ad0a127910db2f84ba2904c88a9f1105
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/VGMath.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 | using Unity.Mathematics;
3 |
4 | namespace Voxell.GPUVectorGraphics
5 | {
6 | internal static class VGMath
7 | {
8 | /// Determines if a point is inside a triangle.
9 | ///
10 | /// https://stackoverflow.com/questions/2049582/how-to-determine-if-a-point-is-in-a-2d-triangle
11 | ///
12 | internal static bool PointInTriangle(float2 p, float2 p0, float2 p1, float2 p2)
13 | {
14 | float d1, d2, d3;
15 | bool hasNeg, hasPos;
16 |
17 | d1 = VertEdgeSign(p, p0, p1);
18 | d2 = VertEdgeSign(p, p1, p2);
19 | d3 = VertEdgeSign(p, p2, p0);
20 |
21 | hasNeg = (d1 < 0.0f) || (d2 < 0.0f) || (d3 < 0.0f);
22 | hasPos = (d1 > 0.0f) || (d2 > 0.0f) || (d3 > 0.0f);
23 |
24 | return !(hasNeg && hasPos);
25 | }
26 |
27 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
28 | internal static float VertEdgeSign(float2 p, float2 p0, float2 p1)
29 | => (p.x - p1.x) * (p0.y - p1.y) - (p0.x - p1.x) * (p.y - p1.y);
30 |
31 | internal static bool LinesIntersect(float2 p1, float2 q1, float2 p2, float2 q2)
32 | {
33 | return (Orientation(p1, q1, p2) != Orientation(p1, q1, q2)
34 | && Orientation(p2, q2, p1) != Orientation(p2, q2, q1));
35 | }
36 |
37 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
38 | internal static int Orientation(float2 p1, float2 p2, float2 p3)
39 | {
40 | float crossProduct = (p2.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p2.x - p1.x);
41 | return (crossProduct < 0.0f) ? -1 : ((crossProduct > 0.0f) ? 1 : 0);
42 | }
43 |
44 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
45 | internal static bool IsClockwise(in float2 p0, in float2 p1, in float2 p2)
46 | {
47 | return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y) < 0.0f;
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/Runtime/VGMath.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: dfa13ecdb4a8b1d41882aad12770ccc3
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/VX.GPUVectorGraphics.Runtime.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "VX.GPUVectorGraphics.Runtime",
3 | "rootNamespace": "",
4 | "references": [
5 | "GUID:d8b63aba1907145bea998dd612889d6b",
6 | "GUID:e0cd26848372d4e5c891c569017e11f1",
7 | "GUID:8a2eafa29b15f444eb6d74f94a930e1d",
8 | "GUID:2665a8d13d1b3f18800f46e256720795",
9 | "GUID:b23efe0d0bd83184681bd63517e3c327"
10 | ],
11 | "includePlatforms": [],
12 | "excludePlatforms": [],
13 | "allowUnsafeCode": false,
14 | "overrideReferences": false,
15 | "precompiledReferences": [],
16 | "autoReferenced": true,
17 | "defineConstraints": [],
18 | "versionDefines": [],
19 | "noEngineReferences": false
20 | }
--------------------------------------------------------------------------------
/Runtime/VX.GPUVectorGraphics.Runtime.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: da829e25e5d77364984881df942d9735
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Shader.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e1263278677204d438e7cfab4e2ba3f2
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Shader/CubicBezier.shadersubgraph:
--------------------------------------------------------------------------------
1 | {
2 | "m_SGVersion": 3,
3 | "m_Type": "UnityEditor.ShaderGraph.GraphData",
4 | "m_ObjectId": "91f4c36ee2c7400da69de5770a04b551",
5 | "m_Properties": [
6 | {
7 | "m_Id": "b74f60ff52314eaf9d500f61acca891d"
8 | }
9 | ],
10 | "m_Keywords": [],
11 | "m_Dropdowns": [],
12 | "m_CategoryData": [
13 | {
14 | "m_Id": "55bdd673903d418fbb2a02c737ce61bc"
15 | }
16 | ],
17 | "m_Nodes": [
18 | {
19 | "m_Id": "dd2ba1bba9e54564a6ec2ac8b267fbd8"
20 | },
21 | {
22 | "m_Id": "b488542ded4b4807a9668cd872b2bbcb"
23 | },
24 | {
25 | "m_Id": "0bdee68fe9864b67b899070bf6a6ca90"
26 | },
27 | {
28 | "m_Id": "faa4cd12c9814b6085e980b39a269ddd"
29 | },
30 | {
31 | "m_Id": "185412b1432e4b1c82d020206ad46f2c"
32 | },
33 | {
34 | "m_Id": "5b9608185e4744b4bde11968a54a41eb"
35 | },
36 | {
37 | "m_Id": "f742d872c3644c91a7e7d0e40377ac4b"
38 | },
39 | {
40 | "m_Id": "f9544d8c79c949e0985fd23aba80a7ae"
41 | }
42 | ],
43 | "m_GroupDatas": [],
44 | "m_StickyNoteDatas": [],
45 | "m_Edges": [
46 | {
47 | "m_OutputSlot": {
48 | "m_Node": {
49 | "m_Id": "0bdee68fe9864b67b899070bf6a6ca90"
50 | },
51 | "m_SlotId": 1
52 | },
53 | "m_InputSlot": {
54 | "m_Node": {
55 | "m_Id": "faa4cd12c9814b6085e980b39a269ddd"
56 | },
57 | "m_SlotId": 0
58 | }
59 | },
60 | {
61 | "m_OutputSlot": {
62 | "m_Node": {
63 | "m_Id": "0bdee68fe9864b67b899070bf6a6ca90"
64 | },
65 | "m_SlotId": 1
66 | },
67 | "m_InputSlot": {
68 | "m_Node": {
69 | "m_Id": "faa4cd12c9814b6085e980b39a269ddd"
70 | },
71 | "m_SlotId": 1
72 | }
73 | },
74 | {
75 | "m_OutputSlot": {
76 | "m_Node": {
77 | "m_Id": "0bdee68fe9864b67b899070bf6a6ca90"
78 | },
79 | "m_SlotId": 2
80 | },
81 | "m_InputSlot": {
82 | "m_Node": {
83 | "m_Id": "f742d872c3644c91a7e7d0e40377ac4b"
84 | },
85 | "m_SlotId": 1
86 | }
87 | },
88 | {
89 | "m_OutputSlot": {
90 | "m_Node": {
91 | "m_Id": "0bdee68fe9864b67b899070bf6a6ca90"
92 | },
93 | "m_SlotId": 3
94 | },
95 | "m_InputSlot": {
96 | "m_Node": {
97 | "m_Id": "5b9608185e4744b4bde11968a54a41eb"
98 | },
99 | "m_SlotId": 1
100 | }
101 | },
102 | {
103 | "m_OutputSlot": {
104 | "m_Node": {
105 | "m_Id": "185412b1432e4b1c82d020206ad46f2c"
106 | },
107 | "m_SlotId": 2
108 | },
109 | "m_InputSlot": {
110 | "m_Node": {
111 | "m_Id": "dd2ba1bba9e54564a6ec2ac8b267fbd8"
112 | },
113 | "m_SlotId": 1
114 | }
115 | },
116 | {
117 | "m_OutputSlot": {
118 | "m_Node": {
119 | "m_Id": "5b9608185e4744b4bde11968a54a41eb"
120 | },
121 | "m_SlotId": 2
122 | },
123 | "m_InputSlot": {
124 | "m_Node": {
125 | "m_Id": "185412b1432e4b1c82d020206ad46f2c"
126 | },
127 | "m_SlotId": 0
128 | }
129 | },
130 | {
131 | "m_OutputSlot": {
132 | "m_Node": {
133 | "m_Id": "b488542ded4b4807a9668cd872b2bbcb"
134 | },
135 | "m_SlotId": 0
136 | },
137 | "m_InputSlot": {
138 | "m_Node": {
139 | "m_Id": "0bdee68fe9864b67b899070bf6a6ca90"
140 | },
141 | "m_SlotId": 0
142 | }
143 | },
144 | {
145 | "m_OutputSlot": {
146 | "m_Node": {
147 | "m_Id": "f742d872c3644c91a7e7d0e40377ac4b"
148 | },
149 | "m_SlotId": 2
150 | },
151 | "m_InputSlot": {
152 | "m_Node": {
153 | "m_Id": "5b9608185e4744b4bde11968a54a41eb"
154 | },
155 | "m_SlotId": 0
156 | }
157 | },
158 | {
159 | "m_OutputSlot": {
160 | "m_Node": {
161 | "m_Id": "f9544d8c79c949e0985fd23aba80a7ae"
162 | },
163 | "m_SlotId": 0
164 | },
165 | "m_InputSlot": {
166 | "m_Node": {
167 | "m_Id": "185412b1432e4b1c82d020206ad46f2c"
168 | },
169 | "m_SlotId": 1
170 | }
171 | },
172 | {
173 | "m_OutputSlot": {
174 | "m_Node": {
175 | "m_Id": "faa4cd12c9814b6085e980b39a269ddd"
176 | },
177 | "m_SlotId": 2
178 | },
179 | "m_InputSlot": {
180 | "m_Node": {
181 | "m_Id": "f742d872c3644c91a7e7d0e40377ac4b"
182 | },
183 | "m_SlotId": 0
184 | }
185 | }
186 | ],
187 | "m_VertexContext": {
188 | "m_Position": {
189 | "x": 0.0,
190 | "y": 0.0
191 | },
192 | "m_Blocks": []
193 | },
194 | "m_FragmentContext": {
195 | "m_Position": {
196 | "x": 0.0,
197 | "y": 0.0
198 | },
199 | "m_Blocks": []
200 | },
201 | "m_PreviewData": {
202 | "serializedMesh": {
203 | "m_SerializedMesh": "{\"mesh\":{\"instanceID\":0}}",
204 | "m_Guid": ""
205 | },
206 | "preventRotation": false
207 | },
208 | "m_Path": "Sub Graphs",
209 | "m_GraphPrecision": 1,
210 | "m_PreviewMode": 2,
211 | "m_OutputNode": {
212 | "m_Id": "dd2ba1bba9e54564a6ec2ac8b267fbd8"
213 | },
214 | "m_ActiveTargets": []
215 | }
216 |
217 | {
218 | "m_SGVersion": 0,
219 | "m_Type": "UnityEditor.ShaderGraph.DynamicValueMaterialSlot",
220 | "m_ObjectId": "07467ea7feda44ceade4aca1fb57bc32",
221 | "m_Id": 0,
222 | "m_DisplayName": "A",
223 | "m_SlotType": 0,
224 | "m_Hidden": false,
225 | "m_ShaderOutputName": "A",
226 | "m_StageCapability": 3,
227 | "m_Value": {
228 | "e00": 0.0,
229 | "e01": 0.0,
230 | "e02": 0.0,
231 | "e03": 0.0,
232 | "e10": 0.0,
233 | "e11": 0.0,
234 | "e12": 0.0,
235 | "e13": 0.0,
236 | "e20": 0.0,
237 | "e21": 0.0,
238 | "e22": 0.0,
239 | "e23": 0.0,
240 | "e30": 0.0,
241 | "e31": 0.0,
242 | "e32": 0.0,
243 | "e33": 0.0
244 | },
245 | "m_DefaultValue": {
246 | "e00": 1.0,
247 | "e01": 0.0,
248 | "e02": 0.0,
249 | "e03": 0.0,
250 | "e10": 0.0,
251 | "e11": 1.0,
252 | "e12": 0.0,
253 | "e13": 0.0,
254 | "e20": 0.0,
255 | "e21": 0.0,
256 | "e22": 1.0,
257 | "e23": 0.0,
258 | "e30": 0.0,
259 | "e31": 0.0,
260 | "e32": 0.0,
261 | "e33": 1.0
262 | }
263 | }
264 |
265 | {
266 | "m_SGVersion": 0,
267 | "m_Type": "UnityEditor.ShaderGraph.DynamicValueMaterialSlot",
268 | "m_ObjectId": "08b49400458d41249bceb741fd8ead60",
269 | "m_Id": 1,
270 | "m_DisplayName": "B",
271 | "m_SlotType": 0,
272 | "m_Hidden": false,
273 | "m_ShaderOutputName": "B",
274 | "m_StageCapability": 3,
275 | "m_Value": {
276 | "e00": 2.0,
277 | "e01": 2.0,
278 | "e02": 2.0,
279 | "e03": 2.0,
280 | "e10": 2.0,
281 | "e11": 2.0,
282 | "e12": 2.0,
283 | "e13": 2.0,
284 | "e20": 2.0,
285 | "e21": 2.0,
286 | "e22": 2.0,
287 | "e23": 2.0,
288 | "e30": 2.0,
289 | "e31": 2.0,
290 | "e32": 2.0,
291 | "e33": 2.0
292 | },
293 | "m_DefaultValue": {
294 | "e00": 1.0,
295 | "e01": 0.0,
296 | "e02": 0.0,
297 | "e03": 0.0,
298 | "e10": 0.0,
299 | "e11": 1.0,
300 | "e12": 0.0,
301 | "e13": 0.0,
302 | "e20": 0.0,
303 | "e21": 0.0,
304 | "e22": 1.0,
305 | "e23": 0.0,
306 | "e30": 0.0,
307 | "e31": 0.0,
308 | "e32": 0.0,
309 | "e33": 1.0
310 | }
311 | }
312 |
313 | {
314 | "m_SGVersion": 0,
315 | "m_Type": "UnityEditor.ShaderGraph.SplitNode",
316 | "m_ObjectId": "0bdee68fe9864b67b899070bf6a6ca90",
317 | "m_Group": {
318 | "m_Id": ""
319 | },
320 | "m_Name": "Split",
321 | "m_DrawState": {
322 | "m_Expanded": false,
323 | "m_Position": {
324 | "serializedVersion": "2",
325 | "x": -107.0,
326 | "y": 0.0,
327 | "width": 120.0,
328 | "height": 125.0
329 | }
330 | },
331 | "m_Slots": [
332 | {
333 | "m_Id": "40f13ec0963c45c4937abd23650aee74"
334 | },
335 | {
336 | "m_Id": "896f1a3ba19b4d7db9a6c9b846d1e8cc"
337 | },
338 | {
339 | "m_Id": "57d09045a0d4458b94cc43a1dd83849a"
340 | },
341 | {
342 | "m_Id": "78dafad169fe4b8eb2751c91405aa6fb"
343 | },
344 | {
345 | "m_Id": "e3a7322b4e94408280104599e55afac6"
346 | }
347 | ],
348 | "synonyms": [
349 | "separate"
350 | ],
351 | "m_Precision": 0,
352 | "m_PreviewExpanded": true,
353 | "m_PreviewMode": 0,
354 | "m_CustomColors": {
355 | "m_SerializableColors": []
356 | }
357 | }
358 |
359 | {
360 | "m_SGVersion": 0,
361 | "m_Type": "UnityEditor.ShaderGraph.MultiplyNode",
362 | "m_ObjectId": "185412b1432e4b1c82d020206ad46f2c",
363 | "m_Group": {
364 | "m_Id": ""
365 | },
366 | "m_Name": "Multiply",
367 | "m_DrawState": {
368 | "m_Expanded": true,
369 | "m_Position": {
370 | "serializedVersion": "2",
371 | "x": 391.0,
372 | "y": 0.0,
373 | "width": 126.0,
374 | "height": 118.0
375 | }
376 | },
377 | "m_Slots": [
378 | {
379 | "m_Id": "07467ea7feda44ceade4aca1fb57bc32"
380 | },
381 | {
382 | "m_Id": "698f7999248043a3adb36f8b2d57a306"
383 | },
384 | {
385 | "m_Id": "ceaa2f3025424970991f1923d1e82c05"
386 | }
387 | ],
388 | "synonyms": [
389 | "multiplication",
390 | "times",
391 | "x"
392 | ],
393 | "m_Precision": 0,
394 | "m_PreviewExpanded": false,
395 | "m_PreviewMode": 0,
396 | "m_CustomColors": {
397 | "m_SerializableColors": []
398 | }
399 | }
400 |
401 | {
402 | "m_SGVersion": 0,
403 | "m_Type": "UnityEditor.ShaderGraph.DynamicVectorMaterialSlot",
404 | "m_ObjectId": "3fde0b7067d845198b86fe7096dc76bc",
405 | "m_Id": 0,
406 | "m_DisplayName": "A",
407 | "m_SlotType": 0,
408 | "m_Hidden": false,
409 | "m_ShaderOutputName": "A",
410 | "m_StageCapability": 3,
411 | "m_Value": {
412 | "x": 1.0,
413 | "y": 1.0,
414 | "z": 1.0,
415 | "w": 1.0
416 | },
417 | "m_DefaultValue": {
418 | "x": 0.0,
419 | "y": 0.0,
420 | "z": 0.0,
421 | "w": 0.0
422 | }
423 | }
424 |
425 | {
426 | "m_SGVersion": 0,
427 | "m_Type": "UnityEditor.ShaderGraph.DynamicVectorMaterialSlot",
428 | "m_ObjectId": "40f13ec0963c45c4937abd23650aee74",
429 | "m_Id": 0,
430 | "m_DisplayName": "In",
431 | "m_SlotType": 0,
432 | "m_Hidden": false,
433 | "m_ShaderOutputName": "In",
434 | "m_StageCapability": 3,
435 | "m_Value": {
436 | "x": 0.0,
437 | "y": 0.0,
438 | "z": 0.0,
439 | "w": 0.0
440 | },
441 | "m_DefaultValue": {
442 | "x": 0.0,
443 | "y": 0.0,
444 | "z": 0.0,
445 | "w": 0.0
446 | }
447 | }
448 |
449 | {
450 | "m_SGVersion": 0,
451 | "m_Type": "UnityEditor.ShaderGraph.DynamicVectorMaterialSlot",
452 | "m_ObjectId": "462e0d8c5bca4d7bb89e85d1ca15c5ae",
453 | "m_Id": 1,
454 | "m_DisplayName": "B",
455 | "m_SlotType": 0,
456 | "m_Hidden": false,
457 | "m_ShaderOutputName": "B",
458 | "m_StageCapability": 3,
459 | "m_Value": {
460 | "x": 1.0,
461 | "y": 1.0,
462 | "z": 1.0,
463 | "w": 1.0
464 | },
465 | "m_DefaultValue": {
466 | "x": 0.0,
467 | "y": 0.0,
468 | "z": 0.0,
469 | "w": 0.0
470 | }
471 | }
472 |
473 | {
474 | "m_SGVersion": 0,
475 | "m_Type": "UnityEditor.ShaderGraph.CategoryData",
476 | "m_ObjectId": "55bdd673903d418fbb2a02c737ce61bc",
477 | "m_Name": "",
478 | "m_ChildObjectList": [
479 | {
480 | "m_Id": "b74f60ff52314eaf9d500f61acca891d"
481 | }
482 | ]
483 | }
484 |
485 | {
486 | "m_SGVersion": 0,
487 | "m_Type": "UnityEditor.ShaderGraph.DynamicVectorMaterialSlot",
488 | "m_ObjectId": "5623051ea6094598a798d302a4fbca20",
489 | "m_Id": 2,
490 | "m_DisplayName": "Out",
491 | "m_SlotType": 1,
492 | "m_Hidden": false,
493 | "m_ShaderOutputName": "Out",
494 | "m_StageCapability": 3,
495 | "m_Value": {
496 | "x": 0.0,
497 | "y": 0.0,
498 | "z": 0.0,
499 | "w": 0.0
500 | },
501 | "m_DefaultValue": {
502 | "x": 0.0,
503 | "y": 0.0,
504 | "z": 0.0,
505 | "w": 0.0
506 | }
507 | }
508 |
509 | {
510 | "m_SGVersion": 0,
511 | "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
512 | "m_ObjectId": "57d09045a0d4458b94cc43a1dd83849a",
513 | "m_Id": 2,
514 | "m_DisplayName": "G",
515 | "m_SlotType": 1,
516 | "m_Hidden": false,
517 | "m_ShaderOutputName": "G",
518 | "m_StageCapability": 3,
519 | "m_Value": 0.0,
520 | "m_DefaultValue": 0.0,
521 | "m_Labels": []
522 | }
523 |
524 | {
525 | "m_SGVersion": 0,
526 | "m_Type": "UnityEditor.ShaderGraph.MultiplyNode",
527 | "m_ObjectId": "5b9608185e4744b4bde11968a54a41eb",
528 | "m_Group": {
529 | "m_Id": ""
530 | },
531 | "m_Name": "Multiply",
532 | "m_DrawState": {
533 | "m_Expanded": true,
534 | "m_Position": {
535 | "serializedVersion": "2",
536 | "x": 265.0,
537 | "y": 0.0,
538 | "width": 126.0,
539 | "height": 118.0
540 | }
541 | },
542 | "m_Slots": [
543 | {
544 | "m_Id": "7f983f0255cd4c759f961f772e933ed6"
545 | },
546 | {
547 | "m_Id": "08b49400458d41249bceb741fd8ead60"
548 | },
549 | {
550 | "m_Id": "c1c025b47abe498cadd08fefb4e4236f"
551 | }
552 | ],
553 | "synonyms": [
554 | "multiplication",
555 | "times",
556 | "x"
557 | ],
558 | "m_Precision": 0,
559 | "m_PreviewExpanded": false,
560 | "m_PreviewMode": 0,
561 | "m_CustomColors": {
562 | "m_SerializableColors": []
563 | }
564 | }
565 |
566 | {
567 | "m_SGVersion": 0,
568 | "m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot",
569 | "m_ObjectId": "698f1e732a9d4a4ba2af85fb8f6d9dfc",
570 | "m_Id": 0,
571 | "m_DisplayName": "Out",
572 | "m_SlotType": 1,
573 | "m_Hidden": false,
574 | "m_ShaderOutputName": "Out",
575 | "m_StageCapability": 3,
576 | "m_Value": {
577 | "x": 0.0,
578 | "y": 0.0,
579 | "z": 0.0,
580 | "w": 0.0
581 | },
582 | "m_DefaultValue": {
583 | "x": 0.0,
584 | "y": 0.0,
585 | "z": 0.0,
586 | "w": 0.0
587 | },
588 | "m_Labels": []
589 | }
590 |
591 | {
592 | "m_SGVersion": 0,
593 | "m_Type": "UnityEditor.ShaderGraph.DynamicValueMaterialSlot",
594 | "m_ObjectId": "698f7999248043a3adb36f8b2d57a306",
595 | "m_Id": 1,
596 | "m_DisplayName": "B",
597 | "m_SlotType": 0,
598 | "m_Hidden": false,
599 | "m_ShaderOutputName": "B",
600 | "m_StageCapability": 3,
601 | "m_Value": {
602 | "e00": 2.0,
603 | "e01": 2.0,
604 | "e02": 2.0,
605 | "e03": 2.0,
606 | "e10": 2.0,
607 | "e11": 2.0,
608 | "e12": 2.0,
609 | "e13": 2.0,
610 | "e20": 2.0,
611 | "e21": 2.0,
612 | "e22": 2.0,
613 | "e23": 2.0,
614 | "e30": 2.0,
615 | "e31": 2.0,
616 | "e32": 2.0,
617 | "e33": 2.0
618 | },
619 | "m_DefaultValue": {
620 | "e00": 1.0,
621 | "e01": 0.0,
622 | "e02": 0.0,
623 | "e03": 0.0,
624 | "e10": 0.0,
625 | "e11": 1.0,
626 | "e12": 0.0,
627 | "e13": 0.0,
628 | "e20": 0.0,
629 | "e21": 0.0,
630 | "e22": 1.0,
631 | "e23": 0.0,
632 | "e30": 0.0,
633 | "e31": 0.0,
634 | "e32": 0.0,
635 | "e33": 1.0
636 | }
637 | }
638 |
639 | {
640 | "m_SGVersion": 0,
641 | "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
642 | "m_ObjectId": "78dafad169fe4b8eb2751c91405aa6fb",
643 | "m_Id": 3,
644 | "m_DisplayName": "B",
645 | "m_SlotType": 1,
646 | "m_Hidden": false,
647 | "m_ShaderOutputName": "B",
648 | "m_StageCapability": 3,
649 | "m_Value": 0.0,
650 | "m_DefaultValue": 0.0,
651 | "m_Labels": []
652 | }
653 |
654 | {
655 | "m_SGVersion": 0,
656 | "m_Type": "UnityEditor.ShaderGraph.DynamicValueMaterialSlot",
657 | "m_ObjectId": "7f983f0255cd4c759f961f772e933ed6",
658 | "m_Id": 0,
659 | "m_DisplayName": "A",
660 | "m_SlotType": 0,
661 | "m_Hidden": false,
662 | "m_ShaderOutputName": "A",
663 | "m_StageCapability": 3,
664 | "m_Value": {
665 | "e00": 0.0,
666 | "e01": 0.0,
667 | "e02": 0.0,
668 | "e03": 0.0,
669 | "e10": 0.0,
670 | "e11": 0.0,
671 | "e12": 0.0,
672 | "e13": 0.0,
673 | "e20": 0.0,
674 | "e21": 0.0,
675 | "e22": 0.0,
676 | "e23": 0.0,
677 | "e30": 0.0,
678 | "e31": 0.0,
679 | "e32": 0.0,
680 | "e33": 0.0
681 | },
682 | "m_DefaultValue": {
683 | "e00": 1.0,
684 | "e01": 0.0,
685 | "e02": 0.0,
686 | "e03": 0.0,
687 | "e10": 0.0,
688 | "e11": 1.0,
689 | "e12": 0.0,
690 | "e13": 0.0,
691 | "e20": 0.0,
692 | "e21": 0.0,
693 | "e22": 1.0,
694 | "e23": 0.0,
695 | "e30": 0.0,
696 | "e31": 0.0,
697 | "e32": 0.0,
698 | "e33": 1.0
699 | }
700 | }
701 |
702 | {
703 | "m_SGVersion": 0,
704 | "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
705 | "m_ObjectId": "896f1a3ba19b4d7db9a6c9b846d1e8cc",
706 | "m_Id": 1,
707 | "m_DisplayName": "R",
708 | "m_SlotType": 1,
709 | "m_Hidden": false,
710 | "m_ShaderOutputName": "R",
711 | "m_StageCapability": 3,
712 | "m_Value": 0.0,
713 | "m_DefaultValue": 0.0,
714 | "m_Labels": []
715 | }
716 |
717 | {
718 | "m_SGVersion": 0,
719 | "m_Type": "UnityEditor.ShaderGraph.DynamicValueMaterialSlot",
720 | "m_ObjectId": "b1bc7f5858ea4eb8ab5cd007c8f30439",
721 | "m_Id": 0,
722 | "m_DisplayName": "A",
723 | "m_SlotType": 0,
724 | "m_Hidden": false,
725 | "m_ShaderOutputName": "A",
726 | "m_StageCapability": 3,
727 | "m_Value": {
728 | "e00": 0.0,
729 | "e01": 0.0,
730 | "e02": 0.0,
731 | "e03": 0.0,
732 | "e10": 0.0,
733 | "e11": 0.0,
734 | "e12": 0.0,
735 | "e13": 0.0,
736 | "e20": 0.0,
737 | "e21": 0.0,
738 | "e22": 0.0,
739 | "e23": 0.0,
740 | "e30": 0.0,
741 | "e31": 0.0,
742 | "e32": 0.0,
743 | "e33": 0.0
744 | },
745 | "m_DefaultValue": {
746 | "e00": 1.0,
747 | "e01": 0.0,
748 | "e02": 0.0,
749 | "e03": 0.0,
750 | "e10": 0.0,
751 | "e11": 1.0,
752 | "e12": 0.0,
753 | "e13": 0.0,
754 | "e20": 0.0,
755 | "e21": 0.0,
756 | "e22": 1.0,
757 | "e23": 0.0,
758 | "e30": 0.0,
759 | "e31": 0.0,
760 | "e32": 0.0,
761 | "e33": 1.0
762 | }
763 | }
764 |
765 | {
766 | "m_SGVersion": 0,
767 | "m_Type": "UnityEditor.ShaderGraph.UVNode",
768 | "m_ObjectId": "b488542ded4b4807a9668cd872b2bbcb",
769 | "m_Group": {
770 | "m_Id": ""
771 | },
772 | "m_Name": "UV",
773 | "m_DrawState": {
774 | "m_Expanded": true,
775 | "m_Position": {
776 | "serializedVersion": "2",
777 | "x": -252.0,
778 | "y": 0.0,
779 | "width": 145.0,
780 | "height": 129.0
781 | }
782 | },
783 | "m_Slots": [
784 | {
785 | "m_Id": "698f1e732a9d4a4ba2af85fb8f6d9dfc"
786 | }
787 | ],
788 | "synonyms": [
789 | "texcoords",
790 | "coords",
791 | "coordinates"
792 | ],
793 | "m_Precision": 0,
794 | "m_PreviewExpanded": false,
795 | "m_PreviewMode": 0,
796 | "m_CustomColors": {
797 | "m_SerializableColors": []
798 | },
799 | "m_OutputChannel": 0
800 | }
801 |
802 | {
803 | "m_SGVersion": 1,
804 | "m_Type": "UnityEditor.ShaderGraph.Internal.Vector1ShaderProperty",
805 | "m_ObjectId": "b74f60ff52314eaf9d500f61acca891d",
806 | "m_Guid": {
807 | "m_GuidSerialized": "4fefd862-66e8-4ef1-bf1d-544b20b77d96"
808 | },
809 | "m_Name": "Alpha",
810 | "m_DefaultRefNameVersion": 1,
811 | "m_RefNameGeneratedByDisplayName": "Alpha",
812 | "m_DefaultReferenceName": "_Alpha",
813 | "m_OverrideReferenceName": "",
814 | "m_GeneratePropertyBlock": true,
815 | "m_UseCustomSlotLabel": false,
816 | "m_CustomSlotLabel": "",
817 | "m_Precision": 0,
818 | "overrideHLSLDeclaration": false,
819 | "hlslDeclarationOverride": 0,
820 | "m_Hidden": false,
821 | "m_Value": 1.0,
822 | "m_FloatType": 0,
823 | "m_RangeValues": {
824 | "x": 0.0,
825 | "y": 1.0
826 | }
827 | }
828 |
829 | {
830 | "m_SGVersion": 0,
831 | "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
832 | "m_ObjectId": "bebd62eebdb1471da638e542d2772058",
833 | "m_Id": 1,
834 | "m_DisplayName": "Alpha",
835 | "m_SlotType": 0,
836 | "m_Hidden": false,
837 | "m_ShaderOutputName": "Alpha",
838 | "m_StageCapability": 3,
839 | "m_Value": 0.0,
840 | "m_DefaultValue": 0.0,
841 | "m_Labels": []
842 | }
843 |
844 | {
845 | "m_SGVersion": 0,
846 | "m_Type": "UnityEditor.ShaderGraph.DynamicValueMaterialSlot",
847 | "m_ObjectId": "c1c025b47abe498cadd08fefb4e4236f",
848 | "m_Id": 2,
849 | "m_DisplayName": "Out",
850 | "m_SlotType": 1,
851 | "m_Hidden": false,
852 | "m_ShaderOutputName": "Out",
853 | "m_StageCapability": 3,
854 | "m_Value": {
855 | "e00": 0.0,
856 | "e01": 0.0,
857 | "e02": 0.0,
858 | "e03": 0.0,
859 | "e10": 0.0,
860 | "e11": 0.0,
861 | "e12": 0.0,
862 | "e13": 0.0,
863 | "e20": 0.0,
864 | "e21": 0.0,
865 | "e22": 0.0,
866 | "e23": 0.0,
867 | "e30": 0.0,
868 | "e31": 0.0,
869 | "e32": 0.0,
870 | "e33": 0.0
871 | },
872 | "m_DefaultValue": {
873 | "e00": 1.0,
874 | "e01": 0.0,
875 | "e02": 0.0,
876 | "e03": 0.0,
877 | "e10": 0.0,
878 | "e11": 1.0,
879 | "e12": 0.0,
880 | "e13": 0.0,
881 | "e20": 0.0,
882 | "e21": 0.0,
883 | "e22": 1.0,
884 | "e23": 0.0,
885 | "e30": 0.0,
886 | "e31": 0.0,
887 | "e32": 0.0,
888 | "e33": 1.0
889 | }
890 | }
891 |
892 | {
893 | "m_SGVersion": 0,
894 | "m_Type": "UnityEditor.ShaderGraph.DynamicValueMaterialSlot",
895 | "m_ObjectId": "ceaa2f3025424970991f1923d1e82c05",
896 | "m_Id": 2,
897 | "m_DisplayName": "Out",
898 | "m_SlotType": 1,
899 | "m_Hidden": false,
900 | "m_ShaderOutputName": "Out",
901 | "m_StageCapability": 3,
902 | "m_Value": {
903 | "e00": 0.0,
904 | "e01": 0.0,
905 | "e02": 0.0,
906 | "e03": 0.0,
907 | "e10": 0.0,
908 | "e11": 0.0,
909 | "e12": 0.0,
910 | "e13": 0.0,
911 | "e20": 0.0,
912 | "e21": 0.0,
913 | "e22": 0.0,
914 | "e23": 0.0,
915 | "e30": 0.0,
916 | "e31": 0.0,
917 | "e32": 0.0,
918 | "e33": 0.0
919 | },
920 | "m_DefaultValue": {
921 | "e00": 1.0,
922 | "e01": 0.0,
923 | "e02": 0.0,
924 | "e03": 0.0,
925 | "e10": 0.0,
926 | "e11": 1.0,
927 | "e12": 0.0,
928 | "e13": 0.0,
929 | "e20": 0.0,
930 | "e21": 0.0,
931 | "e22": 1.0,
932 | "e23": 0.0,
933 | "e30": 0.0,
934 | "e31": 0.0,
935 | "e32": 0.0,
936 | "e33": 1.0
937 | }
938 | }
939 |
940 | {
941 | "m_SGVersion": 0,
942 | "m_Type": "UnityEditor.ShaderGraph.DynamicValueMaterialSlot",
943 | "m_ObjectId": "d3b61112276241ce829ae62b77cf259d",
944 | "m_Id": 1,
945 | "m_DisplayName": "B",
946 | "m_SlotType": 0,
947 | "m_Hidden": false,
948 | "m_ShaderOutputName": "B",
949 | "m_StageCapability": 3,
950 | "m_Value": {
951 | "e00": 2.0,
952 | "e01": 2.0,
953 | "e02": 2.0,
954 | "e03": 2.0,
955 | "e10": 2.0,
956 | "e11": 2.0,
957 | "e12": 2.0,
958 | "e13": 2.0,
959 | "e20": 2.0,
960 | "e21": 2.0,
961 | "e22": 2.0,
962 | "e23": 2.0,
963 | "e30": 2.0,
964 | "e31": 2.0,
965 | "e32": 2.0,
966 | "e33": 2.0
967 | },
968 | "m_DefaultValue": {
969 | "e00": 1.0,
970 | "e01": 0.0,
971 | "e02": 0.0,
972 | "e03": 0.0,
973 | "e10": 0.0,
974 | "e11": 1.0,
975 | "e12": 0.0,
976 | "e13": 0.0,
977 | "e20": 0.0,
978 | "e21": 0.0,
979 | "e22": 1.0,
980 | "e23": 0.0,
981 | "e30": 0.0,
982 | "e31": 0.0,
983 | "e32": 0.0,
984 | "e33": 1.0
985 | }
986 | }
987 |
988 | {
989 | "m_SGVersion": 0,
990 | "m_Type": "UnityEditor.ShaderGraph.SubGraphOutputNode",
991 | "m_ObjectId": "dd2ba1bba9e54564a6ec2ac8b267fbd8",
992 | "m_Group": {
993 | "m_Id": ""
994 | },
995 | "m_Name": "Output",
996 | "m_DrawState": {
997 | "m_Expanded": true,
998 | "m_Position": {
999 | "serializedVersion": "2",
1000 | "x": 516.7500610351563,
1001 | "y": 0.0,
1002 | "width": 0.0,
1003 | "height": 0.0
1004 | }
1005 | },
1006 | "m_Slots": [
1007 | {
1008 | "m_Id": "bebd62eebdb1471da638e542d2772058"
1009 | }
1010 | ],
1011 | "synonyms": [],
1012 | "m_Precision": 0,
1013 | "m_PreviewExpanded": true,
1014 | "m_PreviewMode": 0,
1015 | "m_CustomColors": {
1016 | "m_SerializableColors": []
1017 | },
1018 | "IsFirstSlotValid": true
1019 | }
1020 |
1021 | {
1022 | "m_SGVersion": 0,
1023 | "m_Type": "UnityEditor.ShaderGraph.DynamicValueMaterialSlot",
1024 | "m_ObjectId": "e1568262f8964046b25c1350762b5e93",
1025 | "m_Id": 2,
1026 | "m_DisplayName": "Out",
1027 | "m_SlotType": 1,
1028 | "m_Hidden": false,
1029 | "m_ShaderOutputName": "Out",
1030 | "m_StageCapability": 3,
1031 | "m_Value": {
1032 | "e00": 0.0,
1033 | "e01": 0.0,
1034 | "e02": 0.0,
1035 | "e03": 0.0,
1036 | "e10": 0.0,
1037 | "e11": 0.0,
1038 | "e12": 0.0,
1039 | "e13": 0.0,
1040 | "e20": 0.0,
1041 | "e21": 0.0,
1042 | "e22": 0.0,
1043 | "e23": 0.0,
1044 | "e30": 0.0,
1045 | "e31": 0.0,
1046 | "e32": 0.0,
1047 | "e33": 0.0
1048 | },
1049 | "m_DefaultValue": {
1050 | "e00": 1.0,
1051 | "e01": 0.0,
1052 | "e02": 0.0,
1053 | "e03": 0.0,
1054 | "e10": 0.0,
1055 | "e11": 1.0,
1056 | "e12": 0.0,
1057 | "e13": 0.0,
1058 | "e20": 0.0,
1059 | "e21": 0.0,
1060 | "e22": 1.0,
1061 | "e23": 0.0,
1062 | "e30": 0.0,
1063 | "e31": 0.0,
1064 | "e32": 0.0,
1065 | "e33": 1.0
1066 | }
1067 | }
1068 |
1069 | {
1070 | "m_SGVersion": 0,
1071 | "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
1072 | "m_ObjectId": "e3a7322b4e94408280104599e55afac6",
1073 | "m_Id": 4,
1074 | "m_DisplayName": "A",
1075 | "m_SlotType": 1,
1076 | "m_Hidden": false,
1077 | "m_ShaderOutputName": "A",
1078 | "m_StageCapability": 3,
1079 | "m_Value": 0.0,
1080 | "m_DefaultValue": 0.0,
1081 | "m_Labels": []
1082 | }
1083 |
1084 | {
1085 | "m_SGVersion": 0,
1086 | "m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
1087 | "m_ObjectId": "e836becdc5364c7d8ddb4a8c279bccc9",
1088 | "m_Id": 0,
1089 | "m_DisplayName": "Alpha",
1090 | "m_SlotType": 1,
1091 | "m_Hidden": false,
1092 | "m_ShaderOutputName": "Out",
1093 | "m_StageCapability": 3,
1094 | "m_Value": 0.0,
1095 | "m_DefaultValue": 0.0,
1096 | "m_Labels": []
1097 | }
1098 |
1099 | {
1100 | "m_SGVersion": 0,
1101 | "m_Type": "UnityEditor.ShaderGraph.SubtractNode",
1102 | "m_ObjectId": "f742d872c3644c91a7e7d0e40377ac4b",
1103 | "m_Group": {
1104 | "m_Id": ""
1105 | },
1106 | "m_Name": "Subtract",
1107 | "m_DrawState": {
1108 | "m_Expanded": true,
1109 | "m_Position": {
1110 | "serializedVersion": "2",
1111 | "x": 139.0,
1112 | "y": 0.0,
1113 | "width": 126.0,
1114 | "height": 118.0
1115 | }
1116 | },
1117 | "m_Slots": [
1118 | {
1119 | "m_Id": "3fde0b7067d845198b86fe7096dc76bc"
1120 | },
1121 | {
1122 | "m_Id": "462e0d8c5bca4d7bb89e85d1ca15c5ae"
1123 | },
1124 | {
1125 | "m_Id": "5623051ea6094598a798d302a4fbca20"
1126 | }
1127 | ],
1128 | "synonyms": [
1129 | "subtraction",
1130 | "remove",
1131 | "minus",
1132 | "take away"
1133 | ],
1134 | "m_Precision": 0,
1135 | "m_PreviewExpanded": false,
1136 | "m_PreviewMode": 0,
1137 | "m_CustomColors": {
1138 | "m_SerializableColors": []
1139 | }
1140 | }
1141 |
1142 | {
1143 | "m_SGVersion": 0,
1144 | "m_Type": "UnityEditor.ShaderGraph.PropertyNode",
1145 | "m_ObjectId": "f9544d8c79c949e0985fd23aba80a7ae",
1146 | "m_Group": {
1147 | "m_Id": ""
1148 | },
1149 | "m_Name": "Property",
1150 | "m_DrawState": {
1151 | "m_Expanded": true,
1152 | "m_Position": {
1153 | "serializedVersion": "2",
1154 | "x": 286.0,
1155 | "y": -34.0,
1156 | "width": 105.0,
1157 | "height": 34.0
1158 | }
1159 | },
1160 | "m_Slots": [
1161 | {
1162 | "m_Id": "e836becdc5364c7d8ddb4a8c279bccc9"
1163 | }
1164 | ],
1165 | "synonyms": [],
1166 | "m_Precision": 0,
1167 | "m_PreviewExpanded": true,
1168 | "m_PreviewMode": 0,
1169 | "m_CustomColors": {
1170 | "m_SerializableColors": []
1171 | },
1172 | "m_Property": {
1173 | "m_Id": "b74f60ff52314eaf9d500f61acca891d"
1174 | }
1175 | }
1176 |
1177 | {
1178 | "m_SGVersion": 0,
1179 | "m_Type": "UnityEditor.ShaderGraph.MultiplyNode",
1180 | "m_ObjectId": "faa4cd12c9814b6085e980b39a269ddd",
1181 | "m_Group": {
1182 | "m_Id": ""
1183 | },
1184 | "m_Name": "Multiply",
1185 | "m_DrawState": {
1186 | "m_Expanded": true,
1187 | "m_Position": {
1188 | "serializedVersion": "2",
1189 | "x": 13.0,
1190 | "y": 0.0,
1191 | "width": 126.0,
1192 | "height": 118.0
1193 | }
1194 | },
1195 | "m_Slots": [
1196 | {
1197 | "m_Id": "b1bc7f5858ea4eb8ab5cd007c8f30439"
1198 | },
1199 | {
1200 | "m_Id": "d3b61112276241ce829ae62b77cf259d"
1201 | },
1202 | {
1203 | "m_Id": "e1568262f8964046b25c1350762b5e93"
1204 | }
1205 | ],
1206 | "synonyms": [
1207 | "multiplication",
1208 | "times",
1209 | "x"
1210 | ],
1211 | "m_Precision": 0,
1212 | "m_PreviewExpanded": false,
1213 | "m_PreviewMode": 0,
1214 | "m_CustomColors": {
1215 | "m_SerializableColors": []
1216 | }
1217 | }
1218 |
1219 |
--------------------------------------------------------------------------------
/Shader/CubicBezier.shadersubgraph.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 5851c76176f347c4e823f89e7146f4f2
3 | ScriptedImporter:
4 | internalIDToNameTable: []
5 | externalObjects: {}
6 | serializedVersion: 2
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 | script: {fileID: 11500000, guid: 60072b568d64c40a485e0fc55012dc9f, type: 3}
11 |
--------------------------------------------------------------------------------
/Shader/CubicBezierCurve.shader:
--------------------------------------------------------------------------------
1 | Shader "Unlit/Cubic Bezier"
2 | {
3 | Properties
4 | {
5 | [HDR] _Color("Color", Color) = (0, 1, 1, 1)
6 | _StrokeThickness("Stroke Thickness", Float) = 10
7 | }
8 | SubShader
9 | {
10 | Tags { "RenderType"="Opaque" }
11 | LOD 100
12 | Cull Off
13 |
14 | Pass
15 | {
16 | CGPROGRAM
17 | #pragma vertex vert
18 | #pragma fragment frag
19 |
20 | #include "UnityCG.cginc"
21 |
22 | struct appdata
23 | {
24 | float4 vertex : POSITION;
25 | float3 uv : TEXCOORD0;
26 | };
27 |
28 | struct v2f
29 | {
30 | float3 uv : TEXCOORD0;
31 | float4 vertex : SV_POSITION;
32 | };
33 |
34 | v2f vert (appdata v)
35 | {
36 | v2f o;
37 | o.vertex = UnityObjectToClipPos(v.vertex);
38 | o.uv = v.uv;
39 | return o;
40 | }
41 |
42 | uniform half4 _Color;
43 | uniform float _StrokeThickness;
44 |
45 | half4 frag (v2f i) : SV_Target
46 | {
47 | float3 uv = i.uv;
48 | float alpha = uv.x * uv.x * uv.x - uv.y * uv.z;
49 |
50 | clip(alpha);
51 | return _Color;
52 | }
53 | ENDCG
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Shader/CubicBezierCurve.shader.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b00b4fa244cbb114aa30764ae9f34fa6
3 | ShaderImporter:
4 | externalObjects: {}
5 | defaultTextures: []
6 | nonModifiableTextures: []
7 | preprocessorOverride: 0
8 | userData:
9 | assetBundleName:
10 | assetBundleVariant:
11 |
--------------------------------------------------------------------------------
/Shader/QuadraticBezier.shadersubgraph.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 1d26a66ae7642f1428436d60439cd4f5
3 | ScriptedImporter:
4 | internalIDToNameTable: []
5 | externalObjects: {}
6 | serializedVersion: 2
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 | script: {fileID: 11500000, guid: 60072b568d64c40a485e0fc55012dc9f, type: 3}
11 |
--------------------------------------------------------------------------------
/Shader/QuadraticBezierCurve.shader:
--------------------------------------------------------------------------------
1 | Shader "Unlit/Quadratic Bezier"
2 | {
3 | Properties
4 | {
5 | [HDR] _Color("Color", Color) = (0, 1, 1, 1)
6 | _StrokeThickness("Stroke Thickness", Float) = 10
7 | }
8 | SubShader
9 | {
10 | Tags { "RenderType"="Opaque" }
11 | LOD 100
12 | Cull Off
13 |
14 | Pass
15 | {
16 | CGPROGRAM
17 | #pragma vertex vert
18 | #pragma fragment frag
19 |
20 | #include "UnityCG.cginc"
21 |
22 | struct appdata
23 | {
24 | float4 vertex : POSITION;
25 | float3 uv : TEXCOORD0;
26 | };
27 |
28 | struct v2f
29 | {
30 | float3 uv : TEXCOORD0;
31 | float4 vertex : SV_POSITION;
32 | };
33 |
34 | v2f vert (appdata v)
35 | {
36 | v2f o;
37 | o.vertex = UnityObjectToClipPos(v.vertex);
38 | o.uv = v.uv;
39 | return o;
40 | }
41 |
42 | uniform half4 _Color;
43 | uniform float _StrokeThickness;
44 |
45 | half4 frag (v2f i) : SV_Target
46 | {
47 | float3 uv = i.uv;
48 | float alpha = (uv.x * uv.x - uv.y) * uv.z;
49 |
50 | clip(alpha);
51 | return _Color;
52 | }
53 | ENDCG
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Shader/QuadraticBezierCurve.shader.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 9f0a860722379f9479b1c3bfdea3dc76
3 | ShaderImporter:
4 | externalObjects: {}
5 | defaultTextures: []
6 | nonModifiableTextures: []
7 | preprocessorOverride: 0
8 | userData:
9 | assetBundleName:
10 | assetBundleVariant:
11 |
--------------------------------------------------------------------------------
/Shader/SimpleLitQuadraticBezier.shadergraph.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 1a1e6f47ca0ec4b43a804d8194ed560b
3 | ScriptedImporter:
4 | internalIDToNameTable: []
5 | externalObjects: {}
6 | serializedVersion: 2
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 | script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3}
11 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "voxell.vectorgraphics",
3 | "displayName": "VX GPU Vector Graphics",
4 | "author": "Nixon",
5 | "description": "Generating vector graphics using the power of GPU.",
6 | "keywords": [
7 | "vector",
8 | "graphics",
9 | "voxell"
10 | ],
11 | "license": "Apache 2.0",
12 | "unity": "2020.4",
13 | "unityRelease": "0f1",
14 | "version": "0.3.3-alpha",
15 | "dependencies": {
16 | "com.unity.mathematics": "1.2.5",
17 | "com.unity.collections": "1.2.3",
18 | "com.unity.jobs": "0.11.0-preview.6",
19 | "com.unity.burst": "1.6.5",
20 | "voxell.util": "1.4.0"
21 | },
22 | "hideInEditor": false
23 | }
--------------------------------------------------------------------------------
/package.json.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 636b3ed634303e248903415943533c89
3 | PackageManifestImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------