├── .gitignore
├── .vs
└── UnityVectorEditor
│ └── xs
│ └── sqlite3
│ └── storage.ide
├── Assembly-CSharp-Editor.csproj
├── Assembly-CSharp.csproj
├── Assets
├── Scenes.meta
├── Scenes
│ ├── SampleScene.unity
│ ├── SampleScene.unity.meta
│ ├── SampleShape.asset
│ ├── SampleShape.asset.meta
│ ├── SampleShapeUser.cs
│ └── SampleShapeUser.cs.meta
├── VectorShapes.meta
└── VectorShapes
│ ├── CircleShape.cs
│ ├── CircleShape.cs.meta
│ ├── CompoundShape.cs
│ ├── CompoundShape.cs.meta
│ ├── Editor.meta
│ ├── Editor
│ ├── SerializedShapeDrawer.cs
│ ├── SerializedShapeDrawer.cs.meta
│ ├── SingleSelectionPopup.cs
│ ├── SingleSelectionPopup.cs.meta
│ ├── VectorShapeEditor.cs
│ └── VectorShapeEditor.cs.meta
│ ├── EllipseShape.cs
│ ├── EllipseShape.cs.meta
│ ├── PointShape.cs
│ ├── PointShape.cs.meta
│ ├── PolyShape.cs
│ ├── PolyShape.cs.meta
│ ├── SerializedShape.cs
│ ├── SerializedShape.cs.meta
│ ├── Shader.meta
│ ├── Shader
│ ├── VectorLineMeshBuilder.cs
│ ├── VectorLineMeshBuilder.cs.meta
│ ├── VectorLineShader.shader
│ └── VectorLineShader.shader.meta
│ ├── TextShape.cs
│ ├── TextShape.cs.meta
│ ├── VectorShape.cs
│ ├── VectorShape.cs.meta
│ ├── VectorShapeFIlesDXF.cs
│ ├── VectorShapeFIlesDXF.cs.meta
│ ├── VectorShapeFilesSVG.cs
│ ├── VectorShapeFilesSVG.cs.meta
│ ├── VectorShapeIcons.cs
│ ├── VectorShapeIcons.cs.meta
│ ├── VectorShapeUtils.cs
│ └── VectorShapeUtils.cs.meta
├── LICENSE
├── PREVIEW.png
├── Packages
└── manifest.json
├── ProjectSettings
└── ProjectSettings.asset
├── README.md
└── UnityVectorEditor.sln
/.gitignore:
--------------------------------------------------------------------------------
1 | Library
2 | Temp
3 | ProjectSettings
4 |
--------------------------------------------------------------------------------
/.vs/UnityVectorEditor/xs/sqlite3/storage.ide:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecurtz/UnityVectorEditor/e858f29b975dc0eb15a20bae77e3cfdc68c188b9/.vs/UnityVectorEditor/xs/sqlite3/storage.ide
--------------------------------------------------------------------------------
/Assets/Scenes.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e0f3c76785d7a43478e5e7eb6f82bce9
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Assets/Scenes/SampleScene.unity:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!29 &1
4 | OcclusionCullingSettings:
5 | m_ObjectHideFlags: 0
6 | serializedVersion: 2
7 | m_OcclusionBakeSettings:
8 | smallestOccluder: 5
9 | smallestHole: 0.25
10 | backfaceThreshold: 100
11 | m_SceneGUID: 00000000000000000000000000000000
12 | m_OcclusionCullingData: {fileID: 0}
13 | --- !u!104 &2
14 | RenderSettings:
15 | m_ObjectHideFlags: 0
16 | serializedVersion: 9
17 | m_Fog: 0
18 | m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
19 | m_FogMode: 3
20 | m_FogDensity: 0.01
21 | m_LinearFogStart: 0
22 | m_LinearFogEnd: 300
23 | m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
24 | m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
25 | m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
26 | m_AmbientIntensity: 1
27 | m_AmbientMode: 0
28 | m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
29 | m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
30 | m_HaloStrength: 0.5
31 | m_FlareStrength: 1
32 | m_FlareFadeSpeed: 3
33 | m_HaloTexture: {fileID: 0}
34 | m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
35 | m_DefaultReflectionMode: 0
36 | m_DefaultReflectionResolution: 128
37 | m_ReflectionBounces: 1
38 | m_ReflectionIntensity: 1
39 | m_CustomReflection: {fileID: 0}
40 | m_Sun: {fileID: 170076734}
41 | m_IndirectSpecularColor: {r: 0.44657838, g: 0.49641234, b: 0.57481676, a: 1}
42 | m_UseRadianceAmbientProbe: 0
43 | --- !u!157 &3
44 | LightmapSettings:
45 | m_ObjectHideFlags: 0
46 | serializedVersion: 11
47 | m_GIWorkflowMode: 0
48 | m_GISettings:
49 | serializedVersion: 2
50 | m_BounceScale: 1
51 | m_IndirectOutputScale: 1
52 | m_AlbedoBoost: 1
53 | m_EnvironmentLightingMode: 0
54 | m_EnableBakedLightmaps: 1
55 | m_EnableRealtimeLightmaps: 0
56 | m_LightmapEditorSettings:
57 | serializedVersion: 10
58 | m_Resolution: 2
59 | m_BakeResolution: 10
60 | m_AtlasSize: 512
61 | m_AO: 0
62 | m_AOMaxDistance: 1
63 | m_CompAOExponent: 1
64 | m_CompAOExponentDirect: 0
65 | m_Padding: 2
66 | m_LightmapParameters: {fileID: 0}
67 | m_LightmapsBakeMode: 1
68 | m_TextureCompression: 1
69 | m_FinalGather: 0
70 | m_FinalGatherFiltering: 1
71 | m_FinalGatherRayCount: 256
72 | m_ReflectionCompression: 2
73 | m_MixedBakeMode: 2
74 | m_BakeBackend: 1
75 | m_PVRSampling: 1
76 | m_PVRDirectSampleCount: 32
77 | m_PVRSampleCount: 256
78 | m_PVRBounces: 2
79 | m_PVRFilterTypeDirect: 0
80 | m_PVRFilterTypeIndirect: 0
81 | m_PVRFilterTypeAO: 0
82 | m_PVRFilteringMode: 1
83 | m_PVRCulling: 1
84 | m_PVRFilteringGaussRadiusDirect: 1
85 | m_PVRFilteringGaussRadiusIndirect: 5
86 | m_PVRFilteringGaussRadiusAO: 2
87 | m_PVRFilteringAtrousPositionSigmaDirect: 0.5
88 | m_PVRFilteringAtrousPositionSigmaIndirect: 2
89 | m_PVRFilteringAtrousPositionSigmaAO: 1
90 | m_ShowResolutionOverlay: 1
91 | m_LightingDataAsset: {fileID: 0}
92 | m_UseShadowmask: 1
93 | --- !u!196 &4
94 | NavMeshSettings:
95 | serializedVersion: 2
96 | m_ObjectHideFlags: 0
97 | m_BuildSettings:
98 | serializedVersion: 2
99 | agentTypeID: 0
100 | agentRadius: 0.5
101 | agentHeight: 2
102 | agentSlope: 45
103 | agentClimb: 0.4
104 | ledgeDropHeight: 0
105 | maxJumpAcrossDistance: 0
106 | minRegionArea: 2
107 | manualCellSize: 0
108 | cellSize: 0.16666667
109 | manualTileSize: 0
110 | tileSize: 256
111 | accuratePlacement: 0
112 | debug:
113 | m_Flags: 0
114 | m_NavMeshData: {fileID: 0}
115 | --- !u!1 &170076733
116 | GameObject:
117 | m_ObjectHideFlags: 0
118 | m_CorrespondingSourceObject: {fileID: 0}
119 | m_PrefabInstance: {fileID: 0}
120 | m_PrefabAsset: {fileID: 0}
121 | serializedVersion: 6
122 | m_Component:
123 | - component: {fileID: 170076735}
124 | - component: {fileID: 170076734}
125 | m_Layer: 0
126 | m_Name: Directional Light
127 | m_TagString: Untagged
128 | m_Icon: {fileID: 0}
129 | m_NavMeshLayer: 0
130 | m_StaticEditorFlags: 0
131 | m_IsActive: 1
132 | --- !u!108 &170076734
133 | Light:
134 | m_ObjectHideFlags: 0
135 | m_CorrespondingSourceObject: {fileID: 0}
136 | m_PrefabInstance: {fileID: 0}
137 | m_PrefabAsset: {fileID: 0}
138 | m_GameObject: {fileID: 170076733}
139 | m_Enabled: 1
140 | serializedVersion: 8
141 | m_Type: 1
142 | m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
143 | m_Intensity: 1
144 | m_Range: 10
145 | m_SpotAngle: 30
146 | m_CookieSize: 10
147 | m_Shadows:
148 | m_Type: 2
149 | m_Resolution: -1
150 | m_CustomResolution: -1
151 | m_Strength: 1
152 | m_Bias: 0.05
153 | m_NormalBias: 0.4
154 | m_NearPlane: 0.2
155 | m_Cookie: {fileID: 0}
156 | m_DrawHalo: 0
157 | m_Flare: {fileID: 0}
158 | m_RenderMode: 0
159 | m_CullingMask:
160 | serializedVersion: 2
161 | m_Bits: 4294967295
162 | m_Lightmapping: 1
163 | m_LightShadowCasterMode: 0
164 | m_AreaSize: {x: 1, y: 1}
165 | m_BounceIntensity: 1
166 | m_ColorTemperature: 6570
167 | m_UseColorTemperature: 0
168 | m_ShadowRadius: 0
169 | m_ShadowAngle: 0
170 | --- !u!4 &170076735
171 | Transform:
172 | m_ObjectHideFlags: 0
173 | m_CorrespondingSourceObject: {fileID: 0}
174 | m_PrefabInstance: {fileID: 0}
175 | m_PrefabAsset: {fileID: 0}
176 | m_GameObject: {fileID: 170076733}
177 | m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
178 | m_LocalPosition: {x: 0, y: 3, z: 0}
179 | m_LocalScale: {x: 1, y: 1, z: 1}
180 | m_Children: []
181 | m_Father: {fileID: 0}
182 | m_RootOrder: 1
183 | m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
184 | --- !u!1 &534669902
185 | GameObject:
186 | m_ObjectHideFlags: 0
187 | m_CorrespondingSourceObject: {fileID: 0}
188 | m_PrefabInstance: {fileID: 0}
189 | m_PrefabAsset: {fileID: 0}
190 | serializedVersion: 6
191 | m_Component:
192 | - component: {fileID: 534669905}
193 | - component: {fileID: 534669904}
194 | - component: {fileID: 534669903}
195 | m_Layer: 0
196 | m_Name: Main Camera
197 | m_TagString: MainCamera
198 | m_Icon: {fileID: 0}
199 | m_NavMeshLayer: 0
200 | m_StaticEditorFlags: 0
201 | m_IsActive: 1
202 | --- !u!81 &534669903
203 | AudioListener:
204 | m_ObjectHideFlags: 0
205 | m_CorrespondingSourceObject: {fileID: 0}
206 | m_PrefabInstance: {fileID: 0}
207 | m_PrefabAsset: {fileID: 0}
208 | m_GameObject: {fileID: 534669902}
209 | m_Enabled: 1
210 | --- !u!20 &534669904
211 | Camera:
212 | m_ObjectHideFlags: 0
213 | m_CorrespondingSourceObject: {fileID: 0}
214 | m_PrefabInstance: {fileID: 0}
215 | m_PrefabAsset: {fileID: 0}
216 | m_GameObject: {fileID: 534669902}
217 | m_Enabled: 1
218 | serializedVersion: 2
219 | m_ClearFlags: 1
220 | m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
221 | m_projectionMatrixMode: 1
222 | m_SensorSize: {x: 36, y: 24}
223 | m_LensShift: {x: 0, y: 0}
224 | m_GateFitMode: 2
225 | m_FocalLength: 50
226 | m_NormalizedViewPortRect:
227 | serializedVersion: 2
228 | x: 0
229 | y: 0
230 | width: 1
231 | height: 1
232 | near clip plane: 0.3
233 | far clip plane: 1000
234 | field of view: 60
235 | orthographic: 0
236 | orthographic size: 5
237 | m_Depth: -1
238 | m_CullingMask:
239 | serializedVersion: 2
240 | m_Bits: 4294967295
241 | m_RenderingPath: -1
242 | m_TargetTexture: {fileID: 0}
243 | m_TargetDisplay: 0
244 | m_TargetEye: 3
245 | m_HDR: 1
246 | m_AllowMSAA: 1
247 | m_AllowDynamicResolution: 0
248 | m_ForceIntoRT: 0
249 | m_OcclusionCulling: 1
250 | m_StereoConvergence: 10
251 | m_StereoSeparation: 0.022
252 | --- !u!4 &534669905
253 | Transform:
254 | m_ObjectHideFlags: 0
255 | m_CorrespondingSourceObject: {fileID: 0}
256 | m_PrefabInstance: {fileID: 0}
257 | m_PrefabAsset: {fileID: 0}
258 | m_GameObject: {fileID: 534669902}
259 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
260 | m_LocalPosition: {x: 0, y: 1, z: -10}
261 | m_LocalScale: {x: 1, y: 1, z: 1}
262 | m_Children: []
263 | m_Father: {fileID: 0}
264 | m_RootOrder: 0
265 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
266 | --- !u!1 &1632254178
267 | GameObject:
268 | m_ObjectHideFlags: 0
269 | m_CorrespondingSourceObject: {fileID: 0}
270 | m_PrefabInstance: {fileID: 0}
271 | m_PrefabAsset: {fileID: 0}
272 | serializedVersion: 6
273 | m_Component:
274 | - component: {fileID: 1632254180}
275 | - component: {fileID: 1632254179}
276 | m_Layer: 0
277 | m_Name: Icon Render Camera
278 | m_TagString: Untagged
279 | m_Icon: {fileID: 0}
280 | m_NavMeshLayer: 0
281 | m_StaticEditorFlags: 0
282 | m_IsActive: 1
283 | --- !u!20 &1632254179
284 | Camera:
285 | m_ObjectHideFlags: 0
286 | m_CorrespondingSourceObject: {fileID: 0}
287 | m_PrefabInstance: {fileID: 0}
288 | m_PrefabAsset: {fileID: 0}
289 | m_GameObject: {fileID: 1632254178}
290 | m_Enabled: 0
291 | serializedVersion: 2
292 | m_ClearFlags: 2
293 | m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0}
294 | m_projectionMatrixMode: 1
295 | m_SensorSize: {x: 36, y: 24}
296 | m_LensShift: {x: 0, y: 0}
297 | m_GateFitMode: 2
298 | m_FocalLength: 50
299 | m_NormalizedViewPortRect:
300 | serializedVersion: 2
301 | x: 0
302 | y: 0
303 | width: 1
304 | height: 1
305 | near clip plane: 0.1
306 | far clip plane: 100
307 | field of view: 60
308 | orthographic: 1
309 | orthographic size: 12
310 | m_Depth: 0
311 | m_CullingMask:
312 | serializedVersion: 2
313 | m_Bits: 4294967295
314 | m_RenderingPath: -1
315 | m_TargetTexture: {fileID: 0}
316 | m_TargetDisplay: 0
317 | m_TargetEye: 3
318 | m_HDR: 1
319 | m_AllowMSAA: 1
320 | m_AllowDynamicResolution: 0
321 | m_ForceIntoRT: 0
322 | m_OcclusionCulling: 1
323 | m_StereoConvergence: 10
324 | m_StereoSeparation: 0.022
325 | --- !u!4 &1632254180
326 | Transform:
327 | m_ObjectHideFlags: 0
328 | m_CorrespondingSourceObject: {fileID: 0}
329 | m_PrefabInstance: {fileID: 0}
330 | m_PrefabAsset: {fileID: 0}
331 | m_GameObject: {fileID: 1632254178}
332 | m_LocalRotation: {x: 0, y: 0, z: 0.000002972375, w: 1}
333 | m_LocalPosition: {x: 12, y: 12, z: -1}
334 | m_LocalScale: {x: 1, y: 1, z: 1}
335 | m_Children: []
336 | m_Father: {fileID: 0}
337 | m_RootOrder: 3
338 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
339 | --- !u!1 &1661268765
340 | GameObject:
341 | m_ObjectHideFlags: 0
342 | m_CorrespondingSourceObject: {fileID: 0}
343 | m_PrefabInstance: {fileID: 0}
344 | m_PrefabAsset: {fileID: 0}
345 | serializedVersion: 6
346 | m_Component:
347 | - component: {fileID: 1661268767}
348 | - component: {fileID: 1661268766}
349 | m_Layer: 0
350 | m_Name: ShapeUsingGameObject
351 | m_TagString: Untagged
352 | m_Icon: {fileID: 0}
353 | m_NavMeshLayer: 0
354 | m_StaticEditorFlags: 0
355 | m_IsActive: 1
356 | --- !u!114 &1661268766
357 | MonoBehaviour:
358 | m_ObjectHideFlags: 0
359 | m_CorrespondingSourceObject: {fileID: 0}
360 | m_PrefabInstance: {fileID: 0}
361 | m_PrefabAsset: {fileID: 0}
362 | m_GameObject: {fileID: 1661268765}
363 | m_Enabled: 1
364 | m_EditorHideFlags: 0
365 | m_Script: {fileID: 11500000, guid: 2ada356d7b2f741cdb2765daed2dfdd2, type: 3}
366 | m_Name:
367 | m_EditorClassIdentifier:
368 | shape: {fileID: 11400000, guid: 790bc1fea4add46599cf4211829edb90, type: 2}
369 | --- !u!4 &1661268767
370 | Transform:
371 | m_ObjectHideFlags: 0
372 | m_CorrespondingSourceObject: {fileID: 0}
373 | m_PrefabInstance: {fileID: 0}
374 | m_PrefabAsset: {fileID: 0}
375 | m_GameObject: {fileID: 1661268765}
376 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
377 | m_LocalPosition: {x: 0, y: 0, z: 0}
378 | m_LocalScale: {x: 1, y: 1, z: 1}
379 | m_Children: []
380 | m_Father: {fileID: 0}
381 | m_RootOrder: 2
382 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
383 |
--------------------------------------------------------------------------------
/Assets/Scenes/SampleScene.unity.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d5b456b4e24004c8ba05933cefc759dc
3 | DefaultImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Assets/Scenes/SampleShape.asset:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!114 &11400000
4 | MonoBehaviour:
5 | m_ObjectHideFlags: 0
6 | m_CorrespondingSourceObject: {fileID: 0}
7 | m_PrefabInstance: {fileID: 0}
8 | m_PrefabAsset: {fileID: 0}
9 | m_GameObject: {fileID: 0}
10 | m_Enabled: 1
11 | m_EditorHideFlags: 0
12 | m_Script: {fileID: 11500000, guid: c081e07c8a64f48c98e1c02e172f84f0, type: 3}
13 | m_Name: SampleShape
14 | m_EditorClassIdentifier:
15 | circles:
16 | - penSize: 2
17 | penToMeshScale: 0.23741485
18 | colorOutline: {r: 0, g: 0, b: 0, a: 1}
19 | colorFill: {r: 0.32156864, g: 0.8, b: 0.2627451, a: 1}
20 | closed: 1
21 | guid: 00000000-0000-0000-0000-000000000000
22 | position: {x: 14.267512, y: -14.140124}
23 | radius: 22.272238
24 | startAngle: 0
25 | sweepAngle: 0
26 | ellipses: []
27 | points: []
28 | polys:
29 | - penSize: 2
30 | penToMeshScale: 0.23741485
31 | colorOutline: {r: 0, g: 0, b: 0, a: 1}
32 | colorFill: {r: 0, g: 0, b: 0, a: 0}
33 | closed: 1
34 | guid: 00000000-0000-0000-0000-000000000000
35 | vertices:
36 | - position: {x: -20.891724, y: 56.17943}
37 | enterCP: {x: -20.896053, y: 26.119652}
38 | exitCP: {x: -20.887394, y: 26.119652}
39 | segmentCurves: 0
40 | - position: {x: 5.1430874, y: 11.078723}
41 | enterCP: {x: -20.88523, y: 26.115902}
42 | exitCP: {x: -20.889559, y: 26.108402}
43 | segmentCurves: 0
44 | - position: {x: -46.926537, y: 11.078723}
45 | enterCP: {x: -20.893888, y: 26.108402}
46 | exitCP: {x: -20.898218, y: 26.115902}
47 | segmentCurves: 0
48 | continuousCurves: 1
49 | activeIndex: -1
50 | activeComponent: 0
51 | - penSize: 2
52 | penToMeshScale: 0.23741485
53 | colorOutline: {r: 0.8784314, g: 0.5294118, b: 0.078431375, a: 1}
54 | colorFill: {r: 0, g: 0, b: 0, a: 0}
55 | closed: 1
56 | guid: 00000000-0000-0000-0000-000000000000
57 | vertices:
58 | - position: {x: -34.904465, y: 20.632269}
59 | enterCP: {x: -34.906963, y: -1.9058251}
60 | exitCP: {x: -34.901966, y: -1.9058251}
61 | segmentCurves: 0
62 | - position: {x: -15.382214, y: 9.3618355}
63 | enterCP: {x: -34.901386, y: -1.9061601}
64 | exitCP: {x: -34.898884, y: -1.9104902}
65 | segmentCurves: 0
66 | - position: {x: -15.38221, y: -13.183476}
67 | enterCP: {x: -34.898884, y: -1.9111601}
68 | exitCP: {x: -34.901386, y: -1.9154902}
69 | segmentCurves: 0
70 | - position: {x: -34.904465, y: -24.45392}
71 | enterCP: {x: -34.901966, y: -1.9158251}
72 | exitCP: {x: -34.906963, y: -1.9158251}
73 | segmentCurves: 0
74 | - position: {x: -54.42672, y: -13.183476}
75 | enterCP: {x: -34.907543, y: -1.9154902}
76 | exitCP: {x: -34.910046, y: -1.9111601}
77 | segmentCurves: 0
78 | - position: {x: -54.426716, y: 9.3618355}
79 | enterCP: {x: -34.910046, y: -1.9104902}
80 | exitCP: {x: -34.907543, y: -1.9061601}
81 | segmentCurves: 0
82 | continuousCurves: 1
83 | activeIndex: -1
84 | activeComponent: 0
85 | texts: []
86 |
--------------------------------------------------------------------------------
/Assets/Scenes/SampleShape.asset.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 790bc1fea4add46599cf4211829edb90
3 | NativeFormatImporter:
4 | externalObjects: {}
5 | mainObjectFileID: 11400000
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Assets/Scenes/SampleShapeUser.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 |
5 | public class SampleShapeUser : MonoBehaviour
6 | {
7 | public SerializedShape shape;
8 |
9 | void Update()
10 | {
11 |
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Assets/Scenes/SampleShapeUser.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 2ada356d7b2f741cdb2765daed2dfdd2
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/VectorShapes.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 0899a0484a8d54f03a5627e6feca6b57
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/CircleShape.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Xml;
3 | using UnityEngine;
4 | #if UNITY_EDITOR
5 | using UnityEditor;
6 | #endif
7 | using Unity.VectorGraphics;
8 |
9 | [System.Serializable]
10 | ///
11 | /// Vector circle.
12 | ///
13 | public class CircleShape : VectorShape
14 | {
15 | public class CircleProxy : ScriptableObject, ISerializationCallbackReceiver
16 | {
17 | [HideInInspector]
18 | public CircleShape circle;
19 |
20 | public Vector2 position;
21 | public float radius;
22 | public float startAngle;
23 | public float sweepAngle;
24 |
25 | public void OnBeforeSerialize()
26 | {
27 | if (circle != null)
28 | {
29 | circle.position = position;
30 | circle.radius = radius;
31 | circle.startAngle = startAngle;
32 | circle.sweepAngle = sweepAngle;
33 | }
34 | }
35 |
36 | public void OnAfterDeserialize()
37 | {
38 | }
39 | }
40 |
41 | public CircleProxy GetCircleProxy()
42 | {
43 | CircleProxy proxy = ScriptableObject.CreateInstance();
44 | proxy.name = "Circle";
45 | proxy.circle = this;
46 | proxy.position = position;
47 | proxy.radius = radius;
48 | proxy.startAngle = startAngle;
49 | proxy.sweepAngle = sweepAngle;
50 |
51 | return proxy;
52 | }
53 |
54 | ///
55 | /// Position of center.
56 | ///
57 | [SerializeField]
58 | protected Vector2 position;
59 |
60 | ///
61 | /// Radius of circle.
62 | ///
63 | [SerializeField]
64 | protected float radius;
65 |
66 | ///
67 | /// Starting angle for arcs (in radians).
68 | ///
69 | [SerializeField]
70 | protected float startAngle;
71 |
72 | ///
73 | /// Sweep angle for arcs (in radians).
74 | ///
75 | [SerializeField]
76 | protected float sweepAngle;
77 |
78 | ///
79 | /// Position of center.
80 | ///
81 | public Vector2 Position
82 | {
83 | set
84 | {
85 | position = value;
86 | Dirty = true;
87 | }
88 | get
89 | {
90 | return position;
91 | }
92 | }
93 |
94 | ///
95 | /// Radius of circle.
96 | ///
97 | public float Radius
98 | {
99 | set
100 | {
101 | radius = value;
102 | Dirty = true;
103 | }
104 | get
105 | {
106 | return radius;
107 | }
108 | }
109 |
110 | ///
111 | /// Starting angle for circular arcs (in degrees).
112 | ///
113 | public float StartAngle
114 | {
115 | set
116 | {
117 | startAngle = value * Mathf.Deg2Rad;
118 | Dirty = true;
119 | }
120 | get
121 | {
122 | return startAngle * Mathf.Rad2Deg;
123 | }
124 | }
125 |
126 | ///
127 | /// Sweep angle for circular arcs (in degrees).
128 | ///
129 | public float SweepAngle
130 | {
131 | set
132 | {
133 | sweepAngle = value * Mathf.Deg2Rad;
134 | if (Mathf.Approximately(value, 0f) || (Mathf.Abs(value) >= 360f))
135 | {
136 | closed = true;
137 | }
138 | else
139 | {
140 | closed = false;
141 | }
142 | Dirty = true;
143 | }
144 | get
145 | {
146 | return sweepAngle * Mathf.Rad2Deg;
147 | }
148 | }
149 |
150 | protected CircleShape()
151 | {
152 | }
153 |
154 | ///
155 | /// New circle from center point and radius.
156 | ///
157 | /// Center of circle
158 | /// Radius of circle
159 | public CircleShape(Vector2 center, float rad)
160 | {
161 | position = center;
162 | radius = rad;
163 |
164 | startAngle = 0f;
165 | sweepAngle = 0f;
166 | closed = true;
167 | }
168 |
169 | ///
170 | /// New circular arc from center point, radius, and angles.
171 | ///
172 | /// Center of circle
173 | /// Radius of circle
174 | /// Starting angle of arc (in degrees)
175 | /// Sweep of arc (in degrees)
176 | public CircleShape(Vector2 center, float rad, float angle, float sweep)
177 | {
178 | position = center;
179 | radius = rad;
180 |
181 | startAngle = angle * Mathf.Deg2Rad;
182 | sweepAngle = sweep * Mathf.Deg2Rad;
183 |
184 | if (Mathf.Approximately(sweep, 0f) || (Mathf.Abs(sweep) >= 360f))
185 | {
186 | closed = true;
187 | }
188 | else
189 | {
190 | closed = false;
191 | }
192 | }
193 |
194 | public static CircleShape Create()
195 | {
196 | //CircleShape shape = ScriptableObject.CreateInstance();
197 | CircleShape shape = new CircleShape();
198 |
199 | return shape;
200 | }
201 |
202 | ///
203 | /// New circle from center point and radius.
204 | ///
205 | /// Center of circle
206 | /// Radius of circle
207 | public static CircleShape Create(Vector2 center, float rad)
208 | {
209 | CircleShape shape = Create();
210 |
211 | shape.position = center;
212 | shape.radius = rad;
213 |
214 | shape.startAngle = 0f;
215 | shape.sweepAngle = 0f;
216 | shape.closed = true;
217 |
218 | return shape;
219 | }
220 |
221 | ///
222 | /// New circular arc from center point, radius, and angles.
223 | ///
224 | /// Center of circle
225 | /// Radius of circle
226 | /// Starting angle of arc (in degrees)
227 | /// Sweep of arc (in degrees)
228 | public static CircleShape Create(Vector2 center, float rad, float angle, float sweep)
229 | {
230 | CircleShape shape = Create();
231 |
232 | shape.position = center;
233 | shape.radius = rad;
234 |
235 | shape.startAngle = angle * Mathf.Deg2Rad;
236 | shape.sweepAngle = sweep * Mathf.Deg2Rad;
237 |
238 | if (Mathf.Approximately(sweep, 0f) || (Mathf.Abs(sweep) >= 360f))
239 | {
240 | shape.closed = true;
241 | }
242 | else
243 | {
244 | shape.closed = false;
245 | }
246 |
247 | return shape;
248 | }
249 |
250 | ///
251 | /// Copy of the shape.
252 | ///
253 | /// New shape with properties of existing shape
254 | public override VectorShape Duplicate()
255 | {
256 | return Create(position, radius, startAngle * Mathf.Rad2Deg, sweepAngle * Mathf.Rad2Deg);
257 | }
258 |
259 | ///
260 | /// Distance between a point and the shape.
261 | ///
262 | /// Test point
263 | /// Distance from point to nearest point on shape
264 | public override float Distance(Vector2 pt)
265 | {
266 | return Mathf.Abs(Vector2.Distance(pt, position) - radius);
267 | }
268 |
269 | ///
270 | /// Tests if a shape contains a point
271 | ///
272 | /// Test point
273 | /// Is the point inside the shape?
274 | public override bool Contains(Vector2 pt)
275 | {
276 | return (Vector2.Distance(pt, position) < radius);
277 | }
278 |
279 | ///
280 | /// Tests if a shape is inside a rectangle.
281 | ///
282 | /// Test rectangle
283 | /// Is the shape entirely inside the rectangle?
284 | public override bool IsInside(Rect rect)
285 | {
286 | if (!rect.Contains(position)) return false;
287 |
288 | Vector2 testPt = position;
289 | testPt.x = position.x - radius;
290 | if (!rect.Contains(testPt)) return false;
291 | testPt.x = position.x + radius;
292 | if (!rect.Contains(testPt)) return false;
293 |
294 | testPt = position;
295 | testPt.y = position.y - radius;
296 | if (!rect.Contains(testPt)) return false;
297 | testPt.y = position.y + radius;
298 | if (!rect.Contains(testPt)) return false;
299 |
300 | return true;
301 | }
302 |
303 | ///
304 | /// Rotate the shape around a point.
305 | ///
306 | /// Center of rotation
307 | /// Angle in degrees
308 | public override void RotateAround(Vector2 center, float angle)
309 | {
310 | Matrix2D matrix = Matrix2D.Translate(center) * Matrix2D.RotateRH(angle * Mathf.Deg2Rad) * Matrix2D.Translate(-center);
311 | position = matrix.MultiplyPoint(position);
312 |
313 | Dirty = true;
314 | }
315 |
316 | ///
317 | /// Change the origin of the shape.
318 | ///
319 | /// Direction to move
320 | public override void TranslateBy(Vector2 offset)
321 | {
322 | position += offset;
323 |
324 | Dirty = true;
325 | }
326 |
327 | ///
328 | /// Change the size of the shape.
329 | ///
330 | /// Scaling factor to apply
331 | public override void ScaleBy(float scale)
332 | {
333 | if (scale < Mathf.Epsilon)
334 | {
335 | Debug.LogWarning("Scale must be greater than zero.");
336 | return;
337 | }
338 |
339 | position *= scale;
340 | radius *= scale;
341 |
342 | Dirty = true;
343 | }
344 |
345 | ///
346 | /// Transform the shape by an arbitrary matrix.
347 | ///
348 | /// Matrix to transform shape
349 | public override void TransformBy(Matrix2D matrix)
350 | {
351 | // Attempt to identify uniform scaling
352 | Vector2 pt0 = matrix.MultiplyPoint(position + new Vector2(0, radius));
353 | Vector2 pt1 = matrix.MultiplyPoint(position + new Vector2(0, -radius));
354 | Vector2 pt2 = matrix.MultiplyPoint(position + new Vector2(radius, 0));
355 | Vector2 pt3 = matrix.MultiplyPoint(position + new Vector2(-radius, 0));
356 |
357 | position = matrix.MultiplyPoint(position);
358 |
359 | float distSqr = Vector2.SqrMagnitude(pt0 - position);
360 | if (Mathf.Approximately(distSqr, Vector2.SqrMagnitude(pt1 - position)) &&
361 | Mathf.Approximately(distSqr, Vector2.SqrMagnitude(pt2 - position)) &&
362 | Mathf.Approximately(distSqr, Vector2.SqrMagnitude(pt3 - position)))
363 | {
364 | radius = Mathf.Sqrt(distSqr);
365 | }
366 | else
367 | {
368 | Debug.LogWarning("Ignored matrix change that would destroy circle.");
369 | }
370 |
371 | Dirty = true;
372 | }
373 |
374 | ///
375 | /// Distance between a point and the shape.
376 | ///
377 | /// Test point
378 | /// Snap modes to consider
379 | /// Distance from point to nearest point on shape
380 | public override SnapPoint GetSnap(Vector2 pt, SnapPoint.Mode mode)
381 | {
382 | SnapPoint snap = new SnapPoint();
383 | float distance = float.MaxValue;
384 |
385 | if ((mode & SnapPoint.Mode.Center) != 0)
386 | {
387 | float d = Vector2.Distance(pt, position);
388 | if (d < distance)
389 | {
390 | distance = d;
391 | snap.mode = SnapPoint.Mode.Center;
392 | snap.point = position;
393 | }
394 | }
395 |
396 | if ((mode & SnapPoint.Mode.Midpoint) != 0)
397 | {
398 | float offset45 = 0.7071f * radius;
399 | Vector2[] midPoints =
400 | {
401 | position + new Vector2(radius, 0f),
402 | position + new Vector2(offset45, offset45),
403 | position + new Vector2(0f, radius),
404 | position + new Vector2(-offset45, offset45),
405 | position + new Vector2(-radius, 0f),
406 | position + new Vector2(-offset45, -offset45),
407 | position + new Vector2(0f, -radius),
408 | position + new Vector2(offset45, -offset45),
409 | };
410 |
411 | foreach (Vector2 testPt in midPoints)
412 | {
413 | float d = Vector2.Distance(pt, testPt);
414 | if (d < distance)
415 | {
416 | distance = d;
417 | snap.mode = SnapPoint.Mode.Midpoint;
418 | snap.point = testPt;
419 | }
420 | }
421 | }
422 |
423 | if ((mode & SnapPoint.Mode.Edge) != 0)
424 | {
425 | float d = Distance(pt);
426 | if (d < distance)
427 | {
428 | distance = d;
429 | snap.mode = SnapPoint.Mode.Edge;
430 | float angle = Mathf.Atan2(pt.y - position.y, pt.x - position.x);
431 | snap.point.x = position.x + Mathf.Cos(angle) * radius;
432 | snap.point.y = position.y + Mathf.Sin(angle) * radius;
433 | }
434 | }
435 |
436 | return snap;
437 | }
438 |
439 | ///
440 | /// Tessellate the shape into geometry data.
441 | ///
442 | protected override void GenerateGeometry()
443 | {
444 | if ((shapeGeometry != null) && (!shapeDirty)) return;
445 |
446 | Shape circle = new Shape();
447 | if (closed)
448 | {
449 | VectorUtils.MakeCircleShape(circle, position, radius);
450 | }
451 | else
452 | {
453 | BezierContour contour = new BezierContour();
454 | contour.Segments = VectorUtils.MakeArc(position, startAngle, sweepAngle, radius);
455 | circle.Contours = new BezierContour[] { contour };
456 | }
457 |
458 | circle.PathProps = new PathProperties()
459 | {
460 | Stroke = new Stroke()
461 | {
462 | Color = colorOutline,
463 | HalfThickness = penSize / 2f * penToMeshScale
464 | }
465 | };
466 | if (colorFill != Color.clear)
467 | {
468 | circle.Fill = new SolidFill()
469 | {
470 | Color = colorFill
471 | };
472 | }
473 |
474 | shapeNode = new SceneNode()
475 | {
476 | Transform = matrixTransform,
477 | Shapes = new List
478 | {
479 | circle
480 | }
481 | };
482 |
483 | tessellationScene.Root = shapeNode;
484 | shapeGeometry = VectorUtils.TessellateScene(tessellationScene, tessellationOptions);
485 |
486 | shapeDirty = false;
487 | }
488 |
489 | ///
490 | /// Build a mesh for display with the VectorLineShader.
491 | ///
492 | protected override void GenerateLineMesh()
493 | {
494 | if (closed)
495 | {
496 | lineBuilder.Circle(position, radius, 32);
497 | }
498 | else
499 | {
500 | BezierPathSegment[] segments = VectorUtils.MakeArc(position, startAngle, sweepAngle, radius);
501 |
502 | lineBuilder.BeginPolyLine(segments[0].P0);
503 | int steps = Mathf.CeilToInt(16f * sweepAngle / Mathf.PI / segments.Length);
504 | for (int i = 1; i < segments.Length; i++)
505 | {
506 | lineBuilder.CurveTo(segments[i - 1].P1, segments[i - 1].P2, segments[i].P0, steps);
507 | }
508 | lineBuilder.EndPolyLine();
509 | }
510 | }
511 |
512 | ///
513 | /// Build a 2D bounding box for the shape.
514 | ///
515 | protected override void GenerateBounds()
516 | {
517 | shapeBounds = new Rect(position - new Vector2(radius, radius), new Vector2(radius * 2, radius * 2));
518 | boundsDirty = false;
519 | }
520 |
521 | ///
522 | /// Build a 2D collider for the shape.
523 | ///
524 | protected override void AddColliderToGO(GameObject target)
525 | {
526 | CircleCollider2D[] colliders = target.GetComponents();
527 | CircleCollider2D collider = null;
528 |
529 | for (int i = 0; i < colliders.Length; i++)
530 | {
531 | if (colliders[i].name == this.guid)
532 | {
533 | collider = colliders[i];
534 | }
535 | }
536 |
537 | if (collider == null)
538 | {
539 | collider = collider.gameObject.AddComponent();
540 | collider.name = this.guid;
541 | }
542 |
543 | collider.offset = position;
544 | collider.radius = radius;
545 | }
546 |
547 | ///
548 | /// Serialize the shape to an XML writer.
549 | ///
550 | public override void WriteToXML(XmlWriter writer, Vector2 origin, float scale)
551 | {
552 | Vector2 svgPosition = (position - origin) * new Vector2(scale, -scale);
553 |
554 | writer.WriteStartElement("circle");
555 |
556 | writer.WriteStartAttribute("cx");
557 | writer.WriteValue(svgPosition.x);
558 | writer.WriteEndAttribute();
559 |
560 | writer.WriteStartAttribute("cy");
561 | writer.WriteValue(svgPosition.y);
562 | writer.WriteEndAttribute();
563 |
564 | writer.WriteStartAttribute("r");
565 | writer.WriteValue(radius * scale);
566 | writer.WriteEndAttribute();
567 |
568 | writer.WriteStartAttribute("stroke");
569 | writer.WriteValue(VectorShapeFilesSVG.ConvertColor(colorOutline));
570 | writer.WriteEndAttribute();
571 |
572 | writer.WriteStartAttribute("stroke-width");
573 | writer.WriteValue("1mm");
574 | writer.WriteEndAttribute();
575 |
576 | writer.WriteStartAttribute("fill");
577 | writer.WriteValue(VectorShapeFilesSVG.ConvertColor(colorFill));
578 | writer.WriteEndAttribute();
579 |
580 | writer.WriteEndElement();
581 | }
582 |
583 | #if UNITY_EDITOR
584 | ///
585 | /// Draw the circle to the active camera using editor handles.
586 | ///
587 | /// Is the shape selected?
588 | /// Is it the active shape?
589 | public override void DrawEditorHandles(bool selected, bool active = false)
590 | {
591 | base.DrawEditorHandles(selected, active);
592 |
593 | if (selected)
594 | {
595 | if (boundsDirty) GenerateBounds();
596 | Handles.DrawSolidRectangleWithOutline(shapeBounds, Color.clear, Handles.color);
597 | }
598 |
599 | if (active)
600 | {
601 |
602 | }
603 | }
604 |
605 | ///
606 | /// Respond to GUI input events in editor.
607 | ///
608 | /// The current event
609 | /// Is it the active shape?
610 | /// Did the shape handle the event?
611 | public override bool HandleEditorEvent(Event currEvent, bool active)
612 | {
613 | return false;
614 | }
615 | #endif
616 |
617 | }
--------------------------------------------------------------------------------
/Assets/VectorShapes/CircleShape.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 1757820fbde764527be1d024c1d65efa
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/CompoundShape.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Xml;
3 | using UnityEngine;
4 | #if UNITY_EDITOR
5 | using UnityEditor;
6 | #endif
7 | using Unity.VectorGraphics;
8 |
9 | [System.Serializable]
10 | ///
11 | /// Vector shape composed of other shapes.
12 | ///
13 | public class CompoundShape : VectorShape
14 | {
15 | private List _components;
16 | public List components { get {return _components;} }
17 |
18 | ///
19 | /// New empty compound shape.
20 | ///
21 | public CompoundShape()
22 | {
23 | _components = new List();
24 | }
25 |
26 | ///
27 | /// New empty compound shape.
28 | ///
29 | public static CompoundShape Create()
30 | {
31 | //CompoundShape shape = ScriptableObject.CreateInstance();
32 | CompoundShape shape = new CompoundShape();
33 |
34 | shape._components = new List();
35 |
36 | return shape;
37 | }
38 |
39 | ///
40 | /// Copy of the shape.
41 | ///
42 | /// New shape with properties of existing shape
43 | public override VectorShape Duplicate()
44 | {
45 | CompoundShape duplicate = Create();
46 | foreach (VectorShape component in components)
47 | {
48 | duplicate.AddComponent(component.Duplicate());
49 | }
50 |
51 | return duplicate;
52 | }
53 |
54 | ///
55 | /// Add a component shape.
56 | ///
57 | public void AddComponent(VectorShape shape)
58 | {
59 | _components.Add(shape);
60 |
61 | Dirty = true;
62 | }
63 |
64 | ///
65 | /// Distance between a point and the shape.
66 | ///
67 | /// Test point
68 | /// Distance from point to nearest point on shape
69 | public override float Distance(Vector2 pt)
70 | {
71 | float distance = float.MaxValue;
72 | foreach (VectorShape component in _components)
73 | {
74 | float componentDistance = component.Distance(pt);
75 | distance = Mathf.Min(distance, componentDistance);
76 | }
77 |
78 | return distance;
79 | }
80 |
81 | ///
82 | /// Tests if a shape contains a point
83 | ///
84 | /// Test point
85 | /// Is the point inside the shape?
86 | public override bool Contains(Vector2 pt)
87 | {
88 | foreach (VectorShape component in _components)
89 | {
90 | if (component.Contains(pt)) return true;
91 | }
92 |
93 | return false;
94 | }
95 |
96 | ///
97 | /// Tests if a shape is inside a rectangle.
98 | ///
99 | /// Test rectangle
100 | /// Is the shape entirely inside the rectangle?
101 | public override bool IsInside(Rect rect)
102 | {
103 | foreach (VectorShape component in _components)
104 | {
105 | if (!component.IsInside(rect)) return false;
106 | }
107 |
108 | return true;
109 | }
110 |
111 | ///
112 | /// Rotate the shape around a point.
113 | ///
114 | /// Center of rotation
115 | /// Angle in degrees
116 | public override void RotateAround(Vector2 center, float angle)
117 | {
118 | foreach (VectorShape component in _components)
119 | {
120 | component.RotateAround(center, angle);
121 | }
122 |
123 | Dirty = true;
124 | }
125 |
126 | ///
127 | /// Change the origin of the shape.
128 | ///
129 | /// Direction to move
130 | public override void TranslateBy(Vector2 offset)
131 | {
132 | foreach (VectorShape component in _components)
133 | {
134 | component.TranslateBy(offset);
135 | }
136 |
137 | Dirty = true;
138 | }
139 |
140 | ///
141 | /// Change the size of the shape.
142 | ///
143 | /// Scaling factor to apply
144 | public override void ScaleBy(float scale)
145 | {
146 | if (scale < Mathf.Epsilon)
147 | {
148 | Debug.LogWarning("Scale must be greater than zero.");
149 | return;
150 | }
151 |
152 | foreach (VectorShape component in _components)
153 | {
154 | component.ScaleBy(scale);
155 | }
156 |
157 | Dirty = true;
158 | }
159 |
160 | ///
161 | /// Transform the shape by an arbitrary matrix.
162 | ///
163 | /// Matrix to transform shape
164 | public override void TransformBy(Matrix2D matrix)
165 | {
166 | foreach (VectorShape component in _components)
167 | {
168 | component.TransformBy(matrix);
169 | }
170 |
171 | Dirty = true;
172 | }
173 |
174 | ///
175 | /// Distance between a point and the shape.
176 | ///
177 | /// Test point
178 | /// Snap modes to consider
179 | /// Distance from point to nearest point on shape
180 | public override SnapPoint GetSnap(Vector2 pt, SnapPoint.Mode mode)
181 | {
182 | SnapPoint snap = new SnapPoint();
183 |
184 | return snap;
185 | }
186 |
187 | ///
188 | /// Tessellate the shape into geometry data.
189 | ///
190 | protected override void GenerateGeometry()
191 | {
192 | if ((shapeGeometry != null) && (!shapeDirty)) return;
193 |
194 | shapeGeometry = new List();
195 |
196 | foreach (VectorShape component in _components)
197 | {
198 | shapeGeometry.AddRange(component.ShapeGeometry);
199 | }
200 |
201 | shapeDirty = false;
202 | }
203 |
204 | ///
205 | /// Build a mesh for display with the VectorLineShader.
206 | ///
207 | protected override void GenerateLineMesh()
208 | {
209 | foreach (VectorShape component in _components)
210 | {
211 | shapeGeometry.AddRange(component.ShapeGeometry);
212 | }
213 | }
214 |
215 | ///
216 | /// Build a 2D bounding box for the shape.
217 | ///
218 | protected override void GenerateBounds()
219 | {
220 | if (_components.Count == 0)
221 | {
222 | shapeBounds = new Rect();
223 | }
224 | else
225 | {
226 | shapeBounds = _components[0].ShapeBounds;
227 | for (int i = 1; i < _components.Count; i++)
228 | {
229 | shapeBounds = VectorShapeUtils.RectUnion(shapeBounds, _components[i].ShapeBounds);
230 | }
231 | }
232 | boundsDirty = false;
233 | }
234 |
235 | ///
236 | /// Build a 2D collider for the shape.
237 | ///
238 | protected override void AddColliderToGO(GameObject target)
239 | {
240 | CompositeCollider2D collider = new CompositeCollider2D();
241 | //foreach (VectorShape component in components)
242 | //{
243 | //}
244 |
245 | }
246 |
247 | ///
248 | /// Serialize the shape to an XML writer.
249 | ///
250 | public override void WriteToXML(XmlWriter writer, Vector2 origin, float scale)
251 | {
252 | //writer.WriteStartElement("circle");
253 |
254 | //foreach (VectorShape component in components)
255 | //{
256 | //}
257 |
258 | //writer.WriteEndElement();
259 | }
260 |
261 | #if UNITY_EDITOR
262 | ///
263 | /// Draw the circle to the active camera using editor handles.
264 | ///
265 | /// Is the shape selected?
266 | /// Is it the active shape?
267 | public override void DrawEditorHandles(bool selected, bool active = false)
268 | {
269 | base.DrawEditorHandles(selected, active);
270 |
271 | foreach (VectorShape component in _components)
272 | {
273 | component.DrawEditorHandles(selected, active);
274 | }
275 | }
276 |
277 | ///
278 | /// Respond to GUI input events in editor.
279 | ///
280 | /// The current event
281 | /// Is it the active shape?
282 | /// Did the shape handle the event?
283 | public override bool HandleEditorEvent(Event currEvent, bool active)
284 | {
285 | bool handled = false;
286 | foreach (VectorShape component in _components)
287 | {
288 | handled |= component.HandleEditorEvent(currEvent, active);
289 | }
290 |
291 | return handled;
292 | }
293 | #endif
294 | }
--------------------------------------------------------------------------------
/Assets/VectorShapes/CompoundShape.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 7fa59c0d8f5d54a84812e847216d6e6b
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/Editor.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 347d15c335d0e46cbbd1647d4d27ea57
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/Editor/SerializedShapeDrawer.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using UnityEditor;
3 |
4 | // IngredientDrawer
5 | [CustomPropertyDrawer(typeof(SerializedShape), true)]
6 | public class SerializedShapeDrawer : PropertyDrawer
7 | {
8 | const float padding = 4f;
9 |
10 | const float editButtonWidth = 30f;
11 |
12 | const float penLabelWidth = 24f;
13 | const float penSizeWidth = 30f;
14 | const float fillLabelWidth = 24f;
15 |
16 | const float colorChooserWidth = 24f;
17 |
18 | static GUIContent penLabelContent = new GUIContent("Pen", "Size and color of outline.");
19 | static GUIContent fillLabelContent = new GUIContent("Fill", "Color of interior.");
20 | static GUIContent editButtonContent = new GUIContent("Edit", "Modify the shape data.");
21 |
22 | // Draw the property inside the given rect
23 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
24 | {
25 | // Using BeginProperty / EndProperty on the parent property means that
26 | // prefab override logic works on the entire property.
27 | EditorGUI.BeginProperty(position, label, property);
28 |
29 | // Bail if the ScriptableObject hasn't been initialized
30 | if (property.objectReferenceValue == null)
31 | {
32 | EditorGUI.PropertyField(position, property);
33 | return;
34 | }
35 |
36 | // Draw label
37 | position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
38 |
39 | SerializedObject propertyObject = new SerializedObject(property.objectReferenceValue);
40 |
41 | // Don't make child fields be indented
42 | var indent = EditorGUI.indentLevel;
43 | EditorGUI.indentLevel = 0;
44 |
45 | // Calculate rects
46 | Rect shapeSettingsRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
47 | Rect colorSettingsRect = new Rect(position.x, shapeSettingsRect.yMax + padding, position.width, EditorGUIUtility.singleLineHeight);
48 |
49 | Rect editButtonRect = new Rect(shapeSettingsRect);
50 | editButtonRect.x = shapeSettingsRect.xMax - editButtonWidth;
51 | editButtonRect.width = editButtonWidth;
52 |
53 | //Rect shapeDescriptionRect = new Rect(shapeSettingsRect);
54 | //shapeDescriptionRect.x = shapeSettingsRect.x;
55 | //shapeDescriptionRect.xMax = editButtonRect.x - padding;
56 |
57 | //string shapeType = property.objectReferenceValue.GetType().Name;
58 | //int trimIndex = shapeType.LastIndexOf("Shape");
59 | //if (trimIndex > 0)
60 | //{
61 | // shapeType = shapeType.Substring(0, trimIndex);
62 | //}
63 | //GUIContent shapeLabelContent = new GUIContent(shapeType, "Kind of shape.");
64 |
65 | //GUIStyle rightJustified = new GUIStyle(GUI.skin.label);
66 | //rightJustified.alignment = TextAnchor.MiddleRight;
67 | //EditorGUI.LabelField(shapeDescriptionRect, shapeLabelContent, rightJustified);
68 |
69 | if (GUI.Button(editButtonRect, editButtonContent, EditorStyles.miniButton))
70 | {
71 | SerializedShape serializedShape = property.objectReferenceValue as SerializedShape;
72 |
73 | VectorShapeEditor.OpenEditor(serializedShape);
74 |
75 | EditorUtility.SetDirty(serializedShape);
76 | }
77 | //EditorGUI.PropertyField(shapeSettingsRect, property, GUIContent.none);
78 |
79 | /*
80 | // Go right to left so we overflow back into the label space on small windows
81 | Rect fillColorRect = new Rect(colorSettingsRect);
82 | fillColorRect.width = colorChooserWidth;
83 | fillColorRect.x = colorSettingsRect.xMax - fillColorRect.width;
84 | Rect fillLabelRect = new Rect(colorSettingsRect);
85 | fillLabelRect.width = fillLabelWidth;
86 | fillLabelRect.x = fillColorRect.x - fillLabelRect.width - padding;
87 |
88 | Rect penColorRect = new Rect(colorSettingsRect);
89 | penColorRect.width = colorChooserWidth;
90 | penColorRect.x = fillLabelRect.x - penColorRect.width - padding;
91 | Rect penSizeRect = new Rect(colorSettingsRect);
92 | penSizeRect.width = penSizeWidth;
93 | penSizeRect.x = penColorRect.x - penSizeRect.width - padding;
94 | Rect penLabelRect = new Rect(colorSettingsRect);
95 | penLabelRect.width = penLabelWidth;
96 | penLabelRect.x = penSizeRect.x - penLabelRect.width;
97 |
98 | EditorGUI.BeginChangeCheck();
99 | EditorGUI.LabelField(penLabelRect, penLabelContent);
100 | SerializedProperty penSize = propertyObject.FindProperty("penSize");
101 | SerializedProperty colorOutline = propertyObject.FindProperty("colorOutline");
102 | EditorGUI.PropertyField(penSizeRect, penSize, GUIContent.none);
103 | colorOutline.colorValue = EditorGUI.ColorField(penColorRect, GUIContent.none, colorOutline.colorValue, false, true, false);
104 |
105 | EditorGUI.LabelField(fillLabelRect, fillLabelContent);
106 | SerializedProperty colorFill = propertyObject.FindProperty("colorFill");
107 | colorFill.colorValue = EditorGUI.ColorField(fillColorRect, GUIContent.none, colorFill.colorValue, false, true, false);
108 |
109 | if (EditorGUI.EndChangeCheck() || propertyObject.hasModifiedProperties)
110 | {
111 | SerializedProperty shapeDirty = propertyObject.FindProperty("shapeDirty");
112 | if (shapeDirty != null) shapeDirty.boolValue = true;
113 | SerializedProperty meshDirty = propertyObject.FindProperty("meshDirty");
114 | if (meshDirty != null) meshDirty.boolValue = true;
115 |
116 | propertyObject.ApplyModifiedProperties();
117 | propertyObject.Update();
118 | }
119 | */
120 |
121 | // Set indent back to what it was
122 | EditorGUI.indentLevel = indent;
123 |
124 | EditorGUI.EndProperty();
125 | }
126 |
127 | public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
128 | {
129 | if (property.objectReferenceValue == null)
130 | {
131 | return EditorGUIUtility.singleLineHeight;
132 | }
133 |
134 | return EditorGUIUtility.singleLineHeight + padding;
135 | }
136 | }
--------------------------------------------------------------------------------
/Assets/VectorShapes/Editor/SerializedShapeDrawer.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4b2e9b1c021044776b0121c693731c7d
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/Editor/SingleSelectionPopup.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using UnityEngine;
3 | using UnityEditor;
4 |
5 | public class SingleSelectionPopup : PopupWindowContent
6 | {
7 | int index;
8 | GUIContent[] options;
9 | GUIStyle style;
10 |
11 | public SingleSelectionPopup(int selectedIndex, GUIContent[] displayedOptions)
12 | {
13 | index = selectedIndex;
14 | options = displayedOptions;
15 | style = GUIStyle.none;
16 | }
17 |
18 | public SingleSelectionPopup(int selectedIndex, GUIContent[] displayedOptions, GUIStyle displayedStyle)
19 | {
20 | index = selectedIndex;
21 | options = displayedOptions;
22 | style = displayedStyle;
23 | }
24 |
25 | public override Vector2 GetWindowSize()
26 | {
27 | Vector2 size = Vector2.one;
28 |
29 | for (int i = 0; i < options.Length; i++)
30 | {
31 | Vector2 contentSize = style.CalcSize(options[i]);
32 | size.x = Mathf.Max(size.x, contentSize.x);
33 | size.y += contentSize.y;
34 | }
35 |
36 | return size;
37 | }
38 |
39 | public override void OnGUI(Rect rect)
40 | {
41 | Rect labelRect = rect;
42 |
43 | for (int i = 0; i < options.Length; i++)
44 | {
45 | Vector2 contentSize = style.CalcSize(options[i]);
46 | labelRect.width = Mathf.Min(rect.width, contentSize.x);
47 | labelRect.height = contentSize.y;
48 |
49 | GUI.Label(labelRect, options[i], style);
50 |
51 | labelRect.y += labelRect.height;
52 | }
53 | }
54 |
55 | public override void OnOpen()
56 | {
57 | Debug.Log("Popup opened: " + this);
58 | }
59 |
60 | public override void OnClose()
61 | {
62 | Debug.Log("Popup closed: " + this);
63 | }
64 | }
--------------------------------------------------------------------------------
/Assets/VectorShapes/Editor/SingleSelectionPopup.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 797519715515d413c967199d201e8455
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/Editor/VectorShapeEditor.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d91219672378e4e7c92c87f239c75f5d
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/EllipseShape.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Xml;
3 | using UnityEngine;
4 | #if UNITY_EDITOR
5 | using UnityEditor;
6 | #endif
7 | using Unity.VectorGraphics;
8 |
9 | ///
10 | /// Ellipse equations are taken from Luc Maisonobe's
11 | /// "Quick computation of the distance between a point and an ellipse"
12 | ///
13 |
14 | [System.Serializable]
15 | ///
16 | /// Vector ellipse.
17 | ///
18 | public class EllipseShape : VectorShape
19 | {
20 | ///
21 | /// Position of center.
22 | ///
23 | [SerializeField]
24 | protected Vector2 position;
25 |
26 | ///
27 | /// Major axis of the ellipse.
28 | ///
29 | [SerializeField]
30 | protected Vector2 majorAxis;
31 |
32 | ///
33 | /// Eccentricty of ellipse (ratio of focuss distance to major axis).
34 | ///
35 | [SerializeField]
36 | protected float eccentricity;
37 |
38 | ///
39 | /// Starting angle for elliptical arcs (in radians).
40 | ///
41 | [SerializeField]
42 | protected float startAngle = 0f;
43 |
44 | ///
45 | /// Sweep angle for elliptical arcs (in radians).
46 | ///
47 | [SerializeField]
48 | protected float sweepAngle = Mathf.PI * 2f;
49 |
50 | ///
51 | /// Position of center.
52 | ///
53 | public Vector2 Position
54 | {
55 | set
56 | {
57 | position = value;
58 | Dirty = true;
59 | }
60 | get
61 | {
62 | return position;
63 | }
64 | }
65 |
66 | ///
67 | /// Eccentricty of ellipse (ratio of focuss distance to major axis).
68 | ///
69 | public float Eccentricity
70 | {
71 | set
72 | {
73 | if ((eccentricity >= 0f) && (eccentricity < 1f))
74 | {
75 | eccentricity = value;
76 | Dirty = true;
77 | }
78 | else
79 | {
80 | Debug.LogWarning("Invalid value for eccentricity: " + value);
81 | }
82 | }
83 | get
84 | {
85 | return eccentricity;
86 | }
87 | }
88 |
89 | ///
90 | /// Major axis of the ellipse.
91 | ///
92 | public Vector2 MajorAxis
93 | {
94 | set
95 | {
96 | majorAxis = value;
97 | Dirty = true;
98 | }
99 | get
100 | {
101 | return majorAxis;
102 | }
103 | }
104 |
105 | ///
106 | /// Minor axis of the ellipse (read only).
107 | ///
108 | public Vector2 MinorAxis
109 | {
110 | get
111 | {
112 | Vector2 minorAxis = Vector2.Perpendicular(majorAxis) * Mathf.Sqrt(1f - (eccentricity * eccentricity));
113 | return minorAxis;
114 | }
115 | }
116 |
117 | ///
118 | /// Starting angle for elliptical arcs (in degrees).
119 | ///
120 | public float StartAngle
121 | {
122 | set
123 | {
124 | startAngle = value * Mathf.Deg2Rad;
125 | Dirty = true;
126 | }
127 | get
128 | {
129 | return startAngle * Mathf.Rad2Deg;
130 | }
131 | }
132 |
133 | ///
134 | /// Sweep angle for elliptical arcs (in degrees).
135 | ///
136 | public float SweepAngle
137 | {
138 | set
139 | {
140 | sweepAngle = value * Mathf.Deg2Rad;
141 | if (Mathf.Approximately(value, 0f) || (Mathf.Abs(value) >= 360f))
142 | {
143 | closed = true;
144 | }
145 | else
146 | {
147 | closed = false;
148 | }
149 | Dirty = true;
150 | }
151 | get
152 | {
153 | return sweepAngle * Mathf.Rad2Deg;
154 | }
155 | }
156 |
157 | protected EllipseShape()
158 | {
159 | }
160 |
161 | ///
162 | /// New ellipse from center point and axis radii (SVG format).
163 | ///
164 | /// Center of circle
165 | /// Radius of ellipse on X axis
166 | /// Radius of ellipse on Y axis
167 | /// Rotation from x-axis (in degrees)
168 | public EllipseShape(Vector2 center, float radX, float radY, float rotation = 0f)
169 | {
170 | position = center;
171 | if (radX >= radY)
172 | {
173 | majorAxis = Vector2.right * radX;
174 | eccentricity = Mathf.Sin(Mathf.Atan2(radX, radY));
175 | }
176 | else
177 | {
178 | majorAxis = Vector2.up * radY;
179 | eccentricity = Mathf.Sin(Mathf.Atan2(radY, radX));
180 | }
181 |
182 | majorAxis = Matrix2D.RotateRH(rotation * Mathf.Deg2Rad).MultiplyVector(majorAxis);
183 | }
184 |
185 | ///
186 | /// New ellipse from center point, major axis, and minor axis ratio (DXF format).
187 | ///
188 | /// Center of circle
189 | /// Major axis of the ellipse
190 | /// Ratio of minor axis to major axis
191 | public EllipseShape(Vector2 center, Vector2 major, float ratio)
192 | {
193 | position = center;
194 | majorAxis = major;
195 | float majorLength = major.magnitude;
196 | float minorLength = major.magnitude * ratio;
197 |
198 | eccentricity = Mathf.Sqrt((majorLength * majorLength) - (minorLength * minorLength)) / majorLength;
199 | }
200 |
201 | ///
202 | /// New elliptical arc from center point, major axis, minor axis ration, and angles.
203 | ///
204 | /// Center of circle
205 | /// Major axis of the ellipse
206 | /// Ratio of minor axis to major axis
207 | /// Starting angle of arc (in degrees)
208 | /// Sweep of arc (in degrees)
209 | public EllipseShape(Vector2 center, Vector2 major, float ratio, float angle, float sweep)
210 | {
211 | position = center;
212 | majorAxis = major;
213 | float majorLength = major.magnitude;
214 | float minorLength = major.magnitude * ratio;
215 |
216 | eccentricity = Mathf.Sqrt((majorLength * majorLength) - (minorLength * minorLength)) / majorLength;
217 |
218 | startAngle = angle * Mathf.Deg2Rad;
219 | sweepAngle = sweep * Mathf.Deg2Rad;
220 |
221 | if (Mathf.Approximately(sweep, 0f) || (Mathf.Abs(sweep) >= 360f))
222 | {
223 | closed = true;
224 | }
225 | else
226 | {
227 | closed = false;
228 | }
229 | }
230 |
231 | protected static EllipseShape Create()
232 | {
233 | //EllipseShape shape = ScriptableObject.CreateInstance();
234 | EllipseShape shape = new EllipseShape();
235 |
236 | return shape;
237 | }
238 |
239 | ///
240 | /// New ellipse from center point and axis radii (SVG format).
241 | ///
242 | /// Center of circle
243 | /// Radius of ellipse on X axis
244 | /// Radius of ellipse on Y axis
245 | /// Rotation from x-axis (in degrees)
246 | public static EllipseShape Create(Vector2 center, float radX, float radY, float rotation = 0f)
247 | {
248 | EllipseShape shape = Create();
249 |
250 | shape.position = center;
251 | if (radX >= radY)
252 | {
253 | shape.majorAxis = Vector2.right * radX;
254 | shape.eccentricity = Mathf.Sin(Mathf.Atan2(radX, radY));
255 | }
256 | else
257 | {
258 | shape.majorAxis = Vector2.up * radY;
259 | shape.eccentricity = Mathf.Sin(Mathf.Atan2(radY, radX));
260 | }
261 |
262 | shape.majorAxis = Matrix2D.RotateRH(rotation * Mathf.Deg2Rad).MultiplyVector(shape.majorAxis);
263 |
264 | return shape;
265 | }
266 |
267 | ///
268 | /// New ellipse from center point, major axis, and minor axis ratio (DXF format).
269 | ///
270 | /// Center of circle
271 | /// Major axis of the ellipse
272 | /// Ratio of minor axis to major axis
273 | public static EllipseShape Create(Vector2 center, Vector2 major, float ratio)
274 | {
275 | EllipseShape shape = Create();
276 |
277 | shape.position = center;
278 | shape.majorAxis = major;
279 | float majorLength = major.magnitude;
280 | float minorLength = major.magnitude * ratio;
281 |
282 | shape.eccentricity = Mathf.Sqrt((majorLength * majorLength) - (minorLength * minorLength)) / majorLength;
283 |
284 | return shape;
285 | }
286 |
287 | ///
288 | /// New elliptical arc from center point, major axis, minor axis ration, and angles.
289 | ///
290 | /// Center of circle
291 | /// Major axis of the ellipse
292 | /// Ratio of minor axis to major axis
293 | /// Starting angle of arc (in degrees)
294 | /// Sweep of arc (in degrees)
295 | public static EllipseShape Create(Vector2 center, Vector2 major, float ratio, float angle, float sweep)
296 | {
297 | EllipseShape shape = Create();
298 |
299 | shape.position = center;
300 | shape.majorAxis = major;
301 | float majorLength = major.magnitude;
302 | float minorLength = major.magnitude * ratio;
303 |
304 | shape.eccentricity = Mathf.Sqrt((majorLength * majorLength) - (minorLength * minorLength)) / majorLength;
305 |
306 | shape.startAngle = angle * Mathf.Deg2Rad;
307 | shape.sweepAngle = sweep * Mathf.Deg2Rad;
308 |
309 | if (Mathf.Approximately(sweep, 0f) || (Mathf.Abs(sweep) >= 360f))
310 | {
311 | shape.closed = true;
312 | }
313 | else
314 | {
315 | shape.closed = false;
316 | }
317 |
318 | return shape;
319 | }
320 |
321 | ///
322 | /// Copy of the shape.
323 | ///
324 | /// New shape with properties of existing shape
325 | public override VectorShape Duplicate()
326 | {
327 | float ratio = MinorAxis.magnitude / MajorAxis.magnitude;
328 | return Create(position, majorAxis, ratio, startAngle * Mathf.Rad2Deg, sweepAngle * Mathf.Rad2Deg);
329 | }
330 |
331 | private static Vector2 ClosestEllipsePoint(Vector2 point, float semiMajor, float semiMinor)
332 | {
333 | Vector2 p = new Vector2(Mathf.Abs(point.x), Mathf.Abs(point.y));
334 |
335 | float t = Mathf.PI / 4;
336 |
337 | float a = semiMajor;
338 | float b = semiMinor;
339 |
340 | Vector2 pt;
341 |
342 | float cosT, sinT, deltaC, deltaT;
343 | Vector2 e; Vector2 r; Vector2 q;
344 |
345 | for (int i = 0; i < 3; i++)
346 | {
347 | cosT = Mathf.Cos(t);
348 | sinT = Mathf.Sin(t);
349 |
350 | pt.x = a * cosT;
351 | pt.y = b * sinT;
352 |
353 | e.x = (a * a - b * b) * (cosT * cosT * cosT) / a;
354 | e.y = (b * b - a * a) * (sinT * sinT * sinT) / b;
355 |
356 | r = pt - e;
357 | q = p - e;
358 |
359 | deltaC = r.magnitude * Mathf.Asin((r.x * q.y - r.y * q.x) / (r.magnitude * q.magnitude));
360 | deltaT = deltaC / Mathf.Sqrt(a * a + b * b - pt.sqrMagnitude);
361 |
362 | t += deltaT;
363 | t = Mathf.Clamp(t, 0f, Mathf.PI / 2);
364 | }
365 |
366 | pt.x = a * Mathf.Cos(t) * Mathf.Sign(point.x);
367 | pt.y = b * Mathf.Sin(t) * Mathf.Sign(point.y);
368 |
369 | return pt;
370 | }
371 |
372 | ///
373 | /// Closest point on the shape to a point.
374 | ///
375 | /// Test point
376 | /// Closest point on shape
377 | public Vector2 ClosestPoint(Vector2 pt)
378 | {
379 | float theta = Mathf.Atan2(MajorAxis.y, MajorAxis.x);
380 |
381 | Vector2 major = MajorAxis;
382 | Vector2 minor = MinorAxis;
383 |
384 | Matrix2D matrix = Matrix2D.RotateRH(-theta) * Matrix2D.Translate(-position);
385 |
386 | Vector2 standardPt = matrix.MultiplyPoint(pt);
387 |
388 | Vector2 closestPt = ClosestEllipsePoint(standardPt, major.magnitude, minor.magnitude);
389 |
390 | closestPt = matrix.Inverse().MultiplyPoint(closestPt);
391 |
392 | return closestPt;
393 | }
394 |
395 | ///
396 | /// Distance between a point and the shape.
397 | ///
398 | /// Test point
399 | /// Distance from point to nearest point on shape
400 | public override float Distance(Vector2 pt)
401 | {
402 | Vector2 closest = ClosestPoint(pt);
403 |
404 | return Vector2.Distance(pt, closest);
405 | }
406 |
407 | ///
408 | /// Tests if a shape contains a point
409 | ///
410 | /// Test point
411 | /// Is the point inside the shape?
412 | public override bool Contains(Vector2 pt)
413 | {
414 | Vector2 focus1 = position + majorAxis * eccentricity;
415 | Vector2 focus2 = position - majorAxis * eccentricity;
416 |
417 | float distance1 = Vector2.Distance(pt, focus1);
418 | float distance2 = Vector2.Distance(pt, focus2);
419 | return ((distance1 + distance2) < (majorAxis.magnitude * 2f));
420 | }
421 |
422 | ///
423 | /// Tests if a shape is inside a rectangle.
424 | ///
425 | /// Test rectangle
426 | /// Is the shape entirely inside the rectangle?
427 | public override bool IsInside(Rect rect)
428 | {
429 | if (boundsDirty) GenerateBounds();
430 |
431 | if (rect.xMin > shapeBounds.xMin) return false;
432 | if (rect.xMax < shapeBounds.xMax) return false;
433 | if (rect.yMin > shapeBounds.yMin) return false;
434 | if (rect.yMax < shapeBounds.yMax) return false;
435 |
436 | return true;
437 | }
438 |
439 | ///
440 | /// Rotate the shape around a point.
441 | ///
442 | /// Center of rotation
443 | /// Angle in degrees
444 | public override void RotateAround(Vector2 center, float angle)
445 | {
446 | Matrix2D matrix = Matrix2D.Translate(center) * Matrix2D.RotateRH(angle * Mathf.Deg2Rad) * Matrix2D.Translate(-center);
447 | position = matrix.MultiplyPoint(position);
448 | majorAxis = matrix.MultiplyVector(majorAxis);
449 |
450 | Dirty = true;
451 | }
452 |
453 | ///
454 | /// Change the origin of the shape.
455 | ///
456 | /// Direction to move
457 | public override void TranslateBy(Vector2 offset)
458 | {
459 | position += offset;
460 |
461 | Dirty = true;
462 | }
463 |
464 | ///
465 | /// Transform the shape by an arbitrary matrix.
466 | ///
467 | /// Matrix to transform shape
468 | public override void TransformBy(Matrix2D matrix)
469 | {
470 | position = matrix.MultiplyPoint(position);
471 | majorAxis = matrix.MultiplyVector(majorAxis);
472 |
473 | Dirty = true;
474 | }
475 |
476 | ///
477 | /// Change the size of the shape.
478 | ///
479 | /// Scaling factor to apply
480 | public override void ScaleBy(float scale)
481 | {
482 | if (scale < Mathf.Epsilon)
483 | {
484 | Debug.LogWarning("Scale must be greater than zero.");
485 | return;
486 | }
487 |
488 | position *= scale;
489 | majorAxis *= scale;
490 |
491 | Dirty = true;
492 | }
493 |
494 | ///
495 | /// Distance between a point and the shape.
496 | ///
497 | /// Test point
498 | /// Snap modes to consider
499 | /// Distance from point to nearest point on shape
500 | public override SnapPoint GetSnap(Vector2 pt, SnapPoint.Mode mode)
501 | {
502 | SnapPoint snap = new SnapPoint();
503 | float distance = float.MaxValue;
504 |
505 | if ((mode & SnapPoint.Mode.Center) != 0)
506 | {
507 | Vector2[] centerPoints =
508 | {
509 | position,
510 | position + majorAxis * eccentricity,
511 | position - majorAxis * eccentricity,
512 | };
513 |
514 | foreach (Vector2 testPt in centerPoints)
515 | {
516 | float d = Vector2.Distance(pt, testPt);
517 | if (d < distance)
518 | {
519 | distance = d;
520 | snap.mode = SnapPoint.Mode.Midpoint;
521 | snap.point = testPt;
522 | }
523 | }
524 | }
525 |
526 | if ((mode & SnapPoint.Mode.Midpoint) != 0)
527 | {
528 | Vector2[] midPoints =
529 | {
530 | position + majorAxis,
531 | position + MinorAxis,
532 | position - majorAxis,
533 | position - MinorAxis,
534 | };
535 |
536 | foreach (Vector2 testPt in midPoints)
537 | {
538 | float d = Vector2.Distance(pt, testPt);
539 | if (d < distance)
540 | {
541 | distance = d;
542 | snap.mode = SnapPoint.Mode.Midpoint;
543 | snap.point = testPt;
544 | }
545 | }
546 | }
547 |
548 | if ((mode & SnapPoint.Mode.Edge) != 0)
549 | {
550 | Vector2 closest = ClosestPoint(pt);
551 | float d = Vector2.Distance(pt, closest);
552 |
553 | if (d < distance)
554 | {
555 | distance = d;
556 | snap.mode = SnapPoint.Mode.Edge;
557 | snap.point = closest;
558 | }
559 | }
560 |
561 | return snap;
562 | }
563 |
564 | protected BezierSegment[] GenerateSegments()
565 | {
566 | int numCurves = 4; // Supposed to calculate from max error
567 | float theta = Mathf.Atan2(MajorAxis.y, MajorAxis.x);
568 |
569 | BezierSegment[] segments = new BezierSegment[numCurves];
570 | float deltaAngle = sweepAngle / numCurves;
571 | float sinTheta = Mathf.Sin(theta);
572 | float cosTheta = Mathf.Cos(theta);
573 | float angleB = startAngle;
574 | float a = MajorAxis.magnitude;
575 | float b = MinorAxis.magnitude;
576 | float t = Mathf.Tan(0.5f * deltaAngle);
577 | float alpha = Mathf.Sin(deltaAngle) * (Mathf.Sqrt(4f + 3f * t * t) - 1f) / 3f;
578 |
579 | float sinAngleB = Mathf.Sin(angleB);
580 | float cosAngleB = Mathf.Cos(angleB);
581 | float aSinAngleB = a * sinAngleB;
582 | float aCosAngleB = a * cosAngleB;
583 | float bSinAngleB = b * sinAngleB;
584 | float bCosAngleB = b * cosAngleB;
585 | Vector2 ptB = new Vector2();
586 | ptB.x = position.x + aCosAngleB * cosTheta - bSinAngleB * sinTheta;
587 | ptB.y = position.y + aCosAngleB * sinTheta + bSinAngleB * cosTheta;
588 | Vector2 dotB = new Vector2();
589 | dotB.x = -aSinAngleB * cosTheta - bCosAngleB * sinTheta;
590 | dotB.y = -aSinAngleB * sinTheta + bCosAngleB * cosTheta;
591 |
592 | for (int i = 0; i < numCurves; ++i)
593 | {
594 | float angleA = angleB;
595 | Vector2 ptA = ptB;
596 | Vector2 dotA = dotB;
597 |
598 | angleB += deltaAngle;
599 | sinAngleB = Mathf.Sin(angleB);
600 | cosAngleB = Mathf.Cos(angleB);
601 | aSinAngleB = a * sinAngleB;
602 | aCosAngleB = a * cosAngleB;
603 | bSinAngleB = b * sinAngleB;
604 | bCosAngleB = b * cosAngleB;
605 | ptB.x = position.x + aCosAngleB * cosTheta - bSinAngleB * sinTheta;
606 | ptB.y = position.y + aCosAngleB * sinTheta + bSinAngleB * cosTheta;
607 | dotB.x = -aSinAngleB * cosTheta - bCosAngleB * sinTheta;
608 | dotB.y = -aSinAngleB * sinTheta + bCosAngleB * cosTheta;
609 |
610 | segments[i].P0 = ptA;
611 | segments[i].P1.x = ptA.x + alpha * dotA.x;
612 | segments[i].P1.y = ptA.y + alpha * dotA.y;
613 | segments[i].P2.x = ptB.x - alpha * dotB.x;
614 | segments[i].P2.y = ptB.y - alpha * dotB.y;
615 | segments[i].P3 = ptB;
616 | }
617 |
618 | return segments;
619 | }
620 |
621 | ///
622 | /// Tessellate the shape into geometry data.
623 | ///
624 | protected override void GenerateGeometry()
625 | {
626 | if ((shapeGeometry != null) && (!shapeDirty)) return;
627 |
628 | Shape ellipse = new Shape();
629 |
630 | ellipse.PathProps = new PathProperties()
631 | {
632 | Stroke = new Stroke()
633 | {
634 | Color = colorOutline,
635 | HalfThickness = penSize / 2f * penToMeshScale
636 | }
637 | };
638 | if (colorFill != Color.clear)
639 | {
640 | ellipse.Fill = new SolidFill()
641 | {
642 | Color = colorFill
643 | };
644 | }
645 |
646 | BezierSegment[] segments = GenerateSegments();
647 |
648 | ellipse.Contours = new BezierContour[1];
649 | ellipse.Contours[0] = new BezierContour();
650 | ellipse.Contours[0].Segments = VectorUtils.BezierSegmentsToPath(segments);
651 |
652 | shapeNode = new SceneNode()
653 | {
654 | Transform = matrixTransform,
655 | Shapes = new List
656 | {
657 | ellipse
658 | }
659 | };
660 |
661 | tessellationScene.Root = shapeNode;
662 | shapeGeometry = VectorUtils.TessellateScene(tessellationScene, tessellationOptions);
663 |
664 | shapeDirty = false;
665 | }
666 |
667 | ///
668 | /// Build a mesh for display with the VectorLineShader.
669 | ///
670 | protected override void GenerateLineMesh()
671 | {
672 | BezierSegment[] segments = GenerateSegments();
673 |
674 | lineBuilder.BeginPolyLine(segments[0].P0);
675 |
676 | for (int i = 0; i < segments.Length; i++)
677 | {
678 | BezierSegment segment = segments[i];
679 | lineBuilder.CurveTo(segment.P1, segment.P2, segment.P3, 8);
680 | }
681 |
682 | lineBuilder.EndPolyLine(closed);
683 | }
684 |
685 | ///
686 | /// Build a 2D bounding box for the shape.
687 | ///
688 | protected override void GenerateBounds()
689 | {
690 | float a = MajorAxis.magnitude;
691 | float b = MinorAxis.magnitude;
692 | float theta = Mathf.Atan2(MajorAxis.y, MajorAxis.x);
693 |
694 | float sinTheta = Mathf.Sin(theta);
695 | float cosTheta = Mathf.Cos(theta);
696 | float extentX = Mathf.Sqrt((a * a * cosTheta * cosTheta) + (b * b * sinTheta * sinTheta));
697 | float extentY = Mathf.Sqrt((a * a * sinTheta * sinTheta) + (b * b * cosTheta * cosTheta));
698 |
699 | shapeBounds.xMin = position.x - extentX;
700 | shapeBounds.xMax = position.x + extentX;
701 | shapeBounds.yMin = position.y - extentY;
702 | shapeBounds.yMax = position.y + extentY;
703 |
704 | boundsDirty = false;
705 | }
706 |
707 | ///
708 | /// Build a 2D collider for the shape.
709 | ///
710 | protected override void AddColliderToGO(GameObject target)
711 | {
712 | CircleCollider2D[] colliders = target.GetComponents();
713 | CircleCollider2D collider = null;
714 |
715 | for (int i = 0; i < colliders.Length; i++)
716 | {
717 | if (colliders[i].name == this.guid)
718 | {
719 | collider = colliders[i];
720 | }
721 | }
722 |
723 | // HACK - this is REALLY wrong
724 | if (collider == null)
725 | {
726 | collider = collider.gameObject.AddComponent();
727 | collider.name = this.guid;
728 | }
729 |
730 | collider.offset = position;
731 | collider.radius = majorAxis.magnitude;
732 | }
733 |
734 | ///
735 | /// Serialize the shape to an XML writer.
736 | ///
737 | public override void WriteToXML(XmlWriter writer, Vector2 origin, float scale)
738 | {
739 | }
740 |
741 | #if UNITY_EDITOR
742 | ///
743 | /// Draw the circle to the active camera using editor handles.
744 | ///
745 | /// Is the shape selected?
746 | /// Is it the active shape?
747 | public override void DrawEditorHandles(bool selected, bool active = false)
748 | {
749 | base.DrawEditorHandles(selected, active);
750 |
751 | /*
752 | Vector3 handleP0 = new Vector3();
753 | Vector3 handleP1 = new Vector3();
754 | Vector3 handleP2 = new Vector3();
755 | Vector3 handleP3 = new Vector3();
756 |
757 | if (colorFill != Color.clear)
758 | {
759 | Color colorPrev = Handles.color;
760 | Vector3 center3 = new Vector3(position.x, position.y, 0);
761 |
762 | Handles.color = colorFill;
763 | Handles.DrawSolidDisc(center3, Vector3.forward, radius);
764 | Handles.color = colorPrev;
765 | }
766 |
767 | // Draw the circle using 4 Bezier curves so we can control the pen size
768 | handleP0.x = position.x;
769 | handleP0.y = position.y + radius;
770 | handleP1.x = position.x + radius * bezierCircleConst;
771 | handleP1.y = position.y + radius;
772 | handleP2.x = position.x + radius;
773 | handleP2.y = position.y + radius * bezierCircleConst;
774 | handleP3.x = position.x + radius;
775 | handleP3.y = position.y;
776 | Handles.DrawBezier(handleP0, handleP3, handleP1, handleP2, colorOutline, handleDrawTexture, penSize);
777 |
778 | handleP0.x = position.x + radius;
779 | handleP0.y = position.y;
780 | handleP1.x = position.x + radius;
781 | handleP1.y = position.y - radius * bezierCircleConst;
782 | handleP2.x = position.x + radius * bezierCircleConst;
783 | handleP2.y = position.y - radius;
784 | handleP3.x = position.x;
785 | handleP3.y = position.y - radius;
786 | Handles.DrawBezier(handleP0, handleP3, handleP1, handleP2, colorOutline, handleDrawTexture, penSize);
787 |
788 | handleP0.x = position.x;
789 | handleP0.y = position.y - radius;
790 | handleP1.x = position.x - radius * bezierCircleConst;
791 | handleP1.y = position.y - radius;
792 | handleP2.x = position.x - radius;
793 | handleP2.y = position.y - radius * bezierCircleConst;
794 | handleP3.x = position.x - radius;
795 | handleP3.y = position.y;
796 | Handles.DrawBezier(handleP0, handleP3, handleP1, handleP2, colorOutline, handleDrawTexture, penSize);
797 |
798 | handleP0.x = position.x - radius;
799 | handleP0.y = position.y;
800 | handleP1.x = position.x - radius;
801 | handleP1.y = position.y + radius * bezierCircleConst;
802 | handleP2.x = position.x - radius * bezierCircleConst;
803 | handleP2.y = position.y + radius;
804 | handleP3.x = position.x;
805 | handleP3.y = position.y + radius;
806 | Handles.DrawBezier(handleP0, handleP3, handleP1, handleP2, colorOutline, handleDrawTexture, penSize);
807 | */
808 |
809 | if (active)
810 | {
811 |
812 | }
813 | }
814 |
815 | ///
816 | /// Respond to GUI input events in editor.
817 | ///
818 | /// The current event
819 | /// Is it the active shape?
820 | /// Did the shape handle the event?
821 | public override bool HandleEditorEvent(Event currEvent, bool active)
822 | {
823 | return false;
824 | }
825 | #endif
826 |
827 | }
--------------------------------------------------------------------------------
/Assets/VectorShapes/EllipseShape.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 37d662c8881e7473ea893cc9c063c031
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/PointShape.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Xml;
3 | using UnityEngine;
4 | #if UNITY_EDITOR
5 | using UnityEditor;
6 | #endif
7 | using Unity.VectorGraphics;
8 |
9 | [System.Serializable]
10 | ///
11 | /// Vector point.
12 | ///
13 | public class PointShape : VectorShape
14 | {
15 | ///
16 | /// Visual size of point.
17 | ///
18 | public float pointRadius = 0.1f;
19 |
20 | ///
21 | /// Position of point.
22 | ///
23 | public Vector2 position;
24 |
25 | protected PointShape()
26 | {
27 | }
28 |
29 | ///
30 | /// New point from location.
31 | ///
32 | /// Position of point
33 | public PointShape(Vector2 location)
34 | {
35 | position = location;
36 | }
37 |
38 | ///
39 | /// New point from coordinates.
40 | ///
41 | /// X position of point
42 | /// X position of point
43 | public PointShape(float x, float y)
44 | {
45 | position = new Vector2(x, y);
46 | }
47 |
48 | protected static PointShape Create()
49 | {
50 | //PointShape shape = ScriptableObject.CreateInstance();
51 | PointShape shape = new PointShape();
52 |
53 | return shape;
54 | }
55 |
56 | ///
57 | /// New point from location.
58 | ///
59 | /// Position of point
60 | public static PointShape Create(Vector2 location)
61 | {
62 | PointShape shape = Create();
63 |
64 | shape.position = location;
65 |
66 | return shape;
67 | }
68 |
69 | ///
70 | /// New point from coordinates.
71 | ///
72 | /// X position of point
73 | /// X position of point
74 | public static PointShape Create(float x, float y)
75 | {
76 | PointShape shape = Create();
77 |
78 | shape.position = new Vector2(x, y);
79 |
80 | return shape;
81 | }
82 |
83 | ///
84 | /// Copy of the shape.
85 | ///
86 | /// New shape with properties of existing shape
87 | public override VectorShape Duplicate()
88 | {
89 | return Create(position);
90 | }
91 |
92 | ///
93 | /// Distance between a point and the shape.
94 | ///
95 | /// Test point
96 | /// Distance from point to nearest point on shape
97 | public override float Distance(Vector2 pt)
98 | {
99 | return Vector2.Distance(pt, position);
100 | }
101 |
102 | ///
103 | /// Tests if a shape contains a point
104 | ///
105 | /// Test point
106 | /// Is the point inside the shape?
107 | public override bool Contains(Vector2 pt)
108 | {
109 | return false;
110 | }
111 |
112 | ///
113 | /// Tests if a shape is inside a rectangle.
114 | ///
115 | /// Test rectangle
116 | /// Is the shape entirely inside the rectangle?
117 | public override bool IsInside(Rect rect)
118 | {
119 | return rect.Contains(position);
120 | }
121 |
122 | ///
123 | /// Rotate the shape around a point.
124 | ///
125 | /// Center of rotation
126 | /// Angle in degrees
127 | public override void RotateAround(Vector2 center, float angle)
128 | {
129 | Matrix2D matrix = Matrix2D.Translate(center) * Matrix2D.RotateRH(angle * Mathf.Deg2Rad) * Matrix2D.Translate(-center);
130 | position = matrix.MultiplyPoint(position);
131 |
132 | Dirty = true;
133 | }
134 |
135 | ///
136 | /// Change the origin of the shape.
137 | ///
138 | /// Direction to move
139 | public override void TranslateBy(Vector2 offset)
140 | {
141 | position += offset;
142 |
143 | Dirty = true;
144 | }
145 |
146 | ///
147 | /// Change the size of the shape.
148 | ///
149 | /// Scaling factor to apply
150 | public override void ScaleBy(float scale)
151 | {
152 | if (scale < Mathf.Epsilon)
153 | {
154 | Debug.LogWarning("Scale must be greater than zero.");
155 | return;
156 | }
157 |
158 | position *= scale;
159 |
160 | Dirty = true;
161 | }
162 |
163 | ///
164 | /// Transform the shape by an arbitrary matrix.
165 | ///
166 | /// Matrix to transform shape
167 | public override void TransformBy(Matrix2D matrix)
168 | {
169 | position = matrix.MultiplyPoint(position);
170 |
171 | Dirty = true;
172 | }
173 |
174 | ///
175 | /// Distance between a point and the shape.
176 | ///
177 | /// Test point
178 | /// Snap modes to consider
179 | /// Distance from point to nearest point on shape
180 | public override SnapPoint GetSnap(Vector2 pt, SnapPoint.Mode mode)
181 | {
182 | SnapPoint snap = new SnapPoint();
183 |
184 | snap.point = position;
185 |
186 | if ((mode & SnapPoint.Mode.Center) != 0) snap.mode = SnapPoint.Mode.Center;
187 | else if ((mode & SnapPoint.Mode.Endpoint) != 0) snap.mode = SnapPoint.Mode.Endpoint;
188 | else if ((mode & SnapPoint.Mode.Midpoint) != 0) snap.mode = SnapPoint.Mode.Midpoint;
189 | else if ((mode & SnapPoint.Mode.Edge) != 0) snap.mode = SnapPoint.Mode.Edge;
190 |
191 | return snap;
192 | }
193 |
194 | ///
195 | /// Tessellate the shape into geometry data.
196 | ///
197 | protected override void GenerateGeometry()
198 | {
199 | if ((shapeGeometry != null) && (!shapeDirty)) return;
200 |
201 | var seg1 = VectorUtils.MakePathLine(
202 | new Vector2(position.x, position.y + pointRadius),
203 | new Vector2(position.x, position.y - pointRadius)
204 | );
205 | var seg2 = VectorUtils.MakePathLine(
206 | new Vector2(position.x + pointRadius, position.y),
207 | new Vector2(position.x - pointRadius, position.y)
208 | );
209 |
210 | PathProperties pathProps = new PathProperties()
211 | {
212 | Stroke = new Stroke()
213 | {
214 | Color = colorOutline,
215 | HalfThickness = penSize / 2f * penToMeshScale
216 | }
217 | };
218 |
219 | Shape segment1 = new Shape()
220 | {
221 | Contours = new BezierContour[]
222 | {
223 | new BezierContour {Segments = seg1}
224 | },
225 | PathProps = pathProps
226 | };
227 |
228 | Shape segment2 = new Shape()
229 | {
230 | Contours = new BezierContour[]
231 | {
232 | new BezierContour {Segments = seg2}
233 | },
234 | PathProps = pathProps
235 | };
236 |
237 | shapeNode = new SceneNode()
238 | {
239 | Transform = matrixTransform,
240 | Shapes = new List
241 | {
242 | segment1, segment2
243 | }
244 | };
245 |
246 | tessellationScene.Root = shapeNode;
247 |
248 | shapeGeometry = VectorUtils.TessellateScene(tessellationScene, tessellationOptions);
249 | shapeDirty = false;
250 | }
251 |
252 | ///
253 | /// Build a mesh for display with the VectorLineShader.
254 | ///
255 | protected override void GenerateLineMesh()
256 | {
257 | lineBuilder.BeginPolyLine(new Vector2(position.x, position.y + pointRadius));
258 | lineBuilder.LineTo(new Vector2(position.x, position.y - pointRadius));
259 | lineBuilder.EndPolyLine();
260 |
261 | lineBuilder.BeginPolyLine(new Vector2(position.x + pointRadius, position.y));
262 | lineBuilder.LineTo(new Vector2(position.x - pointRadius, position.y));
263 | lineBuilder.EndPolyLine();
264 | }
265 |
266 | ///
267 | /// Build a 2D bounding box for the shape.
268 | ///
269 | protected override void GenerateBounds()
270 | {
271 | shapeBounds = new Rect(position, Vector2.zero);
272 | boundsDirty = false;
273 | }
274 |
275 | ///
276 | /// Build a 2D collider for the shape.
277 | ///
278 | protected override void AddColliderToGO(GameObject target)
279 | {
280 | CircleCollider2D[] colliders = target.GetComponents();
281 | CircleCollider2D collider = null;
282 |
283 | for (int i = 0; i < colliders.Length; i++)
284 | {
285 | if (colliders[i].name == this.guid)
286 | {
287 | collider = colliders[i];
288 | }
289 | }
290 |
291 | if (collider == null)
292 | {
293 | collider = collider.gameObject.AddComponent();
294 | collider.name = this.guid;
295 | }
296 |
297 | collider.offset = position;
298 | collider.radius = pointRadius;
299 | }
300 |
301 | ///
302 | /// Serialize the shape to an XML writer.
303 | ///
304 | public override void WriteToXML(XmlWriter writer, Vector2 origin, float scale)
305 | {
306 | }
307 |
308 | #if UNITY_EDITOR
309 | ///
310 | /// Draw the point to the active camera using editor handles.
311 | ///
312 | /// Is the shape selected?
313 | /// Is it the active shape?
314 | public override void DrawEditorHandles(bool selected, bool active = false)
315 | {
316 | base.DrawEditorHandles(selected, active);
317 |
318 | /*
319 | Color colorPrev = Handles.color;
320 | Handles.color = colorOutline;
321 |
322 | Vector3[] handlePoints = new Vector3[2];
323 |
324 | // Draw a + to mark the point
325 | handlePoints[0].x = position.x;
326 | handlePoints[0].y = position.y + penExtent;
327 | handlePoints[1].x = position.x;
328 | handlePoints[1].y = position.y - penExtent;
329 | Handles.DrawAAPolyLine(handleDrawTexture, penSize, handlePoints);
330 |
331 | handlePoints[0].x = position.x + penExtent;
332 | handlePoints[0].y = position.y;
333 | handlePoints[1].x = position.x - penExtent;
334 | handlePoints[1].y = position.y;
335 | Handles.DrawAAPolyLine(handleDrawTexture, penSize, handlePoints);
336 |
337 | Handles.color = colorPrev;
338 | */
339 | }
340 |
341 | ///
342 | /// Respond to GUI input events in editor.
343 | ///
344 | /// The current event
345 | /// Is it the active shape?
346 | /// Did the shape handle the event?
347 | public override bool HandleEditorEvent(Event currEvent, bool active)
348 | {
349 | return false;
350 | }
351 | #endif
352 |
353 | }
--------------------------------------------------------------------------------
/Assets/VectorShapes/PointShape.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d67e408129bd048bfa9ab78aa0553a85
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/PolyShape.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: acffde7e0e46c4d309fb3ada4767ad6e
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/SerializedShape.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 |
5 | [CreateAssetMenu(fileName = "Shape", menuName = "Testing/Shape")]
6 | [System.Serializable]
7 | public class SerializedShape : ScriptableObject
8 | {
9 | ///
10 | /// Have to do this crap to use Unity serialization
11 | /// which can't handle class inheritance
12 | ///
13 | [SerializeField]
14 | protected List circles;
15 |
16 | [SerializeField]
17 | protected List ellipses;
18 |
19 | [SerializeField]
20 | protected List points;
21 |
22 | [SerializeField]
23 | protected List polys;
24 |
25 | [SerializeField]
26 | protected List texts;
27 |
28 | [System.NonSerialized]
29 | protected List _components;
30 | public List components
31 | {
32 | get
33 | {
34 | int componentCount = 0;
35 | componentCount += circles.Count;
36 | componentCount += ellipses.Count;
37 | componentCount += points.Count;
38 | componentCount += polys.Count;
39 | componentCount += texts.Count;
40 |
41 | if (_components == null) _components = new List();
42 | if (_components.Count != componentCount)
43 | {
44 | _components.Clear();
45 | _components.AddRange(circles);
46 | _components.AddRange(ellipses);
47 | _components.AddRange(points);
48 | _components.AddRange(polys);
49 | _components.AddRange(texts);
50 | }
51 |
52 | return _components;
53 | }
54 | }
55 |
56 | private void OnEnable()
57 | {
58 | if (circles == null) circles = new List();
59 | if (ellipses == null) ellipses = new List();
60 | if (points == null) points = new List();
61 | if (polys == null) polys = new List();
62 | if (texts == null) texts = new List();
63 | }
64 |
65 | public void SetShapes(List shapes)
66 | {
67 | circles.Clear();
68 | ellipses.Clear();
69 | points.Clear();
70 | polys.Clear();
71 | texts.Clear();
72 |
73 | foreach (VectorShape shape in shapes)
74 | {
75 | AddShape(shape);
76 | }
77 | }
78 |
79 | public void AddShapes(List shapes)
80 | {
81 | foreach (VectorShape shape in shapes)
82 | {
83 | AddShape(shape);
84 | }
85 | }
86 |
87 | public void AddShape(VectorShape shape)
88 | {
89 | if (shape is CircleShape)
90 | {
91 | circles.Add(shape as CircleShape);
92 | }
93 | else if (shape is EllipseShape)
94 | {
95 | ellipses.Add(shape as EllipseShape);
96 | }
97 | else if (shape is PointShape)
98 | {
99 | points.Add(shape as PointShape);
100 | }
101 | else if (shape is PolyShape)
102 | {
103 | polys.Add(shape as PolyShape);
104 | }
105 | else if (shape is TextShape)
106 | {
107 | texts.Add(shape as TextShape);
108 | }
109 | else if (shape is CompoundShape)
110 | {
111 | AddShapes((shape as CompoundShape).components);
112 | }
113 | else
114 | {
115 | Debug.LogWarning("Unknown shape! " + shape);
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/SerializedShape.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: c081e07c8a64f48c98e1c02e172f84f0
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/Shader.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d1dfb8449dd3c4ec5a427d842960c2c4
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/Shader/VectorLineMeshBuilder.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using System.Reflection;
4 | using UnityEngine;
5 | using Unity.VectorGraphics;
6 |
7 | public class VectorLineMeshBuilder
8 | {
9 | const int Buffer_Padding = 16;
10 | const int Buffer_Size = 16384 - Buffer_Padding;
11 |
12 | private List vertexList;
13 | private Vector3[] vertexArray;
14 | private int vertexCount;
15 |
16 | private List dataList;
17 | private Vector4[] dataArray;
18 | // dataCount == vertexCount
19 |
20 | private List triangleList;
21 | private int[] triangleArray;
22 | private int triangleCount;
23 |
24 | private int vertexCountOnOpen;
25 | private Vector2 previousDirection;
26 | private float drawingLength;
27 |
28 | public VectorLineMeshBuilder()
29 | {
30 | vertexList = new List(Buffer_Size + Buffer_Padding);
31 | vertexArray = vertexList.GetBackingArray();
32 | vertexCount = 0;
33 |
34 | dataList = new List(Buffer_Size + Buffer_Padding);
35 | dataArray = dataList.GetBackingArray();
36 |
37 | triangleList = new List(3 * (Buffer_Size + Buffer_Padding));
38 | triangleArray = triangleList.GetBackingArray();
39 | triangleCount = 0;
40 |
41 | vertexCountOnOpen = 0;
42 | drawingLength = 0f;
43 | }
44 |
45 | public void Reset()
46 | {
47 | vertexCount = 0;
48 | triangleCount = 0;
49 | vertexCountOnOpen = 0;
50 | drawingLength = 0f;
51 | }
52 |
53 | ///
54 | /// Open a new section of drawing.
55 | ///
56 | /// Initial vertex position
57 | public void BeginPolyLine(Vector2 point)
58 | {
59 | if (vertexCount > vertexCountOnOpen)
60 | {
61 | Debug.LogError("BeginDrawing called on active drawing");
62 | return;
63 | }
64 | if (vertexCount > Buffer_Size)
65 | {
66 | Debug.LogWarning("Out of space in buffers");
67 | return;
68 | }
69 |
70 | vertexCountOnOpen = vertexCount;
71 |
72 | vertexArray[vertexCount++] = point;
73 | vertexArray[vertexCount++] = point;
74 |
75 | previousDirection = Vector2.zero;
76 | drawingLength = 0f;
77 | }
78 |
79 | ///
80 | /// Add a straight segment onto the drawing.
81 | ///
82 | /// New vertex position
83 | public void LineTo(Vector2 point)
84 | {
85 | if (vertexCount <= vertexCountOnOpen)
86 | {
87 | Debug.LogError("LineTo called on inactive drawing");
88 | return;
89 | }
90 | if (vertexCount > Buffer_Size)
91 | {
92 | Debug.LogWarning("Out of space in buffers");
93 | return;
94 | }
95 |
96 | int previousVertex = vertexCount - 2;
97 | Vector2 segment = (point - (Vector2)vertexArray[previousVertex]);
98 | Vector2 direction = segment.normalized;
99 | Vector2 offset = Vector2.Perpendicular(direction);
100 |
101 | if (previousVertex == vertexCountOnOpen) // First segment
102 | {
103 | Vector4 data = new Vector4(0, 1, offset.x, offset.y);
104 | dataArray[previousVertex++] = data;
105 | dataArray[previousVertex++] = -data;
106 |
107 | drawingLength += segment.magnitude;
108 | data.x = drawingLength;
109 |
110 | dataArray[vertexCount] = data;
111 | vertexArray[vertexCount++] = point;
112 | dataArray[vertexCount] = -data;
113 | vertexArray[vertexCount++] = point;
114 | }
115 | else
116 | {
117 | Vector4 data;
118 | Vector4 previousData = dataArray[previousVertex];
119 | Vector2 previousOffset = new Vector2(previousData.z, previousData.w);
120 |
121 | float extent = 1f + Vector2.Dot(offset, previousOffset);
122 |
123 | if (extent < 0.5f)
124 | {
125 | Vector2 joinOffset;
126 | Vector2 midOffset;
127 |
128 | if (extent < Mathf.Epsilon)
129 | {
130 | joinOffset = previousDirection;
131 | }
132 | else
133 | {
134 | joinOffset = (offset + previousOffset).normalized;
135 | }
136 |
137 | extent = 1f + Vector2.Dot(previousOffset, joinOffset);
138 | midOffset = (previousOffset + joinOffset) / extent;
139 | data = new Vector4(drawingLength, 1, midOffset.x, midOffset.y);
140 | dataArray[previousVertex++] = data;
141 | dataArray[previousVertex--] = -data;
142 |
143 | data = new Vector4(drawingLength, 0, 0, 0);
144 | dataArray[vertexCount] = data;
145 | vertexArray[vertexCount++] = vertexArray[previousVertex];
146 |
147 | // cross product to check which way the corner goes
148 | float sign = -Mathf.Sign(previousDirection.x * direction.y - previousDirection.y * direction.x);
149 | data = new Vector4(drawingLength, sign, sign * joinOffset.x * extent, sign * joinOffset.y * extent);
150 | dataArray[vertexCount] = data;
151 | vertexArray[vertexCount++] = vertexArray[previousVertex];
152 |
153 | triangleArray[triangleCount++] = vertexCount - 2;
154 | if (sign > 0)
155 | {
156 | triangleArray[triangleCount++] = vertexCount - 4;
157 | triangleArray[triangleCount++] = vertexCount - 1;
158 | }
159 | else
160 | {
161 | triangleArray[triangleCount++] = vertexCount - 1;
162 | triangleArray[triangleCount++] = vertexCount - 3;
163 | }
164 |
165 | midOffset = (offset + joinOffset) / extent;
166 | data = new Vector4(drawingLength, 1, midOffset.x, midOffset.y);
167 | dataArray[vertexCount] = data;
168 | vertexArray[vertexCount++] = vertexArray[previousVertex];
169 | dataArray[vertexCount] = -data;
170 | vertexArray[vertexCount++] = vertexArray[previousVertex];
171 |
172 | triangleArray[triangleCount++] = vertexCount - 4;
173 | if (sign > 0)
174 | {
175 | triangleArray[triangleCount++] = vertexCount - 3;
176 | triangleArray[triangleCount++] = vertexCount - 2;
177 | }
178 | else
179 | {
180 | triangleArray[triangleCount++] = vertexCount - 1;
181 | triangleArray[triangleCount++] = vertexCount - 3;
182 | }
183 | }
184 | else
185 | {
186 | Vector2 joinOffset = (offset + previousOffset) / extent;
187 | data = new Vector4(drawingLength, 1, joinOffset.x, joinOffset.y);
188 | dataArray[previousVertex++] = data;
189 | dataArray[previousVertex++] = -data;
190 | }
191 |
192 | drawingLength += segment.magnitude;
193 |
194 | data = new Vector4(drawingLength, 1, offset.x, offset.y);
195 | dataArray[vertexCount] = data;
196 | vertexArray[vertexCount++] = point;
197 | dataArray[vertexCount] = -data;
198 | vertexArray[vertexCount++] = point;
199 | }
200 |
201 | triangleArray[triangleCount++] = vertexCount - 4;
202 | triangleArray[triangleCount++] = vertexCount - 2;
203 | triangleArray[triangleCount++] = vertexCount - 3;
204 |
205 | triangleArray[triangleCount++] = vertexCount - 2;
206 | triangleArray[triangleCount++] = vertexCount - 1;
207 | triangleArray[triangleCount++] = vertexCount - 3;
208 |
209 | previousDirection = direction;
210 | }
211 |
212 | ///
213 | /// Add a quadratic curve segment onto the drawing.
214 | ///
215 | /// Control point position
216 | /// New vertex position
217 | /// Number of segments to include
218 | public void CurveTo(Vector2 control, Vector2 point, int steps)
219 | {
220 | CurveTo(point, control, control, steps);
221 | }
222 |
223 | ///
224 | /// Add a cubic curve segment onto the drawing.
225 | ///
226 | /// Control point A position
227 | /// Control point B position
228 | /// New vertex position
229 | /// Number of segments to include
230 | public void CurveTo(Vector2 controlA, Vector2 controlB, Vector2 point, int steps)
231 | {
232 | if (vertexCount <= vertexCountOnOpen)
233 | {
234 | Debug.LogError("CurveTo called on inactive drawing");
235 | return;
236 | }
237 | if (vertexCount > Buffer_Size)
238 | {
239 | Debug.LogWarning("Out of space in buffers");
240 | return;
241 | }
242 |
243 | int previousVertex = vertexCount - 2;
244 | Vector2 previousPoint = vertexArray[previousVertex];
245 |
246 | BezierSegment bezier = new BezierSegment();
247 | bezier.P0 = previousPoint;
248 | bezier.P1 = controlA;
249 | bezier.P2 = controlB;
250 | bezier.P3 = point;
251 |
252 | float length = VectorUtils.SegmentLength(bezier) / steps;
253 |
254 | float step = 1f / steps;
255 | float t = step;
256 |
257 | Vector2 bezierPoint = VectorUtils.Eval(bezier, t);
258 | Vector2 tangent = VectorUtils.EvalTangent(bezier, t);
259 | Vector2 offset = Vector2.Perpendicular(tangent);
260 | Vector4 data;
261 |
262 | LineTo(bezierPoint);
263 |
264 | for (int i = 1; i < steps; i++)
265 | {
266 | t += step;
267 | drawingLength += length; // Good enough for our purposes.
268 |
269 | bezierPoint = VectorUtils.EvalFull(bezier, t, out tangent);
270 | offset = Vector2.Perpendicular(tangent);
271 | data = new Vector4(drawingLength, 1, offset.x, offset.y);
272 | dataArray[vertexCount] = data;
273 | vertexArray[vertexCount++] = bezierPoint;
274 | dataArray[vertexCount] = -data;
275 | vertexArray[vertexCount++] = bezierPoint;
276 |
277 | triangleArray[triangleCount++] = vertexCount - 4;
278 | triangleArray[triangleCount++] = vertexCount - 2;
279 | triangleArray[triangleCount++] = vertexCount - 3;
280 |
281 | triangleArray[triangleCount++] = vertexCount - 2;
282 | triangleArray[triangleCount++] = vertexCount - 1;
283 | triangleArray[triangleCount++] = vertexCount - 3;
284 | }
285 |
286 | previousDirection = tangent;
287 | }
288 |
289 | public void EndPolyLine(bool closed = false)
290 | {
291 | if (closed)
292 | {
293 | }
294 | else if (vertexCount > vertexCountOnOpen)
295 | {
296 | Vector2 offset = Vector2.Perpendicular(previousDirection);
297 | Vector4 data = new Vector4(drawingLength, 1, offset.x, offset.y);
298 | dataArray[vertexCount - 2] = data;
299 | dataArray[vertexCount - 1] = -data;
300 | }
301 |
302 | vertexCountOnOpen = vertexCount;
303 | }
304 |
305 | public void Circle(Vector2 center, float radius, int steps)
306 | {
307 | if (vertexCount > vertexCountOnOpen)
308 | {
309 | Debug.LogError("Circle called on active drawing");
310 | return;
311 | }
312 | if ((vertexCount + steps) > Buffer_Size)
313 | {
314 | Debug.LogWarning("Out of space in buffers");
315 | return;
316 | }
317 |
318 | vertexCountOnOpen = vertexCount;
319 |
320 | int segments = Mathf.CeilToInt(steps / 4f);
321 | float angle = 0f;
322 | float angleDelta = Mathf.PI / (2 * segments);
323 | Vector2[] offsets = new Vector2[segments];
324 | for (int i = 0; i < segments; i++)
325 | {
326 | offsets[i] = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
327 | angle += angleDelta;
328 | }
329 |
330 | Vector2 offset;
331 | Vector2 point;
332 | Vector4 data;
333 |
334 | float length = angleDelta * radius;
335 | for (int quadrant = 0; quadrant < 4; quadrant++)
336 | {
337 | for (int i = 0; i < segments; i++)
338 | {
339 | offset = offsets[i];
340 | point = center + offset * radius;
341 | data = new Vector4(drawingLength, 1, -offset.x, -offset.y);
342 |
343 | dataArray[vertexCount] = data;
344 | vertexArray[vertexCount++] = point;
345 | dataArray[vertexCount] = -data;
346 | vertexArray[vertexCount++] = point;
347 |
348 | // This is ugly, but we'll clean it up after the loop
349 | triangleArray[triangleCount++] = vertexCount - 2;
350 | triangleArray[triangleCount++] = vertexCount - 0;
351 | triangleArray[triangleCount++] = vertexCount - 1;
352 |
353 | triangleArray[triangleCount++] = vertexCount - 0;
354 | triangleArray[triangleCount++] = vertexCount + 1;
355 | triangleArray[triangleCount++] = vertexCount - 1;
356 |
357 | drawingLength += length;
358 |
359 | offsets[i].x = -offset.y;
360 | offsets[i].y = offset.x;
361 | }
362 | }
363 |
364 | // Fix the out of bounds triangles by repeating first point
365 | offset = offsets[0];
366 | point = center + offset * radius;
367 | data = new Vector4(drawingLength, 1, -offset.x, -offset.y);
368 |
369 | dataArray[vertexCount] = data;
370 | vertexArray[vertexCount++] = point;
371 | dataArray[vertexCount] = -data;
372 | vertexArray[vertexCount++] = point;
373 |
374 | vertexCountOnOpen = vertexCount;
375 | }
376 |
377 | public Mesh GetMesh()
378 | {
379 | Mesh mesh = new Mesh();
380 |
381 | vertexList.SetActiveSize(vertexCount);
382 | mesh.SetVertices(vertexList);
383 |
384 | dataList.SetActiveSize(vertexCount);
385 | mesh.SetUVs(0, dataList);
386 |
387 | triangleList.SetActiveSize(triangleCount);
388 | mesh.SetTriangles(triangleList, 0);
389 |
390 | mesh.UploadMeshData(false);
391 | return mesh;
392 | }
393 | }
394 |
395 | // Extension class for System.Collections.Generic.List to get
396 | // its backing array field via reflection.
397 | // Author: Jackson Dunstan, http://JacksonDunstan.com/articles/3066
398 | public static class ListBackingArrayGetter
399 | {
400 | // Name of the backing array field
401 | private const string FieldName = "_items";
402 |
403 | // Flags passed to Type.GetField to get the backing array field
404 | private const BindingFlags GetFieldFlags = BindingFlags.NonPublic | BindingFlags.Instance;
405 |
406 | // Cached backing array FieldInfo instances per Type
407 | private static readonly Dictionary itemsFields = new Dictionary();
408 |
409 | // Get a List's backing array
410 | public static TElement[] GetBackingArray(this List list)
411 | {
412 | // Check if the FieldInfo is already in the cache
413 | var listType = typeof(List);
414 | FieldInfo fieldInfo;
415 | if (!itemsFields.TryGetValue(listType, out fieldInfo))
416 | {
417 | // Generate the FieldInfo and add it to the cache
418 | fieldInfo = listType.GetField(FieldName, GetFieldFlags);
419 | itemsFields.Add(listType, fieldInfo);
420 | }
421 |
422 | // Get the backing array of the given List
423 | var items = (TElement[])fieldInfo.GetValue(list);
424 | return items;
425 | }
426 | }
427 |
428 | // Extension class for System.Collections.Generic.List to set
429 | // the value of its active size field via reflection.
430 | public static class ListSizeSetter
431 | {
432 | // Name of the size field
433 | private const string FieldName = "_size";
434 |
435 | // Flags passed to Type.GetField to get the size field
436 | private const BindingFlags GetFieldFlags = BindingFlags.NonPublic | BindingFlags.Instance;
437 |
438 | // Cached backing array FieldInfo instances per Type
439 | private static readonly Dictionary itemsFields = new Dictionary();
440 |
441 | // Set a List's active size
442 | public static void SetActiveSize(this List list, int size)
443 | {
444 | // Check if the FieldInfo is already in the cache
445 | var listType = typeof(List);
446 | FieldInfo fieldInfo;
447 | if (!itemsFields.TryGetValue(listType, out fieldInfo))
448 | {
449 | // Generate the FieldInfo and add it to the cache
450 | fieldInfo = listType.GetField(FieldName, GetFieldFlags);
451 | itemsFields.Add(listType, fieldInfo);
452 | }
453 |
454 | // Set the active size of the given List
455 | int newSize = size;
456 | if (newSize < 0) newSize = 0;
457 | if (newSize > list.Capacity) newSize = list.Capacity;
458 |
459 | fieldInfo.SetValue(list, newSize);
460 | }
461 | }
462 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/Shader/VectorLineMeshBuilder.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 1dbcd4befa9264c1492ebe8a6cb52079
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/Shader/VectorLineShader.shader:
--------------------------------------------------------------------------------
1 | // Roughly based on
2 | // https://blog.mapbox.com/drawing-antialiased-lines-with-opengl-8766f34192dc
3 | // and
4 | // https://mattdesl.svbtle.com/drawing-lines-is-hard
5 | Shader "Unlit/VectorLineShader"
6 | {
7 | Properties
8 | {
9 | _LineColor ("Line Color", Color) = (0, 0, 0, 1)
10 | _LineWidth ("Line Width", Float) = 1
11 | _Feather ("Feather", Range (0, 1)) = 0.25
12 | _PixelScale ("Pixel Scale", Float) = 0.1
13 |
14 | _StripeColor ("Stripe Color", Color) = (1, 1, 1, 1)
15 | _StripeGap ("Stripe Gap", Float) = 10
16 | _StripeWidth ("Stripe Width", Float) = 1
17 | }
18 | SubShader
19 | {
20 | Tags { "Queue"="Transparent" "RenderType"="Transparent" "IgnoreProjector"="True" }
21 | Blend SrcAlpha OneMinusSrcAlpha
22 | ZWrite Off
23 | LOD 100
24 |
25 | Pass
26 | {
27 | CGPROGRAM
28 | #pragma vertex vert
29 | #pragma fragment frag
30 |
31 | #pragma multi_compile STRIPES_OFF STRIPES_ON
32 |
33 | #include "UnityCG.cginc"
34 |
35 | struct appdata
36 | {
37 | float4 vertex : POSITION;
38 | float4 normal : TEXCOORD0;
39 | };
40 |
41 | struct v2f
42 | {
43 | float4 vertex : SV_POSITION;
44 | half2 offset : TEXCOORD0;
45 | };
46 |
47 | fixed4 _LineColor;
48 | half _LineWidth;
49 | half _Feather;
50 | half _PixelScale;
51 |
52 | fixed4 _StripeColor;
53 | half _StripeWidth;
54 | half _StripeGap;
55 |
56 | static half _StripeLength = _StripeWidth + _StripeGap;
57 |
58 | v2f vert (appdata v)
59 | {
60 | v2f o;
61 | // UnityObjectToWorldDir without the normalize
62 | float3 normal = mul((float3x3)unity_ObjectToWorld, float3(v.normal.zw, 0.0));
63 | float3 pos = UnityObjectToViewPos(v.vertex);
64 | float3 delta = normal * _LineWidth * _PixelScale;
65 | o.vertex = UnityViewToClipPos(pos + delta);
66 | o.offset.x = abs(v.normal.x);
67 | o.offset.y = v.normal.y;
68 |
69 | return o;
70 | }
71 |
72 | fixed4 frag (v2f f) : SV_Target
73 | {
74 | #if STRIPES_ON
75 | float distX = fmod(f.offset.x, _StripeLength);
76 | float stripe = saturate(abs((_StripeGap - distX) / _StripeWidth) * 2.0);
77 | float4 color = lerp(_StripeColor, _LineColor, stripe);
78 | #else
79 | float4 color = _LineColor;
80 | #endif
81 |
82 | float distY = abs(f.offset.y);
83 | float alpha = saturate((1.0 - distY) / _Feather);
84 |
85 | return float4(color.rgb, alpha * color.a);
86 | }
87 | ENDCG
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/Shader/VectorLineShader.shader.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 100745e9c99b34cda851eeb515eedc76
3 | ShaderImporter:
4 | externalObjects: {}
5 | defaultTextures: []
6 | nonModifiableTextures: []
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/TextShape.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Xml;
3 | using UnityEngine;
4 | #if UNITY_EDITOR
5 | using UnityEditor;
6 | #endif
7 | using Unity.VectorGraphics;
8 |
9 | [System.Serializable]
10 | ///
11 | /// Vector point.
12 | ///
13 | public class TextShape : VectorShape
14 | {
15 | ///
16 | /// Position of text origin.
17 | ///
18 | public Vector2 position;
19 |
20 | ///
21 | /// Rotation of text (in degrees).
22 | ///
23 | public float rotation;
24 |
25 | ///
26 | /// Text.
27 | ///
28 | public string text;
29 |
30 | ///
31 | /// Font.
32 | ///
33 | [SerializeField]
34 | protected string font;
35 |
36 | ///
37 | /// Font size.
38 | ///
39 | [SerializeField]
40 | protected int size;
41 |
42 | protected TextShape()
43 | {
44 | }
45 |
46 | ///
47 | /// New point from location.
48 | ///
49 | /// Position of point
50 | /// Text to display
51 | public TextShape(Vector2 location, string content)
52 | {
53 | position = location;
54 | text = content;
55 | }
56 |
57 | public static TextShape Create()
58 | {
59 | //TextShape shape = ScriptableObject.CreateInstance();
60 | TextShape shape = new TextShape();
61 |
62 | return shape;
63 | }
64 |
65 | ///
66 | /// New point from location.
67 | ///
68 | /// Position of point
69 | /// Text to display
70 | public static TextShape Create(Vector2 location, string content)
71 | {
72 | TextShape shape = Create();
73 |
74 | shape.position = location;
75 | shape.text = content;
76 |
77 | return shape;
78 | }
79 |
80 | ///
81 | /// Copy of the shape.
82 | ///
83 | /// New shape with properties of existing shape
84 | public override VectorShape Duplicate()
85 | {
86 | return Create(position, text);
87 | }
88 |
89 | ///
90 | /// Distance between a point and the shape.
91 | ///
92 | /// Test point
93 | /// Distance from point to nearest point on shape
94 | public override float Distance(Vector2 pt)
95 | {
96 | return Vector2.Distance(pt, position);
97 | }
98 |
99 | ///
100 | /// Tests if a shape contains a point
101 | ///
102 | /// Test point
103 | /// Is the point inside the shape?
104 | public override bool Contains(Vector2 pt)
105 | {
106 | return false;
107 | }
108 |
109 | ///
110 | /// Tests if a shape is inside a rectangle.
111 | ///
112 | /// Test rectangle
113 | /// Is the shape entirely inside the rectangle?
114 | public override bool IsInside(Rect rect)
115 | {
116 | return rect.Contains(position);
117 | }
118 |
119 | ///
120 | /// Rotate the shape around a point.
121 | ///
122 | /// Center of rotation
123 | /// Angle in degrees
124 | public override void RotateAround(Vector2 center, float angle)
125 | {
126 | Matrix2D matrix = Matrix2D.Translate(center) * Matrix2D.RotateRH(angle * Mathf.Deg2Rad) * Matrix2D.Translate(-center);
127 | position = matrix.MultiplyPoint(position);
128 |
129 | Dirty = true;
130 | }
131 |
132 | ///
133 | /// Change the origin of the shape.
134 | ///
135 | /// Direction to move
136 | public override void TranslateBy(Vector2 offset)
137 | {
138 | position += offset;
139 |
140 | Dirty = true;
141 | }
142 |
143 | ///
144 | /// Change the size of the shape.
145 | ///
146 | /// Scaling factor to apply
147 | public override void ScaleBy(float scale)
148 | {
149 | if (scale < Mathf.Epsilon)
150 | {
151 | Debug.LogWarning("Scale must be greater than zero.");
152 | return;
153 | }
154 |
155 | position *= scale;
156 |
157 | Dirty = true;
158 | }
159 |
160 | ///
161 | /// Transform the shape by an arbitrary matrix.
162 | ///
163 | /// Matrix to transform shape
164 | public override void TransformBy(Matrix2D matrix)
165 | {
166 | position = matrix.MultiplyPoint(position);
167 |
168 | Dirty = true;
169 | }
170 |
171 | ///
172 | /// Distance between a point and the shape.
173 | ///
174 | /// Test point
175 | /// Snap modes to consider
176 | /// Distance from point to nearest point on shape
177 | public override SnapPoint GetSnap(Vector2 pt, SnapPoint.Mode mode)
178 | {
179 | SnapPoint snap = new SnapPoint();
180 |
181 | return snap;
182 | }
183 |
184 | ///
185 | /// Tessellate the shape into geometry data.
186 | ///
187 | protected override void GenerateGeometry()
188 | {
189 | if ((shapeGeometry != null) && (!shapeDirty)) return;
190 |
191 | PathProperties pathProps = new PathProperties()
192 | {
193 | Stroke = new Stroke()
194 | {
195 | Color = colorOutline,
196 | HalfThickness = penSize / 2f * penToMeshScale
197 | }
198 | };
199 |
200 | Shape textShape = new Shape()
201 | {
202 | Contours = new BezierContour[]
203 | {
204 | },
205 | PathProps = pathProps
206 | };
207 |
208 | shapeNode = new SceneNode()
209 | {
210 | Transform = matrixTransform,
211 | Shapes = new List
212 | {
213 | textShape
214 | }
215 | };
216 |
217 | tessellationScene.Root = shapeNode;
218 |
219 | shapeGeometry = VectorUtils.TessellateScene(tessellationScene, tessellationOptions);
220 | shapeDirty = false;
221 | }
222 |
223 | ///
224 | /// Build a mesh for display with the VectorLineShader.
225 | ///
226 | protected override void GenerateLineMesh()
227 | {
228 | }
229 |
230 | ///
231 | /// Build a 2D bounding box for the shape.
232 | ///
233 | protected override void GenerateBounds()
234 | {
235 | shapeBounds = new Rect(position, Vector2.zero);
236 | boundsDirty = false;
237 | }
238 |
239 | ///
240 | /// Build a 2D collider for the shape.
241 | ///
242 | protected override void AddColliderToGO(GameObject target)
243 | {
244 | CircleCollider2D[] colliders = target.GetComponents();
245 | CircleCollider2D collider = null;
246 |
247 | for (int i = 0; i < colliders.Length; i++)
248 | {
249 | if (colliders[i].name == this.guid)
250 | {
251 | collider = colliders[i];
252 | }
253 | }
254 |
255 | if (collider == null)
256 | {
257 | collider = collider.gameObject.AddComponent();
258 | collider.name = this.guid;
259 | }
260 |
261 | collider.offset = position;
262 | }
263 |
264 | ///
265 | /// Serialize the shape to an XML writer.
266 | ///
267 | public override void WriteToXML(XmlWriter writer, Vector2 origin, float scale)
268 | {
269 | }
270 |
271 | #if UNITY_EDITOR
272 | ///
273 | /// Draw the point to the active camera using editor handles.
274 | ///
275 | /// Is the shape selected?
276 | /// Is it the active shape?
277 | public override void DrawEditorHandles(bool selected, bool active = false)
278 | {
279 | base.DrawEditorHandles(selected, active);
280 |
281 | /*
282 | Color colorPrev = Handles.color;
283 | Handles.color = colorOutline;
284 |
285 | Vector3[] handlePoints = new Vector3[2];
286 |
287 | // Draw a + to mark the point
288 | handlePoints[0].x = position.x;
289 | handlePoints[0].y = position.y + penExtent;
290 | handlePoints[1].x = position.x;
291 | handlePoints[1].y = position.y - penExtent;
292 | Handles.DrawAAPolyLine(handleDrawTexture, penSize, handlePoints);
293 |
294 | handlePoints[0].x = position.x + penExtent;
295 | handlePoints[0].y = position.y;
296 | handlePoints[1].x = position.x - penExtent;
297 | handlePoints[1].y = position.y;
298 | Handles.DrawAAPolyLine(handleDrawTexture, penSize, handlePoints);
299 |
300 | Handles.color = colorPrev;
301 | */
302 | }
303 |
304 | ///
305 | /// Respond to GUI input events in editor.
306 | ///
307 | /// The current event
308 | /// Is it the active shape?
309 | /// Did the shape handle the event?
310 | public override bool HandleEditorEvent(Event currEvent, bool active)
311 | {
312 | return false;
313 | }
314 | #endif
315 |
316 | }
--------------------------------------------------------------------------------
/Assets/VectorShapes/TextShape.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 1b42e1e547752419fbe335165fdba8a8
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/VectorShape.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Xml;
3 | using UnityEngine;
4 | using Unity.VectorGraphics;
5 |
6 | ///
7 | /// Base class of drawable vector based 2d elements.
8 | ///
9 | public abstract class VectorShape : System.IDisposable
10 | {
11 | public class ShapeProxy : ScriptableObject, ISerializationCallbackReceiver
12 | {
13 | [HideInInspector]
14 | public VectorShape shape;
15 |
16 | [Range(0f, 25f)]
17 | public float penSize;
18 |
19 | public Color32 colorOutline;
20 | public Color32 colorFill;
21 |
22 | public void OnBeforeSerialize()
23 | {
24 | if (shape != null)
25 | {
26 | shape.penSize = penSize;
27 | shape.colorOutline = colorOutline;
28 | shape.colorFill = colorFill;
29 | }
30 | }
31 |
32 | public void OnAfterDeserialize()
33 | {
34 | }
35 | }
36 |
37 | public ShapeProxy GetShapeProxy()
38 | {
39 | ShapeProxy proxy = ScriptableObject.CreateInstance();
40 | proxy.name = "Shape";
41 | proxy.shape = this;
42 | proxy.penSize = penSize;
43 | proxy.colorOutline = colorOutline;
44 | proxy.colorFill = colorFill;
45 |
46 | return proxy;
47 | }
48 |
49 | public class SnapPoint
50 | {
51 | [System.Flags]
52 | public enum Mode
53 | {
54 | None = 0,
55 | Center = 1,
56 | Endpoint = 2,
57 | Midpoint = 4,
58 | Edge = 8
59 | }
60 | public Mode mode = Mode.None;
61 |
62 | public Vector2 point;
63 | }
64 |
65 | ///
66 | /// Pen size for drawing.
67 | ///
68 | [Range(0f, 25f)]
69 | public float penSize = 2f;
70 |
71 | ///
72 | /// Scale between pen and mesh units.
73 | ///
74 | public float penToMeshScale = 0.01f;
75 |
76 | ///
77 | /// Outline color.
78 | ///
79 | public Color colorOutline = Color.black;
80 |
81 | ///
82 | /// Fill color.
83 | ///
84 | public Color colorFill = Color.clear;
85 |
86 | ///
87 | /// Does the last vertex connect back to the first?
88 | ///
89 | [SerializeField]
90 | protected bool closed = true;
91 |
92 | ///
93 | /// ID.
94 | ///
95 | [SerializeField]
96 | protected string guid = new System.Guid().ToString();
97 |
98 | ///
99 | /// Transform matrix.
100 | ///
101 | [SerializeField]
102 | protected Matrix2D matrixTransform = Matrix2D.identity;
103 |
104 | ///
105 | /// Geometry data generated for shape.
106 | ///
107 | protected List shapeGeometry = null;
108 |
109 | ///
110 | /// Scene data generated for shape.
111 | ///
112 | protected SceneNode shapeNode = null;
113 |
114 | ///
115 | /// Mesh generated for tesselated shape.
116 | ///
117 | protected Mesh shapeMesh = null;
118 |
119 | ///
120 | /// Line renderer mesh for shape outline.
121 | ///
122 | protected Mesh lineMesh = null;
123 |
124 | ///
125 | /// Bounds rectangle for shape (may be approximate for some shapes).
126 | ///
127 | protected Rect shapeBounds = Rect.zero;
128 |
129 | protected bool shapeDirty = true;
130 | protected bool lineDirty = true;
131 | protected bool boundsDirty = true;
132 |
133 | ///
134 | /// Level To which the shape selected.
135 | ///
136 | public enum SelectionLevel
137 | {
138 | None,
139 | Shape,
140 | Component,
141 | Vertex
142 | }
143 |
144 | #if UNITY_EDITOR
145 | ///
146 | /// Shared texture for drawing AA lines in the editor.
147 | ///
148 | protected static Texture2D handleDrawTexture;
149 |
150 | ///
151 | /// Scale for drawing handles in the editor.
152 | ///
153 | public static float handleDrawSize = 0f;
154 |
155 | ///
156 | /// Color of a vertex handle
157 | ///
158 | public static Color vertexHandleColor = Color.red;
159 |
160 | ///
161 | /// Color of a control handle
162 | ///
163 | public static Color controlHandleColor = Color.red;
164 | #endif
165 |
166 | ///
167 | /// Shared scene for tessellating shape meshes.
168 | ///
169 | protected static Scene tessellationScene;
170 |
171 | ///
172 | /// Shared settings for tessellating shape meshes.
173 | ///
174 | public static VectorUtils.TessellationOptions tessellationOptions;
175 |
176 | ///
177 | /// Shared builder for making line meshes.
178 | ///
179 | public static VectorLineMeshBuilder lineBuilder;
180 |
181 | static VectorShape()
182 | {
183 | tessellationScene = new Scene();
184 |
185 | tessellationOptions = new VectorUtils.TessellationOptions()
186 | {
187 | StepDistance = 50f,
188 | MaxCordDeviation = float.MaxValue,
189 | MaxTanAngleDeviation = Mathf.PI / 16.0f,
190 | SamplingStepSize = 0.05f
191 | };
192 |
193 | lineBuilder = new VectorLineMeshBuilder();
194 | }
195 |
196 | ///
197 | /// Dispose of the shape mesh.
198 | ///
199 | public void Dispose()
200 | {
201 | if (shapeMesh != null)
202 | {
203 | #if UNITY_EDITOR
204 | UnityEngine.Object.DestroyImmediate(shapeMesh);
205 | #else
206 | UnityEngine.Object.Destroy(shapeMesh);
207 | #endif
208 | }
209 |
210 | shapeDirty = true;
211 | shapeMesh = null;
212 |
213 | if (lineMesh != null)
214 | {
215 | #if UNITY_EDITOR
216 | UnityEngine.Object.DestroyImmediate(lineMesh);
217 | #else
218 | UnityEngine.Object.Destroy(lineMesh);
219 | #endif
220 | }
221 |
222 | lineDirty = true;
223 | lineMesh = null;
224 | }
225 |
226 | ///
227 | /// Mesh built from the tesselated shape.
228 | ///
229 | public Mesh ShapeMesh
230 | {
231 | get
232 | {
233 | if ((shapeMesh == null) || shapeDirty)
234 | {
235 | if (shapeMesh != null)
236 | {
237 | #if UNITY_EDITOR
238 | UnityEngine.Object.DestroyImmediate(shapeMesh);
239 | #else
240 | UnityEngine.Object.Destroy(shapeMesh);
241 | #endif
242 | }
243 |
244 | GenerateGeometry();
245 |
246 | shapeMesh = new Mesh();
247 | if (shapeGeometry != null)
248 | {
249 | VectorUtils.FillMesh(shapeMesh, shapeGeometry, 1.0f);
250 | }
251 | shapeDirty = false;
252 | }
253 |
254 | return shapeMesh;
255 | }
256 | }
257 |
258 | ///
259 | /// Mesh of the shape outline for VectorLineShader.
260 | ///
261 | public Mesh LineMesh
262 | {
263 | get
264 | {
265 | if ((lineMesh == null) || lineDirty)
266 | {
267 | if (lineMesh != null)
268 | {
269 | #if UNITY_EDITOR
270 | UnityEngine.Object.DestroyImmediate(lineMesh);
271 | #else
272 | UnityEngine.Object.Destroy(lineMesh);
273 | #endif
274 | }
275 |
276 | lineBuilder.Reset();
277 |
278 | GenerateLineMesh();
279 |
280 | lineMesh = lineBuilder.GetMesh();
281 | lineDirty = false;
282 | }
283 |
284 | return lineMesh;
285 | }
286 | }
287 |
288 | ///
289 | /// Mesh of the filled shape (may be empty).
290 | ///
291 | public Mesh FillMesh
292 | {
293 | get
294 | {
295 | return null;
296 | }
297 | }
298 |
299 | ///
300 | /// 2D bounding box of the shape.
301 | ///
302 | public Rect ShapeBounds
303 | {
304 | get
305 | {
306 | if (boundsDirty)
307 | {
308 | GenerateBounds();
309 | }
310 |
311 | return shapeBounds;
312 | }
313 | }
314 |
315 | ///
316 | /// Tessellated geometry of the shape.
317 | ///
318 | public List ShapeGeometry
319 | {
320 | get
321 | {
322 | if ((shapeGeometry == null) || shapeDirty)
323 | {
324 | GenerateGeometry();
325 | }
326 |
327 | return shapeGeometry;
328 | }
329 | }
330 |
331 | ///
332 | /// Is the shape dirty?
333 | ///
334 | public bool Dirty
335 | {
336 | set
337 | {
338 | if (value)
339 | {
340 | shapeDirty = true;
341 | lineDirty = true;
342 | boundsDirty = true;
343 | }
344 | }
345 | get
346 | {
347 | return shapeDirty;
348 | }
349 | }
350 |
351 | ///
352 | /// Is the shape closed?
353 | ///
354 | public bool Closed
355 | {
356 | set
357 | {
358 | closed = value;
359 | }
360 | get
361 | {
362 | return closed;
363 | }
364 | }
365 |
366 | ///
367 | /// ID of the shape
368 | ///
369 | public string ID
370 | {
371 | set
372 | {
373 | guid = value;
374 | }
375 | get
376 | {
377 | return guid;
378 | }
379 | }
380 |
381 | ///
382 | /// Copy of the shape.
383 | ///
384 | /// New shape with properties of existing shape
385 | public abstract VectorShape Duplicate();
386 |
387 | ///
388 | /// Distance between a point and the shape.
389 | ///
390 | /// Test point
391 | /// Distance from point to nearest point on shape
392 | public abstract float Distance(Vector2 pt);
393 |
394 | ///
395 | /// Tests if a shape contains a point.
396 | ///
397 | /// Test point
398 | /// Is the point inside the shape?
399 | public abstract bool Contains(Vector2 pt);
400 |
401 | ///
402 | /// Tests if a shape is inside a rectangle.
403 | ///
404 | /// Test rectangle
405 | /// Is the shape entirely inside the rectangle?
406 | public abstract bool IsInside(Rect rect);
407 |
408 | ///
409 | /// Rotate the shape around a point.
410 | ///
411 | /// Center of rotation
412 | /// Angle in degrees
413 | public abstract void RotateAround(Vector2 center, float angle);
414 |
415 | ///
416 | /// Change the origin of the shape.
417 | ///
418 | /// Offset to move shape
419 | public abstract void TranslateBy(Vector2 offset);
420 |
421 | ///
422 | /// Change the size of the shape.
423 | ///
424 | /// Scaling factor to apply
425 | public abstract void ScaleBy(float scale);
426 |
427 | ///
428 | /// Transform the shape by an arbitrary matrix.
429 | ///
430 | /// Matrix to transform shape
431 | public abstract void TransformBy(Matrix2D matrix);
432 |
433 | ///
434 | /// Build a mesh for display with the VectorLineShader.
435 | ///
436 | protected abstract void GenerateLineMesh();
437 |
438 | ///
439 | /// Distance between a point and the shape.
440 | ///
441 | /// Test point
442 | /// Snap modes to consider
443 | /// Distance from point to nearest point on shape
444 | public abstract SnapPoint GetSnap(Vector2 pt, SnapPoint.Mode mode);
445 |
446 | ///
447 | /// Tessellate the shape into geometry data.
448 | ///
449 | protected abstract void GenerateGeometry();
450 |
451 | ///
452 | /// Build a 2D bounding box for the shape.
453 | ///
454 | protected abstract void GenerateBounds();
455 |
456 | ///
457 | /// Add a 2D collider for the shape to a game object.
458 | ///
459 | protected abstract void AddColliderToGO(GameObject target);
460 |
461 | ///
462 | /// Serialize the shape to an XML writer.
463 | ///
464 | public abstract void WriteToXML(XmlWriter writer, Vector2 origin, float scale);
465 |
466 | #if UNITY_EDITOR
467 | ///
468 | /// Draw the shape to the active camera using editor handles.
469 | ///
470 | /// Is the shape selected?
471 | /// Is it the active shape?
472 | public virtual void DrawEditorHandles(bool selected, bool active = false)
473 | {
474 | if (handleDrawTexture == null)
475 | {
476 | handleDrawTexture = new Texture2D(1, 2);
477 | handleDrawTexture.SetPixel(0, 0, Color.white);
478 | handleDrawTexture.SetPixel(0, 1, Color.clear);
479 | handleDrawTexture.Apply();
480 | }
481 | }
482 |
483 | ///
484 | /// Respond to GUI input events in editor.
485 | ///
486 | /// The current event
487 | /// Is it the active shape?
488 | /// Did the shape handle the event?
489 | public abstract bool HandleEditorEvent(Event currEvent, bool active);
490 |
491 | ///
492 | /// Calculate distance from GUI ray to shape.
493 | ///
494 | /// Distance from ray in screen space
495 | //public abstract float DistanceFromRay();
496 | #endif
497 |
498 | }
--------------------------------------------------------------------------------
/Assets/VectorShapes/VectorShape.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 1f56a792f6c504498a8d25fc73c48892
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/VectorShapeFIlesDXF.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Unity.VectorGraphics;
5 |
6 | #if DXF_SUPPORT
7 |
8 | using IxMilia.Dxf;
9 | using IxMilia.Dxf.Entities;
10 |
11 | public static class VectorShapeFilesDXF
12 | {
13 | static float dxfScale = 1f;
14 | public static Vector2 ConvertPoint(DxfPoint pt)
15 | {
16 | return new Vector2((float)pt.X * dxfScale, (float)pt.Y * dxfScale);
17 | }
18 | public static Vector2 ConvertPoint(double ptX, double ptY)
19 | {
20 | return new Vector2((float)ptX * dxfScale, (float)ptY * dxfScale);
21 | }
22 | public static Vector2 ConvertVector(DxfVector vector)
23 | {
24 | return new Vector2((float)vector.X * dxfScale, (float)vector.Y * dxfScale);
25 | }
26 |
27 | public static Color32 ConvertColor(DxfColor color)
28 | {
29 | int intColor = 0;
30 | try
31 | {
32 | color.ToRGB();
33 | }
34 | catch (System.NotSupportedException)
35 | {
36 | }
37 |
38 | byte colorRed = (byte)((intColor >> 16) & 0xFF);
39 | byte colorGreen = (byte)((intColor >> 8) & 0xFF);
40 | byte colorBlue = (byte)((intColor >> 0) & 0xFF);
41 | return new Color32(colorRed, colorGreen, colorBlue, 255);
42 | }
43 |
44 | ///
45 | /// Parse DXF into VectorShape list.
46 | ///
47 | public static List ReadDXF(Stream dxfStream)
48 | {
49 | List shapes = new List();
50 |
51 | DxfFile dxfFile = DxfFile.Load(dxfStream);
52 |
53 | Dictionary layerColors = new Dictionary();
54 | foreach (DxfLayer layer in dxfFile.Layers)
55 | {
56 | layerColors.Add(layer.Name, ConvertColor(layer.Color));
57 | }
58 |
59 | foreach (DxfEntity entity in dxfFile.Entities)
60 | {
61 | VectorShape shape = null;
62 |
63 | switch (entity.EntityType)
64 | {
65 | case DxfEntityType.Point:
66 | DxfModelPoint point = entity as DxfModelPoint;
67 | shape = new PointShape(ConvertPoint(point.Location));
68 | break;
69 |
70 | case DxfEntityType.Line:
71 | DxfLine line = entity as DxfLine;
72 | Vector2[] endpoints = new Vector2[2];
73 | endpoints[0] = ConvertPoint(line.P1);
74 | endpoints[1] = ConvertPoint(line.P2);
75 | shape = new PolyShape(endpoints);
76 | break;
77 |
78 | case DxfEntityType.Spline:
79 | DxfSpline spline = entity as DxfSpline;
80 | if ((spline.NumberOfControlPoints % spline.DegreeOfCurve) != 1)
81 | {
82 | Debug.LogError("Invalid spline data! Wrong number of points. " + spline);
83 | break;
84 | }
85 |
86 | Vector2[] controlPoints = new Vector2[spline.NumberOfControlPoints];
87 | for (int i = 0; i < controlPoints.Length; i++)
88 | {
89 | controlPoints[i] = ConvertPoint(spline.ControlPoints[i]);
90 | }
91 | shape = new PolyShape(controlPoints[0]);
92 | PolyShape shapeSpline = shape as PolyShape;
93 |
94 | switch (spline.DegreeOfCurve)
95 | {
96 | case 1:
97 |
98 | for (int i = 1; i < controlPoints.Length; i++)
99 | {
100 | shapeSpline.LineTo(controlPoints[i]);
101 | }
102 | break;
103 |
104 | case 2:
105 | for (int i = 1; i < controlPoints.Length; i += 2)
106 | {
107 | shapeSpline.CurveTo(controlPoints[i + 1], controlPoints[i]);
108 | }
109 | break;
110 |
111 | case 3:
112 | for (int i = 1; i < controlPoints.Length; i += 3)
113 | {
114 | shapeSpline.CurveTo(controlPoints[i + 2], controlPoints[i], controlPoints[i + 1]);
115 | }
116 | break;
117 |
118 | default:
119 | Debug.LogWarning("Spline with unsupported curve of degree: " + spline.DegreeOfCurve);
120 | break;
121 | }
122 | break;
123 |
124 | case DxfEntityType.Arc:
125 | DxfArc arc = entity as DxfArc;
126 | // If the arc is a complete circle just make one of those
127 | float startAngle = (float)arc.StartAngle;
128 | while (startAngle < 0f)
129 | {
130 | startAngle += 360f;
131 | }
132 | float endAngle = (float)arc.EndAngle;
133 | while (endAngle < startAngle)
134 | {
135 | endAngle += 360f;
136 | }
137 |
138 | float sweep = endAngle - startAngle;
139 | shape = new CircleShape(ConvertPoint(arc.Center), (float)arc.Radius, startAngle, sweep);
140 | break;
141 |
142 | case DxfEntityType.Circle:
143 | DxfCircle circle = entity as DxfCircle;
144 | shape = new CircleShape(ConvertPoint(circle.Center), (float)circle.Radius * dxfScale);
145 | break;
146 |
147 | case DxfEntityType.Ellipse:
148 | DxfEllipse ellipse = entity as DxfEllipse;
149 | // If the ellipse is actually a circle just make one of those
150 | if (Mathf.Approximately((float)ellipse.MinorAxisRatio, 1f))
151 | {
152 | shape = new CircleShape(ConvertPoint(ellipse.Center), (float)ellipse.MajorAxis.Length * dxfScale);
153 | }
154 | else
155 | {
156 | shape = new EllipseShape(ConvertPoint(ellipse.Center), ConvertVector(ellipse.MajorAxis), (float)ellipse.MinorAxisRatio);
157 | }
158 | break;
159 |
160 | case DxfEntityType.Polyline:
161 | DxfPolyline polyline = entity as DxfPolyline;
162 | if (polyline.ContainsVertices)
163 | {
164 | Vector2[] vertices = new Vector2[polyline.Vertices.Count];
165 | for (int i = 0; i < vertices.Length; i++)
166 | {
167 | vertices[i] = ConvertPoint(polyline.Vertices[i].Location);
168 | }
169 |
170 | shape = new PolyShape(vertices[0]);
171 | PolyShape shapePolyline = shape as PolyShape;
172 |
173 | for (int i = 1; i < vertices.Length; i++)
174 | {
175 | float bulge = (float)polyline.Vertices[i - 1].Bulge;
176 | shapePolyline.ArcToDXF(vertices[i], bulge);
177 | }
178 |
179 | if (polyline.IsClosed)
180 | {
181 | float bulge = (float)polyline.Vertices[vertices.Length - 1].Bulge;
182 | shapePolyline.ArcToDXF(vertices[0], bulge);
183 | shape.Closed = true;
184 | }
185 | }
186 | break;
187 |
188 | case DxfEntityType.LwPolyline:
189 | {
190 | DxfLwPolyline lwPolyline = entity as DxfLwPolyline;
191 | Vector2[] vertices = new Vector2[lwPolyline.Vertices.Count];
192 | for (int i = 0; i < vertices.Length; i++)
193 | {
194 | DxfLwPolylineVertex lwpVertex = lwPolyline.Vertices[i];
195 | vertices[i] = ConvertPoint(lwpVertex.X, lwpVertex.Y);
196 | }
197 |
198 | shape = new PolyShape(vertices[0]);
199 | PolyShape shapePolyline = shape as PolyShape;
200 |
201 | for (int i = 1; i < vertices.Length; i++)
202 | {
203 | float bulge = (float)lwPolyline.Vertices[i - 1].Bulge;
204 | shapePolyline.ArcToDXF(vertices[i], bulge);
205 | }
206 |
207 | if (lwPolyline.IsClosed)
208 | {
209 | float bulge = (float)lwPolyline.Vertices[vertices.Length - 1].Bulge;
210 | shapePolyline.ArcToDXF(vertices[0], bulge);
211 | shape.Closed = true;
212 | }
213 | }
214 | break;
215 |
216 | default:
217 | Debug.Log("Unhandled entity of type: " + entity.EntityType);
218 | break;
219 | }
220 |
221 | if (shape != null)
222 | {
223 | if (entity.IsVisible)
224 | {
225 | Color32 shapeColor = ConvertColor(entity.Color);
226 | //layerColors.TryGetValue(entity.Layer, out shapeColor);
227 |
228 | shape.colorOutline = shapeColor;
229 | shapes.Add(shape);
230 | }
231 | }
232 | }
233 |
234 | return shapes;
235 | }
236 | }
237 |
238 | #endif
239 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/VectorShapeFIlesDXF.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 8007be60e4f86431e8953236ce701683
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/VectorShapeFilesSVG.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Xml;
3 | using System.Collections.Generic;
4 | using UnityEngine;
5 | using Unity.VectorGraphics;
6 |
7 | public class VectorShapeFilesSVG
8 | {
9 | ///
10 | /// Measurement units for SVG files.
11 | ///
12 | public enum Unit
13 | {
14 | None,
15 | Pixels,
16 | Millimeters,
17 | Centimeters,
18 | Inches
19 | }
20 | private const float InchToMM = 25.4f;
21 | private const float InchToCM = 2.54f;
22 |
23 | ///
24 | /// Convert between SVG units.
25 | ///
26 | public static string UnitSuffix(Unit unit)
27 | {
28 | switch (unit)
29 | {
30 | case Unit.Pixels:
31 | return "px";
32 | case Unit.Millimeters:
33 | return "mm";
34 | case Unit.Centimeters:
35 | return "cm";
36 | case Unit.Inches:
37 | return "in";
38 | default:
39 | return "";
40 | }
41 | }
42 |
43 |
44 | ///
45 | /// Convert between SVG units.
46 | ///
47 | public static float ConvertUnits(float measurement, Unit fromUnit, Unit toUnit)
48 | {
49 | float result = measurement;
50 |
51 | switch (fromUnit)
52 | {
53 | case Unit.Pixels:
54 | switch (toUnit)
55 | {
56 | case Unit.Millimeters:
57 | result = measurement / Screen.dpi * InchToMM;
58 | break;
59 | case Unit.Centimeters:
60 | result = measurement / Screen.dpi * InchToCM;
61 | break;
62 | case Unit.Inches:
63 | result = measurement / Screen.dpi;
64 | break;
65 | }
66 | break;
67 |
68 | case Unit.Millimeters:
69 | switch (toUnit)
70 | {
71 | case Unit.Pixels:
72 | result = measurement * Screen.dpi / InchToMM;
73 | break;
74 | case Unit.Centimeters:
75 | result = measurement / 10f;
76 | break;
77 | case Unit.Inches:
78 | result = measurement / InchToMM;
79 | break;
80 | }
81 | break;
82 |
83 | case Unit.Centimeters:
84 | switch (toUnit)
85 | {
86 | case Unit.Pixels:
87 | result = measurement * Screen.dpi / InchToCM;
88 | break;
89 | case Unit.Millimeters:
90 | result = measurement * 10f;
91 | break;
92 | case Unit.Inches:
93 | result = measurement / InchToCM;
94 | break;
95 | }
96 | break;
97 |
98 | case Unit.Inches:
99 | switch (toUnit)
100 | {
101 | case Unit.Pixels:
102 | result = measurement * Screen.dpi;
103 | break;
104 | case Unit.Millimeters:
105 | result = measurement * InchToMM;
106 | break;
107 | case Unit.Centimeters:
108 | result = measurement * InchToCM;
109 | break;
110 | }
111 | break;
112 | }
113 |
114 | return result;
115 | }
116 |
117 | ///
118 | /// Convert Unity color to SVG string
119 | ///
120 | public static string ConvertColor(Color color)
121 | {
122 | if (color.a <= Mathf.Epsilon) return "none";
123 |
124 | return "#" + ColorUtility.ToHtmlStringRGB(color);
125 | }
126 |
127 | private static VectorShape ParseContour(BezierContour contour, Matrix2D transform)
128 | {
129 | VectorShape vectorShape = PolyShape.Create(contour);
130 | vectorShape.TransformBy(transform);
131 |
132 | return vectorShape;
133 | }
134 |
135 | private static VectorShape TryParseShapeToCircle(Shape shape, Matrix2D transform)
136 | {
137 | if (shape.Contours.Length > 1) return null;
138 |
139 | BezierContour contour = shape.Contours[0];
140 | if (contour.Segments.Length < 5) return null;
141 | if (!contour.Closed) return null;
142 |
143 | BezierSegment[] segments = new BezierSegment[contour.Segments.Length - 1];
144 | for (int i = 0; i < segments.Length; i++)
145 | {
146 | segments[i].P0 = transform.MultiplyPoint(contour.Segments[i].P0);
147 | segments[i].P1 = transform.MultiplyPoint(contour.Segments[i].P1);
148 | segments[i].P2 = transform.MultiplyPoint(contour.Segments[i].P2);
149 | segments[i].P3 = transform.MultiplyPoint(contour.Segments[(i + 1)].P0);
150 | }
151 |
152 | Rect shapeBounds = VectorUtils.Bounds(VectorUtils.BezierSegmentsToPath(segments));
153 | Vector2 center = shapeBounds.center;
154 | float radius = (shapeBounds.width + shapeBounds.height) / 4f;
155 | float error = radius / 200f;
156 | for (int i = 0; i < segments.Length; i++)
157 | {
158 | if (Mathf.Abs(Vector2.Distance(center, segments[i].P0) - radius) > error)
159 | {
160 | return null;
161 | }
162 |
163 | Vector2 midpoint = VectorUtils.Eval(segments[i], 0.5f);
164 | if (Mathf.Abs(Vector2.Distance(center, midpoint) - radius) > error)
165 | {
166 | return null;
167 | }
168 | }
169 |
170 | CircleShape circle = CircleShape.Create(center, radius);
171 | circle.colorOutline = Color.red;
172 | return circle;
173 | }
174 |
175 | private static VectorShape ParseShape(Shape shape, Matrix2D transform)
176 | {
177 | VectorShape vectorShape = PolyShape.Create(shape, transform);
178 |
179 | return vectorShape;
180 | }
181 |
182 | ///
183 | /// Add node and children into shape list.
184 | ///
185 | public static void RecurseSVGNodes(SceneNode node, Matrix2D nodeTransform, List shapes)
186 | {
187 | if (node.Shapes != null)
188 | {
189 | foreach (Shape shape in node.Shapes)
190 | {
191 | VectorShape vectorShape = TryParseShapeToCircle(shape, nodeTransform);
192 | if (vectorShape == null)
193 | {
194 | vectorShape = ParseShape(shape, nodeTransform);
195 | }
196 | if (vectorShape != null)
197 | {
198 | shapes.Add(vectorShape);
199 | }
200 | //foreach (BezierContour contour in shape.Contours)
201 | //{
202 | // VectorShape vectorShape = ParseContour(contour, nodeTransform);
203 | // if (vectorShape != null)
204 | // {
205 | // shapes.Add(vectorShape);
206 | // if (shape.PathProps.Stroke != null)
207 | // {
208 | // vectorShape.colorOutline = shape.PathProps.Stroke.Color;
209 | // if ((vectorShape.colorOutline.g > 0.99f) && (vectorShape.colorOutline.b < Mathf.Epsilon) && (vectorShape.colorOutline.r < Mathf.Epsilon))
210 | // {
211 | // foreach (BezierPathSegment segment in contour.Segments)
212 | // {
213 | // Debug.Log(nodeTransform.MultiplyPoint(segment.P0).x);
214 | // }
215 | // }
216 | // }
217 | // }
218 | //}
219 | }
220 | }
221 |
222 | if (node.Children != null)
223 | {
224 | foreach (SceneNode child in node.Children)
225 | {
226 | Matrix2D childTransform = nodeTransform * child.Transform;
227 | RecurseSVGNodes(child, childTransform, shapes);
228 | }
229 | }
230 | }
231 |
232 | ///
233 | /// Parse SVG into VectorShape list.
234 | ///
235 | public static List ReadSVG(System.IO.TextReader svg)
236 | {
237 | List shapes = new List();
238 |
239 | SVGParser.SceneInfo sceneInfo = SVGParser.ImportSVG(svg);
240 | //Debug.Log(sceneInfo.SceneViewport);
241 |
242 | Matrix2D rootTransform = Matrix2D.Scale(new Vector2(0.01f, -0.01f)) * sceneInfo.Scene.Root.Transform;
243 | RecurseSVGNodes(sceneInfo.Scene.Root, rootTransform, shapes);
244 |
245 | return shapes;
246 | }
247 |
248 | protected XmlWriter svgWriter;
249 | protected Unit svgUnits;
250 |
251 | ///
252 | /// .
253 | ///
254 | public VectorShapeFilesSVG()
255 | {
256 | }
257 |
258 | ///
259 | /// Initialize an XmlWriter for outputting svg data to a stream.
260 | ///
261 | /// Output stream
262 | /// Document rect
263 | /// Unit for measurements
264 | public void Open(Stream stream, Rect bounds, Unit unit = Unit.Millimeters)
265 | {
266 | XmlWriterSettings settings = new XmlWriterSettings();
267 | settings.Indent = true;
268 | settings.NewLineOnAttributes = false;
269 |
270 | svgWriter = XmlWriter.Create(stream, settings);
271 | svgUnits = unit;
272 |
273 | svgWriter.WriteStartDocument();
274 | svgWriter.WriteStartElement("svg", "http://www.w3.org/2000/svg");
275 |
276 | svgWriter.WriteStartAttribute("width");
277 | svgWriter.WriteValue(bounds.width);
278 | svgWriter.WriteValue(UnitSuffix(unit));
279 | svgWriter.WriteEndAttribute();
280 |
281 | svgWriter.WriteStartAttribute("height");
282 | svgWriter.WriteValue(bounds.height);
283 | svgWriter.WriteValue(UnitSuffix(unit));
284 | svgWriter.WriteEndAttribute();
285 |
286 | svgWriter.WriteStartAttribute("viewBox");
287 | svgWriter.WriteValue(bounds.x);
288 | svgWriter.WriteValue(" ");
289 | svgWriter.WriteValue(-(bounds.y + bounds.height));
290 | svgWriter.WriteValue(" ");
291 | svgWriter.WriteValue(bounds.width);
292 | svgWriter.WriteValue(" ");
293 | svgWriter.WriteValue(bounds.height);
294 | svgWriter.WriteEndAttribute();
295 | }
296 |
297 | ///
298 | /// Open a new element tag in the xml.
299 | ///
300 | /// ID of element block to open
301 | public void OpenElement(string element)
302 | {
303 | svgWriter.WriteStartElement(element);
304 | }
305 |
306 | ///
307 | /// Close an element tag in the xml.
308 | ///
309 | /// ID of element block to close (ignored)
310 | public void CloseElement(string element = null)
311 | {
312 | svgWriter.WriteEndElement();
313 | }
314 |
315 | ///
316 | /// Add a list of shapes to SVG as a new group.
317 | ///
318 | /// List of shapes
319 | /// ID of group
320 | public void AddShapeGroup(List shapes, string id)
321 | {
322 | svgWriter.WriteStartElement("g");
323 |
324 | svgWriter.WriteStartAttribute("id");
325 | svgWriter.WriteValue(id);
326 | svgWriter.WriteEndAttribute();
327 |
328 | foreach (VectorShape shape in shapes)
329 | {
330 | shape.WriteToXML(svgWriter, Vector2.zero, 1f);
331 | }
332 |
333 | svgWriter.WriteEndElement();
334 | }
335 |
336 | ///
337 | /// Add an element that reuses a defined object.
338 | ///
339 | public void AddUseElement(string id, Vector2 position, float rotation)
340 | {
341 | svgWriter.WriteStartElement("use");
342 |
343 | svgWriter.WriteStartAttribute("xlink", "href", "http://www.w3.org/1999/xlink");
344 | svgWriter.WriteValue("#" + id);
345 | svgWriter.WriteEndAttribute();
346 |
347 | svgWriter.WriteStartAttribute("transform");
348 | svgWriter.WriteValue("translate(" + position.x + ", " + -position.y + ") rotate(" + -rotation + ")");
349 | svgWriter.WriteEndAttribute();
350 |
351 | svgWriter.WriteEndElement();
352 | }
353 |
354 | ///
355 | /// Close the writer.
356 | ///
357 | public void Close()
358 | {
359 | if (svgWriter == null) return;
360 |
361 | svgWriter.WriteEndElement();
362 | svgWriter.WriteEndDocument();
363 |
364 | svgWriter.Close();
365 | }
366 | }
367 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/VectorShapeFilesSVG.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 98d6cc10d01924b429e5ded41bed2183
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/VectorShapeIcons.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Unity.VectorGraphics;
5 |
6 | #if UNITY_EDITOR
7 | using UnityEditor;
8 | #endif
9 |
10 | public static class VectorShapeIcons
11 | {
12 | static Camera renderCamera;
13 | static Material renderMaterial;
14 | static Mesh renderMesh;
15 |
16 | static VectorUtils.TessellationOptions tessellationOptions;
17 |
18 | static void VerifyCamera()
19 | {
20 | if (renderCamera == null)
21 | {
22 | GameObject cameraObject = GameObject.Find("Icon Render Camera");
23 | if (cameraObject == null)
24 | {
25 | cameraObject = new GameObject("Icon Render Camera");
26 | }
27 | renderCamera = cameraObject.GetComponent();
28 | if (renderCamera == null)
29 | {
30 | renderCamera = cameraObject.AddComponent();
31 | }
32 |
33 | renderCamera.orthographic = true;
34 | renderCamera.orthographicSize = 1f;
35 | renderCamera.clearFlags = CameraClearFlags.SolidColor;
36 | renderCamera.backgroundColor = Color.clear;
37 | renderCamera.nearClipPlane = 0.1f;
38 | renderCamera.farClipPlane = 100.0f;
39 | renderCamera.depth = Camera.main.depth + 1;
40 | renderCamera.enabled = false;
41 |
42 | renderMaterial = new Material(Shader.Find("UI/Default"));
43 |
44 | tessellationOptions = new VectorUtils.TessellationOptions()
45 | {
46 | StepDistance = 0.1f,
47 | MaxCordDeviation = float.MaxValue,
48 | MaxTanAngleDeviation = Mathf.PI / 16.0f,
49 | SamplingStepSize = 0.01f
50 | };
51 | }
52 | }
53 |
54 | #if false
55 | ///
56 | /// Create a Texture2D icon of a SVG image (editor only version).
57 | ///
58 | /// String containing svg content.
59 | /// PreviewRenderUtility to use for drawing
60 | ///
61 | /// Standard header and footer will be included if not found in svgContent
62 | ///
63 | public static Texture2D GetIcon(string svgContent, PreviewRenderUtility renderUtil)
64 | {
65 | string svg;
66 | if (svgContent.StartsWith(""))
67 | {
68 | svg = svgContent;
69 | }
70 | else
71 | {
72 | svg = svgIconHeader + svgContent;
73 | }
74 |
75 | if (!svg.EndsWith(svgIconFooter))
76 | {
77 | svg = svg + svgIconFooter;
78 | }
79 |
80 | // Parse the SVG
81 | SVGParser.SceneInfo sceneInfo = SVGParser.ImportSVG(new System.IO.StringReader(svg));
82 | int width = Mathf.CeilToInt(sceneInfo.SceneViewport.width);
83 | int height = Mathf.CeilToInt(sceneInfo.SceneViewport.height);
84 | if ((width > 64) || (height > 64)) Debug.LogWarning("SVG icon of unusual size!");
85 |
86 | // Save the render state and get a temporary render texture
87 | RenderTexture activeTexture = RenderTexture.active;
88 | renderUtil.camera.targetTexture = RenderTexture.GetTemporary(width * 2, height * 2, 8, RenderTextureFormat.ARGB32);
89 | renderUtil.camera.backgroundColor = Color.clear;
90 |
91 | // Generate the mesh
92 | Mesh iconMesh = new Mesh();
93 | List iconGeometry = VectorUtils.TessellateScene(sceneInfo.Scene, tessellationOptions);
94 | VectorUtils.FillMesh(iconMesh, iconGeometry, 1f);
95 |
96 | // Activate the render texture and draw the mesh into it
97 | RenderTexture.active = renderUtil.camera.targetTexture;
98 | float cameraSize = renderUtil.camera.orthographicSize;
99 | Vector3 cameraPosition = renderUtil.camera.transform.position;
100 | renderUtil.camera.orthographicSize = sceneInfo.SceneViewport.height / 2;
101 | renderUtil.camera.transform.position = new Vector3(sceneInfo.SceneViewport.center.x, sceneInfo.SceneViewport.center.y, -1);
102 | // HACK until FillMesh() flpYAxis is fixed
103 | renderUtil.camera.transform.Rotate(0, 0, 180f);
104 | renderUtil.DrawMesh(iconMesh, Matrix4x4.identity, renderMaterial, 0);
105 | renderUtil.camera.Render();
106 | renderUtil.camera.transform.Rotate(0, 0, 180f);
107 | renderUtil.camera.orthographicSize = cameraSize;
108 | renderUtil.camera.transform.position = cameraPosition;
109 | Texture2D iconTexture = new Texture2D(width * 2, height * 2);
110 | iconTexture.ReadPixels(new Rect(0, 0, width * 2, height * 2), 0, 0);
111 | iconTexture.Apply();
112 |
113 | // Restore the render state and release the temporary objects
114 | RenderTexture.active = activeTexture;
115 | RenderTexture.ReleaseTemporary(renderUtil.camera.targetTexture);
116 | UnityEngine.Object.DestroyImmediate(iconMesh);
117 |
118 | return iconTexture;
119 | }
120 |
121 | ///
122 | /// Create a Texture2D icon out of a VectorShape (editor only version).
123 | ///
124 | public static Texture2D GetIcon(VectorShape shape, PreviewRenderUtility renderUtil)
125 | {
126 | VectorUtils.TessellationOptions activeOptions = VectorShape.tessellationOptions;
127 | VectorShape.tessellationOptions = tessellationOptions;
128 | shape.Dirty = true;
129 |
130 | Rect shapeBounds = shape.ShapeBounds;
131 | int width = Mathf.CeilToInt(shapeBounds.width);
132 | int height = Mathf.CeilToInt(shapeBounds.height);
133 |
134 | // Save the render state and get a temporary render texture
135 | RenderTexture activeTexture = RenderTexture.active;
136 | renderUtil.camera.targetTexture = RenderTexture.GetTemporary(width * 2, height * 2, 8, RenderTextureFormat.ARGB32);
137 | renderUtil.camera.backgroundColor = Color.clear;
138 |
139 | // Activate the render texture and draw the shape into it
140 | RenderTexture.active = renderUtil.camera.targetTexture;
141 | float cameraSize = renderUtil.camera.orthographicSize;
142 | Vector3 cameraPosition = renderUtil.camera.transform.position;
143 | renderUtil.camera.orthographicSize = shapeBounds.height / 2;
144 | renderUtil.camera.transform.position = new Vector3(shapeBounds.center.x, shapeBounds.center.y, -1);
145 |
146 | Matrix4x4 drawMatrix = Matrix4x4.identity;
147 | renderUtil.DrawMesh(shape.ShapeMesh, drawMatrix, renderMaterial, 0);
148 |
149 | renderUtil.camera.Render();
150 | renderUtil.camera.orthographicSize = cameraSize;
151 | renderUtil.camera.transform.position = cameraPosition;
152 | Texture2D iconTexture = new Texture2D(width * 2, height * 2);
153 | iconTexture.ReadPixels(new Rect(0, 0, width * 2, height * 2), 0, 0);
154 | iconTexture.Apply();
155 |
156 | // Restore the render state and release the temporary render texture
157 | RenderTexture.active = activeTexture;
158 | RenderTexture.ReleaseTemporary(renderUtil.camera.targetTexture);
159 |
160 | VectorShape.tessellationOptions = activeOptions;
161 | shape.Dirty = true;
162 |
163 | return iconTexture;
164 | }
165 | #endif
166 |
167 | static void OnPostRender(Camera camera)
168 | {
169 | if ((camera == renderCamera) && (renderMesh != null))
170 | {
171 | renderMaterial.SetPass(0);
172 | Graphics.DrawMeshNow(renderMesh, Vector3.zero, Quaternion.identity);
173 | }
174 | }
175 |
176 | ///
177 | /// Create a Texture2D icon of a SVG image.
178 | ///
179 | /// String containing svg content.
180 | ///
181 | /// Standard header and footer will be included if not found in svgContent
182 | ///
183 | public static Texture2D GetIcon(string svgContent)
184 | {
185 | string svg;
186 | if (svgContent.StartsWith(""))
187 | {
188 | svg = svgContent;
189 | }
190 | else
191 | {
192 | svg = svgIconHeader + svgContent;
193 | }
194 |
195 | if (!svg.EndsWith(svgIconFooter))
196 | {
197 | svg = svg + svgIconFooter;
198 | }
199 |
200 | // Parse the SVG
201 | SVGParser.SceneInfo sceneInfo = SVGParser.ImportSVG(new System.IO.StringReader(svg));
202 | int width = Mathf.CeilToInt(sceneInfo.SceneViewport.width);
203 | int height = Mathf.CeilToInt(sceneInfo.SceneViewport.height);
204 | if ((width > 64) || (height > 64)) Debug.LogWarning("SVG icon of unusual size!");
205 |
206 | // Save the render state and get a temporary render texture
207 | VerifyCamera();
208 | RenderTexture activeTexture = RenderTexture.active;
209 | RenderTexture tempTexture = RenderTexture.GetTemporary(width, height, 8, RenderTextureFormat.ARGB32); ;
210 |
211 | // Generate the mesh
212 | renderMesh = new Mesh();
213 | List iconGeometry = VectorUtils.TessellateScene(sceneInfo.Scene, tessellationOptions);
214 | VectorUtils.FillMesh(renderMesh, iconGeometry, 1f);
215 |
216 | // Activate the render texture and draw the mesh into it
217 | renderCamera.orthographicSize = sceneInfo.SceneViewport.height / 2;
218 | renderCamera.transform.position = new Vector3(sceneInfo.SceneViewport.center.x, sceneInfo.SceneViewport.center.y, -1);
219 |
220 | renderCamera.targetTexture = tempTexture;
221 |
222 | Camera.onPostRender += OnPostRender;
223 |
224 | // HACK until FillMesh() flipYAxis is fixed
225 | renderCamera.transform.Rotate(0, 0, 180f);
226 | renderCamera.Render();
227 | renderCamera.transform.Rotate(0, 0, 180f);
228 |
229 | Camera.onPostRender -= OnPostRender;
230 |
231 | RenderTexture.active = renderCamera.targetTexture;
232 |
233 | Texture2D iconTexture = new Texture2D(width, height);
234 | iconTexture.ReadPixels(new Rect(0, 0, width, height), 0, 0);
235 | iconTexture.Apply();
236 |
237 | // Restore the render state and release the temporary objects
238 | RenderTexture.active = activeTexture;
239 | renderCamera.targetTexture = activeTexture;
240 | RenderTexture.ReleaseTemporary(tempTexture);
241 |
242 | UnityEngine.Object.DestroyImmediate(renderMesh);
243 | renderMesh = null;
244 |
245 | return iconTexture;
246 | }
247 |
248 | ///
249 | /// Create a Texture2D icon out of a VectorShape.
250 | ///
251 | public static Texture2D GetIcon(VectorShape shape)
252 | {
253 | VectorUtils.TessellationOptions activeOptions = VectorShape.tessellationOptions;
254 | VectorShape.tessellationOptions = tessellationOptions;
255 | shape.Dirty = true;
256 |
257 | Rect shapeBounds = shape.ShapeBounds;
258 | int width = Mathf.CeilToInt(shapeBounds.width);
259 | int height = Mathf.CeilToInt(shapeBounds.height);
260 | renderMesh = shape.ShapeMesh;
261 |
262 | // Save the render state and get a temporary render texture
263 | VerifyCamera();
264 | RenderTexture activeTexture = RenderTexture.active;
265 | RenderTexture tempTexture = RenderTexture.GetTemporary(width, height, 8, RenderTextureFormat.ARGB32); ;
266 |
267 | // Activate the render texture and draw the mesh into it
268 | renderCamera.orthographicSize = shapeBounds.height / 2;
269 | renderCamera.transform.position = new Vector3(shapeBounds.center.x, shapeBounds.center.y, -1);
270 |
271 | renderCamera.targetTexture = tempTexture;
272 |
273 | Camera.onPostRender += OnPostRender;
274 |
275 | renderCamera.Render();
276 |
277 | Camera.onPostRender -= OnPostRender;
278 |
279 | RenderTexture.active = renderCamera.targetTexture;
280 |
281 | Texture2D iconTexture = new Texture2D(width, height);
282 | iconTexture.ReadPixels(new Rect(0, 0, width, height), 0, 0);
283 | iconTexture.Apply();
284 |
285 | // Restore the render state and release the temporary objects
286 | RenderTexture.active = activeTexture;
287 | renderCamera.targetTexture = activeTexture;
288 | RenderTexture.ReleaseTemporary(tempTexture);
289 |
290 | VectorShape.tessellationOptions = activeOptions;
291 | shape.Dirty = true;
292 |
293 | renderMesh = null;
294 |
295 | return iconTexture;
296 | }
297 |
298 | ///
299 | /// Create a Sprite icon of a SVG image.
300 | ///
301 | /// String containing svg content.
302 | ///
303 | /// Standard header and footer will be included if not found in svgContent
304 | ///
305 | public static Sprite GetSprite(string svgContent)
306 | {
307 | string svg;
308 | if (svgContent.StartsWith(""))
309 | {
310 | svg = svgContent;
311 | }
312 | else
313 | {
314 | svg = svgIconHeader + svgContent;
315 | }
316 |
317 | if (!svg.EndsWith(svgIconFooter))
318 | {
319 | svg = svg + svgIconFooter;
320 | }
321 |
322 | // Parse the SVG
323 | SVGParser.SceneInfo sceneInfo = SVGParser.ImportSVG(new System.IO.StringReader(svg));
324 | int width = Mathf.CeilToInt(sceneInfo.SceneViewport.width);
325 | int height = Mathf.CeilToInt(sceneInfo.SceneViewport.height);
326 | if ((width > 64) || (height > 64)) Debug.LogWarning("SVG icon of unusual size!");
327 |
328 | List iconGeometry = VectorUtils.TessellateScene(sceneInfo.Scene, tessellationOptions);
329 |
330 | Sprite sprite = VectorUtils.BuildSprite(iconGeometry, 100f, VectorUtils.Alignment.Center, Vector2.zero, 128, true);
331 |
332 | return sprite;
333 | }
334 |
335 | ///
336 | /// Create a Sprite icon out of a VectorShape.
337 | ///
338 | public static Sprite GetSprite(VectorShape shape)
339 | {
340 | Rect shapeBounds = shape.ShapeBounds;
341 | int width = Mathf.CeilToInt(shapeBounds.width);
342 | int height = Mathf.CeilToInt(shapeBounds.height);
343 | List iconGeometry = shape.ShapeGeometry;
344 |
345 | Sprite sprite = VectorUtils.BuildSprite(iconGeometry, 100f, VectorUtils.Alignment.Center, Vector2.zero, 128, true);
346 |
347 | return sprite;
348 | }
349 |
350 | const string svgIconHeader =
351 | "" +
352 | "" +
353 | "";
357 |
358 |
359 | // Editing tools
360 | public const string iconView =
361 | "";
362 |
363 | public const string iconBrush =
364 | "";
365 |
366 | public const string iconMagnify =
367 | "";
368 |
369 | public const string iconArrowAll =
370 | "";
371 |
372 | public const string iconSelectionRect =
373 | "";
374 |
375 | public const string iconShapes =
376 | "";
377 |
378 |
379 | // Selection levels
380 | public const string iconSelectObject =
381 | "";
382 |
383 | public const string iconSelectSegment =
384 | "";
385 |
386 | public const string iconSelectVertex =
387 | "";
388 |
389 |
390 | // Simple shapes
391 | public const string iconPoint =
392 | "";
393 |
394 | public const string iconCircle =
395 | "";
396 |
397 | public const string iconFilledCircle =
398 | "";
399 |
400 | public const string iconTriangle =
401 | "";
402 |
403 | public const string iconSquare =
404 | "";
405 |
406 | public const string iconPentagon =
407 | "";
408 |
409 | public const string iconHexagon =
410 | "";
411 |
412 | public const string iconPolygon =
413 | "";
414 |
415 | public const string iconVerticalDots =
416 | "";
417 | }
418 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/VectorShapeIcons.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 8bde8653997e740ad8353e2ec03c627f
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/VectorShapeUtils.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | public static class VectorShapeUtils
4 | {
5 | ///
6 | /// Union of two Rects
7 | ///
8 | /// The union.
9 | /// Rect A
10 | /// Rect B
11 | public static Rect RectUnion(Rect rectA, Rect rectB)
12 | {
13 | return Rect.MinMaxRect(Mathf.Min(rectA.xMin, rectB.xMin),
14 | Mathf.Min(rectA.yMin, rectB.yMin),
15 | Mathf.Max(rectA.xMax, rectB.xMax),
16 | Mathf.Max(rectA.yMax, rectB.yMax));
17 | }
18 |
19 |
20 | ///
21 | /// Point on a quadratic curve between pt0 and pt2.
22 | ///
23 | /// Starting point
24 | /// Control point
25 | /// Ending point
26 | /// Distance along curve
27 | public static Vector2 EvaluateQuadraticCurve(Vector2 pt0, Vector2 pt1, Vector2 pt2, float t)
28 | {
29 | Vector2 p0 = Vector2.Lerp(pt0, pt1, t);
30 | Vector2 p1 = Vector2.Lerp(pt1, pt2, t);
31 | return Vector2.Lerp(p0, p1, t);
32 | }
33 |
34 | ///
35 | /// Point on a cubic curve between pt0 and pt3.
36 | ///
37 | /// Starting point
38 | /// Control point
39 | /// Control point
40 | /// Ending point
41 | /// Distance along curve
42 | public static Vector2 EvaluateCubicCurve(Vector2 pt0, Vector2 pt1, Vector2 pt2, Vector2 pt3, float t)
43 | {
44 | Vector2 p0 = EvaluateQuadraticCurve(pt0, pt1, pt2, t);
45 | Vector2 p1 = EvaluateQuadraticCurve(pt1, pt2, pt3, t);
46 | return Vector2.Lerp(p0, p1, t);
47 | }
48 |
49 | ///
50 | /// Closest point on a line segment to given point.
51 | ///
52 | /// Test point
53 | /// Start of line segment
54 | /// End of line segment
55 | /// Closet point on segment
56 | public static Vector2 ClosestPointOnLineSegment(Vector2 pt, Vector2 segA, Vector2 segB)
57 | {
58 | float segLength = (segB - segA).sqrMagnitude;
59 | if (segLength < Mathf.Epsilon) // Segment is actually a point
60 | return segA;
61 |
62 | float t = Vector2.Dot(pt - segA, segB - segA) / segLength;
63 | if (t < 0.0) // Beyond the 'a' end of the segment
64 | return segA;
65 | if (t > 1.0) // Beyond the 'b' end of the segment
66 | return segB;
67 |
68 | // Projection falls on the segment
69 | Vector2 projection = segA + t * (segB - segA);
70 | return projection;
71 | }
72 |
73 | ///
74 | /// Distance between a point and a line segment.
75 | ///
76 | /// Test point
77 | /// Start of line segment
78 | /// End of line segment
79 | /// Distance
80 | public static float DistancePointToLineSegment(Vector2 pt, Vector2 segA, Vector2 segB)
81 | {
82 | Vector2 closest = ClosestPointOnLineSegment(pt, segA, segB);
83 | return Vector2.Distance(pt, closest);
84 | }
85 |
86 | ///
87 | /// Number of steps when approximating Bezier curves.
88 | ///
89 | public static int bezierSteps = 12;
90 |
91 | ///
92 | /// APPROXIMATE closest point on a bezier curve segment to given point.
93 | ///
94 | /// Test point
95 | /// Start of curve
96 | /// Control point A
97 | /// Control point B
98 | /// End of curve
99 | /// Closest point on the curve (approximate)
100 | public static Vector2 ClosetPointOnBezierCurve(Vector2 pt, Vector2 curveA, Vector2 controlA, Vector2 controlB, Vector2 curveB)
101 | {
102 | Vector2 closest = curveA;
103 | float sqrDistance = (pt - curveA).sqrMagnitude;
104 |
105 | float step = 1f / bezierSteps;
106 | float t = step;
107 | for (int i = 1; i < bezierSteps; i++)
108 | {
109 | Vector2 curvePt = EvaluateCubicCurve(curveA, controlA, controlB, curveB, t);
110 | float sqrDistance2 = (pt - curvePt).sqrMagnitude;
111 | if (sqrDistance2 < sqrDistance)
112 | {
113 | sqrDistance = sqrDistance2;
114 | closest = curvePt;
115 | }
116 |
117 | t += step;
118 | }
119 |
120 | return closest;
121 | }
122 |
123 | ///
124 | /// Distance between a point and a Bezier curve
125 | ///
126 | /// Test point
127 | /// Start of curve
128 | /// Control point A
129 | /// Control point B
130 | /// End of curve
131 | /// Distance (approximate)
132 | public static float DistancePointToBezierCurve(Vector2 pt, Vector2 curveA, Vector2 controlA, Vector2 controlB, Vector2 curveB)
133 | {
134 | Vector2 closest = ClosetPointOnBezierCurve(pt, curveA, controlA, curveB, controlB);
135 |
136 | return Vector2.Distance(pt, closest);
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/Assets/VectorShapes/VectorShapeUtils.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 6de1439a6cf1949a087f20e22cda860f
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Eli Curtz
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 |
--------------------------------------------------------------------------------
/PREVIEW.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecurtz/UnityVectorEditor/e858f29b975dc0eb15a20bae77e3cfdc68c188b9/PREVIEW.png
--------------------------------------------------------------------------------
/Packages/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "com.unity.package-manager-ui": "2.0.7",
4 | "com.unity.modules.animation": "1.0.0",
5 | "com.unity.modules.assetbundle": "1.0.0",
6 | "com.unity.modules.audio": "1.0.0",
7 | "com.unity.modules.cloth": "1.0.0",
8 | "com.unity.modules.director": "1.0.0",
9 | "com.unity.modules.imageconversion": "1.0.0",
10 | "com.unity.modules.imgui": "1.0.0",
11 | "com.unity.modules.jsonserialize": "1.0.0",
12 | "com.unity.modules.particlesystem": "1.0.0",
13 | "com.unity.modules.physics": "1.0.0",
14 | "com.unity.modules.physics2d": "1.0.0",
15 | "com.unity.modules.screencapture": "1.0.0",
16 | "com.unity.modules.tilemap": "1.0.0",
17 | "com.unity.modules.ui": "1.0.0",
18 | "com.unity.modules.uielements": "1.0.0",
19 | "com.unity.modules.umbra": "1.0.0",
20 | "com.unity.modules.unitywebrequest": "1.0.0",
21 | "com.unity.modules.unitywebrequestassetbundle": "1.0.0",
22 | "com.unity.modules.unitywebrequestaudio": "1.0.0",
23 | "com.unity.modules.unitywebrequesttexture": "1.0.0",
24 | "com.unity.modules.unitywebrequestwww": "1.0.0",
25 | "com.unity.vectorgraphics": "1.0.0-preview.24"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/ProjectSettings/ProjectSettings.asset:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!129 &1
4 | PlayerSettings:
5 | m_ObjectHideFlags: 0
6 | serializedVersion: 15
7 | productGUID: 2a17d8bc098194c0fbe418e33bba5894
8 | AndroidProfiler: 0
9 | AndroidFilterTouchesWhenObscured: 0
10 | AndroidEnableSustainedPerformanceMode: 0
11 | defaultScreenOrientation: 4
12 | targetDevice: 2
13 | useOnDemandResources: 0
14 | accelerometerFrequency: 60
15 | companyName: DefaultCompany
16 | productName: UnityVectorEditor
17 | defaultCursor: {fileID: 0}
18 | cursorHotspot: {x: 0, y: 0}
19 | m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1}
20 | m_ShowUnitySplashScreen: 1
21 | m_ShowUnitySplashLogo: 1
22 | m_SplashScreenOverlayOpacity: 1
23 | m_SplashScreenAnimation: 1
24 | m_SplashScreenLogoStyle: 1
25 | m_SplashScreenDrawMode: 0
26 | m_SplashScreenBackgroundAnimationZoom: 1
27 | m_SplashScreenLogoAnimationZoom: 1
28 | m_SplashScreenBackgroundLandscapeAspect: 1
29 | m_SplashScreenBackgroundPortraitAspect: 1
30 | m_SplashScreenBackgroundLandscapeUvs:
31 | serializedVersion: 2
32 | x: 0
33 | y: 0
34 | width: 1
35 | height: 1
36 | m_SplashScreenBackgroundPortraitUvs:
37 | serializedVersion: 2
38 | x: 0
39 | y: 0
40 | width: 1
41 | height: 1
42 | m_SplashScreenLogos: []
43 | m_VirtualRealitySplashScreen: {fileID: 0}
44 | m_HolographicTrackingLossScreen: {fileID: 0}
45 | defaultScreenWidth: 1024
46 | defaultScreenHeight: 768
47 | defaultScreenWidthWeb: 960
48 | defaultScreenHeightWeb: 600
49 | m_StereoRenderingPath: 0
50 | m_ActiveColorSpace: 0
51 | m_MTRendering: 1
52 | m_StackTraceTypes: 010000000100000001000000010000000100000001000000
53 | iosShowActivityIndicatorOnLoading: -1
54 | androidShowActivityIndicatorOnLoading: -1
55 | iosAppInBackgroundBehavior: 0
56 | displayResolutionDialog: 1
57 | iosAllowHTTPDownload: 1
58 | allowedAutorotateToPortrait: 1
59 | allowedAutorotateToPortraitUpsideDown: 1
60 | allowedAutorotateToLandscapeRight: 1
61 | allowedAutorotateToLandscapeLeft: 1
62 | useOSAutorotation: 1
63 | use32BitDisplayBuffer: 1
64 | preserveFramebufferAlpha: 0
65 | disableDepthAndStencilBuffers: 0
66 | androidStartInFullscreen: 1
67 | androidRenderOutsideSafeArea: 0
68 | androidBlitType: 0
69 | defaultIsNativeResolution: 1
70 | macRetinaSupport: 1
71 | runInBackground: 1
72 | captureSingleScreen: 0
73 | muteOtherAudioSources: 0
74 | Prepare IOS For Recording: 0
75 | Force IOS Speakers When Recording: 0
76 | deferSystemGesturesMode: 0
77 | hideHomeButton: 0
78 | submitAnalytics: 1
79 | usePlayerLog: 1
80 | bakeCollisionMeshes: 0
81 | forceSingleInstance: 0
82 | resizableWindow: 0
83 | useMacAppStoreValidation: 0
84 | macAppStoreCategory: public.app-category.games
85 | gpuSkinning: 1
86 | graphicsJobs: 0
87 | xboxPIXTextureCapture: 0
88 | xboxEnableAvatar: 0
89 | xboxEnableKinect: 0
90 | xboxEnableKinectAutoTracking: 0
91 | xboxEnableFitness: 0
92 | visibleInBackground: 1
93 | allowFullscreenSwitch: 1
94 | graphicsJobMode: 0
95 | fullscreenMode: 1
96 | xboxSpeechDB: 0
97 | xboxEnableHeadOrientation: 0
98 | xboxEnableGuest: 0
99 | xboxEnablePIXSampling: 0
100 | metalFramebufferOnly: 0
101 | xboxOneResolution: 0
102 | xboxOneSResolution: 0
103 | xboxOneXResolution: 3
104 | xboxOneMonoLoggingLevel: 0
105 | xboxOneLoggingLevel: 1
106 | xboxOneDisableEsram: 0
107 | xboxOnePresentImmediateThreshold: 0
108 | switchQueueCommandMemory: 0
109 | switchQueueControlMemory: 16384
110 | switchQueueComputeMemory: 262144
111 | switchNVNShaderPoolsGranularity: 33554432
112 | switchNVNDefaultPoolsGranularity: 16777216
113 | switchNVNOtherPoolsGranularity: 16777216
114 | vulkanEnableSetSRGBWrite: 0
115 | m_SupportedAspectRatios:
116 | 4:3: 1
117 | 5:4: 1
118 | 16:10: 1
119 | 16:9: 1
120 | Others: 1
121 | bundleVersion: 0.1
122 | preloadedAssets: []
123 | metroInputSource: 0
124 | wsaTransparentSwapchain: 0
125 | m_HolographicPauseOnTrackingLoss: 1
126 | xboxOneDisableKinectGpuReservation: 1
127 | xboxOneEnable7thCore: 1
128 | isWsaHolographicRemotingEnabled: 0
129 | vrSettings:
130 | cardboard:
131 | depthFormat: 0
132 | enableTransitionView: 0
133 | daydream:
134 | depthFormat: 0
135 | useSustainedPerformanceMode: 0
136 | enableVideoLayer: 0
137 | useProtectedVideoMemory: 0
138 | minimumSupportedHeadTracking: 0
139 | maximumSupportedHeadTracking: 1
140 | hololens:
141 | depthFormat: 1
142 | depthBufferSharingEnabled: 1
143 | oculus:
144 | sharedDepthBuffer: 1
145 | dashSupport: 1
146 | enable360StereoCapture: 0
147 | protectGraphicsMemory: 0
148 | enableFrameTimingStats: 0
149 | useHDRDisplay: 0
150 | m_ColorGamuts: 00000000
151 | targetPixelDensity: 30
152 | resolutionScalingMode: 0
153 | androidSupportedAspectRatio: 1
154 | androidMaxAspectRatio: 2.1
155 | applicationIdentifier: {}
156 | buildNumber: {}
157 | AndroidBundleVersionCode: 1
158 | AndroidMinSdkVersion: 16
159 | AndroidTargetSdkVersion: 0
160 | AndroidPreferredInstallLocation: 1
161 | aotOptions:
162 | stripEngineCode: 1
163 | iPhoneStrippingLevel: 0
164 | iPhoneScriptCallOptimization: 0
165 | ForceInternetPermission: 0
166 | ForceSDCardPermission: 0
167 | CreateWallpaper: 0
168 | APKExpansionFiles: 0
169 | keepLoadedShadersAlive: 0
170 | StripUnusedMeshComponents: 1
171 | VertexChannelCompressionMask: 4054
172 | iPhoneSdkVersion: 988
173 | iOSTargetOSVersionString: 9.0
174 | tvOSSdkVersion: 0
175 | tvOSRequireExtendedGameController: 0
176 | tvOSTargetOSVersionString: 9.0
177 | uIPrerenderedIcon: 0
178 | uIRequiresPersistentWiFi: 0
179 | uIRequiresFullScreen: 1
180 | uIStatusBarHidden: 1
181 | uIExitOnSuspend: 0
182 | uIStatusBarStyle: 0
183 | iPhoneSplashScreen: {fileID: 0}
184 | iPhoneHighResSplashScreen: {fileID: 0}
185 | iPhoneTallHighResSplashScreen: {fileID: 0}
186 | iPhone47inSplashScreen: {fileID: 0}
187 | iPhone55inPortraitSplashScreen: {fileID: 0}
188 | iPhone55inLandscapeSplashScreen: {fileID: 0}
189 | iPhone58inPortraitSplashScreen: {fileID: 0}
190 | iPhone58inLandscapeSplashScreen: {fileID: 0}
191 | iPadPortraitSplashScreen: {fileID: 0}
192 | iPadHighResPortraitSplashScreen: {fileID: 0}
193 | iPadLandscapeSplashScreen: {fileID: 0}
194 | iPadHighResLandscapeSplashScreen: {fileID: 0}
195 | appleTVSplashScreen: {fileID: 0}
196 | appleTVSplashScreen2x: {fileID: 0}
197 | tvOSSmallIconLayers: []
198 | tvOSSmallIconLayers2x: []
199 | tvOSLargeIconLayers: []
200 | tvOSLargeIconLayers2x: []
201 | tvOSTopShelfImageLayers: []
202 | tvOSTopShelfImageLayers2x: []
203 | tvOSTopShelfImageWideLayers: []
204 | tvOSTopShelfImageWideLayers2x: []
205 | iOSLaunchScreenType: 0
206 | iOSLaunchScreenPortrait: {fileID: 0}
207 | iOSLaunchScreenLandscape: {fileID: 0}
208 | iOSLaunchScreenBackgroundColor:
209 | serializedVersion: 2
210 | rgba: 0
211 | iOSLaunchScreenFillPct: 100
212 | iOSLaunchScreenSize: 100
213 | iOSLaunchScreenCustomXibPath:
214 | iOSLaunchScreeniPadType: 0
215 | iOSLaunchScreeniPadImage: {fileID: 0}
216 | iOSLaunchScreeniPadBackgroundColor:
217 | serializedVersion: 2
218 | rgba: 0
219 | iOSLaunchScreeniPadFillPct: 100
220 | iOSLaunchScreeniPadSize: 100
221 | iOSLaunchScreeniPadCustomXibPath:
222 | iOSUseLaunchScreenStoryboard: 0
223 | iOSLaunchScreenCustomStoryboardPath:
224 | iOSDeviceRequirements: []
225 | iOSURLSchemes: []
226 | iOSBackgroundModes: 0
227 | iOSMetalForceHardShadows: 0
228 | metalEditorSupport: 1
229 | metalAPIValidation: 1
230 | iOSRenderExtraFrameOnPause: 0
231 | appleDeveloperTeamID:
232 | iOSManualSigningProvisioningProfileID:
233 | tvOSManualSigningProvisioningProfileID:
234 | iOSManualSigningProvisioningProfileType: 0
235 | tvOSManualSigningProvisioningProfileType: 0
236 | appleEnableAutomaticSigning: 0
237 | iOSRequireARKit: 0
238 | iOSAutomaticallyDetectAndAddCapabilities: 1
239 | appleEnableProMotion: 0
240 | clonedFromGUID: c0afd0d1d80e3634a9dac47e8a0426ea
241 | templatePackageId: com.unity.template.3d@1.3.0
242 | templateDefaultScene: Assets/Scenes/SampleScene.unity
243 | AndroidTargetArchitectures: 5
244 | AndroidSplashScreenScale: 0
245 | androidSplashScreen: {fileID: 0}
246 | AndroidKeystoreName:
247 | AndroidKeyaliasName:
248 | AndroidBuildApkPerCpuArchitecture: 0
249 | AndroidTVCompatibility: 1
250 | AndroidIsGame: 1
251 | AndroidEnableTango: 0
252 | androidEnableBanner: 1
253 | androidUseLowAccuracyLocation: 0
254 | m_AndroidBanners:
255 | - width: 320
256 | height: 180
257 | banner: {fileID: 0}
258 | androidGamepadSupportLevel: 0
259 | resolutionDialogBanner: {fileID: 0}
260 | m_BuildTargetIcons: []
261 | m_BuildTargetPlatformIcons: []
262 | m_BuildTargetBatching:
263 | - m_BuildTarget: Standalone
264 | m_StaticBatching: 1
265 | m_DynamicBatching: 0
266 | - m_BuildTarget: tvOS
267 | m_StaticBatching: 1
268 | m_DynamicBatching: 0
269 | - m_BuildTarget: Android
270 | m_StaticBatching: 1
271 | m_DynamicBatching: 0
272 | - m_BuildTarget: iPhone
273 | m_StaticBatching: 1
274 | m_DynamicBatching: 0
275 | - m_BuildTarget: WebGL
276 | m_StaticBatching: 0
277 | m_DynamicBatching: 0
278 | m_BuildTargetGraphicsAPIs:
279 | - m_BuildTarget: AndroidPlayer
280 | m_APIs: 0b00000008000000
281 | m_Automatic: 1
282 | - m_BuildTarget: iOSSupport
283 | m_APIs: 10000000
284 | m_Automatic: 1
285 | - m_BuildTarget: AppleTVSupport
286 | m_APIs: 10000000
287 | m_Automatic: 0
288 | - m_BuildTarget: WebGLSupport
289 | m_APIs: 0b000000
290 | m_Automatic: 1
291 | m_BuildTargetVRSettings:
292 | - m_BuildTarget: Standalone
293 | m_Enabled: 0
294 | m_Devices:
295 | - Oculus
296 | - OpenVR
297 | m_BuildTargetEnableVuforiaSettings: []
298 | openGLRequireES31: 0
299 | openGLRequireES31AEP: 0
300 | m_TemplateCustomTags: {}
301 | mobileMTRendering:
302 | Android: 1
303 | iPhone: 1
304 | tvOS: 1
305 | m_BuildTargetGroupLightmapEncodingQuality: []
306 | m_BuildTargetGroupLightmapSettings: []
307 | playModeTestRunnerEnabled: 0
308 | runPlayModeTestAsEditModeTest: 0
309 | actionOnDotNetUnhandledException: 1
310 | enableInternalProfiler: 0
311 | logObjCUncaughtExceptions: 1
312 | enableCrashReportAPI: 0
313 | cameraUsageDescription:
314 | locationUsageDescription:
315 | microphoneUsageDescription:
316 | switchNetLibKey:
317 | switchSocketMemoryPoolSize: 6144
318 | switchSocketAllocatorPoolSize: 128
319 | switchSocketConcurrencyLimit: 14
320 | switchScreenResolutionBehavior: 2
321 | switchUseCPUProfiler: 0
322 | switchApplicationID: 0x01004b9000490000
323 | switchNSODependencies:
324 | switchTitleNames_0:
325 | switchTitleNames_1:
326 | switchTitleNames_2:
327 | switchTitleNames_3:
328 | switchTitleNames_4:
329 | switchTitleNames_5:
330 | switchTitleNames_6:
331 | switchTitleNames_7:
332 | switchTitleNames_8:
333 | switchTitleNames_9:
334 | switchTitleNames_10:
335 | switchTitleNames_11:
336 | switchTitleNames_12:
337 | switchTitleNames_13:
338 | switchTitleNames_14:
339 | switchPublisherNames_0:
340 | switchPublisherNames_1:
341 | switchPublisherNames_2:
342 | switchPublisherNames_3:
343 | switchPublisherNames_4:
344 | switchPublisherNames_5:
345 | switchPublisherNames_6:
346 | switchPublisherNames_7:
347 | switchPublisherNames_8:
348 | switchPublisherNames_9:
349 | switchPublisherNames_10:
350 | switchPublisherNames_11:
351 | switchPublisherNames_12:
352 | switchPublisherNames_13:
353 | switchPublisherNames_14:
354 | switchIcons_0: {fileID: 0}
355 | switchIcons_1: {fileID: 0}
356 | switchIcons_2: {fileID: 0}
357 | switchIcons_3: {fileID: 0}
358 | switchIcons_4: {fileID: 0}
359 | switchIcons_5: {fileID: 0}
360 | switchIcons_6: {fileID: 0}
361 | switchIcons_7: {fileID: 0}
362 | switchIcons_8: {fileID: 0}
363 | switchIcons_9: {fileID: 0}
364 | switchIcons_10: {fileID: 0}
365 | switchIcons_11: {fileID: 0}
366 | switchIcons_12: {fileID: 0}
367 | switchIcons_13: {fileID: 0}
368 | switchIcons_14: {fileID: 0}
369 | switchSmallIcons_0: {fileID: 0}
370 | switchSmallIcons_1: {fileID: 0}
371 | switchSmallIcons_2: {fileID: 0}
372 | switchSmallIcons_3: {fileID: 0}
373 | switchSmallIcons_4: {fileID: 0}
374 | switchSmallIcons_5: {fileID: 0}
375 | switchSmallIcons_6: {fileID: 0}
376 | switchSmallIcons_7: {fileID: 0}
377 | switchSmallIcons_8: {fileID: 0}
378 | switchSmallIcons_9: {fileID: 0}
379 | switchSmallIcons_10: {fileID: 0}
380 | switchSmallIcons_11: {fileID: 0}
381 | switchSmallIcons_12: {fileID: 0}
382 | switchSmallIcons_13: {fileID: 0}
383 | switchSmallIcons_14: {fileID: 0}
384 | switchManualHTML:
385 | switchAccessibleURLs:
386 | switchLegalInformation:
387 | switchMainThreadStackSize: 1048576
388 | switchPresenceGroupId:
389 | switchLogoHandling: 0
390 | switchReleaseVersion: 0
391 | switchDisplayVersion: 1.0.0
392 | switchStartupUserAccount: 0
393 | switchTouchScreenUsage: 0
394 | switchSupportedLanguagesMask: 0
395 | switchLogoType: 0
396 | switchApplicationErrorCodeCategory:
397 | switchUserAccountSaveDataSize: 0
398 | switchUserAccountSaveDataJournalSize: 0
399 | switchApplicationAttribute: 0
400 | switchCardSpecSize: -1
401 | switchCardSpecClock: -1
402 | switchRatingsMask: 0
403 | switchRatingsInt_0: 0
404 | switchRatingsInt_1: 0
405 | switchRatingsInt_2: 0
406 | switchRatingsInt_3: 0
407 | switchRatingsInt_4: 0
408 | switchRatingsInt_5: 0
409 | switchRatingsInt_6: 0
410 | switchRatingsInt_7: 0
411 | switchRatingsInt_8: 0
412 | switchRatingsInt_9: 0
413 | switchRatingsInt_10: 0
414 | switchRatingsInt_11: 0
415 | switchLocalCommunicationIds_0:
416 | switchLocalCommunicationIds_1:
417 | switchLocalCommunicationIds_2:
418 | switchLocalCommunicationIds_3:
419 | switchLocalCommunicationIds_4:
420 | switchLocalCommunicationIds_5:
421 | switchLocalCommunicationIds_6:
422 | switchLocalCommunicationIds_7:
423 | switchParentalControl: 0
424 | switchAllowsScreenshot: 1
425 | switchAllowsVideoCapturing: 1
426 | switchAllowsRuntimeAddOnContentInstall: 0
427 | switchDataLossConfirmation: 0
428 | switchUserAccountLockEnabled: 0
429 | switchSystemResourceMemory: 16777216
430 | switchSupportedNpadStyles: 3
431 | switchNativeFsCacheSize: 32
432 | switchIsHoldTypeHorizontal: 0
433 | switchSupportedNpadCount: 8
434 | switchSocketConfigEnabled: 0
435 | switchTcpInitialSendBufferSize: 32
436 | switchTcpInitialReceiveBufferSize: 64
437 | switchTcpAutoSendBufferSizeMax: 256
438 | switchTcpAutoReceiveBufferSizeMax: 256
439 | switchUdpSendBufferSize: 9
440 | switchUdpReceiveBufferSize: 42
441 | switchSocketBufferEfficiency: 4
442 | switchSocketInitializeEnabled: 1
443 | switchNetworkInterfaceManagerInitializeEnabled: 1
444 | switchPlayerConnectionEnabled: 1
445 | ps4NPAgeRating: 12
446 | ps4NPTitleSecret:
447 | ps4NPTrophyPackPath:
448 | ps4ParentalLevel: 11
449 | ps4ContentID: ED1633-NPXX51362_00-0000000000000000
450 | ps4Category: 0
451 | ps4MasterVersion: 01.00
452 | ps4AppVersion: 01.00
453 | ps4AppType: 0
454 | ps4ParamSfxPath:
455 | ps4VideoOutPixelFormat: 0
456 | ps4VideoOutInitialWidth: 1920
457 | ps4VideoOutBaseModeInitialWidth: 1920
458 | ps4VideoOutReprojectionRate: 60
459 | ps4PronunciationXMLPath:
460 | ps4PronunciationSIGPath:
461 | ps4BackgroundImagePath:
462 | ps4StartupImagePath:
463 | ps4StartupImagesFolder:
464 | ps4IconImagesFolder:
465 | ps4SaveDataImagePath:
466 | ps4SdkOverride:
467 | ps4BGMPath:
468 | ps4ShareFilePath:
469 | ps4ShareOverlayImagePath:
470 | ps4PrivacyGuardImagePath:
471 | ps4NPtitleDatPath:
472 | ps4RemotePlayKeyAssignment: -1
473 | ps4RemotePlayKeyMappingDir:
474 | ps4PlayTogetherPlayerCount: 0
475 | ps4EnterButtonAssignment: 1
476 | ps4ApplicationParam1: 0
477 | ps4ApplicationParam2: 0
478 | ps4ApplicationParam3: 0
479 | ps4ApplicationParam4: 0
480 | ps4DownloadDataSize: 0
481 | ps4GarlicHeapSize: 2048
482 | ps4ProGarlicHeapSize: 2560
483 | ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ
484 | ps4pnSessions: 1
485 | ps4pnPresence: 1
486 | ps4pnFriends: 1
487 | ps4pnGameCustomData: 1
488 | playerPrefsSupport: 0
489 | enableApplicationExit: 0
490 | resetTempFolder: 1
491 | restrictedAudioUsageRights: 0
492 | ps4UseResolutionFallback: 0
493 | ps4ReprojectionSupport: 0
494 | ps4UseAudio3dBackend: 0
495 | ps4SocialScreenEnabled: 0
496 | ps4ScriptOptimizationLevel: 0
497 | ps4Audio3dVirtualSpeakerCount: 14
498 | ps4attribCpuUsage: 0
499 | ps4PatchPkgPath:
500 | ps4PatchLatestPkgPath:
501 | ps4PatchChangeinfoPath:
502 | ps4PatchDayOne: 0
503 | ps4attribUserManagement: 0
504 | ps4attribMoveSupport: 0
505 | ps4attrib3DSupport: 0
506 | ps4attribShareSupport: 0
507 | ps4attribExclusiveVR: 0
508 | ps4disableAutoHideSplash: 0
509 | ps4videoRecordingFeaturesUsed: 0
510 | ps4contentSearchFeaturesUsed: 0
511 | ps4attribEyeToEyeDistanceSettingVR: 0
512 | ps4IncludedModules: []
513 | monoEnv:
514 | splashScreenBackgroundSourceLandscape: {fileID: 0}
515 | splashScreenBackgroundSourcePortrait: {fileID: 0}
516 | spritePackerPolicy:
517 | webGLMemorySize: 256
518 | webGLExceptionSupport: 1
519 | webGLNameFilesAsHashes: 0
520 | webGLDataCaching: 1
521 | webGLDebugSymbols: 0
522 | webGLEmscriptenArgs:
523 | webGLModulesDirectory:
524 | webGLTemplate: APPLICATION:Default
525 | webGLAnalyzeBuildSize: 0
526 | webGLUseEmbeddedResources: 0
527 | webGLCompressionFormat: 1
528 | webGLLinkerTarget: 1
529 | webGLThreadsSupport: 0
530 | scriptingDefineSymbols: {}
531 | platformArchitecture: {}
532 | scriptingBackend: {}
533 | il2cppCompilerConfiguration: {}
534 | managedStrippingLevel: {}
535 | incrementalIl2cppBuild: {}
536 | allowUnsafeCode: 0
537 | additionalIl2CppArgs:
538 | scriptingRuntimeVersion: 1
539 | apiCompatibilityLevelPerPlatform:
540 | Standalone: 3
541 | m_RenderingPath: 1
542 | m_MobileRenderingPath: 1
543 | metroPackageName: Template_3D
544 | metroPackageVersion:
545 | metroCertificatePath:
546 | metroCertificatePassword:
547 | metroCertificateSubject:
548 | metroCertificateIssuer:
549 | metroCertificateNotAfter: 0000000000000000
550 | metroApplicationDescription: Template_3D
551 | wsaImages: {}
552 | metroTileShortName:
553 | metroTileShowName: 0
554 | metroMediumTileShowName: 0
555 | metroLargeTileShowName: 0
556 | metroWideTileShowName: 0
557 | metroSupportStreamingInstall: 0
558 | metroLastRequiredScene: 0
559 | metroDefaultTileSize: 1
560 | metroTileForegroundText: 2
561 | metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0}
562 | metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628,
563 | a: 1}
564 | metroSplashScreenUseBackgroundColor: 0
565 | platformCapabilities: {}
566 | metroTargetDeviceFamilies: {}
567 | metroFTAName:
568 | metroFTAFileTypes: []
569 | metroProtocolName:
570 | metroCompilationOverrides: 1
571 | XboxOneProductId:
572 | XboxOneUpdateKey:
573 | XboxOneSandboxId:
574 | XboxOneContentId:
575 | XboxOneTitleId:
576 | XboxOneSCId:
577 | XboxOneGameOsOverridePath:
578 | XboxOnePackagingOverridePath:
579 | XboxOneAppManifestOverridePath:
580 | XboxOneVersion: 1.0.0.0
581 | XboxOnePackageEncryption: 0
582 | XboxOnePackageUpdateGranularity: 2
583 | XboxOneDescription:
584 | XboxOneLanguage:
585 | - enus
586 | XboxOneCapability: []
587 | XboxOneGameRating: {}
588 | XboxOneIsContentPackage: 0
589 | XboxOneEnableGPUVariability: 1
590 | XboxOneSockets: {}
591 | XboxOneSplashScreen: {fileID: 0}
592 | XboxOneAllowedProductIds: []
593 | XboxOnePersistentLocalStorageSize: 0
594 | XboxOneXTitleMemory: 8
595 | xboxOneScriptCompiler: 1
596 | XboxOneOverrideIdentityName:
597 | vrEditorSettings:
598 | daydream:
599 | daydreamIconForeground: {fileID: 0}
600 | daydreamIconBackground: {fileID: 0}
601 | cloudServicesEnabled:
602 | UNet: 1
603 | luminIcon:
604 | m_Name:
605 | m_ModelFolderPath:
606 | m_PortalFolderPath:
607 | luminCert:
608 | m_CertPath:
609 | m_PrivateKeyPath:
610 | luminIsChannelApp: 0
611 | luminVersion:
612 | m_VersionCode: 1
613 | m_VersionName:
614 | facebookSdkVersion: 7.9.4
615 | facebookAppId:
616 | facebookCookies: 1
617 | facebookLogging: 1
618 | facebookStatus: 1
619 | facebookXfbml: 0
620 | facebookFrictionlessRequests: 1
621 | apiCompatibilityLevel: 6
622 | cloudProjectId:
623 | framebufferDepthMemorylessMode: 0
624 | projectName:
625 | organizationId:
626 | cloudEnabled: 0
627 | enableNativePlatformBackendsForNewInputSystem: 0
628 | disableOldInputManagerSupport: 0
629 | legacyClampBlendShapeWeights: 0
630 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Unity Vector Editor #
2 |
3 | Simple editor window for making basic vector shapes for the experimental com.unity.vectorgraphics package. It uses some custom vector shape classes, but should be easy to modify for working directly with the Unity classes.
4 |
5 | 
6 | ## Contents ##
7 | ### License ###
8 | The Unity Vector Editor source code is released under the MIT License.
9 | ### Packages Folder ###
10 | Contains the manifest file required for importing com.unity.vectorgraphics into your Unity project. For more information check the documentation in the **[Unity Vector Graphics Samples](https://github.com/Unity-Technologies/vector-graphics-samples)**.
11 | ### Assets/VectorShapes Folder ###
12 | Contains the C# source code for some simple utility classes representing basic shapes.
13 | ### Assets/VectorShapes/Editor Folder ###
14 | Contains the C# source code for the custom editor window.
15 |
16 |
--------------------------------------------------------------------------------
/UnityVectorEditor.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio for Mac
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Assembly-CSharp", "Assembly-CSharp.csproj", "{BB9611A0-5675-E126-33C5-75BCF1539C1B}"
5 | EndProject
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Assembly-CSharp-Editor", "Assembly-CSharp-Editor.csproj", "{8EEF50EB-C261-9F49-DC6A-3A2ED6A2AD99}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {BB9611A0-5675-E126-33C5-75BCF1539C1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {BB9611A0-5675-E126-33C5-75BCF1539C1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {BB9611A0-5675-E126-33C5-75BCF1539C1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {BB9611A0-5675-E126-33C5-75BCF1539C1B}.Release|Any CPU.Build.0 = Release|Any CPU
18 | {8EEF50EB-C261-9F49-DC6A-3A2ED6A2AD99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {8EEF50EB-C261-9F49-DC6A-3A2ED6A2AD99}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {8EEF50EB-C261-9F49-DC6A-3A2ED6A2AD99}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {8EEF50EB-C261-9F49-DC6A-3A2ED6A2AD99}.Release|Any CPU.Build.0 = Release|Any CPU
22 | EndGlobalSection
23 | GlobalSection(SolutionProperties) = preSolution
24 | HideSolutionNode = FALSE
25 | EndGlobalSection
26 | EndGlobal
27 |
--------------------------------------------------------------------------------