├── .codacy.yaml ├── .editorconfig ├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── pull_request_template.md ├── .gitignore ├── Images ├── Bezier3DSpline01.png ├── Bezier3DSpline02.png ├── Bezier3DSpline03.png ├── Bezier3DSpline_MirrorHandleMovement01.gif ├── Bezier3DSpline_Move01.gif ├── Bezier3DSpline_Rotate01.gif ├── Bezier3DSpline_VisualizeRotation01.gif ├── CreateBezierSplineComponent01.png ├── CreateBezierSplineComponent02.png ├── CreateBezierSplineDataAsset01.png ├── Example01.gif └── SceneView_UI01.png ├── Siccity_license.txt ├── Unity ├── .gitignore ├── Assets │ ├── .gitkeep │ ├── ExampleContent.meta │ ├── ExampleContent │ │ ├── .gitignore │ │ ├── Art.meta │ │ ├── Art │ │ │ ├── Materials.meta │ │ │ └── Materials │ │ │ │ ├── Red.mat │ │ │ │ └── Red.mat.meta │ │ ├── Bezier3DSplineData.asset │ │ ├── Bezier3DSplineData.asset.meta │ │ ├── Scenes.meta │ │ └── Scenes │ │ │ ├── Example.unity │ │ │ └── Example.unity.meta │ ├── JCMG.meta │ ├── JCMG │ │ ├── Curves.meta │ │ └── Curves │ │ │ ├── Docs.meta │ │ │ ├── Docs │ │ │ ├── Images.meta │ │ │ └── Images │ │ │ │ ├── portrait.png │ │ │ │ ├── portrait.png.meta │ │ │ │ ├── social_share_image.png │ │ │ │ └── social_share_image.png.meta │ │ │ ├── Licenses.meta │ │ │ ├── Licenses │ │ │ ├── Siccity_license.txt │ │ │ ├── Siccity_license.txt.meta │ │ │ ├── license.txt │ │ │ └── license.txt.meta │ │ │ ├── Scripts.meta │ │ │ └── Scripts │ │ │ ├── AssemblyInfo.cs │ │ │ ├── AssemblyInfo.cs.meta │ │ │ ├── Components.meta │ │ │ ├── Components │ │ │ ├── Bezier3DSpline.cs │ │ │ ├── Bezier3DSpline.cs.meta │ │ │ ├── SplineWalker.cs │ │ │ └── SplineWalker.cs.meta │ │ │ ├── Core.meta │ │ │ ├── Core │ │ │ ├── Bezier3DCurve.cs │ │ │ ├── Bezier3DCurve.cs.meta │ │ │ ├── ConstantAnimationCurve.cs │ │ │ ├── ConstantAnimationCurve.cs.meta │ │ │ ├── ExtendedAnimationCurves.cs │ │ │ ├── ExtendedAnimationCurves.cs.meta │ │ │ ├── Knot.cs │ │ │ ├── Knot.cs.meta │ │ │ ├── NullableQuaternion.cs │ │ │ ├── NullableQuaternion.cs.meta │ │ │ ├── QuaternionAnimationCurve.cs │ │ │ ├── QuaternionAnimationCurve.cs.meta │ │ │ ├── Vector3AnimationCurve.cs │ │ │ └── Vector3AnimationCurve.cs.meta │ │ │ ├── Editor.meta │ │ │ ├── Editor │ │ │ ├── CurveEditorState.cs │ │ │ ├── CurveEditorState.cs.meta │ │ │ ├── CurveEditorStyles.cs │ │ │ ├── CurveEditorStyles.cs.meta │ │ │ ├── CurvePreferences.cs │ │ │ ├── CurvePreferences.cs.meta │ │ │ ├── Icons.meta │ │ │ ├── Icons │ │ │ │ ├── Bezier3DCurveDataIcon.png │ │ │ │ ├── Bezier3DCurveDataIcon.png.meta │ │ │ │ ├── IconTemplate.psd │ │ │ │ ├── IconTemplate.psd.meta │ │ │ │ ├── SplineWalkerIcon.png │ │ │ │ └── SplineWalkerIcon.png.meta │ │ │ ├── Inspectors.meta │ │ │ ├── Inspectors │ │ │ │ ├── Bezier3DSplineDataInspector.cs │ │ │ │ ├── Bezier3DSplineDataInspector.cs.meta │ │ │ │ ├── Bezier3DSplineInspector.cs │ │ │ │ └── Bezier3DSplineInspector.cs.meta │ │ │ ├── JCMG.Curves.Editor.asmdef │ │ │ ├── JCMG.Curves.Editor.asmdef.meta │ │ │ ├── MenuItems.cs │ │ │ ├── MenuItems.cs.meta │ │ │ ├── ObjectPreviews.meta │ │ │ ├── ObjectPreviews │ │ │ │ ├── Base3DSplineDataPreview.cs │ │ │ │ ├── Base3DSplineDataPreview.cs.meta │ │ │ │ ├── Bezier3DSplineDataPreview.cs │ │ │ │ ├── Bezier3DSplineDataPreview.cs.meta │ │ │ │ ├── Bezier3DSplinePreview.cs │ │ │ │ └── Bezier3DSplinePreview.cs.meta │ │ │ ├── SceneGUIConstants.cs │ │ │ ├── SceneGUIConstants.cs.meta │ │ │ ├── Tools.meta │ │ │ ├── Tools │ │ │ │ ├── HotkeyTools.cs │ │ │ │ ├── HotkeyTools.cs.meta │ │ │ │ ├── SceneGUITools.cs │ │ │ │ └── SceneGUITools.cs.meta │ │ │ ├── VersionConstants.cs │ │ │ ├── VersionConstants.cs.meta │ │ │ ├── Window.meta │ │ │ └── Window │ │ │ │ ├── AboutWindow.cs │ │ │ │ └── AboutWindow.cs.meta │ │ │ ├── Interfaces.meta │ │ │ ├── Interfaces │ │ │ ├── IBezier3DSplineData.cs │ │ │ ├── IBezier3DSplineData.cs.meta │ │ │ ├── IReadOnly3DSplineData.cs │ │ │ └── IReadOnly3DSplineData.cs.meta │ │ │ ├── JCMG.Curves.asmdef │ │ │ ├── JCMG.Curves.asmdef.meta │ │ │ ├── ScriptableObjects.meta │ │ │ ├── ScriptableObjects │ │ │ ├── Bezier3DSplineData.cs │ │ │ └── Bezier3DSplineData.cs.meta │ │ │ ├── Tools.meta │ │ │ └── Tools │ │ │ ├── SceneGUITools.cs │ │ │ └── SceneGUITools.cs.meta │ ├── PackageManifest.meta │ └── PackageManifest │ │ ├── Generated.meta │ │ ├── Generated │ │ ├── 7321978f-bf2f-4983-8a03-e0b53e9137d6.meta │ │ └── 7321978f-bf2f-4983-8a03-e0b53e9137d6 │ │ │ ├── package.json │ │ │ └── package.json.meta │ │ ├── PackageManifestConfig.asset │ │ └── PackageManifestConfig.asset.meta ├── JCMG.Curves.Editor.csproj.DotSettings ├── JCMG.Curves.csproj.DotSettings ├── Packages │ └── manifest.json └── ProjectSettings │ ├── AudioManager.asset │ ├── ClusterInputManager.asset │ ├── DynamicsManager.asset │ ├── EditorBuildSettings.asset │ ├── EditorSettings.asset │ ├── GraphicsSettings.asset │ ├── InputManager.asset │ ├── NavMeshAreas.asset │ ├── Physics2DSettings.asset │ ├── PresetManager.asset │ ├── ProjectSettings.asset │ ├── ProjectVersion.txt │ ├── QualitySettings.asset │ ├── TagManager.asset │ ├── TimeManager.asset │ ├── UnityConnectSettings.asset │ ├── VFXManager.asset │ └── XRSettings.asset ├── contributing.md ├── license.txt ├── readme.md └── usage.md /.codacy.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | exclude_paths: 4 | - 'DocFXProject/**' 5 | - '.github/**' 6 | - 'docs/**' 7 | - 'license.md' 8 | - 'license.txt' 9 | - 'readme.md' 10 | - '.gitignore' 11 | - '.gitattributes' 12 | - '.editorconfig' -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | indent_style = tab 3 | indent_size = 4 4 | end_of_line = lf 5 | trim_trailing_whitespace = true 6 | insert_final_newline = true -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. 2 | *.cs eol=lf 3 | 4 | # Explicitly declare text files you want to always be normalized and converted 5 | # to native line endings on checkout. 6 | *.cs text 7 | *.md text 8 | *.meta text 9 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | github: jeffcampbellmakesgames 3 | ko_fi: stampyturtle 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG] Title goes here" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | _A clear and concise description of what the bug is._ 12 | 13 | **Unity Version:** 14 | _Unity 2019.1.0f2 for example_ 15 | 16 | **To Reproduce** 17 | _Steps to reproduce the behavior:_ 18 | 19 | 1. Go to '...' 20 | 2. Click on '....' 21 | 3. Scroll down to '....' 22 | 4. See error 23 | 24 | **Expected behavior** 25 | _A clear and concise description of what you expected to happen._ 26 | 27 | **Screenshots** 28 | _If applicable, add screenshots to help explain your problem._ 29 | 30 | **Additional context** 31 | _Add any other context about the problem here._ 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | _A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]_ 12 | 13 | **Describe the solution you'd like** 14 | _A clear and concise description of what you want to happen._ 15 | 16 | **Describe alternatives you've considered** 17 | _A clear and concise description of any alternative solutions or features you've considered._ 18 | 19 | **Additional context** 20 | _Add any other context or screenshots about the feature request here._ 21 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. 4 | 5 | Fixes # (issue) 6 | 7 | # How Has This Been Tested? 8 | 9 | Please describe the tests that you ran to verify your changes. Please also note any relevant details for your test configuration. 10 | 11 | - [ ] Test A 12 | - [ ] Test B 13 | 14 | # Checklist: 15 | 16 | - [ ] My code follows the style guidelines of this project 17 | - [ ] I have performed a self-review of my own code 18 | - [ ] I have commented my code, particularly in hard-to-understand areas 19 | - [ ] I have made corresponding changes to the documentation 20 | - [ ] My changes generate no new warnings 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | 3 | [Bb]uilds/ -------------------------------------------------------------------------------- /Images/Bezier3DSpline01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffcampbellmakesgames/unity-curves/268a2ebd354247bb3e7be73fc8d4f55670a5cdf9/Images/Bezier3DSpline01.png -------------------------------------------------------------------------------- /Images/Bezier3DSpline02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffcampbellmakesgames/unity-curves/268a2ebd354247bb3e7be73fc8d4f55670a5cdf9/Images/Bezier3DSpline02.png -------------------------------------------------------------------------------- /Images/Bezier3DSpline03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffcampbellmakesgames/unity-curves/268a2ebd354247bb3e7be73fc8d4f55670a5cdf9/Images/Bezier3DSpline03.png -------------------------------------------------------------------------------- /Images/Bezier3DSpline_MirrorHandleMovement01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffcampbellmakesgames/unity-curves/268a2ebd354247bb3e7be73fc8d4f55670a5cdf9/Images/Bezier3DSpline_MirrorHandleMovement01.gif -------------------------------------------------------------------------------- /Images/Bezier3DSpline_Move01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffcampbellmakesgames/unity-curves/268a2ebd354247bb3e7be73fc8d4f55670a5cdf9/Images/Bezier3DSpline_Move01.gif -------------------------------------------------------------------------------- /Images/Bezier3DSpline_Rotate01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffcampbellmakesgames/unity-curves/268a2ebd354247bb3e7be73fc8d4f55670a5cdf9/Images/Bezier3DSpline_Rotate01.gif -------------------------------------------------------------------------------- /Images/Bezier3DSpline_VisualizeRotation01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffcampbellmakesgames/unity-curves/268a2ebd354247bb3e7be73fc8d4f55670a5cdf9/Images/Bezier3DSpline_VisualizeRotation01.gif -------------------------------------------------------------------------------- /Images/CreateBezierSplineComponent01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffcampbellmakesgames/unity-curves/268a2ebd354247bb3e7be73fc8d4f55670a5cdf9/Images/CreateBezierSplineComponent01.png -------------------------------------------------------------------------------- /Images/CreateBezierSplineComponent02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffcampbellmakesgames/unity-curves/268a2ebd354247bb3e7be73fc8d4f55670a5cdf9/Images/CreateBezierSplineComponent02.png -------------------------------------------------------------------------------- /Images/CreateBezierSplineDataAsset01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffcampbellmakesgames/unity-curves/268a2ebd354247bb3e7be73fc8d4f55670a5cdf9/Images/CreateBezierSplineDataAsset01.png -------------------------------------------------------------------------------- /Images/Example01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffcampbellmakesgames/unity-curves/268a2ebd354247bb3e7be73fc8d4f55670a5cdf9/Images/Example01.gif -------------------------------------------------------------------------------- /Images/SceneView_UI01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffcampbellmakesgames/unity-curves/268a2ebd354247bb3e7be73fc8d4f55670a5cdf9/Images/SceneView_UI01.png -------------------------------------------------------------------------------- /Siccity_license.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Thor Brigsted 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /Unity/.gitignore: -------------------------------------------------------------------------------- 1 | # =============== # 2 | # Unity generated # 3 | # =============== # 4 | [Ll]ogs/ 5 | [Tt]emp/ 6 | [Oo]bj/ 7 | [Bb]uild 8 | /[Ll]ibrary/ 9 | sysinfo.txt 10 | *.stackdump 11 | 12 | # JetBrains Plugin 13 | JetBrains/ 14 | JetBrains.meta 15 | 16 | # ============================================= # 17 | # Visual Studio / MonoDevelop / Rider generated # 18 | # ============================================= # 19 | [Ee]xported[Oo]bj/ 20 | .vs/ 21 | /*.userprefs 22 | /*.csproj 23 | /*.pidb 24 | /*.suo 25 | /*.sln* 26 | /*.user 27 | /*.unityproj 28 | /*.booproj 29 | /.idea*/ 30 | 31 | # ============ # 32 | # OS generated # 33 | # ============ # 34 | .DS_Store* 35 | ._* 36 | .Spotlight-V100 37 | .Trashes 38 | ehthumbs.db 39 | [Tt]humbs.db 40 | [Dd]esktop.ini -------------------------------------------------------------------------------- /Unity/Assets/.gitkeep: -------------------------------------------------------------------------------- 1 | This hidden file is created to preserve potentially empty folders in git commits. -------------------------------------------------------------------------------- /Unity/Assets/ExampleContent.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 620d20fc345515344a7e6606a3f08259 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/ExampleContent/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | \.vs/ 3 | 4 | Library/ 5 | 6 | Temp/ 7 | 8 | *.sln 9 | 10 | *.csproj 11 | 12 | Bezier3D\.userprefs 13 | 14 | README.md.meta 15 | LICENSE.md.meta -------------------------------------------------------------------------------- /Unity/Assets/ExampleContent/Art.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c7ffdf1c9ef8bb149aa78a53d1a9c24a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/ExampleContent/Art/Materials.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f3976c7220e25d449a5ede57223d09c0 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/ExampleContent/Art/Materials/Red.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_PrefabParentObject: {fileID: 0} 8 | m_PrefabInternal: {fileID: 0} 9 | m_Name: Red 10 | m_Shader: {fileID: 10755, guid: 0000000000000000f000000000000000, type: 0} 11 | m_ShaderKeywords: 12 | m_LightmapFlags: 4 13 | m_EnableInstancingVariants: 0 14 | m_DoubleSidedGI: 0 15 | m_CustomRenderQueue: -1 16 | stringTagMap: {} 17 | disabledShaderPasses: [] 18 | m_SavedProperties: 19 | serializedVersion: 3 20 | m_TexEnvs: 21 | - _BumpMap: 22 | m_Texture: {fileID: 0} 23 | m_Scale: {x: 1, y: 1} 24 | m_Offset: {x: 0, y: 0} 25 | - _DetailAlbedoMap: 26 | m_Texture: {fileID: 0} 27 | m_Scale: {x: 1, y: 1} 28 | m_Offset: {x: 0, y: 0} 29 | - _DetailMask: 30 | m_Texture: {fileID: 0} 31 | m_Scale: {x: 1, y: 1} 32 | m_Offset: {x: 0, y: 0} 33 | - _DetailNormalMap: 34 | m_Texture: {fileID: 0} 35 | m_Scale: {x: 1, y: 1} 36 | m_Offset: {x: 0, y: 0} 37 | - _EmissionMap: 38 | m_Texture: {fileID: 0} 39 | m_Scale: {x: 1, y: 1} 40 | m_Offset: {x: 0, y: 0} 41 | - _MainTex: 42 | m_Texture: {fileID: 0} 43 | m_Scale: {x: 1, y: 1} 44 | m_Offset: {x: 0, y: 0} 45 | - _MetallicGlossMap: 46 | m_Texture: {fileID: 0} 47 | m_Scale: {x: 1, y: 1} 48 | m_Offset: {x: 0, y: 0} 49 | - _OcclusionMap: 50 | m_Texture: {fileID: 0} 51 | m_Scale: {x: 1, y: 1} 52 | m_Offset: {x: 0, y: 0} 53 | - _ParallaxMap: 54 | m_Texture: {fileID: 0} 55 | m_Scale: {x: 1, y: 1} 56 | m_Offset: {x: 0, y: 0} 57 | m_Floats: 58 | - _BumpScale: 1 59 | - _Cutoff: 0.5 60 | - _DetailNormalMapScale: 1 61 | - _DstBlend: 0 62 | - _GlossMapScale: 1 63 | - _Glossiness: 0.5 64 | - _GlossyReflections: 1 65 | - _Metallic: 0 66 | - _Mode: 0 67 | - _OcclusionStrength: 1 68 | - _Parallax: 0.02 69 | - _SmoothnessTextureChannel: 0 70 | - _SpecularHighlights: 1 71 | - _SrcBlend: 1 72 | - _UVSec: 0 73 | - _ZWrite: 1 74 | m_Colors: 75 | - _Color: {r: 0.8627451, g: 0, b: 0, a: 1} 76 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 77 | -------------------------------------------------------------------------------- /Unity/Assets/ExampleContent/Art/Materials/Red.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4b4714dbfdf5f964ab32a3d5005d95cc 3 | timeCreated: 1503295819 4 | licenseType: Free 5 | NativeFormatImporter: 6 | mainObjectFileID: 2100000 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Unity/Assets/ExampleContent/Bezier3DSplineData.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b83cdd41bd45d1d4dbe98965eee8a8e0 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/ExampleContent/Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f4b4c690ac78d8c4d80793894b1f9429 3 | folderAsset: yes 4 | timeCreated: 1504774200 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Unity/Assets/ExampleContent/Scenes/Example.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7a560b9db64c1e545a6e8a9550f58446 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 36c829b800d0a2c4989f6fb263801195 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 563bd956a3113b74294192fccab9b301 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Docs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7ccf5c90fc7a2eb4f9e29da46ada2e3b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Docs/Images.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 35d496f281fbc5144ab85257279fad35 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Docs/Images/portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffcampbellmakesgames/unity-curves/268a2ebd354247bb3e7be73fc8d4f55670a5cdf9/Unity/Assets/JCMG/Curves/Docs/Images/portrait.png -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Docs/Images/portrait.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 46743cf676633b94bb8e103447c732cf 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 10 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: -1 36 | mipBias: -100 37 | wrapU: -1 38 | wrapV: -1 39 | wrapW: -1 40 | nPOTScale: 1 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 0 53 | spriteTessellationDetail: -1 54 | textureType: 0 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | platformSettings: 61 | - serializedVersion: 3 62 | buildTarget: DefaultTexturePlatform 63 | maxTextureSize: 2048 64 | resizeAlgorithm: 0 65 | textureFormat: -1 66 | textureCompression: 1 67 | compressionQuality: 50 68 | crunchedCompression: 0 69 | allowsAlphaSplitting: 0 70 | overridden: 0 71 | androidETC2FallbackOverride: 0 72 | forceMaximumCompressionQuality_BC6H_BC7: 0 73 | spriteSheet: 74 | serializedVersion: 2 75 | sprites: [] 76 | outline: [] 77 | physicsShape: [] 78 | bones: [] 79 | spriteID: 80 | internalID: 0 81 | vertices: [] 82 | indices: 83 | edges: [] 84 | weights: [] 85 | secondaryTextures: [] 86 | spritePackingTag: 87 | pSDRemoveMatte: 0 88 | pSDShowRemoveMatteOption: 0 89 | userData: 90 | assetBundleName: 91 | assetBundleVariant: 92 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Docs/Images/social_share_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffcampbellmakesgames/unity-curves/268a2ebd354247bb3e7be73fc8d4f55670a5cdf9/Unity/Assets/JCMG/Curves/Docs/Images/social_share_image.png -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Docs/Images/social_share_image.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 682980204b2aea846bee4e8fd6ac2483 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 10 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: -1 36 | mipBias: -100 37 | wrapU: -1 38 | wrapV: -1 39 | wrapW: -1 40 | nPOTScale: 1 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 0 53 | spriteTessellationDetail: -1 54 | textureType: 0 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | platformSettings: 61 | - serializedVersion: 3 62 | buildTarget: DefaultTexturePlatform 63 | maxTextureSize: 2048 64 | resizeAlgorithm: 0 65 | textureFormat: -1 66 | textureCompression: 1 67 | compressionQuality: 50 68 | crunchedCompression: 0 69 | allowsAlphaSplitting: 0 70 | overridden: 0 71 | androidETC2FallbackOverride: 0 72 | forceMaximumCompressionQuality_BC6H_BC7: 0 73 | spriteSheet: 74 | serializedVersion: 2 75 | sprites: [] 76 | outline: [] 77 | physicsShape: [] 78 | bones: [] 79 | spriteID: 80 | internalID: 0 81 | vertices: [] 82 | indices: 83 | edges: [] 84 | weights: [] 85 | secondaryTextures: [] 86 | spritePackingTag: 87 | pSDRemoveMatte: 0 88 | pSDShowRemoveMatteOption: 0 89 | userData: 90 | assetBundleName: 91 | assetBundleVariant: 92 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Licenses.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 40527a6e86e0a9347a098edd331a55ab 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Licenses/Siccity_license.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Thor Brigsted 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Licenses/Siccity_license.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5df5e3a5055b0ad40b9d8b67b8fff331 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Licenses/license.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Jeff Campbell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Licenses/license.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 27cdff8b8528ce64c841361d384e1ff0 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 66a2f4def4d45434d94abfb0bc1c25ce 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 |  2 | using System.Runtime.CompilerServices; 3 | 4 | [assembly: InternalsVisibleTo("JCMG.Curves.Editor")] 5 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/AssemblyInfo.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 87fe00a2aca8eb349840a39d564c827a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Components.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7d1b72941a5ad714db71f38f47d8225e 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Components/Bezier3DSpline.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using UnityEngine; 4 | 5 | namespace JCMG.Curves 6 | { 7 | /// 8 | /// A Bezier 3D spline whose positions and rotations are transformed by a 's ; 9 | /// 10 | [AddComponentMenu("JCMG/Curves/Bezier3DSpline")] 11 | [ExecuteInEditMode] 12 | public sealed class Bezier3DSpline : MonoBehaviour, 13 | IBezier3DSplineData 14 | { 15 | #region Properties 16 | 17 | /// 18 | /// Returns true if the spline is a closed loop, otherwise false. 19 | /// 20 | public bool IsClosed 21 | { 22 | get { return _splineData.IsClosed; } 23 | } 24 | 25 | /// 26 | /// Returns the density of the curve caches. This determines the number of interpolation steps calculated 27 | /// per curve. 28 | /// 29 | public int InterpolationStepsPerCurve 30 | { 31 | get { return _splineData.InterpolationStepsPerCurve; } 32 | } 33 | 34 | /// 35 | /// Returns the number of curves in the spline. 36 | /// 37 | public int CurveCount 38 | { 39 | get { return _splineData.CurveCount; } 40 | } 41 | 42 | /// 43 | /// Returns the number of s in the spline. 44 | /// 45 | public int KnotCount 46 | { 47 | get { return _splineData.KnotCount; } 48 | } 49 | 50 | /// 51 | /// Returns the total length of the spline based on the length of all curves. 52 | /// 53 | public float TotalLength 54 | { 55 | get { return _splineData.TotalLength; } 56 | } 57 | 58 | /// 59 | /// Returns the internal of this scene-based spline. 60 | /// 61 | internal Bezier3DSplineData SplineData 62 | { 63 | get { return _splineData; } 64 | } 65 | 66 | #endregion 67 | 68 | #region Fields 69 | 70 | [HideInInspector] 71 | [SerializeField] 72 | private Bezier3DSplineData _splineData; 73 | 74 | #endregion 75 | 76 | #region Unity 77 | 78 | private void Awake() 79 | { 80 | if (_splineData == null) 81 | { 82 | _splineData = ScriptableObject.CreateInstance(); 83 | } 84 | } 85 | 86 | private void Reset() 87 | { 88 | _splineData = ScriptableObject.CreateInstance(); 89 | } 90 | 91 | #if UNITY_EDITOR 92 | 93 | private void OnDrawGizmos() 94 | { 95 | if (UnityEditor.Selection.objects.Contains(this)) 96 | { 97 | return; 98 | } 99 | 100 | SceneGUITools.DrawCurveLinesGizmos(this, transform); 101 | } 102 | 103 | #endif 104 | 105 | #endregion 106 | 107 | #region Settings 108 | 109 | /// 110 | /// Recache all individual curves with new interpolation step count. 111 | /// 112 | /// Number of steps per curve to cache position and rotation. 113 | public void SetStepsPerCurve(int stepCount) 114 | { 115 | _splineData.SetStepsPerCurve(stepCount); 116 | } 117 | 118 | /// 119 | /// Setting spline to closed will generate an extra curve, connecting end point to start point. 120 | /// 121 | public void SetClosed(bool isClosed) 122 | { 123 | _splineData.SetClosed(isClosed); 124 | } 125 | 126 | #endregion 127 | 128 | #region Helpers 129 | 130 | /// 131 | /// Returns a normalized value [0-1] based on the passed compared 132 | /// to the of the spline. 133 | /// 134 | /// 135 | /// 136 | public float GetNormalizedValueForSplineDistance(float splineDistance) 137 | { 138 | throw new NotImplementedException(); 139 | } 140 | 141 | /// 142 | /// Returns a normalized value [0-1] based on the passed compared 143 | /// to the of the that the distance falls along 144 | /// the spline. 145 | /// 146 | /// 147 | /// 148 | public float GetCurveDistanceForSplineDistance(float splineDistance) 149 | { 150 | return _splineData.GetCurveDistanceForSplineDistance(splineDistance); 151 | } 152 | 153 | /// 154 | /// Returns the length of the spline leading up to and ending on the at 155 | /// position in the collection. 156 | /// 157 | /// 158 | /// 159 | public float GetSplineDistanceForKnotIndex(int index) 160 | { 161 | return _splineData.GetSplineDistanceForKnotIndex(index); 162 | } 163 | 164 | /// 165 | /// Returns the length of the spline leading up to and ending at the end of the at 166 | /// position in the collection. 167 | /// 168 | /// 169 | /// 170 | public float GetSplineDistanceForCurveIndex(int index) 171 | { 172 | return _splineData.GetSplineDistanceForCurveIndex(index); 173 | } 174 | 175 | public float GetSplineDistanceForNormalizedValue(float value) 176 | { 177 | return _splineData.GetSplineDistanceForNormalizedValue(value); 178 | } 179 | 180 | #endregion 181 | 182 | #region Actions 183 | 184 | /// 185 | /// Flip the spline direction. 186 | /// 187 | public void Flip() 188 | { 189 | _splineData.Flip(); 190 | } 191 | 192 | #endregion 193 | 194 | #region Curve 195 | 196 | /// 197 | /// Get at position in the collection. 198 | /// 199 | public Bezier3DCurve GetCurve(int index) 200 | { 201 | return _splineData.GetCurve(index); 202 | } 203 | 204 | /// 205 | /// Returns the where falls upon it along the spline; 206 | /// and are initialized to the position in the collection 207 | /// and the normalized value [0-1] of time through the curve. 208 | /// 209 | /// 210 | /// 211 | /// 212 | /// 213 | public Bezier3DCurve GetCurveIndexTime(float splineDist, out int index, out float curveTime) 214 | { 215 | return _splineData.GetCurveIndexTime(splineDist, out index, out curveTime); 216 | } 217 | 218 | /// 219 | /// Get the curve indices in direct contact with the at position 220 | /// in the collection. 221 | /// 222 | public void GetCurveIndicesForKnot(int knotIndex, out int preCurveIndex, out int postCurveIndex) 223 | { 224 | _splineData.GetCurveIndicesForKnot(knotIndex, out preCurveIndex, out postCurveIndex); 225 | } 226 | 227 | #endregion 228 | 229 | #region Rotation 230 | 231 | /// 232 | /// Returns rotation along spline at set distance along the . 233 | /// 234 | public Quaternion GetRotation(float splineDistance) 235 | { 236 | return _splineData.GetRotation(splineDistance, transform); 237 | } 238 | 239 | /// 240 | /// Returns rotation along spline at set distance along the . Uses approximation. 241 | /// 242 | public Quaternion GetRotationFast(float splineDistance) 243 | { 244 | return _splineData.GetRotationFast(splineDistance, transform); 245 | } 246 | 247 | /// 248 | /// Returns a rotation along the spline where is a normalized value between [0-1] of 249 | /// its . 250 | /// 251 | /// 252 | /// 253 | public Quaternion GetNormalizedRotation(float value) 254 | { 255 | var splineDistance = _splineData.GetSplineDistanceForNormalizedValue(value); 256 | return GetRotation(splineDistance); 257 | } 258 | 259 | /// 260 | /// Returns rotation along spline at set distance along the in local coordinates. 261 | /// Uses approximation. 262 | /// 263 | internal Quaternion GetRotationLocal(float splineDistance) 264 | { 265 | return _splineData.GetRotationLocal(splineDistance); 266 | } 267 | 268 | /// 269 | /// Returns rotation along spline at set distance along the in local coordinates. 270 | /// Uses approximation. 271 | /// 272 | internal Quaternion GetRotationLocalFast(float splineDistance) 273 | { 274 | return _splineData.GetRotationLocalFast(splineDistance); 275 | } 276 | 277 | #endregion 278 | 279 | #region Position 280 | 281 | /// 282 | /// Returns position along spline at set distance along the . 283 | /// 284 | public Vector3 GetPosition(float splineDistance) 285 | { 286 | return _splineData.GetPosition(splineDistance, transform); 287 | } 288 | 289 | /// 290 | /// Returns a position along the spline where is a normalized value between [0-1] of 291 | /// its . 292 | /// 293 | /// 294 | /// 295 | public Vector3 GetNormalizedPosition(float value) 296 | { 297 | var splineDistance = GetSplineDistanceForNormalizedValue(value); 298 | return GetPosition(splineDistance); 299 | } 300 | 301 | /// 302 | /// Returns position along spline at set distance along the . 303 | /// 304 | internal Vector3 GetPointLocal(float splineDistance) 305 | { 306 | return _splineData.GetPositionLocal(splineDistance); 307 | } 308 | 309 | #endregion 310 | 311 | #region Direction 312 | 313 | /// 314 | /// Returns up vector at set distance along the . 315 | /// 316 | public Vector3 GetUp(float splineDistance) 317 | { 318 | return _splineData.GetUp(splineDistance, transform); 319 | } 320 | 321 | /// 322 | /// Returns up vector at set distance along the in local coordinates. 323 | /// 324 | internal Vector3 GetUpLocal(float splineDistance) 325 | { 326 | return _splineData.GetUpLocal(splineDistance); 327 | } 328 | 329 | /// 330 | /// Returns left vector at set distance along the . 331 | /// 332 | public Vector3 GetLeft(float splineDistance) 333 | { 334 | return _splineData.GetLeft(splineDistance, transform); 335 | } 336 | 337 | /// 338 | /// Returns left vector at set distance along the in local coordinates. 339 | /// 340 | internal Vector3 GetLeftLocal(float splineDistance) 341 | { 342 | return _splineData.GetLeftLocal(splineDistance); 343 | } 344 | 345 | /// 346 | /// Returns right vector at set distance along the . 347 | /// 348 | public Vector3 GetRight(float splineDistance) 349 | { 350 | return _splineData.GetRight(splineDistance, transform); 351 | } 352 | 353 | /// 354 | /// Returns right vector at set distance along the in local coordinates. 355 | /// 356 | internal Vector3 GetRightLocal(float splineDistance) 357 | { 358 | return _splineData.GetRightLocal(splineDistance); 359 | } 360 | 361 | /// 362 | /// Returns forward vector at set distance along the . 363 | /// 364 | public Vector3 GetForward(float splineDistance) 365 | { 366 | return _splineData.GetForward(splineDistance, transform); 367 | } 368 | 369 | /// 370 | /// Returns forward vector at set distance along the . Uses approximation. 371 | /// 372 | public Vector3 GetForwardFast(float splineDistance) 373 | { 374 | return _splineData.GetForwardFast(splineDistance, transform); 375 | } 376 | 377 | /// 378 | /// Returns forward vector at set distance along the in local coordinates. 379 | /// 380 | internal Vector3 GetForwardLocal(float splineDistance) 381 | { 382 | return _splineData.GetForwardLocal(splineDistance); 383 | } 384 | 385 | /// 386 | /// Returns forward vector at set distance along the in local coordinates. Uses 387 | /// approximation. 388 | /// 389 | internal Vector3 GetForwardLocalFast(float splineDistance) 390 | { 391 | return _splineData.GetForwardLocalFast(splineDistance); 392 | } 393 | 394 | #endregion 395 | 396 | #region Knot 397 | 398 | /// 399 | /// Adds a new to the end of the spline. 400 | /// 401 | /// 402 | public void AddKnot(Knot knot) 403 | { 404 | _splineData.AddKnot(knot); 405 | } 406 | 407 | /// 408 | /// Returns info in local coordinates at the position in the collection. 409 | /// 410 | public Knot GetKnot(int index) 411 | { 412 | return _splineData.GetKnot(index); 413 | } 414 | 415 | /// 416 | /// Inserts a new at the position in the collection. 417 | /// 418 | /// 419 | /// 420 | public void InsertKnot(int index, Knot knot) 421 | { 422 | _splineData.InsertKnot(index, knot); 423 | } 424 | 425 | /// 426 | /// Removes the at the position in the collection. 427 | /// 428 | /// 429 | public void RemoveKnot(int index) 430 | { 431 | _splineData.RemoveKnot(index); 432 | } 433 | 434 | /// 435 | /// Set info in local coordinates at the 436 | /// position in the collection. 437 | /// 438 | public void SetKnot(int index, Knot knot) 439 | { 440 | _splineData.SetKnot(index, knot); 441 | } 442 | 443 | /// 444 | /// Get the knot indices in direct contact with knot. If a knot is not found before and/or after, that index 445 | /// will be initialized to -1. 446 | /// 447 | public void GetKnotIndicesForKnot(int knotIndex, out int preKnotIndex, out int postKnotIndex) 448 | { 449 | _splineData.GetKnotIndicesForKnot(knotIndex, out preKnotIndex, out postKnotIndex); 450 | } 451 | 452 | #endregion 453 | } 454 | } 455 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Components/Bezier3DSpline.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3f0e6588f74691844b25110a973044fa 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {fileID: 2800000, guid: c5c32b6c450791943b0b231a833c00b6, type: 3} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Components/SplineWalker.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace JCMG.Curves 4 | { 5 | /// 6 | /// Moves a transform along a spline at either a constant speed or over a fixed time duration. 7 | /// 8 | [AddComponentMenu("JCMG/Curves/SplineWalker")] 9 | public sealed class SplineWalker : MonoBehaviour 10 | { 11 | private enum MoveType 12 | { 13 | UseConstantSpeed, 14 | UseFixedDuration 15 | } 16 | 17 | private enum LoopType 18 | { 19 | Clamp, 20 | Loop, 21 | PingPong 22 | } 23 | 24 | #pragma warning disable 0649 25 | 26 | [Header("Scene References")] 27 | [SerializeField] 28 | private Bezier3DSpline _spline; 29 | 30 | [Space] 31 | [Header("Movement Settings")] 32 | [SerializeField] 33 | private LoopType _loopType; 34 | 35 | [SerializeField] 36 | private MoveType _moveType; 37 | 38 | [SerializeField] 39 | private float _startingSplineDistance; 40 | 41 | [Space] 42 | [Header("Constant Speed")] 43 | 44 | [SerializeField] 45 | private float _speed = 1; 46 | 47 | [Space] 48 | [Header("Over Fixed Duration")] 49 | [SerializeField] 50 | private float _duration; 51 | 52 | [Space] 53 | [Header("Debugging")] 54 | [SerializeField] 55 | private float _currentTime; 56 | 57 | [SerializeField] 58 | private float _currentSplineDistance; 59 | 60 | #pragma warning restore 0649 61 | 62 | private bool _isMovingForward; 63 | private Vector3 _currentPosition; 64 | private Quaternion _currentRotation; 65 | 66 | private void Start() 67 | { 68 | _isMovingForward = true; 69 | 70 | if (_spline == null) 71 | { 72 | Debug.LogError("Please assign a spline to this SplineWalker.", this); 73 | enabled = false; 74 | } 75 | else 76 | { 77 | _startingSplineDistance = Mathf.Clamp(_startingSplineDistance, 0, _spline.TotalLength); 78 | _currentSplineDistance = _startingSplineDistance; 79 | _currentTime = _currentSplineDistance / _spline.TotalLength; 80 | _currentPosition = _spline.GetPosition(_currentSplineDistance); 81 | _currentRotation = _spline.GetRotation(_currentSplineDistance); 82 | 83 | transform.SetPositionAndRotation(_currentPosition, _currentRotation); 84 | } 85 | } 86 | 87 | private void Update() 88 | { 89 | SetTargetPositionAndRotation(); 90 | 91 | var lerpPosition = Vector3.Lerp(transform.position, _currentPosition, Time.deltaTime * 25f); 92 | var lerpRotation = Quaternion.Lerp(transform.rotation, _currentRotation, Time.deltaTime * 25f); 93 | 94 | transform.SetPositionAndRotation(lerpPosition, lerpRotation); 95 | } 96 | 97 | private void SetTargetPositionAndRotation() 98 | { 99 | if (_moveType == MoveType.UseConstantSpeed) 100 | { 101 | var length = _spline.TotalLength; 102 | 103 | switch (_loopType) 104 | { 105 | case LoopType.Clamp: 106 | _currentSplineDistance += Time.unscaledDeltaTime * _speed; 107 | _currentSplineDistance = Mathf.Clamp(_currentSplineDistance, 0, length); 108 | break; 109 | case LoopType.Loop: 110 | _currentSplineDistance += Time.unscaledDeltaTime * _speed; 111 | _currentSplineDistance = Mathf.Repeat(_currentSplineDistance, length); 112 | break; 113 | case LoopType.PingPong: 114 | if (_isMovingForward) 115 | { 116 | _currentSplineDistance += Time.unscaledDeltaTime * _speed; 117 | } 118 | else if (!_isMovingForward) 119 | { 120 | _currentSplineDistance -= Time.unscaledDeltaTime * _speed; 121 | } 122 | 123 | _currentSplineDistance = Mathf.Clamp(_currentSplineDistance, 0, length); 124 | if (_currentSplineDistance <= 0 && !_isMovingForward || 125 | _currentSplineDistance >= length && _isMovingForward) 126 | { 127 | _isMovingForward = !_isMovingForward; 128 | } 129 | 130 | break; 131 | } 132 | 133 | _currentPosition = _spline.GetPosition(_currentSplineDistance); 134 | _currentRotation = _spline.GetRotation(_currentSplineDistance); 135 | } 136 | else if(_moveType == MoveType.UseFixedDuration) 137 | { 138 | switch (_loopType) 139 | { 140 | case LoopType.Clamp: 141 | _currentTime += Time.unscaledDeltaTime; 142 | _currentTime = Mathf.Clamp(_currentTime, 0, _duration); 143 | break; 144 | case LoopType.Loop: 145 | _currentTime += Time.unscaledDeltaTime; 146 | _currentTime = Mathf.Repeat(_currentTime, _duration); 147 | break; 148 | case LoopType.PingPong: 149 | if (_isMovingForward) 150 | { 151 | _currentTime += Time.unscaledDeltaTime; 152 | } 153 | else if (!_isMovingForward) 154 | { 155 | _currentTime -= Time.unscaledDeltaTime; 156 | } 157 | 158 | _currentTime = Mathf.Clamp(_currentTime, 0, _duration); 159 | if (_currentTime <= 0 && !_isMovingForward || 160 | _currentTime >= _duration && _isMovingForward) 161 | { 162 | _isMovingForward = !_isMovingForward; 163 | } 164 | 165 | break; 166 | } 167 | 168 | var progress = _currentTime / _duration; 169 | 170 | _currentPosition = _spline.GetNormalizedPosition(progress); 171 | _currentRotation = _spline.GetNormalizedRotation(progress); 172 | } 173 | } 174 | 175 | #if UNITY_EDITOR 176 | 177 | private void OnValidate() 178 | { 179 | if (_spline == null) 180 | { 181 | return; 182 | } 183 | 184 | _startingSplineDistance = Mathf.Clamp(_startingSplineDistance, 0, _spline.TotalLength); 185 | _currentSplineDistance = _startingSplineDistance; 186 | _currentTime = _currentSplineDistance / _spline.TotalLength; 187 | _currentPosition = _spline.GetPosition(_currentSplineDistance); 188 | _currentRotation = _spline.GetRotation(_currentSplineDistance); 189 | 190 | transform.SetPositionAndRotation(_currentPosition, _currentRotation); 191 | } 192 | 193 | #endif 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Components/SplineWalker.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e990ee1fd69e3a040a8ec8a4d9349c6b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {fileID: 2800000, guid: d2f3876f83c47304fb039eb650289db8, type: 3} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Core.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9575181e155d52b4aac13d016cdbeb70 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Core/Bezier3DCurve.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace JCMG.Curves 5 | { 6 | /// 7 | /// Immutable Bezier curve between two points. 8 | /// 9 | [System.Serializable] 10 | public class Bezier3DCurve 11 | { 12 | /// 13 | /// Start point. 14 | /// 15 | public Vector3 StartPoint 16 | { 17 | get { return _startPoint; } 18 | } 19 | 20 | /// 21 | /// First handle. Local to start point. 22 | /// 23 | public Vector3 FirstHandle 24 | { 25 | get { return _firstHandle; } 26 | } 27 | 28 | /// 29 | /// Second handle. Local to end point. 30 | /// 31 | public Vector3 SecondHandle 32 | { 33 | get { return _secondHandle; } 34 | } 35 | 36 | /// 37 | /// End point 38 | /// 39 | public Vector3 EndPoint 40 | { 41 | get { return _endPoint; } 42 | } 43 | 44 | /// 45 | /// Total length of the curve 46 | /// . 47 | public float Length 48 | { 49 | get { return _length; } 50 | } 51 | 52 | /// 53 | /// True if the curve is defined as a straight line. 54 | /// 55 | public bool IsLinear 56 | { 57 | get { return _isLinear; } 58 | } 59 | 60 | public AnimationCurve DistanceCache 61 | { 62 | get { return _distanceCache; } 63 | } 64 | 65 | [SerializeField] 66 | private Vector3 _startPoint; 67 | 68 | [SerializeField] 69 | private Vector3 _firstHandle; 70 | 71 | [SerializeField] 72 | private Vector3 _startHandleWorldPosition; 73 | 74 | [SerializeField] 75 | private Vector3 _endHandleWorldPosition; 76 | 77 | [SerializeField] 78 | private Vector3 _secondHandle; 79 | 80 | [SerializeField] 81 | private AnimationCurve _distanceCache; 82 | 83 | [SerializeField] 84 | private Vector3 _endPoint; 85 | 86 | [SerializeField] 87 | private bool _isLinear; 88 | 89 | [SerializeField] 90 | private float _length; 91 | 92 | [SerializeField] 93 | private Vector3AnimationCurve _tangentCache; 94 | 95 | /// Constructor 96 | /// Start point 97 | /// First handle. Local to start point 98 | /// Second handle. Local to end point 99 | /// End point 100 | public Bezier3DCurve(Vector3 startPoint, Vector3 firstHandle, Vector3 secondHandle, Vector3 endPoint, int steps) 101 | { 102 | _startPoint = startPoint; 103 | _firstHandle = firstHandle; 104 | _secondHandle = secondHandle; 105 | _endPoint = endPoint; 106 | _startHandleWorldPosition = startPoint + firstHandle; 107 | _endHandleWorldPosition = endPoint + secondHandle; 108 | _isLinear = Math.Abs(firstHandle.sqrMagnitude) < 0.00001f && 109 | Math.Abs(secondHandle.sqrMagnitude) < 0.00001f; 110 | 111 | _distanceCache = GetDistanceCache( 112 | startPoint, 113 | startPoint + firstHandle, 114 | secondHandle + endPoint, 115 | endPoint, 116 | steps); 117 | 118 | _tangentCache = GetTangentCache( 119 | startPoint, 120 | startPoint + firstHandle, 121 | secondHandle + endPoint, 122 | endPoint, 123 | steps); 124 | 125 | _length = _distanceCache.keys[_distanceCache.keys.Length - 1].time; 126 | } 127 | 128 | #region Public methods 129 | 130 | public Vector3 GetPoint(float t) 131 | { 132 | return GetPoint( 133 | _startPoint, 134 | _startHandleWorldPosition, 135 | _endHandleWorldPosition, 136 | _endPoint, 137 | t); 138 | } 139 | 140 | public void GetPoint(float t, out Vector3 point) 141 | { 142 | GetPoint( 143 | ref _startPoint, 144 | ref _startHandleWorldPosition, 145 | ref _endHandleWorldPosition, 146 | ref _endPoint, 147 | t, 148 | out point); 149 | } 150 | 151 | public void GetForward(float t, out Vector3 forward) 152 | { 153 | GetForward( 154 | ref _startPoint, 155 | ref _startHandleWorldPosition, 156 | ref _endHandleWorldPosition, 157 | ref _endPoint, 158 | t, 159 | out forward); 160 | } 161 | 162 | 163 | public Vector3 GetForward(float t) 164 | { 165 | return GetForward( 166 | _startPoint, 167 | _startHandleWorldPosition, 168 | _endHandleWorldPosition, 169 | _endPoint, 170 | t); 171 | } 172 | 173 | public Vector3 GetForwardFast(float t) 174 | { 175 | return _tangentCache.Evaluate(t); 176 | } 177 | 178 | public float ConvertDistanceToTime(float distance) 179 | { 180 | return _distanceCache.Evaluate(distance); 181 | } 182 | 183 | #endregion 184 | 185 | #region Private methods 186 | 187 | private static Vector3AnimationCurve GetTangentCache(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, int steps) 188 | { 189 | var curve = new Vector3AnimationCurve(); //time = distance, value = time 190 | var delta = 1f / steps; 191 | for (var i = 0; i < steps + 1; i++) 192 | { 193 | curve.AddKey( 194 | delta * i, 195 | GetForward( 196 | p0, 197 | p1, 198 | p2, 199 | p3, 200 | delta * i) 201 | .normalized); 202 | } 203 | 204 | return curve; 205 | } 206 | 207 | private static AnimationCurve GetDistanceCache(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, int steps) 208 | { 209 | var curve = new AnimationCurve(); //time = distance, value = time 210 | var prevPos = Vector3.zero; 211 | var totalLength = 0f; 212 | for (var i = 0; i <= steps; i++) 213 | { 214 | //Normalize i 215 | var t = (float)i / (float)steps; 216 | 217 | //Get position from t 218 | var newPos = GetPoint( 219 | p0, 220 | p1, 221 | p2, 222 | p3, 223 | t); 224 | 225 | //First step 226 | if (i == 0) 227 | { 228 | //Add point at (0,0) 229 | prevPos = GetPoint( 230 | p0, 231 | p1, 232 | p2, 233 | p3, 234 | 0); 235 | curve.AddKey(0, 0); 236 | } 237 | //Per step 238 | else 239 | { 240 | //Get distance from previous point 241 | var segmentLength = Vector3.Distance(prevPos, newPos); 242 | 243 | //Accumulate total distance traveled 244 | totalLength += segmentLength; 245 | 246 | //Save current position for next iteration 247 | prevPos = newPos; 248 | 249 | //Cache data 250 | curve.AddKey(totalLength, t); 251 | } 252 | } 253 | 254 | return curve; 255 | } 256 | 257 | public static Vector3 GetPoint(Vector3 a, Vector3 b, Vector3 c, Vector3 d, float t) 258 | { 259 | t = Mathf.Clamp01(t); 260 | var oneMinusT = 1f - t; 261 | return 262 | oneMinusT * oneMinusT * oneMinusT * a + 263 | 3f * oneMinusT * oneMinusT * t * b + 264 | 3f * oneMinusT * t * t * c + 265 | t * t * t * d; 266 | } 267 | 268 | private static Vector3 GetForward(Vector3 a, Vector3 b, Vector3 c, Vector3 d, float t) 269 | { 270 | //Also known as first derivative 271 | t = Mathf.Clamp01(t); 272 | var oneMinusT = 1f - t; 273 | return 274 | 3f * oneMinusT * oneMinusT * (b - a) + 275 | 6f * oneMinusT * t * (c - b) + 276 | 3f * t * t * (d - c); 277 | } 278 | 279 | private static void GetForward(ref Vector3 a, ref Vector3 b, ref Vector3 c, ref Vector3 d, float t, out Vector3 result) 280 | { 281 | //Also known as first derivative 282 | var oneMinusT = 1f - t; 283 | var baScale = 3f * oneMinusT * oneMinusT; 284 | var cbScale = 6f * oneMinusT * t; 285 | var dcScale = 3f * t * t; 286 | 287 | result.x = baScale * (b.x - a.x) + cbScale * (c.x - b.x) + dcScale * (d.x - c.x); 288 | result.y = baScale * (b.y - a.y) + cbScale * (c.y - b.y) + dcScale * (d.y - c.y); 289 | result.z = baScale * (b.z - a.z) + cbScale * (c.z - b.z) + dcScale * (d.z - c.z); 290 | } 291 | 292 | private static void GetPoint(ref Vector3 a, ref Vector3 b, ref Vector3 c, ref Vector3 d, float t, out Vector3 result) 293 | { 294 | var oneMinusT = 1f - t; 295 | var aScale = oneMinusT * oneMinusT * oneMinusT; 296 | var bScale = 3f * oneMinusT * oneMinusT * t; 297 | var cScale = 3f * oneMinusT * t * t; 298 | var dScale = t * t * t; 299 | 300 | result.x = aScale * a.x + bScale * b.x + cScale * c.x + dScale * d.x; 301 | result.y = aScale * a.y + bScale * b.y + cScale * c.y + dScale * d.y; 302 | result.z = aScale * a.z + bScale * b.z + cScale * c.z + dScale * d.z; 303 | } 304 | 305 | #endregion 306 | } 307 | } 308 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Core/Bezier3DCurve.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 74e4d65f14457b345a17854149e24d40 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Core/ConstantAnimationCurve.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | 4 | namespace JCMG.Curves 5 | { 6 | /// 7 | /// Similar to AnimationCurve, except all values are constant. No smoothing applied between keys. 8 | /// 9 | [System.Serializable] 10 | public class ConstantAnimationCurve 11 | { 12 | /// 13 | /// The number of keys in the curve. 14 | /// 15 | public int Length 16 | { 17 | get { return _time.Count; } 18 | } 19 | 20 | [SerializeField] 21 | List _time; 22 | 23 | [SerializeField] 24 | List _value; 25 | 26 | public ConstantAnimationCurve() 27 | { 28 | _value = new List(); 29 | _time = new List(); 30 | } 31 | 32 | /// 33 | /// Returns the float value at in the curve. 34 | /// 35 | /// 36 | /// 37 | public float Evaluate(float time) 38 | { 39 | if (Length == 0) 40 | { 41 | return 0; 42 | } 43 | 44 | var returnValue = GetKeyValue(0); 45 | for (var i = 0; i < _time.Count; i++) 46 | { 47 | if (_time[i] <= time) 48 | { 49 | returnValue = _value[i]; 50 | } 51 | else 52 | { 53 | break; 54 | } 55 | } 56 | 57 | return returnValue; 58 | } 59 | 60 | /// 61 | /// Adds float at on the curve. 62 | /// 63 | /// 64 | /// 65 | public void AddKey(float time, float value) 66 | { 67 | for (var i = 0; i < _time.Count; i++) 68 | { 69 | if (_time[i] > time) 70 | { 71 | _time.Insert(i, time); 72 | _value.Insert(i, value); 73 | return; 74 | } 75 | else if (_time[i] == time) 76 | { 77 | _time[i] = time; 78 | _value[i] = value; 79 | return; 80 | } 81 | } 82 | 83 | _time.Add(time); 84 | _value.Add(value); 85 | } 86 | 87 | /// 88 | /// Gets the last value of the curve. 89 | /// 90 | public float EvaluateEnd() 91 | { 92 | return _value[_value.Count - 1]; 93 | } 94 | 95 | /// 96 | /// Returns the time value at the position in the curve. 97 | /// 98 | /// 99 | /// 100 | public float GetKeyTime(int keyIndex) 101 | { 102 | return _time[keyIndex]; 103 | } 104 | 105 | /// 106 | /// Returns the float value at the position in the curve. 107 | /// 108 | /// 109 | /// 110 | public float GetKeyValue(int keyIndex) 111 | { 112 | return _value[keyIndex]; 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Core/ConstantAnimationCurve.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 68c5f9e36dc199e4f9c5285c05805235 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Core/ExtendedAnimationCurves.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace JCMG.Curves 4 | { 5 | /// 6 | /// Class Extensions 7 | /// 8 | public static class ExtendedAnimationCurves 9 | { 10 | public static void Serialize(this AnimationCurve anim, out float[] times, out float[] values) 11 | { 12 | times = new float[anim.length]; 13 | values = new float[anim.length]; 14 | for (var i = 0; i < anim.length; i++) 15 | { 16 | times[i] = anim.keys[i].time; 17 | values[i] = anim.keys[i].value; 18 | } 19 | } 20 | 21 | public static AnimationCurve Deserialize(float[] times, float[] values) 22 | { 23 | var anim = new AnimationCurve(); 24 | if (times.Length != values.Length) 25 | { 26 | Debug.LogWarning("Input data lengths do not match"); 27 | } 28 | else 29 | { 30 | for (var i = 0; i < times.Length; i++) 31 | { 32 | anim.AddKey(new Keyframe(times[i], values[i])); 33 | } 34 | } 35 | 36 | return anim; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Core/ExtendedAnimationCurves.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e28b7486b5d05454a94c012c6496ffb5 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Core/Knot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace JCMG.Curves 5 | { 6 | /// 7 | /// A user-configurable control point that can be altered to update a curve. 8 | /// 9 | public struct Knot 10 | { 11 | /// 12 | /// Returns true if a custom rotation has been specified, otherwise false. 13 | /// 14 | public bool IsUsingRotation => rotation != null; 15 | 16 | /// 17 | /// Returns true if a handles are auto-adjusted, otherwise false. 18 | /// 19 | public bool IsUsingAutoHandles => Math.Abs(auto) > .00001f; 20 | 21 | /// 22 | /// Position of the knot local to spline. 23 | /// 24 | public Vector3 position; 25 | 26 | /// 27 | /// Left handle position local to knot position. 28 | /// 29 | public Vector3 handleIn; 30 | 31 | /// 32 | /// Right handle position local to knot position. 33 | /// 34 | public Vector3 handleOut; 35 | 36 | /// 37 | /// Any value above 0 will result in an automatically configured knot (ignoring handle inputs). 38 | /// 39 | public float auto; 40 | 41 | /// 42 | /// The rotation to influence the any point along the curve before or after this knot. 43 | /// 44 | public Quaternion? rotation; 45 | 46 | /// Constructor 47 | /// Position of the knot local to spline 48 | /// Left handle position local to knot position 49 | /// Right handle position local to knot position 50 | /// Any value above 0 will result in an automatically configured knot (ignoring handle inputs) 51 | /// The rotation to influence the any point along the curve before or after this knot 52 | public Knot( 53 | Vector3 position, 54 | Vector3 handleIn, 55 | Vector3 handleOut, 56 | float automatic = 0f, 57 | Quaternion? rotation = null) 58 | { 59 | this.position = position; 60 | this.handleIn = handleIn; 61 | this.handleOut = handleOut; 62 | auto = automatic; 63 | this.rotation = rotation; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Core/Knot.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 84a74be362038eb448d2ae528e35f20e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Core/NullableQuaternion.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace JCMG.Curves 5 | { 6 | /// 7 | /// A serializable version of a nullable-Quaternion. 8 | /// 9 | [Serializable] 10 | public struct NullableQuaternion 11 | { 12 | /// 13 | /// Returns the value. 14 | /// 15 | public Quaternion Value 16 | { 17 | get { return rotation; } 18 | } 19 | 20 | /// 21 | /// Returns the value if present, otherwise null. 22 | /// 23 | public Quaternion? NullableValue 24 | { 25 | get { return hasValue ? (Quaternion?)rotation : null; } 26 | } 27 | 28 | /// 29 | /// Returns true if a value is present, otherwise false. 30 | /// 31 | public bool HasValue 32 | { 33 | get { return hasValue; } 34 | } 35 | 36 | [SerializeField] 37 | private Quaternion rotation; 38 | 39 | [SerializeField] 40 | private bool hasValue; 41 | 42 | public NullableQuaternion(Quaternion? rot) 43 | { 44 | rotation = rot.HasValue ? rot.Value : Quaternion.identity; 45 | hasValue = rot.HasValue; 46 | } 47 | 48 | /// 49 | /// User-defined conversion from nullable type to NullableQuaternion 50 | /// 51 | /// 52 | public static implicit operator NullableQuaternion(Quaternion? r) 53 | { 54 | return new NullableQuaternion(r); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Core/NullableQuaternion.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 630cdd6c9d8b7fe4c833d5140f65e681 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Core/QuaternionAnimationCurve.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace JCMG.Curves 4 | { 5 | /// 6 | /// Animation curve which stores quaternions, and can evaluate smoothed values in between keyframes. 7 | /// 8 | [System.Serializable] 9 | public class QuaternionAnimationCurve 10 | { 11 | [System.Serializable] 12 | public class Serializable 13 | { 14 | public float[] xT; 15 | public float[] xV; 16 | public float[] yT; 17 | public float[] yV; 18 | public float[] zT; 19 | public float[] zV; 20 | public float[] wT; 21 | public float[] wV; 22 | 23 | public Serializable(QuaternionAnimationCurve curve) 24 | { 25 | curve.xQ.Serialize(out xT, out xV); 26 | curve.yQ.Serialize(out yT, out yV); 27 | curve.zQ.Serialize(out zT, out zV); 28 | curve.wQ.Serialize(out wT, out wV); 29 | } 30 | } 31 | 32 | /// 33 | /// The number of keys in the curve. 34 | /// 35 | public int Length 36 | { 37 | get { return xQ.length; } 38 | } 39 | 40 | [SerializeField] 41 | private AnimationCurve xQ; 42 | 43 | [SerializeField] 44 | private AnimationCurve yQ; 45 | 46 | [SerializeField] 47 | private AnimationCurve zQ; 48 | 49 | [SerializeField] 50 | private AnimationCurve wQ; 51 | 52 | public QuaternionAnimationCurve() 53 | { 54 | wQ = new AnimationCurve(); 55 | zQ = new AnimationCurve(); 56 | yQ = new AnimationCurve(); 57 | xQ = new AnimationCurve(); 58 | } 59 | 60 | public QuaternionAnimationCurve(Serializable serialized) 61 | { 62 | wQ = new AnimationCurve(); 63 | zQ = new AnimationCurve(); 64 | yQ = new AnimationCurve(); 65 | xQ = new AnimationCurve(); 66 | 67 | xQ = ExtendedAnimationCurves.Deserialize(serialized.xT, serialized.xV); 68 | yQ = ExtendedAnimationCurves.Deserialize(serialized.yT, serialized.yV); 69 | zQ = ExtendedAnimationCurves.Deserialize(serialized.zT, serialized.zV); 70 | wQ = ExtendedAnimationCurves.Deserialize(serialized.wT, serialized.wV); 71 | } 72 | 73 | /// 74 | /// Returns the at in the curve. 75 | /// 76 | /// 77 | /// 78 | public Quaternion Evaluate(float time) 79 | { 80 | return new Quaternion( 81 | xQ.Evaluate(time), 82 | yQ.Evaluate(time), 83 | zQ.Evaluate(time), 84 | wQ.Evaluate(time)); 85 | } 86 | 87 | /// 88 | /// Adds at on the curve. 89 | /// 90 | /// 91 | /// 92 | public void AddKey(float time, Quaternion value) 93 | { 94 | xQ.AddKey(time, value.x); 95 | yQ.AddKey(time, value.y); 96 | zQ.AddKey(time, value.z); 97 | wQ.AddKey(time, value.w); 98 | } 99 | 100 | /// 101 | /// Gets the rotation of the last key. 102 | /// 103 | public Quaternion EvaluateEnd() 104 | { 105 | return GetKeyValue(xQ.length - 1); 106 | } 107 | 108 | /// 109 | /// Returns the time value at the position in the curve. 110 | /// 111 | /// 112 | /// 113 | public float GetKeyTime(int keyIndex) 114 | { 115 | return wQ.keys[keyIndex].time; 116 | } 117 | 118 | /// 119 | /// Returns the value at the position in the curve. 120 | /// 121 | /// 122 | /// 123 | public Quaternion GetKeyValue(int keyIndex) 124 | { 125 | return new Quaternion( 126 | xQ.keys[keyIndex].value, 127 | yQ.keys[keyIndex].value, 128 | zQ.keys[keyIndex].value, 129 | wQ.keys[keyIndex].value); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Core/QuaternionAnimationCurve.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fe2316d4eb4973c4d8ad11fd7e59465c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Core/Vector3AnimationCurve.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace JCMG.Curves 4 | { 5 | /// 6 | /// Animation curve which stores , and can evaluate smoothed values in between keyframes. 7 | /// 8 | [System.Serializable] 9 | public class Vector3AnimationCurve 10 | { 11 | [System.Serializable] 12 | public class Serializable 13 | { 14 | public float[] xT; 15 | public float[] xV; 16 | public float[] yT; 17 | public float[] yV; 18 | public float[] zT; 19 | public float[] zV; 20 | 21 | public Serializable(Vector3AnimationCurve curve) 22 | { 23 | curve.xV.Serialize(out xT, out xV); 24 | curve.yV.Serialize(out yT, out yV); 25 | curve.zV.Serialize(out zT, out zV); 26 | } 27 | } 28 | 29 | /// 30 | /// The number of keys in the curve. 31 | /// 32 | public int Length 33 | { 34 | get { return xV.length; } 35 | } 36 | 37 | [SerializeField] 38 | private AnimationCurve xV; 39 | 40 | [SerializeField] 41 | private AnimationCurve yV; 42 | 43 | [SerializeField] 44 | private AnimationCurve zV; 45 | 46 | public Vector3AnimationCurve() 47 | { 48 | xV = new AnimationCurve(); 49 | yV = new AnimationCurve(); 50 | zV = new AnimationCurve(); 51 | } 52 | 53 | public Vector3AnimationCurve(Serializable serialized) 54 | { 55 | xV = new AnimationCurve(); 56 | yV = new AnimationCurve(); 57 | zV = new AnimationCurve(); 58 | 59 | xV = ExtendedAnimationCurves.Deserialize(serialized.xT, serialized.xV); 60 | yV = ExtendedAnimationCurves.Deserialize(serialized.yT, serialized.yV); 61 | zV = ExtendedAnimationCurves.Deserialize(serialized.zT, serialized.zV); 62 | } 63 | 64 | /// 65 | /// Returns the at in the curve. 66 | /// 67 | /// 68 | /// 69 | public Vector3 Evaluate(float time) 70 | { 71 | return new Vector3(xV.Evaluate(time), yV.Evaluate(time), zV.Evaluate(time)); 72 | } 73 | 74 | /// 75 | /// Adds at on the curve. 76 | /// 77 | /// 78 | /// 79 | public void AddKey(float time, Vector3 value) 80 | { 81 | xV.AddKey(time, value.x); 82 | yV.AddKey(time, value.y); 83 | zV.AddKey(time, value.z); 84 | } 85 | 86 | /// 87 | /// Gets the of the last key. 88 | /// 89 | public Vector3 EvaluateEnd() 90 | { 91 | return GetKeyValue(xV.length - 1); 92 | } 93 | 94 | /// 95 | /// Returns the time value at the position in the curve. 96 | /// 97 | /// 98 | /// 99 | public float GetKeyTime(int keyIndex) 100 | { 101 | return xV.keys[keyIndex].time; 102 | } 103 | 104 | /// 105 | /// Returns the value at the position in the curve. 106 | /// 107 | /// 108 | /// 109 | public Vector3 GetKeyValue(int keyIndex) 110 | { 111 | return new Vector3(xV.keys[keyIndex].value, yV.keys[keyIndex].value, zV.keys[keyIndex].value); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Core/Vector3AnimationCurve.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c519766a13b361841aac0125bb4a7420 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: de73badbd2f40df47b9eddaae710f038 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/CurveEditorState.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEditor; 3 | 4 | namespace JCMG.Curves.Editor 5 | { 6 | /// 7 | /// Shared state for modifying curves in the Unity Editor. 8 | /// 9 | internal static class CurveEditorState 10 | { 11 | public static bool HasKnotSelected => SelectedKnotIndex != -1; 12 | 13 | public static bool HasSingleKnotSelected => SelectedKnots.Count == 1; 14 | 15 | public static bool HasMultipleKnotsSelected => SelectedKnots.Count > 1; 16 | 17 | public static int SelectedKnotIndex { get; set; } 18 | 19 | public static List SelectedKnots { get; set; } 20 | 21 | static CurveEditorState() 22 | { 23 | SelectedKnots = new List(); 24 | } 25 | 26 | public static bool ValidateSelectedKnotIsValid(IReadOnly3DSplineData splineData) 27 | { 28 | return SelectedKnotIndex > splineData.CurveCount; 29 | } 30 | 31 | public static void ClearKnotSelection() 32 | { 33 | SelectKnot(-1, false); 34 | } 35 | 36 | public static void SelectKnot(int i, bool add) 37 | { 38 | SelectedKnotIndex = i; 39 | if (i == -1) 40 | { 41 | SelectedKnots.Clear(); 42 | Tools.hidden = false; 43 | } 44 | else 45 | { 46 | Tools.hidden = true; 47 | if (add) 48 | { 49 | if (SelectedKnots.Contains(i)) 50 | { 51 | SelectedKnots.Remove(i); 52 | if (SelectedKnots.Count == 0) 53 | { 54 | SelectedKnotIndex = -1; 55 | Tools.hidden = false; 56 | } 57 | else 58 | { 59 | SelectedKnotIndex = SelectedKnots[SelectedKnots.Count - 1]; 60 | } 61 | } 62 | else 63 | { 64 | SelectedKnots.Add(i); 65 | 66 | SelectedKnotIndex = i; 67 | } 68 | } 69 | else 70 | { 71 | SelectedKnots.Clear(); 72 | SelectedKnots.Add(i); 73 | 74 | SelectedKnotIndex = i; 75 | } 76 | } 77 | } 78 | 79 | public static void Reset() 80 | { 81 | ClearKnotSelection(); 82 | 83 | SelectedKnots.Clear(); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/CurveEditorState.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c51d16d3870c27c46b9f0a84fd34a681 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/CurveEditorStyles.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace JCMG.Curves.Editor 5 | { 6 | /// 7 | /// GUI constants and styles for the Unity Editor. 8 | /// 9 | internal static class CurveEditorStyles 10 | { 11 | public static GUIStyle HeaderStyle 12 | { 13 | get 14 | { 15 | if(_headerStyle == null) 16 | { 17 | _headerStyle = new GUIStyle(EditorStyles.boldLabel); 18 | _headerStyle.padding.right += 4; 19 | _headerStyle.normal.textColor = TextColor; 20 | _headerStyle.fontSize += 1; 21 | } 22 | 23 | return _headerStyle; 24 | } 25 | } 26 | 27 | public static GUIStyle LabelStyle 28 | { 29 | get 30 | { 31 | if(_labelStyle == null) 32 | { 33 | _labelStyle = new GUIStyle(EditorStyles.label); 34 | _labelStyle.padding.right += 4; 35 | _labelStyle.normal.textColor = TextColor; 36 | } 37 | 38 | return _labelStyle; 39 | } 40 | } 41 | 42 | public static Color TextColor 43 | { 44 | get 45 | { 46 | if (_textColor == null) 47 | { 48 | _textColor = new Color(0.7f, 0.7f, 0.7f); 49 | } 50 | 51 | return _textColor.Value; 52 | } 53 | } 54 | 55 | private static GUIStyle _headerStyle; 56 | private static GUIStyle _labelStyle; 57 | private static Color? _textColor; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/CurveEditorStyles.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 19af2718e33854d43bda9ffa58e6ecb8 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/CurvePreferences.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace JCMG.Curves.Editor 5 | { 6 | /// 7 | /// An editor class for managing project and user preferences for the Curves library. 8 | /// 9 | public static class CurvePreferences 10 | { 11 | /// 12 | /// Returns true if debug features should be enabled, otherwise false. 13 | /// 14 | public static bool IsDebugEnabled 15 | { 16 | get 17 | { 18 | if (!_isDebugEnabled.HasValue) 19 | { 20 | _isDebugEnabled = GetBoolPref(ENABLE_DEBUG_PREF, ENABLE_DEBUG_DEFAULT); 21 | } 22 | 23 | return _isDebugEnabled.Value; 24 | 25 | } 26 | set 27 | { 28 | _isDebugEnabled = value; 29 | 30 | EditorPrefs.SetBool(ENABLE_DEBUG_PREF, value); 31 | } 32 | } 33 | 34 | /// 35 | /// Returns true if rotation visualization info should be enabled, otherwise false. 36 | /// 37 | public static bool ShouldVisualizeRotation 38 | { 39 | get 40 | { 41 | if(!_shouldVisualizeRotation.HasValue) 42 | { 43 | _shouldVisualizeRotation = GetBoolPref(SHOW_ROTATION_PREF, SHOW_ROTATION_DEFAULT); 44 | } 45 | 46 | return _shouldVisualizeRotation.Value; 47 | } 48 | set 49 | { 50 | _shouldVisualizeRotation = value; 51 | 52 | EditorPrefs.SetBool(SHOW_ROTATION_PREF, value); 53 | } 54 | } 55 | 56 | /// 57 | /// Returns true if handle movement should be mirrored, otherwise false. 58 | /// 59 | public static bool ShouldMirrorHandleMovement 60 | { 61 | get 62 | { 63 | if (!_shouldMirrorHandleMovement.HasValue) 64 | { 65 | _shouldMirrorHandleMovement = GetBoolPref(MIRROR_HANDLE_MOVEMENT_PREF, MIRROR_HANDLE_MOVEMENT_DEFAULT); 66 | } 67 | 68 | return _shouldMirrorHandleMovement.Value; 69 | } 70 | set 71 | { 72 | _shouldMirrorHandleMovement = value; 73 | 74 | EditorPrefs.SetBool(MIRROR_HANDLE_MOVEMENT_PREF, value); 75 | } 76 | } 77 | 78 | /// 79 | /// The maximum distance from the SceneView camera at which editor graphics should be drawn for the curve before 80 | /// being culled. 81 | /// 82 | public static float MaximumViewDistance 83 | { 84 | get 85 | { 86 | if (!_maximumViewDistance.HasValue) 87 | { 88 | _maximumViewDistance = GetFloatPref(MAX_VIEW_DISTANCE_PREF, MAX_VIEW_DISTANCE_DEFAULT); 89 | } 90 | 91 | return _maximumViewDistance.Value; 92 | } 93 | set 94 | { 95 | _maximumViewDistance = value; 96 | 97 | EditorPrefs.SetFloat(MAX_VIEW_DISTANCE_PREF, value); 98 | } 99 | } 100 | 101 | // Caching layer 102 | private static bool? _isDebugEnabled; 103 | private static bool? _shouldVisualizeRotation; 104 | private static bool? _shouldMirrorHandleMovement; 105 | private static float? _maximumViewDistance; 106 | 107 | // UI 108 | private const string PREFERENCES_TITLE_PATH = "Preferences/JCMG Curves"; 109 | private const string USER_PREFERENCES_HEADER = "User Preferences"; 110 | 111 | private static readonly GUILayoutOption MAX_WIDTH; 112 | 113 | // Searchable Fields 114 | private static readonly string[] KEYWORDS = 115 | { 116 | "Curve", 117 | "Curves" 118 | }; 119 | 120 | // User Editor Preferences 121 | private const string SHOW_ROTATION_PREF = "JCMG.Curves.ShowRotationVisualization"; 122 | private const string ENABLE_DEBUG_PREF = "JCMG.Curves.EnableDebug"; 123 | private const string MIRROR_HANDLE_MOVEMENT_PREF = "JCMG.Curves.MirrorHandleMovement"; 124 | private const string MAX_VIEW_DISTANCE_PREF = "JCMG.Curves.MaximumViewDistance"; 125 | 126 | private const bool SHOW_ROTATION_DEFAULT = true; 127 | private const bool ENABLE_DEBUG_DEFAULT = true; 128 | private const bool MIRROR_HANDLE_MOVEMENT_DEFAULT = true; 129 | private const float MAX_VIEW_DISTANCE_DEFAULT = 200f; 130 | 131 | static CurvePreferences() 132 | { 133 | MAX_WIDTH = GUILayout.MaxWidth(175f); 134 | } 135 | 136 | [SettingsProvider] 137 | private static SettingsProvider CreatePersonalPreferenceSettingsProvider() 138 | { 139 | return new SettingsProvider(PREFERENCES_TITLE_PATH, SettingsScope.User) 140 | { 141 | guiHandler = DrawPersonalPrefsGUI, keywords = KEYWORDS 142 | }; 143 | } 144 | 145 | private static void DrawAllGUI() 146 | { 147 | DrawPersonalPrefsGUI(); 148 | } 149 | 150 | private static void DrawPersonalPrefsGUI(string value = "") 151 | { 152 | EditorGUILayout.LabelField(USER_PREFERENCES_HEADER, EditorStyles.boldLabel); 153 | 154 | // Enable Orientation Visualization 155 | EditorGUILayout.HelpBox( 156 | "This will enable visualization of a point's rotation along the curve, " + 157 | "with lines drawn to show its local forward, up, and right vectors.", 158 | MessageType.Info); 159 | 160 | GUI.changed = false; 161 | using (new EditorGUILayout.HorizontalScope()) 162 | { 163 | EditorGUILayout.LabelField("Should Visualize Rotation", MAX_WIDTH); 164 | var drawEventPref = EditorGUILayout.Toggle(ShouldVisualizeRotation); 165 | if (GUI.changed) 166 | { 167 | ShouldVisualizeRotation = drawEventPref; 168 | SceneView.RepaintAll(); 169 | } 170 | } 171 | 172 | // Enable Debugging 173 | EditorGUILayout.Space(); 174 | EditorGUILayout.HelpBox( 175 | "This will enable debug features for troubleshooting purposes", 176 | MessageType.Info); 177 | 178 | GUI.changed = false; 179 | using (new EditorGUILayout.HorizontalScope()) 180 | { 181 | EditorGUILayout.LabelField("Enable Debug", MAX_WIDTH); 182 | var enableDebugPref = EditorGUILayout.Toggle( IsDebugEnabled, MAX_WIDTH); 183 | if (GUI.changed) 184 | { 185 | IsDebugEnabled = enableDebugPref; 186 | SceneView.RepaintAll(); 187 | } 188 | } 189 | 190 | // Enable Mirror Handle Movement 191 | EditorGUILayout.Space(); 192 | EditorGUILayout.HelpBox( 193 | "When enabled, moving a handle will cause the other handle to copy its " + 194 | "movement in the opposite direction.", 195 | MessageType.Info); 196 | 197 | GUI.changed = false; 198 | using (new EditorGUILayout.HorizontalScope()) 199 | { 200 | EditorGUILayout.LabelField("Mirror Handle Movement", MAX_WIDTH); 201 | var mirrorHandleMovementPref = EditorGUILayout.Toggle(ShouldMirrorHandleMovement, MAX_WIDTH); 202 | if (GUI.changed) 203 | { 204 | ShouldMirrorHandleMovement = mirrorHandleMovementPref; 205 | SceneView.RepaintAll(); 206 | } 207 | } 208 | 209 | // Max View Distance 210 | EditorGUILayout.Space(); 211 | EditorGUILayout.HelpBox( 212 | "The maximum distance at which the curve orientation and other secondary graphics will be drawn in the " + 213 | "SceneView.", 214 | MessageType.Info); 215 | 216 | GUI.changed = false; 217 | using (new EditorGUILayout.HorizontalScope()) 218 | { 219 | EditorGUILayout.LabelField("Maximum View Distance", MAX_WIDTH); 220 | var newViewDistance = Mathf.Max(0, EditorGUILayout.FloatField(MaximumViewDistance, MAX_WIDTH)); 221 | if (GUI.changed) 222 | { 223 | MaximumViewDistance = newViewDistance; 224 | SceneView.RepaintAll(); 225 | } 226 | } 227 | } 228 | 229 | /// 230 | /// Returns the current bool preference; if none exists, the default is set and returned. 231 | /// 232 | /// 233 | /// 234 | /// 235 | private static bool GetBoolPref(string key, bool defaultValue) 236 | { 237 | if (!EditorPrefs.HasKey(key)) 238 | { 239 | EditorPrefs.SetBool(key, defaultValue); 240 | } 241 | 242 | return EditorPrefs.GetBool(key); 243 | } 244 | 245 | /// 246 | /// Returns the current float preference; if none exists, the default is set and returned. 247 | /// 248 | /// 249 | /// 250 | /// 251 | private static float GetFloatPref(string key, float defaultValue) 252 | { 253 | if (!EditorPrefs.HasKey(key)) 254 | { 255 | EditorPrefs.SetFloat(key, defaultValue); 256 | } 257 | 258 | return EditorPrefs.GetFloat(key); 259 | } 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/CurvePreferences.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ba2dd14dd659cda4abf7ad439803e71f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Icons.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 85d9a51db23905f47a1a37776f3128b9 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Icons/Bezier3DCurveDataIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffcampbellmakesgames/unity-curves/268a2ebd354247bb3e7be73fc8d4f55670a5cdf9/Unity/Assets/JCMG/Curves/Scripts/Editor/Icons/Bezier3DCurveDataIcon.png -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Icons/Bezier3DCurveDataIcon.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c5c32b6c450791943b0b231a833c00b6 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 10 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | platformSettings: 61 | - serializedVersion: 3 62 | buildTarget: DefaultTexturePlatform 63 | maxTextureSize: 2048 64 | resizeAlgorithm: 0 65 | textureFormat: -1 66 | textureCompression: 1 67 | compressionQuality: 50 68 | crunchedCompression: 0 69 | allowsAlphaSplitting: 0 70 | overridden: 0 71 | androidETC2FallbackOverride: 0 72 | forceMaximumCompressionQuality_BC6H_BC7: 0 73 | - serializedVersion: 3 74 | buildTarget: Standalone 75 | maxTextureSize: 2048 76 | resizeAlgorithm: 0 77 | textureFormat: -1 78 | textureCompression: 1 79 | compressionQuality: 50 80 | crunchedCompression: 0 81 | allowsAlphaSplitting: 0 82 | overridden: 0 83 | androidETC2FallbackOverride: 0 84 | forceMaximumCompressionQuality_BC6H_BC7: 0 85 | - serializedVersion: 3 86 | buildTarget: Android 87 | maxTextureSize: 2048 88 | resizeAlgorithm: 0 89 | textureFormat: -1 90 | textureCompression: 1 91 | compressionQuality: 50 92 | crunchedCompression: 0 93 | allowsAlphaSplitting: 0 94 | overridden: 0 95 | androidETC2FallbackOverride: 0 96 | forceMaximumCompressionQuality_BC6H_BC7: 0 97 | spriteSheet: 98 | serializedVersion: 2 99 | sprites: [] 100 | outline: [] 101 | physicsShape: [] 102 | bones: [] 103 | spriteID: 104 | internalID: 0 105 | vertices: [] 106 | indices: 107 | edges: [] 108 | weights: [] 109 | secondaryTextures: [] 110 | spritePackingTag: 111 | pSDRemoveMatte: 0 112 | pSDShowRemoveMatteOption: 0 113 | userData: 114 | assetBundleName: 115 | assetBundleVariant: 116 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Icons/IconTemplate.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffcampbellmakesgames/unity-curves/268a2ebd354247bb3e7be73fc8d4f55670a5cdf9/Unity/Assets/JCMG/Curves/Scripts/Editor/Icons/IconTemplate.psd -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Icons/IconTemplate.psd.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9d16932e19cb4564b83e61862132c615 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 10 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: -1 36 | mipBias: -100 37 | wrapU: -1 38 | wrapV: -1 39 | wrapW: -1 40 | nPOTScale: 1 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 0 53 | spriteTessellationDetail: -1 54 | textureType: 0 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | platformSettings: 61 | - serializedVersion: 3 62 | buildTarget: DefaultTexturePlatform 63 | maxTextureSize: 2048 64 | resizeAlgorithm: 0 65 | textureFormat: -1 66 | textureCompression: 1 67 | compressionQuality: 50 68 | crunchedCompression: 0 69 | allowsAlphaSplitting: 0 70 | overridden: 0 71 | androidETC2FallbackOverride: 0 72 | forceMaximumCompressionQuality_BC6H_BC7: 0 73 | spriteSheet: 74 | serializedVersion: 2 75 | sprites: [] 76 | outline: [] 77 | physicsShape: [] 78 | bones: [] 79 | spriteID: 80 | internalID: 0 81 | vertices: [] 82 | indices: 83 | edges: [] 84 | weights: [] 85 | secondaryTextures: [] 86 | spritePackingTag: 87 | pSDRemoveMatte: 0 88 | pSDShowRemoveMatteOption: 0 89 | userData: 90 | assetBundleName: 91 | assetBundleVariant: 92 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Icons/SplineWalkerIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffcampbellmakesgames/unity-curves/268a2ebd354247bb3e7be73fc8d4f55670a5cdf9/Unity/Assets/JCMG/Curves/Scripts/Editor/Icons/SplineWalkerIcon.png -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Icons/SplineWalkerIcon.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d2f3876f83c47304fb039eb650289db8 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 10 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | platformSettings: 61 | - serializedVersion: 3 62 | buildTarget: DefaultTexturePlatform 63 | maxTextureSize: 2048 64 | resizeAlgorithm: 0 65 | textureFormat: -1 66 | textureCompression: 1 67 | compressionQuality: 50 68 | crunchedCompression: 0 69 | allowsAlphaSplitting: 0 70 | overridden: 0 71 | androidETC2FallbackOverride: 0 72 | forceMaximumCompressionQuality_BC6H_BC7: 0 73 | - serializedVersion: 3 74 | buildTarget: Standalone 75 | maxTextureSize: 2048 76 | resizeAlgorithm: 0 77 | textureFormat: -1 78 | textureCompression: 1 79 | compressionQuality: 50 80 | crunchedCompression: 0 81 | allowsAlphaSplitting: 0 82 | overridden: 0 83 | androidETC2FallbackOverride: 0 84 | forceMaximumCompressionQuality_BC6H_BC7: 0 85 | - serializedVersion: 3 86 | buildTarget: Android 87 | maxTextureSize: 2048 88 | resizeAlgorithm: 0 89 | textureFormat: -1 90 | textureCompression: 1 91 | compressionQuality: 50 92 | crunchedCompression: 0 93 | allowsAlphaSplitting: 0 94 | overridden: 0 95 | androidETC2FallbackOverride: 0 96 | forceMaximumCompressionQuality_BC6H_BC7: 0 97 | spriteSheet: 98 | serializedVersion: 2 99 | sprites: [] 100 | outline: [] 101 | physicsShape: [] 102 | bones: [] 103 | spriteID: 104 | internalID: 0 105 | vertices: [] 106 | indices: 107 | edges: [] 108 | weights: [] 109 | secondaryTextures: [] 110 | spritePackingTag: 111 | pSDRemoveMatte: 0 112 | pSDShowRemoveMatteOption: 0 113 | userData: 114 | assetBundleName: 115 | assetBundleVariant: 116 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Inspectors.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e66086bcdd585e846bdceaa37590e9d6 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Inspectors/Bezier3DSplineDataInspector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEditor; 3 | using UnityEngine; 4 | 5 | namespace JCMG.Curves.Editor 6 | { 7 | [CustomEditor(typeof(Bezier3DSplineData))] 8 | public sealed class Bezier3DSplineDataInspector : UnityEditor.Editor 9 | { 10 | /// 11 | /// Get or sets whether or not this inspector should be drawing the scene GUI. Default is true. 12 | /// 13 | public bool ShouldDrawSceneGUI 14 | { 15 | get 16 | { 17 | return _shouldDrawSceneGUI; 18 | } 19 | set 20 | { 21 | if (_shouldDrawSceneGUI && !value) 22 | { 23 | SceneView.duringSceneGui -= OnSceneGUI; 24 | } 25 | else if (!_shouldDrawSceneGUI && value) 26 | { 27 | SceneView.duringSceneGui += OnSceneGUI; 28 | } 29 | 30 | _shouldDrawSceneGUI = value; 31 | } 32 | } 33 | 34 | #pragma warning disable 0649 35 | public event Action SplineUpdated; 36 | #pragma warning restore 0649 37 | 38 | private bool _shouldDrawSceneGUI; 39 | private Bezier3DSplineData _spline; 40 | private static Bezier3DSplineData _copyAndPasteSplineData; 41 | 42 | internal void Awake() 43 | { 44 | ShouldDrawSceneGUI = true; 45 | } 46 | 47 | private void OnDestroy() 48 | { 49 | ShouldDrawSceneGUI = false; 50 | } 51 | 52 | internal void OnEnable() 53 | { 54 | CurveEditorState.Reset(); 55 | 56 | _spline = target as Bezier3DSplineData; 57 | } 58 | 59 | internal void OnDisable() 60 | { 61 | ShouldDrawSceneGUI = false; 62 | 63 | Tools.hidden = false; 64 | CurveEditorState.ClearKnotSelection(); 65 | Repaint(); 66 | } 67 | 68 | private void OnSceneGUI(SceneView sceneView) 69 | { 70 | if (ShouldDrawSceneGUI) 71 | { 72 | OnSceneGUI(); 73 | } 74 | } 75 | 76 | internal void OnSceneGUI() 77 | { 78 | HotkeyTools.CheckGeneralHotkeys(_spline, SplineUpdated); 79 | 80 | SceneGUITools.DrawCurveLinesHandles(_spline); 81 | SceneGUITools.DrawSceneScreenUI(); 82 | 83 | ValidateSelected(); 84 | SceneGUITools.DrawUnselectedKnots(_spline, this); 85 | 86 | if (CurvePreferences.ShouldVisualizeRotation) 87 | { 88 | SceneGUITools.DrawCurveOrientations(_spline); 89 | } 90 | 91 | if (CurveEditorState.HasKnotSelected) 92 | { 93 | if (CurveEditorState.HasSingleKnotSelected) 94 | { 95 | SceneGUITools.DrawSelectedSplitters(_spline, SplineUpdated); 96 | SceneGUITools.DrawSelectedKnot(_spline, SplineUpdated, this); 97 | 98 | // Hotkeys 99 | HotkeyTools.CheckSelectedKnotHotkeys(_spline, SplineUpdated); 100 | } 101 | else 102 | { 103 | SceneGUITools.DrawMultiSelect(_spline, this); 104 | } 105 | } 106 | } 107 | 108 | public override void OnInspectorGUI() 109 | { 110 | ValidateSelected(); 111 | 112 | // Spline Properties 113 | EditorGUI.indentLevel = 0; 114 | GUILayout.BeginVertical(GUI.skin.box); 115 | EditorGUILayout.LabelField("Spline Settings", EditorStyles.boldLabel); 116 | EditorGUILayout.Space(5); 117 | DrawInterpolationSteps(); 118 | DrawClosedToggle(); 119 | 120 | // Spline Actions 121 | GUILayout.BeginVertical(GUI.skin.box); 122 | EditorGUILayout.LabelField("Actions", EditorStyles.boldLabel); 123 | EditorGUILayout.Space(5); 124 | DrawSplineFlipAction(); 125 | DrawCopySplineDataToClipboard(); 126 | DrawPasteSplineDataToClipboard(); 127 | DrawResetSplineData(); 128 | GUILayout.EndVertical(); 129 | 130 | GUILayout.EndVertical(); 131 | 132 | // Selected Point Properties 133 | EditorGUILayout.Space(); 134 | if (CurveEditorState.HasKnotSelected) 135 | { 136 | // Header information for selected knot. 137 | GUILayout.BeginVertical(GUI.skin.box); 138 | EditorGUILayout.LabelField( 139 | $"Selected Knot (index = {CurveEditorState.SelectedKnotIndex})", 140 | EditorStyles.boldLabel); 141 | EditorGUILayout.Space(2); 142 | 143 | var knot = _spline.GetKnot(CurveEditorState.SelectedKnotIndex); 144 | 145 | // Draw Position 146 | DrawKnotPosition(knot); 147 | EditorGUILayout.Space(2); 148 | 149 | // Draw Orientation 150 | DrawKnotOrientationToggle(knot); 151 | DrawKnotOrientationValue(knot); 152 | 153 | EditorGUILayout.Space(2); 154 | 155 | // Draw Auto-Handle 156 | DrawKnotAutoHandleToggle(knot); 157 | if (knot.IsUsingAutoHandles) 158 | { 159 | DrawKnotAutoHandleValue(knot); 160 | } 161 | else 162 | { 163 | DrawKnotHandleValues(knot); 164 | } 165 | 166 | GUILayout.EndVertical(); 167 | } 168 | } 169 | 170 | private void ValidateSelected() 171 | { 172 | if (CurveEditorState.ValidateSelectedKnotIsValid(_spline)) 173 | { 174 | CurveEditorState.ClearKnotSelection(); 175 | 176 | Repaint(); 177 | } 178 | } 179 | 180 | private void DrawInterpolationSteps() 181 | { 182 | using (var changeCheck = new EditorGUI.ChangeCheckScope()) 183 | { 184 | var steps = _spline.InterpolationStepsPerCurve; 185 | steps = EditorGUILayout.DelayedIntField("Interpolation Steps Per Curve", steps); 186 | 187 | if (changeCheck.changed) 188 | { 189 | Undo.RecordObject(_spline, "Set interpolation steps per curve"); 190 | 191 | _spline.SetStepsPerCurve(steps); 192 | SplineUpdated?.Invoke(_spline); 193 | } 194 | } 195 | } 196 | 197 | private void DrawClosedToggle() 198 | { 199 | using (var changeCheck = new EditorGUI.ChangeCheckScope()) 200 | { 201 | var closed = _spline.IsClosed; 202 | closed = EditorGUILayout.Toggle( 203 | new GUIContent("Closed", "Generate an extra curve, connecting the final point to the first point."), 204 | closed); 205 | 206 | if (changeCheck.changed) 207 | { 208 | Undo.RecordObject(_spline, "Set closed"); 209 | 210 | _spline.SetClosed(closed); 211 | SplineUpdated?.Invoke(_spline); 212 | SceneView.RepaintAll(); 213 | } 214 | } 215 | } 216 | 217 | private void DrawSplineFlipAction() 218 | { 219 | if (GUILayout.Button(new GUIContent("Flip", "Flip spline direction."))) 220 | { 221 | Undo.RecordObject(_spline, "Flip spline"); 222 | 223 | _spline.Flip(); 224 | SplineUpdated?.Invoke(_spline); 225 | SceneView.RepaintAll(); 226 | } 227 | } 228 | 229 | private void DrawCopySplineDataToClipboard() 230 | { 231 | if (GUILayout.Button(new GUIContent("Copy To Clipboard", "Copies this spline to the inspector"))) 232 | { 233 | _copyAndPasteSplineData = _spline; 234 | } 235 | } 236 | 237 | private void DrawPasteSplineDataToClipboard() 238 | { 239 | using (new EditorGUI.DisabledGroupScope(_copyAndPasteSplineData == null)) 240 | { 241 | if (GUILayout.Button(new GUIContent("Paste From Clipboard", "Copies this spline to the inspector"))) 242 | { 243 | Undo.RecordObject(_spline, "Paste spline"); 244 | 245 | EditorUtility.CopySerialized(_copyAndPasteSplineData, _spline); 246 | } 247 | } 248 | } 249 | 250 | private void DrawResetSplineData() 251 | { 252 | if (GUILayout.Button(new GUIContent("Reset", "Resets the spline back to its starting values"))) 253 | { 254 | Undo.RecordObject(_spline, "Reset spline"); 255 | 256 | _spline.Reset(); 257 | } 258 | } 259 | 260 | private void DrawKnotPosition(Knot knot) 261 | { 262 | // Draw Position 263 | using (var changeCheck = new EditorGUI.ChangeCheckScope()) 264 | { 265 | knot.position = EditorGUILayout.Vector3Field("Position", knot.position); 266 | 267 | if (changeCheck.changed) 268 | { 269 | Undo.RecordObject(_spline, "Edit Bezier Point"); 270 | 271 | _spline.SetKnot(CurveEditorState.SelectedKnotIndex, knot); 272 | 273 | SplineUpdated?.Invoke(_spline); 274 | SceneView.RepaintAll(); 275 | } 276 | } 277 | } 278 | 279 | private void DrawKnotOrientationToggle(Knot knot) 280 | { 281 | using (var changeCheck = new EditorGUI.ChangeCheckScope()) 282 | { 283 | EditorGUILayout.BeginHorizontal(); 284 | EditorGUILayout.PrefixLabel(new GUIContent("Uses Orientation Anchor")); 285 | var isUsingOrientation = GUILayout.Toggle(knot.IsUsingRotation, string.Empty); 286 | EditorGUILayout.EndHorizontal(); 287 | 288 | if (changeCheck.changed) 289 | { 290 | Undo.RecordObject(_spline, "Toggle Bezier Orientation Anchor"); 291 | 292 | knot.rotation = !knot.IsUsingRotation ? (Quaternion?)Quaternion.identity : null; 293 | _spline.SetKnot(CurveEditorState.SelectedKnotIndex, knot); 294 | 295 | SplineUpdated?.Invoke(_spline); 296 | SceneView.RepaintAll(); 297 | } 298 | } 299 | } 300 | 301 | private void DrawKnotOrientationValue(Knot knot) 302 | { 303 | if (knot.IsUsingRotation) 304 | { 305 | using (var changeCheck = new EditorGUI.ChangeCheckScope()) 306 | { 307 | var orientationEuler = knot.rotation.Value.eulerAngles; 308 | orientationEuler = EditorGUILayout.Vector3Field("Orientation", orientationEuler); 309 | 310 | if (changeCheck.changed) 311 | { 312 | Undo.RecordObject(_spline, "Modify Knot Rotaton"); 313 | 314 | knot.rotation = Quaternion.Euler(orientationEuler); 315 | _spline.SetKnot(CurveEditorState.SelectedKnotIndex, knot); 316 | 317 | SceneView.RepaintAll(); 318 | } 319 | } 320 | } 321 | } 322 | 323 | private void DrawKnotAutoHandleToggle(Knot knot) 324 | { 325 | using (var changeCheck = new EditorGUI.ChangeCheckScope()) 326 | { 327 | EditorGUILayout.BeginHorizontal(); 328 | EditorGUILayout.PrefixLabel(new GUIContent("Uses Auto Handles")); 329 | var isUsingAutoHandles = GUILayout.Toggle(knot.IsUsingAutoHandles, string.Empty); 330 | EditorGUILayout.EndHorizontal(); 331 | 332 | if (changeCheck.changed) 333 | { 334 | Undo.RecordObject(_spline, "Toggle Bezier Auto Handles"); 335 | 336 | knot.auto = isUsingAutoHandles ? 0.33f : 0f; 337 | _spline.SetKnot(CurveEditorState.SelectedKnotIndex, knot); 338 | 339 | SplineUpdated?.Invoke(_spline); 340 | SceneView.RepaintAll(); 341 | } 342 | } 343 | } 344 | 345 | private void DrawKnotAutoHandleValue(Knot knot) 346 | { 347 | // Auto-Handles Distance 348 | using (var changeCheck = new EditorGUI.ChangeCheckScope()) 349 | { 350 | knot.auto = EditorGUILayout.FloatField("Distance", knot.auto); 351 | 352 | if (changeCheck.changed) 353 | { 354 | Undo.RecordObject(_spline, "Edit Bezier Point"); 355 | 356 | _spline.SetKnot(CurveEditorState.SelectedKnotIndex, knot); 357 | 358 | SplineUpdated?.Invoke(_spline); 359 | SceneView.RepaintAll(); 360 | } 361 | } 362 | } 363 | 364 | private void DrawKnotHandleValues(Knot knot) 365 | { 366 | // In-Handle 367 | using (var changeCheck = new EditorGUI.ChangeCheckScope()) 368 | { 369 | knot.handleIn = EditorGUILayout.Vector3Field("Handle in", knot.handleIn); 370 | 371 | if (changeCheck.changed) 372 | { 373 | Undo.RecordObject(_spline, "Edit Bezier Handle"); 374 | 375 | if (CurvePreferences.ShouldMirrorHandleMovement) 376 | { 377 | knot.handleOut = -knot.handleIn; 378 | } 379 | _spline.SetKnot(CurveEditorState.SelectedKnotIndex, knot); 380 | 381 | SplineUpdated?.Invoke(_spline); 382 | SceneView.RepaintAll(); 383 | } 384 | } 385 | 386 | // Out-Handle 387 | using (var changeCheck = new EditorGUI.ChangeCheckScope()) 388 | { 389 | knot.handleOut = EditorGUILayout.Vector3Field("Handle out", knot.handleOut); 390 | 391 | if (changeCheck.changed) 392 | { 393 | Undo.RecordObject(_spline, "Edit Bezier Handle"); 394 | 395 | if (CurvePreferences.ShouldMirrorHandleMovement) 396 | { 397 | knot.handleIn = -knot.handleOut; 398 | } 399 | _spline.SetKnot(CurveEditorState.SelectedKnotIndex, knot); 400 | 401 | SplineUpdated?.Invoke(_spline); 402 | SceneView.RepaintAll(); 403 | } 404 | } 405 | } 406 | } 407 | } 408 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Inspectors/Bezier3DSplineDataInspector.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ae5a321944a38fc4d8fc9f3397a0ab14 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Inspectors/Bezier3DSplineInspector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEditor; 3 | 4 | namespace JCMG.Curves.Editor 5 | { 6 | [CustomEditor(typeof(Bezier3DSpline))] 7 | public sealed class Bezier3DSplineInspector : UnityEditor.Editor 8 | { 9 | #pragma warning disable 0649 10 | public event Action SplineUpdated; 11 | #pragma warning restore 0649 12 | 13 | private Bezier3DSpline _spline; 14 | private Bezier3DSplineDataInspector _splineDataEditor; 15 | 16 | private void OnEnable() 17 | { 18 | CurveEditorState.Reset(); 19 | 20 | _spline = (Bezier3DSpline)target; 21 | 22 | _splineDataEditor = (Bezier3DSplineDataInspector)CreateEditor(_spline.SplineData, typeof(Bezier3DSplineDataInspector)); 23 | _splineDataEditor.ShouldDrawSceneGUI = false; 24 | } 25 | 26 | private void OnDisable() 27 | { 28 | _splineDataEditor.OnDisable(); 29 | 30 | DestroyImmediate(_splineDataEditor); 31 | } 32 | 33 | public override void OnInspectorGUI() 34 | { 35 | _spline = (Bezier3DSpline)target; 36 | 37 | _splineDataEditor.OnInspectorGUI(); 38 | } 39 | 40 | private void OnSceneGUI() 41 | { 42 | HotkeyTools.CheckGeneralHotkeys(_spline, SplineUpdated); 43 | 44 | SceneGUITools.DrawCurveLinesHandles(_spline, _spline.transform); 45 | SceneGUITools.DrawSceneScreenUI(); 46 | 47 | ValidateSelected(); 48 | 49 | SceneGUITools.DrawUnselectedKnots(_spline, this, _spline.transform); 50 | 51 | if (CurvePreferences.ShouldVisualizeRotation) 52 | { 53 | SceneGUITools.DrawCurveOrientations(_spline); 54 | } 55 | 56 | if (CurveEditorState.HasKnotSelected) 57 | { 58 | if (CurveEditorState.HasSingleKnotSelected) 59 | { 60 | SceneGUITools.DrawSelectedSplitters(_spline.SplineData, SplineUpdated, _spline.transform); 61 | SceneGUITools.DrawSelectedKnot(_spline.SplineData, SplineUpdated, this, _spline.transform); 62 | 63 | // Hotkeys 64 | HotkeyTools.CheckSelectedKnotHotkeys(_spline, SplineUpdated); 65 | } 66 | else 67 | { 68 | SceneGUITools.DrawMultiSelect(_spline, this, _spline.transform); 69 | } 70 | } 71 | } 72 | 73 | private void ValidateSelected() 74 | { 75 | if (CurveEditorState.ValidateSelectedKnotIsValid(_spline)) 76 | { 77 | CurveEditorState.ClearKnotSelection(); 78 | 79 | Repaint(); 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Inspectors/Bezier3DSplineInspector.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f6a91a7f55c3e474c94806960b2d7a6c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/JCMG.Curves.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "JCMG.Curves.Editor", 3 | "references": [ 4 | "GUID:466f8dfa7a6bcc34f8b53de55b1bbd94" 5 | ], 6 | "includePlatforms": [ 7 | "Editor" 8 | ], 9 | "excludePlatforms": [], 10 | "allowUnsafeCode": false, 11 | "overrideReferences": false, 12 | "precompiledReferences": [], 13 | "autoReferenced": true, 14 | "defineConstraints": [], 15 | "versionDefines": [], 16 | "noEngineReferences": false 17 | } -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/JCMG.Curves.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 269e8f16c3ed16f4bb6f3a3fcdcfd27a 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/MenuItems.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace JCMG.Curves.Editor 5 | { 6 | /// 7 | /// Menu items for the curves library. 8 | /// 9 | internal static class MenuItems 10 | { 11 | [MenuItem("GameObject/JCMG/Curves/Bezier3DSpline", false, 10)] 12 | internal static void CreateBezierSpline() 13 | { 14 | var obj = new GameObject("Bezier3DSpline").AddComponent(); 15 | 16 | Selection.objects = new Object[] 17 | { 18 | obj.gameObject 19 | }; 20 | 21 | EditorGUIUtility.PingObject(obj.gameObject); 22 | } 23 | 24 | [MenuItem("Tools/JCMG/Curves/Submit bug or feature request")] 25 | internal static void OpenURLToGitHubIssuesSection() 26 | { 27 | const string GITHUB_ISSUES_URL = "https://github.com/jeffcampbellmakesgames/unity-curves/issues"; 28 | 29 | Application.OpenURL(GITHUB_ISSUES_URL); 30 | } 31 | 32 | [MenuItem("Tools/JCMG/Curves/Donate to support development")] 33 | internal static void OpenURLToKoFi() 34 | { 35 | const string KOFI_URL = "https://ko-fi.com/stampyturtle"; 36 | 37 | Application.OpenURL(KOFI_URL); 38 | } 39 | 40 | [MenuItem("Tools/JCMG/Curves/About")] 41 | internal static void OpenAboutModalDialog() 42 | { 43 | AboutWindow.View(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/MenuItems.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0257aac608e7e8a418a91b92dc089f91 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/ObjectPreviews.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c8c9fe547a1676240bacdcc8ef2c8af1 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/ObjectPreviews/Base3DSplineDataPreview.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace JCMG.Curves.Editor 5 | { 6 | internal abstract class Base3DSplineDataPreview : ObjectPreview 7 | { 8 | public sealed override GUIContent GetPreviewTitle() 9 | { 10 | return new GUIContent("Properties"); 11 | } 12 | 13 | public sealed override bool HasPreviewGUI() 14 | { 15 | return true; 16 | } 17 | 18 | protected void DrawProperty(ref Rect labelRect, ref Rect valueRect, string label, string value) 19 | { 20 | EditorGUI.LabelField(labelRect, label, CurveEditorStyles.LabelStyle); 21 | EditorGUI.LabelField(valueRect, value); 22 | 23 | labelRect.y += EditorGUIUtility.singleLineHeight; 24 | valueRect.y += EditorGUIUtility.singleLineHeight; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/ObjectPreviews/Base3DSplineDataPreview.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bf6cc90050e110f4b80cd668aa242fee 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/ObjectPreviews/Bezier3DSplineDataPreview.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace JCMG.Curves.Editor 5 | { 6 | [CustomPreview(typeof(Bezier3DSplineData))] 7 | internal sealed class Bezier3DSplineDataPreview : Base3DSplineDataPreview 8 | { 9 | public override void OnPreviewGUI(Rect rect, GUIStyle background) 10 | { 11 | if (Event.current.type != EventType.Repaint) 12 | { 13 | return; 14 | } 15 | 16 | var spline = (Bezier3DSplineData)target; 17 | 18 | var rectOffset = new RectOffset( 19 | -5, 20 | -5, 21 | -5, 22 | -5); 23 | rect = rectOffset.Add(rect); 24 | 25 | var position1 = rect; 26 | position1.width = 110f; 27 | 28 | var position2 = rect; 29 | position2.xMin += 110f; 30 | position2.width = 110f; 31 | 32 | EditorGUI.LabelField(position1, "Property", CurveEditorStyles.HeaderStyle); 33 | EditorGUI.LabelField(position2, "Value", CurveEditorStyles.HeaderStyle); 34 | 35 | position1.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; 36 | position2.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; 37 | 38 | DrawProperty( 39 | ref position1, 40 | ref position2, 41 | "Point Count", 42 | spline.KnotCount.ToString()); 43 | DrawProperty( 44 | ref position1, 45 | ref position2, 46 | "Total Length", 47 | spline.TotalLength.ToString("F")); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/ObjectPreviews/Bezier3DSplineDataPreview.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1dc0e165b70675e40a6a6809273a51af 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/ObjectPreviews/Bezier3DSplinePreview.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace JCMG.Curves.Editor 5 | { 6 | [CustomPreview(typeof(Bezier3DSpline))] 7 | internal sealed class Bezier3DSplinePreview : Base3DSplineDataPreview 8 | { 9 | public override void OnPreviewGUI(Rect rect, GUIStyle background) 10 | { 11 | if (Event.current.type != EventType.Repaint) 12 | { 13 | return; 14 | } 15 | 16 | var spline = (Bezier3DSpline)target; 17 | 18 | var rectOffset = new RectOffset( 19 | -5, 20 | -5, 21 | -5, 22 | -5); 23 | rect = rectOffset.Add(rect); 24 | 25 | var position1 = rect; 26 | position1.width = 110f; 27 | 28 | var position2 = rect; 29 | position2.xMin += 110f; 30 | position2.width = 110f; 31 | 32 | EditorGUI.LabelField(position1, "Property", CurveEditorStyles.HeaderStyle); 33 | EditorGUI.LabelField(position2, "Value", CurveEditorStyles.HeaderStyle); 34 | 35 | position1.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; 36 | position2.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; 37 | 38 | DrawProperty( 39 | ref position1, 40 | ref position2, 41 | "Point Count", 42 | spline.KnotCount.ToString()); 43 | 44 | DrawProperty( 45 | ref position1, 46 | ref position2, 47 | "Total Length", 48 | spline.TotalLength.ToString("F")); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/ObjectPreviews/Bezier3DSplinePreview.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0c865634102966c46ac55ec636acbc9c 3 | timeCreated: 1503151146 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/SceneGUIConstants.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace JCMG.Curves.Editor 4 | { 5 | internal static class SceneGUIConstants 6 | { 7 | // TODO some of these seem like they could be preferences. 8 | public static float HandleSize { get; } 9 | 10 | public static Vector2 GUIOffset { get; } 11 | 12 | static SceneGUIConstants() 13 | { 14 | HandleSize = 0.1f; 15 | GUIOffset = new Vector2(10, 10); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/SceneGUIConstants.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a844dcaf435956a46a661512edbf0360 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Tools.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e52e66c8227afd341bddd96f63525910 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Tools/HotkeyTools.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEditor; 3 | using UnityEngine; 4 | 5 | namespace JCMG.Curves.Editor 6 | { 7 | internal static class HotkeyTools 8 | { 9 | private const string UNDO_REDO_PERFORMED = "UndoRedoPerformed"; 10 | 11 | public static void CheckGeneralHotkeys( 12 | IBezier3DSplineData splineData, 13 | Action onUpdateSpline) 14 | { 15 | var evt = Event.current; 16 | switch (evt.type) 17 | { 18 | // Undo Last Command 19 | case EventType.ValidateCommand: 20 | if (evt.commandName == UNDO_REDO_PERFORMED) 21 | { 22 | onUpdateSpline?.Invoke(splineData); 23 | } 24 | break; 25 | 26 | // Flip Spline 27 | case EventType.KeyDown: 28 | if (evt.keyCode == KeyCode.I) 29 | { 30 | if ((evt.modifiers & (EventModifiers.Control | EventModifiers.Command)) != 0) 31 | { 32 | splineData.Flip(); 33 | } 34 | } 35 | break; 36 | } 37 | } 38 | 39 | public static void CheckSelectedKnotHotkeys( 40 | IBezier3DSplineData splineData, 41 | Action onUpdateSpline) 42 | { 43 | var evt = Event.current; 44 | switch (evt.type) 45 | { 46 | case EventType.KeyDown: 47 | // Delete Selected Knot 48 | if (evt.keyCode == KeyCode.Delete) 49 | { 50 | if (splineData.KnotCount > 2) 51 | { 52 | Undo.RecordObject((UnityEngine.Object)splineData, "Remove Bezier Point"); 53 | splineData.RemoveKnot(CurveEditorState.SelectedKnotIndex); 54 | 55 | CurveEditorState.ClearKnotSelection(); 56 | 57 | onUpdateSpline?.Invoke(splineData); 58 | } 59 | 60 | evt.Use(); 61 | } 62 | 63 | // Focus Selected Knot 64 | if (evt.keyCode == KeyCode.F) 65 | { 66 | var dist = splineData.GetSplineDistanceForKnotIndex(CurveEditorState.SelectedKnotIndex); 67 | var pos = splineData.GetPosition(dist); 68 | 69 | SceneView.lastActiveSceneView.Frame(new Bounds(pos, Vector3.one * 5f), false); 70 | 71 | evt.Use(); 72 | } 73 | 74 | // Clear Knot Selection 75 | if (evt.keyCode == KeyCode.Escape) 76 | { 77 | CurveEditorState.ClearKnotSelection(); 78 | evt.Use(); 79 | } 80 | 81 | break; 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Tools/HotkeyTools.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 02623d97de819cf4b924a82e32b13f7b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Tools/SceneGUITools.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEditor; 3 | using UnityEngine; 4 | 5 | namespace JCMG.Curves.Editor 6 | { 7 | /// 8 | /// Helper methods for drawing in the scene 9 | /// 10 | public static class SceneGUITools 11 | { 12 | public static void DrawCurveLinesHandles(IBezier3DSplineData splineData, Transform transform = null) 13 | { 14 | Handles.color = Color.yellow; 15 | 16 | //Loop through each curve in spline 17 | var segments = splineData.InterpolationStepsPerCurve; 18 | var spacing = 1f / segments; 19 | for (var i = 0; i < splineData.CurveCount; i++) 20 | { 21 | var curve = splineData.GetCurve(i); 22 | 23 | //Get curve in world space 24 | Vector3 a, b, c, d; 25 | 26 | if (transform != null) 27 | { 28 | a = transform.TransformPoint(curve.StartPoint); 29 | b = transform.TransformPoint(curve.FirstHandle + curve.StartPoint); 30 | c = transform.TransformPoint(curve.SecondHandle + curve.EndPoint); 31 | d = transform.TransformPoint(curve.EndPoint); 32 | } 33 | else 34 | { 35 | a = curve.StartPoint; 36 | b = curve.FirstHandle + curve.StartPoint; 37 | c = curve.SecondHandle + curve.EndPoint; 38 | d = curve.EndPoint; 39 | } 40 | 41 | var prev = Bezier3DCurve.GetPoint( 42 | a, 43 | b, 44 | c, 45 | d, 46 | 0f); 47 | 48 | for (var k = 0; k <= segments; k++) 49 | { 50 | var cur = Bezier3DCurve.GetPoint( 51 | a, 52 | b, 53 | c, 54 | d, 55 | k * spacing); 56 | Handles.DrawLine(prev, cur); 57 | prev = cur; 58 | } 59 | } 60 | } 61 | 62 | public static void DrawCurveOrientations(IBezier3DSplineData splineData) 63 | { 64 | var sceneViewCameraPosition = SceneView.lastActiveSceneView.camera.transform.position; 65 | var maxViewDistance = CurvePreferences.MaximumViewDistance; 66 | 67 | for (var dist = 0f; dist < splineData.TotalLength; dist += 1) 68 | { 69 | var point = splineData.GetPosition(dist); 70 | 71 | if (Vector3.Distance(sceneViewCameraPosition, point) > maxViewDistance) 72 | { 73 | continue; 74 | } 75 | 76 | // Draw Up Vector 77 | var up = splineData.GetUp(dist); 78 | Handles.color = Handles.yAxisColor; 79 | Handles.DrawLine(point, point + up); 80 | 81 | // Draw Forward Vector 82 | var forward = splineData.GetForward(dist); 83 | Handles.color = Handles.zAxisColor; 84 | Handles.DrawLine(point, point + forward); 85 | 86 | // Draw Right Vector 87 | var right = splineData.GetRight(dist); 88 | Handles.color = Handles.xAxisColor; 89 | Handles.DrawLine(point, point + right); 90 | } 91 | } 92 | 93 | public static void DrawSelectedKnot( 94 | Bezier3DSplineData splineData, 95 | Action onUpdateSpline, 96 | UnityEditor.Editor editorWindow, 97 | Transform transform = null) 98 | { 99 | var knot = splineData.GetKnot(CurveEditorState.SelectedKnotIndex); 100 | Handles.color = Color.green; 101 | 102 | var knotWorldPos = transform == null 103 | ? knot.position 104 | : transform.TransformPoint(knot.position); 105 | 106 | if (knot.rotation.HasValue) 107 | { 108 | Handles.color = Handles.yAxisColor; 109 | var rot = knot.rotation.Value; 110 | Handles.ArrowHandleCap( 111 | 0, 112 | knotWorldPos, 113 | rot * Quaternion.AngleAxis(90, Vector3.left), 114 | 0.15f, 115 | EventType.Repaint); 116 | } 117 | 118 | if (Tools.current == Tool.Move) 119 | { 120 | //Position handle 121 | using (var changeCheck = new EditorGUI.ChangeCheckScope()) 122 | { 123 | knotWorldPos = Handles.PositionHandle(knotWorldPos, Tools.handleRotation); 124 | 125 | if (changeCheck.changed) 126 | { 127 | Undo.RecordObject(splineData, "Edit Bezier Point"); 128 | knot.position = transform == null ? knotWorldPos : transform.InverseTransformPoint(knotWorldPos); 129 | splineData.SetKnot(CurveEditorState.SelectedKnotIndex, knot); 130 | onUpdateSpline?.Invoke(splineData); 131 | editorWindow.Repaint(); 132 | } 133 | } 134 | 135 | Handles.color = Color.white; 136 | 137 | //In Handle 138 | if (knot.handleIn != Vector3.zero) 139 | { 140 | using (var changeCheck = new EditorGUI.ChangeCheckScope()) 141 | { 142 | var inHandleWorldPos = transform == null 143 | ? knot.position + knot.handleIn 144 | : transform.TransformPoint(knot.position + knot.handleIn); 145 | 146 | inHandleWorldPos = Handles.PositionHandle(inHandleWorldPos, Tools.handleRotation); 147 | 148 | if (changeCheck.changed) 149 | { 150 | Undo.RecordObject(splineData, "Edit Bezier Handle"); 151 | knot.handleIn = transform == null 152 | ? inHandleWorldPos - knot.position 153 | : transform.InverseTransformPoint(inHandleWorldPos) - knot.position; 154 | knot.auto = 0; 155 | if (CurvePreferences.ShouldMirrorHandleMovement) 156 | { 157 | knot.handleOut = -knot.handleIn; 158 | } 159 | 160 | splineData.SetKnot(CurveEditorState.SelectedKnotIndex, knot); 161 | onUpdateSpline?.Invoke(splineData); 162 | editorWindow.Repaint(); 163 | } 164 | 165 | Handles.DrawLine(knotWorldPos, inHandleWorldPos); 166 | } 167 | } 168 | 169 | //outHandle 170 | if (knot.handleOut != Vector3.zero) 171 | { 172 | using (var changeCheck = new EditorGUI.ChangeCheckScope()) 173 | { 174 | var outHandleWorldPos = transform == null 175 | ? knot.position + knot.handleOut 176 | : transform.TransformPoint(knot.position + knot.handleOut); 177 | 178 | outHandleWorldPos = Handles.PositionHandle(outHandleWorldPos, Tools.handleRotation); 179 | 180 | if (changeCheck.changed) 181 | { 182 | Undo.RecordObject(splineData, "Edit Bezier Handle"); 183 | knot.handleOut = transform == null 184 | ? outHandleWorldPos - knot.position 185 | : transform.InverseTransformPoint(outHandleWorldPos) - knot.position; 186 | knot.auto = 0; 187 | if (CurvePreferences.ShouldMirrorHandleMovement) 188 | { 189 | knot.handleIn = -knot.handleOut; 190 | } 191 | 192 | splineData.SetKnot(CurveEditorState.SelectedKnotIndex, knot); 193 | onUpdateSpline?.Invoke(splineData); 194 | editorWindow.Repaint(); 195 | } 196 | 197 | Handles.DrawLine(knotWorldPos, outHandleWorldPos); 198 | } 199 | } 200 | 201 | } 202 | else if (Tools.current == Tool.Rotate) 203 | { 204 | //Rotation handle 205 | using (var changeCheck = new EditorGUI.ChangeCheckScope()) 206 | { 207 | var rot = (knot.rotation.HasValue ? knot.rotation.Value : Quaternion.identity).normalized; 208 | rot = Handles.RotationHandle(rot, knotWorldPos); 209 | if (changeCheck.changed) 210 | { 211 | Undo.RecordObject(splineData, "Edit Bezier Point"); 212 | knot.rotation = rot; 213 | splineData.SetKnot(CurveEditorState.SelectedKnotIndex, knot); 214 | onUpdateSpline?.Invoke(splineData); 215 | editorWindow.Repaint(); 216 | } 217 | } 218 | } 219 | } 220 | 221 | public static void DrawMultiSelect( 222 | IBezier3DSplineData splineData, 223 | UnityEditor.Editor editorWindow, 224 | Transform transform = null) 225 | { 226 | Handles.color = Color.blue; 227 | for (var i = 0; i < CurveEditorState.SelectedKnots.Count; i++) 228 | { 229 | if (Handles.Button( 230 | transform == null 231 | ? splineData.GetKnot(CurveEditorState.SelectedKnots[i]).position 232 | : transform.TransformPoint(splineData.GetKnot(CurveEditorState.SelectedKnots[i]).position), 233 | Camera.current.transform.rotation, 234 | SceneGUIConstants.HandleSize, 235 | SceneGUIConstants.HandleSize, 236 | Handles.CircleHandleCap)) 237 | { 238 | CurveEditorState.SelectKnot(CurveEditorState.SelectedKnots[i], true); 239 | editorWindow.Repaint(); 240 | } 241 | } 242 | 243 | var handlePos = Vector3.zero; 244 | if (Tools.pivotMode == PivotMode.Center) 245 | { 246 | for (var i = 0; i < CurveEditorState.SelectedKnots.Count; i++) 247 | { 248 | handlePos += splineData.GetKnot(CurveEditorState.SelectedKnots[i]).position; 249 | } 250 | 251 | handlePos /= CurveEditorState.SelectedKnots.Count; 252 | } 253 | else 254 | { 255 | handlePos = splineData.GetKnot(CurveEditorState.SelectedKnotIndex).position; 256 | } 257 | 258 | if (transform != null) 259 | { 260 | handlePos = transform.TransformPoint(handlePos); 261 | } 262 | 263 | Handles.PositionHandle(handlePos, Tools.handleRotation); 264 | } 265 | 266 | public static void DrawUnselectedKnots( 267 | IBezier3DSplineData splineData, 268 | UnityEditor.Editor editorWindow, 269 | Transform transform = null) 270 | { 271 | for (var i = 0; i < splineData.KnotCount; i++) 272 | { 273 | if (CurveEditorState.SelectedKnots.Contains(i)) 274 | { 275 | continue; 276 | } 277 | 278 | var knot = splineData.GetKnot(i); 279 | var knotWorldPos = transform == null 280 | ? knot.position 281 | : transform.TransformPoint(knot.position); 282 | 283 | if (knot.rotation.HasValue) 284 | { 285 | Handles.color = Handles.yAxisColor; 286 | var rot = knot.rotation.Value; 287 | Handles.ArrowHandleCap( 288 | 0, 289 | knotWorldPos, 290 | rot * Quaternion.AngleAxis(90, Vector3.left), 291 | 0.15f, 292 | EventType.Repaint); 293 | } 294 | 295 | Handles.color = Color.white; 296 | if (Handles.Button( 297 | knotWorldPos, 298 | Camera.current.transform.rotation, 299 | HandleUtility.GetHandleSize(knotWorldPos) * SceneGUIConstants.HandleSize, 300 | HandleUtility.GetHandleSize(knotWorldPos) * SceneGUIConstants.HandleSize, 301 | Handles.CircleHandleCap)) 302 | { 303 | CurveEditorState.SelectKnot(i, Event.current.control); 304 | editorWindow.Repaint(); 305 | } 306 | } 307 | } 308 | 309 | public static void DrawSelectedSplitters( 310 | Bezier3DSplineData splineData, 311 | Action onUpdateSpline, 312 | Transform transform = null) 313 | { 314 | Handles.color = Color.white; 315 | 316 | //Start add 317 | if (!splineData.IsClosed && CurveEditorState.SelectedKnotIndex == 0) 318 | { 319 | var curve = splineData.GetCurve(0); 320 | var a = transform == null 321 | ? curve.StartPoint 322 | : transform.TransformPoint(curve.StartPoint); 323 | var b = transform == null 324 | ? curve.FirstHandle.normalized * 2f 325 | : transform.TransformDirection(curve.FirstHandle).normalized * 2f; 326 | 327 | var handleScale = HandleUtility.GetHandleSize(a); 328 | b *= handleScale; 329 | Handles.DrawDottedLine(a, a - b, 3f); 330 | if (Handles.Button( 331 | a - b, 332 | Camera.current.transform.rotation, 333 | handleScale * SceneGUIConstants.HandleSize * 0.4f, 334 | handleScale * SceneGUIConstants.HandleSize * 0.4f, 335 | Handles.DotHandleCap)) 336 | { 337 | Undo.RecordObject(splineData, "Add Bezier Point"); 338 | var knot = splineData.GetKnot(CurveEditorState.SelectedKnotIndex); 339 | splineData.InsertKnot( 340 | 0, 341 | new Knot( 342 | curve.StartPoint - curve.FirstHandle.normalized * handleScale * 2, 343 | Vector3.zero, 344 | curve.FirstHandle.normalized * 0.5f, 345 | knot.auto, 346 | knot.rotation)); 347 | onUpdateSpline?.Invoke(splineData); 348 | } 349 | } 350 | 351 | //End add 352 | if (!splineData.IsClosed && CurveEditorState.SelectedKnotIndex == splineData.CurveCount) 353 | { 354 | var curve = splineData.GetCurve(splineData.CurveCount - 1); 355 | var c = transform == null 356 | ? curve.SecondHandle.normalized * 2f 357 | : transform.TransformDirection(curve.SecondHandle).normalized * 2f; 358 | var d = transform == null 359 | ? curve.EndPoint 360 | : transform.TransformPoint(curve.EndPoint); 361 | var handleScale = HandleUtility.GetHandleSize(d); 362 | c *= handleScale; 363 | Handles.DrawDottedLine(d, d - c, 3f); 364 | 365 | if (Handles.Button( 366 | d - c, 367 | Camera.current.transform.rotation, 368 | handleScale * SceneGUIConstants.HandleSize * 0.4f, 369 | handleScale * SceneGUIConstants.HandleSize * 0.4f, 370 | Handles.DotHandleCap)) 371 | { 372 | Undo.RecordObject(splineData, "Add Bezier Point"); 373 | 374 | var knot = splineData.GetKnot(CurveEditorState.SelectedKnotIndex); 375 | splineData.AddKnot( 376 | new Knot( 377 | curve.EndPoint - curve.SecondHandle.normalized * handleScale * 2, 378 | curve.SecondHandle.normalized * 0.5f, 379 | Vector3.zero, 380 | knot.auto, 381 | knot.rotation)); 382 | 383 | CurveEditorState.SelectKnot(splineData.CurveCount, false); 384 | 385 | onUpdateSpline?.Invoke(splineData); 386 | } 387 | } 388 | 389 | // Prev split 390 | if (splineData.IsClosed || CurveEditorState.SelectedKnotIndex != 0) 391 | { 392 | var curve = splineData.GetCurve(CurveEditorState.SelectedKnotIndex == 0 ? splineData.CurveCount - 1 : CurveEditorState.SelectedKnotIndex - 1); 393 | var centerLocal = curve.GetPoint(curve.ConvertDistanceToTime(curve.Length * 0.5f)); 394 | var center = transform == null ? centerLocal : transform.TransformPoint(centerLocal); 395 | 396 | var a = curve.StartPoint + curve.FirstHandle; 397 | var b = curve.SecondHandle + curve.EndPoint; 398 | var ab = (b - a) * 0.3f; 399 | var handleScale = HandleUtility.GetHandleSize(center); 400 | 401 | if (Handles.Button( 402 | center, 403 | Camera.current.transform.rotation, 404 | handleScale * SceneGUIConstants.HandleSize * 0.4f, 405 | handleScale * SceneGUIConstants.HandleSize * 0.4f, 406 | Handles.DotHandleCap)) 407 | { 408 | Undo.RecordObject(splineData, "Add Bezier Point"); 409 | var knot = splineData.GetKnot(CurveEditorState.SelectedKnotIndex); 410 | splineData.InsertKnot( 411 | CurveEditorState.SelectedKnotIndex == 0 ? splineData.CurveCount : CurveEditorState.SelectedKnotIndex, 412 | new Knot( 413 | centerLocal, 414 | -ab, 415 | ab, 416 | knot.auto, 417 | knot.rotation)); 418 | 419 | if (CurveEditorState.SelectedKnotIndex == 0) 420 | { 421 | CurveEditorState.SelectKnot(splineData.CurveCount - 1, false); 422 | } 423 | 424 | onUpdateSpline?.Invoke(splineData); 425 | } 426 | } 427 | 428 | // Next split 429 | if (CurveEditorState.SelectedKnotIndex != splineData.CurveCount) 430 | { 431 | var curve = splineData.GetCurve(CurveEditorState.SelectedKnotIndex); 432 | var centerLocal = curve.GetPoint(curve.ConvertDistanceToTime(curve.Length * 0.5f)); 433 | var center = transform == null ? centerLocal : transform.TransformPoint(centerLocal); 434 | 435 | var a = curve.StartPoint + curve.FirstHandle; 436 | var b = curve.SecondHandle + curve.EndPoint; 437 | var ab = (b - a) * 0.3f; 438 | var handleScale = HandleUtility.GetHandleSize(center); 439 | if (Handles.Button( 440 | center, 441 | Camera.current.transform.rotation, 442 | handleScale * SceneGUIConstants.HandleSize * 0.4f, 443 | handleScale * SceneGUIConstants.HandleSize * 0.4f, 444 | Handles.DotHandleCap)) 445 | { 446 | Undo.RecordObject(splineData, "Add Bezier Point"); 447 | splineData.InsertKnot(CurveEditorState.SelectedKnotIndex + 1, new Knot(centerLocal, -ab, ab)); 448 | CurveEditorState.SelectKnot(CurveEditorState.SelectedKnotIndex + 1, false); 449 | onUpdateSpline?.Invoke(splineData); 450 | } 451 | } 452 | } 453 | 454 | public static void DrawSceneScreenUI() 455 | { 456 | Handles.BeginGUI(); 457 | var defaultColor = GUI.contentColor; 458 | var guiLayoutOptions = new GUILayoutOption[] 459 | { 460 | GUILayout.MaxWidth(50f), 461 | GUILayout.MinWidth(50f), 462 | GUILayout.MinHeight(50f), 463 | GUILayout.MaxHeight(50f) 464 | }; 465 | using (new GUILayout.AreaScope(new Rect(SceneGUIConstants.GUIOffset, new Vector2(125f, 50f)))) 466 | { 467 | using (new GUILayout.HorizontalScope()) 468 | { 469 | GUI.contentColor = CurvePreferences.ShouldMirrorHandleMovement ? Color.green : Color.red; 470 | if (GUILayout.Button(new GUIContent( 471 | (Texture2D)EditorGUIUtility.Load("EchoFilter Icon"), 472 | "Should opposite handles mirror edited handles?"), 473 | guiLayoutOptions)) 474 | { 475 | CurvePreferences.ShouldMirrorHandleMovement = !CurvePreferences.ShouldMirrorHandleMovement; 476 | } 477 | 478 | GUI.contentColor = CurvePreferences.ShouldVisualizeRotation ? Color.white : Color.red; 479 | if (GUILayout.Button(new GUIContent( 480 | (Texture2D)EditorGUIUtility.Load("Transform Icon"), 481 | "Should visualize rotation along spline?"), 482 | guiLayoutOptions)) 483 | { 484 | CurvePreferences.ShouldVisualizeRotation = !CurvePreferences.ShouldVisualizeRotation; 485 | } 486 | } 487 | } 488 | Handles.EndGUI(); 489 | } 490 | } 491 | } 492 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Tools/SceneGUITools.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: feda812df5330644da804507970c2f25 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/VersionConstants.cs: -------------------------------------------------------------------------------- 1 | namespace JCMG.Curves.Editor 2 | { 3 | /// 4 | /// Version info for this library. 5 | /// 6 | internal static class VersionConstants 7 | { 8 | // Version 9 | public const string VERSION = "1.1.1"; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/VersionConstants.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7bed5e8f28933a74fb4ccf1cc036bfaf 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Window.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4ee1d68d1abb9c64aa63225f6ed4b098 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Window/AboutWindow.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace JCMG.Curves.Editor 5 | { 6 | /// 7 | /// A window that shows information about the library and its contributors. 8 | /// 9 | internal sealed class AboutWindow : EditorWindow 10 | { 11 | #pragma warning disable 0649 12 | 13 | [SerializeField] 14 | private Texture2D _socialShareImage; 15 | 16 | [SerializeField] 17 | private Texture2D _portraitImage; 18 | 19 | #pragma warning restore 0649 20 | 21 | private const string WINDOW_TITLE = "JCMG Curves"; 22 | private const string VERSION_LABEL = "Version:"; 23 | private const string GITHUB_LABEL = "GitHub:"; 24 | private const string KOFI_LABEL = "KOFI:"; 25 | private const string TWITTER_LABEL = "Twitter:"; 26 | 27 | private const string GITHUB_URL = "https://github.com/jeffcampbellmakesgames"; 28 | private const string KOFI_URL = "https://ko-fi.com/stampyturtle"; 29 | private const string TWITTER_URL = "https://twitter.com/StampyTurtle"; 30 | 31 | private const string SHARE_MESSAGE = "Hi there! My name is Jeff Campbell and I make open source tools for game " + 32 | "developers.\n\nIf you enjoy using this tool and want to support its development " + 33 | "and other high-quality, free open-source tools, follow me on Twitter, " + 34 | "GitHub, and consider buying me a coffee on Ko-Fi."; 35 | 36 | public static void View() 37 | { 38 | var window = CreateInstance(); 39 | window.minSize = new Vector2(512f, 490f); 40 | window.maxSize = window.minSize; 41 | window.titleContent = new GUIContent(WINDOW_TITLE); 42 | window.position = new Rect( 43 | Screen.currentResolution.width / 2f, 44 | Screen.currentResolution.height / 2f, 45 | 0f, 46 | 0f); 47 | window.ShowUtility(); 48 | } 49 | 50 | private void OnGUI() 51 | { 52 | // JCMG Share Image 53 | if (_socialShareImage != null) 54 | { 55 | GUILayout.Label(_socialShareImage); 56 | 57 | DrawSeparator(); 58 | } 59 | 60 | // COC Version 61 | using (new EditorGUILayout.HorizontalScope()) 62 | { 63 | EditorGUILayout.LabelField(VERSION_LABEL, EditorStyles.boldLabel, GUILayout.Width(75f)); 64 | EditorGUILayout.LabelField(VersionConstants.VERSION); 65 | } 66 | 67 | DrawSeparator(); 68 | 69 | // Share message and portrait 70 | using (new EditorGUILayout.HorizontalScope()) 71 | { 72 | if (_portraitImage != null) 73 | { 74 | GUILayout.Label(_portraitImage, GUILayout.Width(96f), GUILayout.Height(96f)); 75 | } 76 | EditorGUILayout.SelectableLabel(SHARE_MESSAGE, EditorStyles.textArea, GUILayout.Height(96f)); 77 | } 78 | 79 | // Links for Github, KoFi, and Twitter 80 | var originalColor = GUI.contentColor; 81 | 82 | // Twitter 83 | using (new EditorGUILayout.HorizontalScope()) 84 | { 85 | EditorGUILayout.LabelField(TWITTER_LABEL, EditorStyles.boldLabel, GUILayout.Width(75f)); 86 | GUI.contentColor = Color.cyan; 87 | if (GUILayout.Button(TWITTER_URL, GUI.skin.label)) 88 | { 89 | Application.OpenURL(TWITTER_URL); 90 | } 91 | 92 | GUI.contentColor = originalColor; 93 | } 94 | 95 | // Github 96 | using (new EditorGUILayout.HorizontalScope()) 97 | { 98 | EditorGUILayout.LabelField(GITHUB_LABEL, EditorStyles.boldLabel, GUILayout.Width(75f)); 99 | GUI.contentColor = Color.cyan; 100 | if (GUILayout.Button(GITHUB_URL, GUI.skin.label)) 101 | { 102 | Application.OpenURL(GITHUB_URL); 103 | } 104 | GUI.contentColor = originalColor; 105 | } 106 | 107 | // KOFI 108 | using (new EditorGUILayout.HorizontalScope()) 109 | { 110 | EditorGUILayout.LabelField(KOFI_LABEL, EditorStyles.boldLabel, GUILayout.Width(75f)); 111 | GUI.contentColor = Color.cyan; 112 | if (GUILayout.Button(KOFI_URL, GUI.skin.label)) 113 | { 114 | Application.OpenURL(KOFI_URL); 115 | } 116 | 117 | GUI.contentColor = originalColor; 118 | } 119 | } 120 | 121 | private void DrawSeparator() 122 | { 123 | GUILayout.Box(string.Empty, GUILayout.ExpandWidth(true), GUILayout.Height(1)); 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Editor/Window/AboutWindow.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9b1786740535b4e498488c9a45423efe 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: 7 | - m_ViewDataDictionary: {instanceID: 0} 8 | - _socialShareImage: {fileID: 2800000, guid: 682980204b2aea846bee4e8fd6ac2483, type: 3} 9 | - _portraitImage: {fileID: 2800000, guid: 46743cf676633b94bb8e103447c732cf, type: 3} 10 | executionOrder: 0 11 | icon: {instanceID: 0} 12 | userData: 13 | assetBundleName: 14 | assetBundleVariant: 15 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Interfaces.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d10a7d8436e25bb4ea68f3d1c1f126a8 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Interfaces/IBezier3DSplineData.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace JCMG.Curves 3 | { 4 | /// 5 | /// A Bezier 3D spline. 6 | /// 7 | public interface IBezier3DSplineData : IReadOnly3DSplineData 8 | { 9 | // Settings 10 | void SetStepsPerCurve(int stepCount); 11 | void SetClosed(bool isClosed); 12 | 13 | // Actions 14 | void Flip(); 15 | 16 | // Curve 17 | Bezier3DCurve GetCurve(int index); 18 | Bezier3DCurve GetCurveIndexTime(float splineDist, out int index, out float curveTime); 19 | void GetCurveIndicesForKnot(int knotIndex, out int preCurveIndex, out int postCurveIndex); 20 | 21 | // Knot 22 | void InsertKnot(int index, Knot knot); 23 | void RemoveKnot(int index); 24 | void SetKnot(int index, Knot knot); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Interfaces/IBezier3DSplineData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3d0c5d716c4067742b47ce276192a2da 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Interfaces/IReadOnly3DSplineData.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace JCMG.Curves 4 | { 5 | /// 6 | /// A read-only 3D-spline 7 | /// 8 | public interface IReadOnly3DSplineData 9 | { 10 | // Properties 11 | bool IsClosed { get; } 12 | int InterpolationStepsPerCurve { get; } 13 | int CurveCount { get; } 14 | int KnotCount { get; } 15 | float TotalLength { get; } 16 | 17 | // Helper 18 | float GetNormalizedValueForSplineDistance(float splineDistance); 19 | float GetCurveDistanceForSplineDistance(float splineDistance); 20 | float GetSplineDistanceForKnotIndex(int index); 21 | float GetSplineDistanceForCurveIndex(int index); 22 | float GetSplineDistanceForNormalizedValue(float value); 23 | 24 | // Orientation 25 | Quaternion GetRotation(float splineDistance); 26 | Quaternion GetRotationFast(float splineDistance); 27 | Quaternion GetNormalizedRotation(float value); 28 | 29 | // Position 30 | Vector3 GetPosition(float splineDistance); 31 | Vector3 GetNormalizedPosition(float value); 32 | 33 | // Direction 34 | Vector3 GetUp(float splineDistance); 35 | Vector3 GetLeft(float splineDistance); 36 | Vector3 GetRight(float splineDistance); 37 | Vector3 GetForward(float splineDistance); 38 | Vector3 GetForwardFast(float splineDistance); 39 | 40 | // Knot 41 | void AddKnot(Knot knot); 42 | Knot GetKnot(int index); 43 | void GetKnotIndicesForKnot(int knotIndex, out int preKnotIndex, out int postKnotIndex); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Interfaces/IReadOnly3DSplineData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 016cc8fc557b4e64ab4b5c2b12c5de3d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/JCMG.Curves.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "JCMG.Curves" 3 | } 4 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/JCMG.Curves.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 466f8dfa7a6bcc34f8b53de55b1bbd94 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/ScriptableObjects.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ceeaeda0ce5214242bb22e80a259bc2a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/ScriptableObjects/Bezier3DSplineData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d1ae1d2d83c13f8419ed3ac9e3124a9e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {fileID: 2800000, guid: c5c32b6c450791943b0b231a833c00b6, type: 3} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Tools.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4af500f8c0ce5f24e9044eed552122db 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Tools/SceneGUITools.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace JCMG.Curves 4 | { 5 | /// 6 | /// Helper methods for drawing in the scene 7 | /// 8 | public static class SceneGUITools 9 | { 10 | public static void DrawCurveLinesGizmos(IBezier3DSplineData splineData, Transform transform = null) 11 | { 12 | Gizmos.color = Color.white; 13 | 14 | //Loop through each curve in spline 15 | var segments = splineData.InterpolationStepsPerCurve; 16 | var spacing = 1f / segments; 17 | for (var i = 0; i < splineData.CurveCount; i++) 18 | { 19 | var curve = splineData.GetCurve(i); 20 | 21 | //Get curve in world space 22 | Vector3 a, b, c, d; 23 | 24 | if (transform != null) 25 | { 26 | a = transform.TransformPoint(curve.StartPoint); 27 | b = transform.TransformPoint(curve.FirstHandle + curve.StartPoint); 28 | c = transform.TransformPoint(curve.SecondHandle + curve.EndPoint); 29 | d = transform.TransformPoint(curve.EndPoint); 30 | } 31 | else 32 | { 33 | a = curve.StartPoint; 34 | b = curve.FirstHandle + curve.StartPoint; 35 | c = curve.SecondHandle + curve.EndPoint; 36 | d = curve.EndPoint; 37 | } 38 | 39 | var prev = Bezier3DCurve.GetPoint( 40 | a, 41 | b, 42 | c, 43 | d, 44 | 0f); 45 | 46 | for (var k = 0; k <= segments; k++) 47 | { 48 | var cur = Bezier3DCurve.GetPoint( 49 | a, 50 | b, 51 | c, 52 | d, 53 | k * spacing); 54 | Gizmos.DrawLine(prev, cur); 55 | prev = cur; 56 | } 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Unity/Assets/JCMG/Curves/Scripts/Tools/SceneGUITools.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 677a367687bfeda49801913ec18d9363 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Unity/Assets/PackageManifest.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 78c74eda01c7c214b922293bb49f87fd 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/PackageManifest/Generated.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 10952e9f644a447498cf7be784377982 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/PackageManifest/Generated/7321978f-bf2f-4983-8a03-e0b53e9137d6.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 87e67c7d57c124040b428fffc03dbc57 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/Assets/PackageManifest/Generated/7321978f-bf2f-4983-8a03-e0b53e9137d6/package.json: -------------------------------------------------------------------------------- 1 | {"name":"com.jeffcampbellmakesgames.curves","displayName":"JCMG Curves","version":"1.1.1","unity":"2019.3","description":"JCMG Curves is a 3D Bezier curve library focused on ease of use in both its API and Unity Editor integration.","keywords":["Curve","Curves"],"category":""} -------------------------------------------------------------------------------- /Unity/Assets/PackageManifest/Generated/7321978f-bf2f-4983-8a03-e0b53e9137d6/package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 15dd5b8a156150e47953a6e3f4adbec5 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Unity/Assets/PackageManifest/PackageManifestConfig.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: a29f67b488b4458983fd973bbda8c8fa, type: 3} 13 | m_Name: PackageManifestConfig 14 | m_EditorClassIdentifier: 15 | packageSourcePaths: 16 | - Assets/JCMG 17 | packageIgnorePaths: [] 18 | packageDestinationPath: ../../unity-curves-release 19 | legacyPackageDestinationPath: ../Builds 20 | packageName: com.jeffcampbellmakesgames.curves 21 | displayName: JCMG Curves 22 | packageVersion: 1.1.1 23 | unityVersion: 2019.3 24 | description: JCMG Curves is a 3D Bezier curve library focused on ease of use in 25 | both its API and Unity Editor integration. 26 | category: 27 | keywords: 28 | - Curve 29 | - Curves 30 | dependencies: [] 31 | _id: 7321978f-bf2f-4983-8a03-e0b53e9137d6 32 | -------------------------------------------------------------------------------- /Unity/Assets/PackageManifest/PackageManifestConfig.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e5d74438a60135a4a8a911eb84cbdce8 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Unity/JCMG.Curves.Editor.csproj.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True 4 | True 5 | True 6 | True 7 | True -------------------------------------------------------------------------------- /Unity/JCMG.Curves.csproj.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True 4 | True 5 | True 6 | True 7 | True 8 | True -------------------------------------------------------------------------------- /Unity/Packages/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "com.jeffcampbellmakesgames.packagetools": "https://github.com/jeffcampbellmakesgames/unity-package-tools.git#release/stable", 4 | "com.unity.ext.nunit": "1.0.0", 5 | "com.unity.ide.rider": "1.1.4", 6 | "com.unity.ide.vscode": "1.1.4", 7 | "com.unity.test-framework": "1.1.9", 8 | "com.unity.textmeshpro": "2.0.1", 9 | "com.unity.ugui": "1.0.0", 10 | "com.unity.modules.ai": "1.0.0", 11 | "com.unity.modules.androidjni": "1.0.0", 12 | "com.unity.modules.animation": "1.0.0", 13 | "com.unity.modules.assetbundle": "1.0.0", 14 | "com.unity.modules.audio": "1.0.0", 15 | "com.unity.modules.cloth": "1.0.0", 16 | "com.unity.modules.director": "1.0.0", 17 | "com.unity.modules.imageconversion": "1.0.0", 18 | "com.unity.modules.imgui": "1.0.0", 19 | "com.unity.modules.jsonserialize": "1.0.0", 20 | "com.unity.modules.particlesystem": "1.0.0", 21 | "com.unity.modules.physics": "1.0.0", 22 | "com.unity.modules.physics2d": "1.0.0", 23 | "com.unity.modules.screencapture": "1.0.0", 24 | "com.unity.modules.terrain": "1.0.0", 25 | "com.unity.modules.terrainphysics": "1.0.0", 26 | "com.unity.modules.tilemap": "1.0.0", 27 | "com.unity.modules.ui": "1.0.0", 28 | "com.unity.modules.uielements": "1.0.0", 29 | "com.unity.modules.umbra": "1.0.0", 30 | "com.unity.modules.unityanalytics": "1.0.0", 31 | "com.unity.modules.unitywebrequest": "1.0.0", 32 | "com.unity.modules.unitywebrequestassetbundle": "1.0.0", 33 | "com.unity.modules.unitywebrequestaudio": "1.0.0", 34 | "com.unity.modules.unitywebrequesttexture": "1.0.0", 35 | "com.unity.modules.unitywebrequestwww": "1.0.0", 36 | "com.unity.modules.vehicles": "1.0.0", 37 | "com.unity.modules.video": "1.0.0", 38 | "com.unity.modules.vr": "1.0.0", 39 | "com.unity.modules.wind": "1.0.0", 40 | "com.unity.modules.xr": "1.0.0" 41 | }, 42 | "lock": { 43 | "com.jeffcampbellmakesgames.packagetools": { 44 | "revision": "release/stable", 45 | "hash": "feaded99c976be564b7e52d2a47fed249e94bddd" 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Unity/ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!11 &1 4 | AudioManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Volume: 1 8 | Rolloff Scale: 1 9 | Doppler Factor: 1 10 | Default Speaker Mode: 2 11 | m_SampleRate: 0 12 | m_DSPBufferSize: 1024 13 | m_VirtualVoiceCount: 512 14 | m_RealVoiceCount: 32 15 | m_SpatializerPlugin: 16 | m_AmbisonicDecoderPlugin: 17 | m_DisableAudio: 0 18 | m_VirtualizeEffects: 1 19 | m_RequestedDSPBufferSize: 1024 20 | -------------------------------------------------------------------------------- /Unity/ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!236 &1 4 | ClusterInputManager: 5 | m_ObjectHideFlags: 0 6 | m_Inputs: [] 7 | -------------------------------------------------------------------------------- /Unity/ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!55 &1 4 | PhysicsManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 11 7 | m_Gravity: {x: 0, y: -9.81, z: 0} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_BounceThreshold: 2 10 | m_SleepThreshold: 0.005 11 | m_DefaultContactOffset: 0.01 12 | m_DefaultSolverIterations: 6 13 | m_DefaultSolverVelocityIterations: 1 14 | m_QueriesHitBackfaces: 0 15 | m_QueriesHitTriggers: 1 16 | m_EnableAdaptiveForce: 0 17 | m_ClothInterCollisionDistance: 0 18 | m_ClothInterCollisionStiffness: 0 19 | m_ContactsGeneration: 1 20 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 21 | m_AutoSimulation: 1 22 | m_AutoSyncTransforms: 0 23 | m_ReuseCollisionCallbacks: 1 24 | m_ClothInterCollisionSettingsToggle: 0 25 | m_ContactPairsMode: 0 26 | m_BroadphaseType: 0 27 | m_WorldBounds: 28 | m_Center: {x: 0, y: 0, z: 0} 29 | m_Extent: {x: 250, y: 250, z: 250} 30 | m_WorldSubdivisions: 8 31 | m_FrictionType: 0 32 | m_EnableEnhancedDeterminism: 0 33 | m_EnableUnifiedHeightmaps: 1 34 | m_DefaultMaxAngluarSpeed: 7 35 | -------------------------------------------------------------------------------- /Unity/ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1045 &1 4 | EditorBuildSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Scenes: [] 8 | m_configObjects: {} 9 | -------------------------------------------------------------------------------- /Unity/ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!159 &1 4 | EditorSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 9 7 | m_ExternalVersionControlSupport: Hidden Meta Files 8 | m_SerializationMode: 2 9 | m_LineEndingsForNewScripts: 2 10 | m_DefaultBehaviorMode: 0 11 | m_PrefabRegularEnvironment: {fileID: 0} 12 | m_PrefabUIEnvironment: {fileID: 0} 13 | m_SpritePackerMode: 0 14 | m_SpritePackerPaddingPower: 1 15 | m_EtcTextureCompressorBehavior: 1 16 | m_EtcTextureFastCompressor: 1 17 | m_EtcTextureNormalCompressor: 2 18 | m_EtcTextureBestCompressor: 4 19 | m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref 20 | m_ProjectGenerationRootNamespace: 21 | m_CollabEditorSettings: 22 | inProgressEnabled: 1 23 | m_EnableTextureStreamingInEditMode: 1 24 | m_EnableTextureStreamingInPlayMode: 1 25 | m_AsyncShaderCompilation: 1 26 | m_EnterPlayModeOptionsEnabled: 0 27 | m_EnterPlayModeOptions: 3 28 | m_ShowLightmapResolutionOverlay: 1 29 | m_UseLegacyProbeSampleCount: 1 30 | m_AssetPipelineMode: 1 31 | m_CacheServerMode: 0 32 | m_CacheServerEndpoint: 33 | m_CacheServerNamespacePrefix: default 34 | m_CacheServerEnableDownload: 1 35 | m_CacheServerEnableUpload: 1 36 | -------------------------------------------------------------------------------- /Unity/ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!30 &1 4 | GraphicsSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 12 7 | m_Deferred: 8 | m_Mode: 1 9 | m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} 10 | m_DeferredReflections: 11 | m_Mode: 1 12 | m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} 13 | m_ScreenSpaceShadows: 14 | m_Mode: 1 15 | m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} 16 | m_LegacyDeferred: 17 | m_Mode: 1 18 | m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} 19 | m_DepthNormals: 20 | m_Mode: 1 21 | m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} 22 | m_MotionVectors: 23 | m_Mode: 1 24 | m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} 25 | m_LightHalo: 26 | m_Mode: 1 27 | m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} 28 | m_LensFlare: 29 | m_Mode: 1 30 | m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} 31 | m_AlwaysIncludedShaders: 32 | - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} 33 | - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} 34 | - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} 35 | - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} 36 | - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} 37 | - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} 38 | m_PreloadedShaders: [] 39 | m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, 40 | type: 0} 41 | m_CustomRenderPipeline: {fileID: 0} 42 | m_TransparencySortMode: 0 43 | m_TransparencySortAxis: {x: 0, y: 0, z: 1} 44 | m_DefaultRenderingPath: 1 45 | m_DefaultMobileRenderingPath: 1 46 | m_TierSettings: [] 47 | m_LightmapStripping: 0 48 | m_FogStripping: 0 49 | m_InstancingStripping: 0 50 | m_LightmapKeepPlain: 1 51 | m_LightmapKeepDirCombined: 1 52 | m_LightmapKeepDynamicPlain: 1 53 | m_LightmapKeepDynamicDirCombined: 1 54 | m_LightmapKeepShadowMask: 1 55 | m_LightmapKeepSubtractive: 1 56 | m_FogKeepLinear: 1 57 | m_FogKeepExp: 1 58 | m_FogKeepExp2: 1 59 | m_AlbedoSwatchInfos: [] 60 | m_LightsUseLinearIntensity: 0 61 | m_LightsUseColorTemperature: 0 62 | -------------------------------------------------------------------------------- /Unity/ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!13 &1 4 | InputManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Axes: 8 | - serializedVersion: 3 9 | m_Name: Horizontal 10 | descriptiveName: 11 | descriptiveNegativeName: 12 | negativeButton: left 13 | positiveButton: right 14 | altNegativeButton: a 15 | altPositiveButton: d 16 | gravity: 3 17 | dead: 0.001 18 | sensitivity: 3 19 | snap: 1 20 | invert: 0 21 | type: 0 22 | axis: 0 23 | joyNum: 0 24 | - serializedVersion: 3 25 | m_Name: Vertical 26 | descriptiveName: 27 | descriptiveNegativeName: 28 | negativeButton: down 29 | positiveButton: up 30 | altNegativeButton: s 31 | altPositiveButton: w 32 | gravity: 3 33 | dead: 0.001 34 | sensitivity: 3 35 | snap: 1 36 | invert: 0 37 | type: 0 38 | axis: 0 39 | joyNum: 0 40 | - serializedVersion: 3 41 | m_Name: Fire1 42 | descriptiveName: 43 | descriptiveNegativeName: 44 | negativeButton: 45 | positiveButton: left ctrl 46 | altNegativeButton: 47 | altPositiveButton: mouse 0 48 | gravity: 1000 49 | dead: 0.001 50 | sensitivity: 1000 51 | snap: 0 52 | invert: 0 53 | type: 0 54 | axis: 0 55 | joyNum: 0 56 | - serializedVersion: 3 57 | m_Name: Fire2 58 | descriptiveName: 59 | descriptiveNegativeName: 60 | negativeButton: 61 | positiveButton: left alt 62 | altNegativeButton: 63 | altPositiveButton: mouse 1 64 | gravity: 1000 65 | dead: 0.001 66 | sensitivity: 1000 67 | snap: 0 68 | invert: 0 69 | type: 0 70 | axis: 0 71 | joyNum: 0 72 | - serializedVersion: 3 73 | m_Name: Fire3 74 | descriptiveName: 75 | descriptiveNegativeName: 76 | negativeButton: 77 | positiveButton: left shift 78 | altNegativeButton: 79 | altPositiveButton: mouse 2 80 | gravity: 1000 81 | dead: 0.001 82 | sensitivity: 1000 83 | snap: 0 84 | invert: 0 85 | type: 0 86 | axis: 0 87 | joyNum: 0 88 | - serializedVersion: 3 89 | m_Name: Jump 90 | descriptiveName: 91 | descriptiveNegativeName: 92 | negativeButton: 93 | positiveButton: space 94 | altNegativeButton: 95 | altPositiveButton: 96 | gravity: 1000 97 | dead: 0.001 98 | sensitivity: 1000 99 | snap: 0 100 | invert: 0 101 | type: 0 102 | axis: 0 103 | joyNum: 0 104 | - serializedVersion: 3 105 | m_Name: Mouse X 106 | descriptiveName: 107 | descriptiveNegativeName: 108 | negativeButton: 109 | positiveButton: 110 | altNegativeButton: 111 | altPositiveButton: 112 | gravity: 0 113 | dead: 0 114 | sensitivity: 0.1 115 | snap: 0 116 | invert: 0 117 | type: 1 118 | axis: 0 119 | joyNum: 0 120 | - serializedVersion: 3 121 | m_Name: Mouse Y 122 | descriptiveName: 123 | descriptiveNegativeName: 124 | negativeButton: 125 | positiveButton: 126 | altNegativeButton: 127 | altPositiveButton: 128 | gravity: 0 129 | dead: 0 130 | sensitivity: 0.1 131 | snap: 0 132 | invert: 0 133 | type: 1 134 | axis: 1 135 | joyNum: 0 136 | - serializedVersion: 3 137 | m_Name: Mouse ScrollWheel 138 | descriptiveName: 139 | descriptiveNegativeName: 140 | negativeButton: 141 | positiveButton: 142 | altNegativeButton: 143 | altPositiveButton: 144 | gravity: 0 145 | dead: 0 146 | sensitivity: 0.1 147 | snap: 0 148 | invert: 0 149 | type: 1 150 | axis: 2 151 | joyNum: 0 152 | - serializedVersion: 3 153 | m_Name: Horizontal 154 | descriptiveName: 155 | descriptiveNegativeName: 156 | negativeButton: 157 | positiveButton: 158 | altNegativeButton: 159 | altPositiveButton: 160 | gravity: 0 161 | dead: 0.19 162 | sensitivity: 1 163 | snap: 0 164 | invert: 0 165 | type: 2 166 | axis: 0 167 | joyNum: 0 168 | - serializedVersion: 3 169 | m_Name: Vertical 170 | descriptiveName: 171 | descriptiveNegativeName: 172 | negativeButton: 173 | positiveButton: 174 | altNegativeButton: 175 | altPositiveButton: 176 | gravity: 0 177 | dead: 0.19 178 | sensitivity: 1 179 | snap: 0 180 | invert: 1 181 | type: 2 182 | axis: 1 183 | joyNum: 0 184 | - serializedVersion: 3 185 | m_Name: Fire1 186 | descriptiveName: 187 | descriptiveNegativeName: 188 | negativeButton: 189 | positiveButton: joystick button 0 190 | altNegativeButton: 191 | altPositiveButton: 192 | gravity: 1000 193 | dead: 0.001 194 | sensitivity: 1000 195 | snap: 0 196 | invert: 0 197 | type: 0 198 | axis: 0 199 | joyNum: 0 200 | - serializedVersion: 3 201 | m_Name: Fire2 202 | descriptiveName: 203 | descriptiveNegativeName: 204 | negativeButton: 205 | positiveButton: joystick button 1 206 | altNegativeButton: 207 | altPositiveButton: 208 | gravity: 1000 209 | dead: 0.001 210 | sensitivity: 1000 211 | snap: 0 212 | invert: 0 213 | type: 0 214 | axis: 0 215 | joyNum: 0 216 | - serializedVersion: 3 217 | m_Name: Fire3 218 | descriptiveName: 219 | descriptiveNegativeName: 220 | negativeButton: 221 | positiveButton: joystick button 2 222 | altNegativeButton: 223 | altPositiveButton: 224 | gravity: 1000 225 | dead: 0.001 226 | sensitivity: 1000 227 | snap: 0 228 | invert: 0 229 | type: 0 230 | axis: 0 231 | joyNum: 0 232 | - serializedVersion: 3 233 | m_Name: Jump 234 | descriptiveName: 235 | descriptiveNegativeName: 236 | negativeButton: 237 | positiveButton: joystick button 3 238 | altNegativeButton: 239 | altPositiveButton: 240 | gravity: 1000 241 | dead: 0.001 242 | sensitivity: 1000 243 | snap: 0 244 | invert: 0 245 | type: 0 246 | axis: 0 247 | joyNum: 0 248 | - serializedVersion: 3 249 | m_Name: Submit 250 | descriptiveName: 251 | descriptiveNegativeName: 252 | negativeButton: 253 | positiveButton: return 254 | altNegativeButton: 255 | altPositiveButton: joystick button 0 256 | gravity: 1000 257 | dead: 0.001 258 | sensitivity: 1000 259 | snap: 0 260 | invert: 0 261 | type: 0 262 | axis: 0 263 | joyNum: 0 264 | - serializedVersion: 3 265 | m_Name: Submit 266 | descriptiveName: 267 | descriptiveNegativeName: 268 | negativeButton: 269 | positiveButton: enter 270 | altNegativeButton: 271 | altPositiveButton: space 272 | gravity: 1000 273 | dead: 0.001 274 | sensitivity: 1000 275 | snap: 0 276 | invert: 0 277 | type: 0 278 | axis: 0 279 | joyNum: 0 280 | - serializedVersion: 3 281 | m_Name: Cancel 282 | descriptiveName: 283 | descriptiveNegativeName: 284 | negativeButton: 285 | positiveButton: escape 286 | altNegativeButton: 287 | altPositiveButton: joystick button 1 288 | gravity: 1000 289 | dead: 0.001 290 | sensitivity: 1000 291 | snap: 0 292 | invert: 0 293 | type: 0 294 | axis: 0 295 | joyNum: 0 296 | -------------------------------------------------------------------------------- /Unity/ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!126 &1 4 | NavMeshProjectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | areas: 8 | - name: Walkable 9 | cost: 1 10 | - name: Not Walkable 11 | cost: 1 12 | - name: Jump 13 | cost: 2 14 | - name: 15 | cost: 1 16 | - name: 17 | cost: 1 18 | - name: 19 | cost: 1 20 | - name: 21 | cost: 1 22 | - name: 23 | cost: 1 24 | - name: 25 | cost: 1 26 | - name: 27 | cost: 1 28 | - name: 29 | cost: 1 30 | - name: 31 | cost: 1 32 | - name: 33 | cost: 1 34 | - name: 35 | cost: 1 36 | - name: 37 | cost: 1 38 | - name: 39 | cost: 1 40 | - name: 41 | cost: 1 42 | - name: 43 | cost: 1 44 | - name: 45 | cost: 1 46 | - name: 47 | cost: 1 48 | - name: 49 | cost: 1 50 | - name: 51 | cost: 1 52 | - name: 53 | cost: 1 54 | - name: 55 | cost: 1 56 | - name: 57 | cost: 1 58 | - name: 59 | cost: 1 60 | - name: 61 | cost: 1 62 | - name: 63 | cost: 1 64 | - name: 65 | cost: 1 66 | - name: 67 | cost: 1 68 | - name: 69 | cost: 1 70 | - name: 71 | cost: 1 72 | m_LastAgentTypeID: -887442657 73 | m_Settings: 74 | - serializedVersion: 2 75 | agentTypeID: 0 76 | agentRadius: 0.5 77 | agentHeight: 2 78 | agentSlope: 45 79 | agentClimb: 0.75 80 | ledgeDropHeight: 0 81 | maxJumpAcrossDistance: 0 82 | minRegionArea: 2 83 | manualCellSize: 0 84 | cellSize: 0.16666667 85 | manualTileSize: 0 86 | tileSize: 256 87 | accuratePlacement: 0 88 | debug: 89 | m_Flags: 0 90 | m_SettingNames: 91 | - Humanoid 92 | -------------------------------------------------------------------------------- /Unity/ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!19 &1 4 | Physics2DSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 4 7 | m_Gravity: {x: 0, y: -9.81} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_VelocityIterations: 8 10 | m_PositionIterations: 3 11 | m_VelocityThreshold: 1 12 | m_MaxLinearCorrection: 0.2 13 | m_MaxAngularCorrection: 8 14 | m_MaxTranslationSpeed: 100 15 | m_MaxRotationSpeed: 360 16 | m_BaumgarteScale: 0.2 17 | m_BaumgarteTimeOfImpactScale: 0.75 18 | m_TimeToSleep: 0.5 19 | m_LinearSleepTolerance: 0.01 20 | m_AngularSleepTolerance: 2 21 | m_DefaultContactOffset: 0.01 22 | m_JobOptions: 23 | serializedVersion: 2 24 | useMultithreading: 0 25 | useConsistencySorting: 0 26 | m_InterpolationPosesPerJob: 100 27 | m_NewContactsPerJob: 30 28 | m_CollideContactsPerJob: 100 29 | m_ClearFlagsPerJob: 200 30 | m_ClearBodyForcesPerJob: 200 31 | m_SyncDiscreteFixturesPerJob: 50 32 | m_SyncContinuousFixturesPerJob: 50 33 | m_FindNearestContactsPerJob: 100 34 | m_UpdateTriggerContactsPerJob: 100 35 | m_IslandSolverCostThreshold: 100 36 | m_IslandSolverBodyCostScale: 1 37 | m_IslandSolverContactCostScale: 10 38 | m_IslandSolverJointCostScale: 10 39 | m_IslandSolverBodiesPerJob: 50 40 | m_IslandSolverContactsPerJob: 50 41 | m_AutoSimulation: 1 42 | m_QueriesHitTriggers: 1 43 | m_QueriesStartInColliders: 1 44 | m_CallbacksOnDisable: 1 45 | m_ReuseCollisionCallbacks: 1 46 | m_AutoSyncTransforms: 0 47 | m_AlwaysShowColliders: 0 48 | m_ShowColliderSleep: 1 49 | m_ShowColliderContacts: 0 50 | m_ShowColliderAABB: 0 51 | m_ContactArrowScale: 0.2 52 | m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} 53 | m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} 54 | m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} 55 | m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} 56 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 57 | -------------------------------------------------------------------------------- /Unity/ProjectSettings/PresetManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1386491679 &1 4 | PresetManager: 5 | m_ObjectHideFlags: 0 6 | m_DefaultList: [] 7 | -------------------------------------------------------------------------------- /Unity/ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 2019.3.0f6 2 | m_EditorVersionWithRevision: 2019.3.0f6 (27ab2135bccf) 3 | -------------------------------------------------------------------------------- /Unity/ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!47 &1 4 | QualitySettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 5 7 | m_CurrentQuality: 5 8 | m_QualitySettings: 9 | - serializedVersion: 2 10 | name: Very Low 11 | pixelLightCount: 0 12 | shadows: 0 13 | shadowResolution: 0 14 | shadowProjection: 1 15 | shadowCascades: 1 16 | shadowDistance: 15 17 | shadowNearPlaneOffset: 3 18 | shadowCascade2Split: 0.33333334 19 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 20 | shadowmaskMode: 0 21 | blendWeights: 1 22 | textureQuality: 1 23 | anisotropicTextures: 0 24 | antiAliasing: 0 25 | softParticles: 0 26 | softVegetation: 0 27 | realtimeReflectionProbes: 0 28 | billboardsFaceCameraPosition: 0 29 | vSyncCount: 0 30 | lodBias: 0.3 31 | maximumLODLevel: 0 32 | streamingMipmapsActive: 0 33 | streamingMipmapsAddAllCameras: 1 34 | streamingMipmapsMemoryBudget: 512 35 | streamingMipmapsRenderersPerFrame: 512 36 | streamingMipmapsMaxLevelReduction: 2 37 | streamingMipmapsMaxFileIORequests: 1024 38 | particleRaycastBudget: 4 39 | asyncUploadTimeSlice: 2 40 | asyncUploadBufferSize: 16 41 | asyncUploadPersistentBuffer: 1 42 | resolutionScalingFixedDPIFactor: 1 43 | excludedTargetPlatforms: [] 44 | - serializedVersion: 2 45 | name: Low 46 | pixelLightCount: 0 47 | shadows: 0 48 | shadowResolution: 0 49 | shadowProjection: 1 50 | shadowCascades: 1 51 | shadowDistance: 20 52 | shadowNearPlaneOffset: 3 53 | shadowCascade2Split: 0.33333334 54 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 55 | shadowmaskMode: 0 56 | blendWeights: 2 57 | textureQuality: 0 58 | anisotropicTextures: 0 59 | antiAliasing: 0 60 | softParticles: 0 61 | softVegetation: 0 62 | realtimeReflectionProbes: 0 63 | billboardsFaceCameraPosition: 0 64 | vSyncCount: 0 65 | lodBias: 0.4 66 | maximumLODLevel: 0 67 | streamingMipmapsActive: 0 68 | streamingMipmapsAddAllCameras: 1 69 | streamingMipmapsMemoryBudget: 512 70 | streamingMipmapsRenderersPerFrame: 512 71 | streamingMipmapsMaxLevelReduction: 2 72 | streamingMipmapsMaxFileIORequests: 1024 73 | particleRaycastBudget: 16 74 | asyncUploadTimeSlice: 2 75 | asyncUploadBufferSize: 16 76 | asyncUploadPersistentBuffer: 1 77 | resolutionScalingFixedDPIFactor: 1 78 | excludedTargetPlatforms: [] 79 | - serializedVersion: 2 80 | name: Medium 81 | pixelLightCount: 1 82 | shadows: 1 83 | shadowResolution: 0 84 | shadowProjection: 1 85 | shadowCascades: 1 86 | shadowDistance: 20 87 | shadowNearPlaneOffset: 3 88 | shadowCascade2Split: 0.33333334 89 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 90 | shadowmaskMode: 0 91 | blendWeights: 2 92 | textureQuality: 0 93 | anisotropicTextures: 1 94 | antiAliasing: 0 95 | softParticles: 0 96 | softVegetation: 0 97 | realtimeReflectionProbes: 0 98 | billboardsFaceCameraPosition: 0 99 | vSyncCount: 1 100 | lodBias: 0.7 101 | maximumLODLevel: 0 102 | streamingMipmapsActive: 0 103 | streamingMipmapsAddAllCameras: 1 104 | streamingMipmapsMemoryBudget: 512 105 | streamingMipmapsRenderersPerFrame: 512 106 | streamingMipmapsMaxLevelReduction: 2 107 | streamingMipmapsMaxFileIORequests: 1024 108 | particleRaycastBudget: 64 109 | asyncUploadTimeSlice: 2 110 | asyncUploadBufferSize: 16 111 | asyncUploadPersistentBuffer: 1 112 | resolutionScalingFixedDPIFactor: 1 113 | excludedTargetPlatforms: [] 114 | - serializedVersion: 2 115 | name: High 116 | pixelLightCount: 2 117 | shadows: 2 118 | shadowResolution: 1 119 | shadowProjection: 1 120 | shadowCascades: 2 121 | shadowDistance: 40 122 | shadowNearPlaneOffset: 3 123 | shadowCascade2Split: 0.33333334 124 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 125 | shadowmaskMode: 1 126 | blendWeights: 2 127 | textureQuality: 0 128 | anisotropicTextures: 1 129 | antiAliasing: 0 130 | softParticles: 0 131 | softVegetation: 1 132 | realtimeReflectionProbes: 1 133 | billboardsFaceCameraPosition: 1 134 | vSyncCount: 1 135 | lodBias: 1 136 | maximumLODLevel: 0 137 | streamingMipmapsActive: 0 138 | streamingMipmapsAddAllCameras: 1 139 | streamingMipmapsMemoryBudget: 512 140 | streamingMipmapsRenderersPerFrame: 512 141 | streamingMipmapsMaxLevelReduction: 2 142 | streamingMipmapsMaxFileIORequests: 1024 143 | particleRaycastBudget: 256 144 | asyncUploadTimeSlice: 2 145 | asyncUploadBufferSize: 16 146 | asyncUploadPersistentBuffer: 1 147 | resolutionScalingFixedDPIFactor: 1 148 | excludedTargetPlatforms: [] 149 | - serializedVersion: 2 150 | name: Very High 151 | pixelLightCount: 3 152 | shadows: 2 153 | shadowResolution: 2 154 | shadowProjection: 1 155 | shadowCascades: 2 156 | shadowDistance: 70 157 | shadowNearPlaneOffset: 3 158 | shadowCascade2Split: 0.33333334 159 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 160 | shadowmaskMode: 1 161 | blendWeights: 4 162 | textureQuality: 0 163 | anisotropicTextures: 2 164 | antiAliasing: 2 165 | softParticles: 1 166 | softVegetation: 1 167 | realtimeReflectionProbes: 1 168 | billboardsFaceCameraPosition: 1 169 | vSyncCount: 1 170 | lodBias: 1.5 171 | maximumLODLevel: 0 172 | streamingMipmapsActive: 0 173 | streamingMipmapsAddAllCameras: 1 174 | streamingMipmapsMemoryBudget: 512 175 | streamingMipmapsRenderersPerFrame: 512 176 | streamingMipmapsMaxLevelReduction: 2 177 | streamingMipmapsMaxFileIORequests: 1024 178 | particleRaycastBudget: 1024 179 | asyncUploadTimeSlice: 2 180 | asyncUploadBufferSize: 16 181 | asyncUploadPersistentBuffer: 1 182 | resolutionScalingFixedDPIFactor: 1 183 | excludedTargetPlatforms: [] 184 | - serializedVersion: 2 185 | name: Ultra 186 | pixelLightCount: 4 187 | shadows: 2 188 | shadowResolution: 2 189 | shadowProjection: 1 190 | shadowCascades: 4 191 | shadowDistance: 150 192 | shadowNearPlaneOffset: 3 193 | shadowCascade2Split: 0.33333334 194 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 195 | shadowmaskMode: 1 196 | blendWeights: 4 197 | textureQuality: 0 198 | anisotropicTextures: 2 199 | antiAliasing: 2 200 | softParticles: 1 201 | softVegetation: 1 202 | realtimeReflectionProbes: 1 203 | billboardsFaceCameraPosition: 1 204 | vSyncCount: 1 205 | lodBias: 2 206 | maximumLODLevel: 0 207 | streamingMipmapsActive: 0 208 | streamingMipmapsAddAllCameras: 1 209 | streamingMipmapsMemoryBudget: 512 210 | streamingMipmapsRenderersPerFrame: 512 211 | streamingMipmapsMaxLevelReduction: 2 212 | streamingMipmapsMaxFileIORequests: 1024 213 | particleRaycastBudget: 4096 214 | asyncUploadTimeSlice: 2 215 | asyncUploadBufferSize: 16 216 | asyncUploadPersistentBuffer: 1 217 | resolutionScalingFixedDPIFactor: 1 218 | excludedTargetPlatforms: [] 219 | m_PerPlatformDefaultQuality: 220 | Android: 2 221 | Lumin: 5 222 | Nintendo 3DS: 5 223 | Nintendo Switch: 5 224 | PS4: 5 225 | PSP2: 2 226 | Standalone: 5 227 | WebGL: 3 228 | Windows Store Apps: 5 229 | XboxOne: 5 230 | iPhone: 2 231 | tvOS: 2 232 | -------------------------------------------------------------------------------- /Unity/ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!78 &1 4 | TagManager: 5 | serializedVersion: 2 6 | tags: [] 7 | layers: 8 | - Default 9 | - TransparentFX 10 | - Ignore Raycast 11 | - 12 | - Water 13 | - UI 14 | - 15 | - 16 | - 17 | - 18 | - 19 | - 20 | - 21 | - 22 | - 23 | - 24 | - 25 | - 26 | - 27 | - 28 | - 29 | - 30 | - 31 | - 32 | - 33 | - 34 | - 35 | - 36 | - 37 | - 38 | - 39 | - 40 | m_SortingLayers: 41 | - name: Default 42 | uniqueID: 0 43 | locked: 0 44 | -------------------------------------------------------------------------------- /Unity/ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!5 &1 4 | TimeManager: 5 | m_ObjectHideFlags: 0 6 | Fixed Timestep: 0.02 7 | Maximum Allowed Timestep: 0.33333334 8 | m_TimeScale: 1 9 | Maximum Particle Timestep: 0.03 10 | -------------------------------------------------------------------------------- /Unity/ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!310 &1 4 | UnityConnectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 1 7 | m_Enabled: 0 8 | m_TestMode: 0 9 | m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events 10 | m_EventUrl: https://cdp.cloud.unity3d.com/v1/events 11 | m_ConfigUrl: https://config.uca.cloud.unity3d.com 12 | m_TestInitMode: 0 13 | CrashReportingSettings: 14 | m_EventUrl: https://perf-events.cloud.unity3d.com 15 | m_Enabled: 0 16 | m_LogBufferSize: 10 17 | m_CaptureEditorExceptions: 1 18 | UnityPurchasingSettings: 19 | m_Enabled: 0 20 | m_TestMode: 0 21 | UnityAnalyticsSettings: 22 | m_Enabled: 0 23 | m_TestMode: 0 24 | m_InitializeOnStartup: 1 25 | UnityAdsSettings: 26 | m_Enabled: 0 27 | m_InitializeOnStartup: 1 28 | m_TestMode: 0 29 | m_IosGameId: 30 | m_AndroidGameId: 31 | m_GameIds: {} 32 | m_GameId: 33 | PerformanceReportingSettings: 34 | m_Enabled: 0 35 | -------------------------------------------------------------------------------- /Unity/ProjectSettings/VFXManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!937362698 &1 4 | VFXManager: 5 | m_ObjectHideFlags: 0 6 | m_IndirectShader: {fileID: 0} 7 | m_CopyBufferShader: {fileID: 0} 8 | m_SortShader: {fileID: 0} 9 | m_RenderPipeSettingsPath: 10 | m_FixedTimeStep: 0.016666668 11 | m_MaxDeltaTime: 0.05 12 | -------------------------------------------------------------------------------- /Unity/ProjectSettings/XRSettings.asset: -------------------------------------------------------------------------------- 1 | { 2 | "m_SettingKeys": [ 3 | "VR Device Disabled", 4 | "VR Device User Alert" 5 | ], 6 | "m_SettingValues": [ 7 | "False", 8 | "False" 9 | ] 10 | } -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | Thanks for considering contributing! Read the guidelines below before you submit an issue or create a PR. 2 | 3 | # Project structure 4 | The project structure is split between several branches 5 | * **master:** This is the stable branch and all releases/packages are generated from this. 6 | * **develop:** This is the primary development branch which all PRs should be made to and is generally considered less-stable. This is occasionally merged into **master** and a new release tag/package is generated from this. 7 | * **releases/stable:** This branch is orphaned and contains only the package contents for the library. This is updated in sync with tagged releases on **master** and each commit that changes these contents should result in the version in **package.json** being changed. 8 | 9 | This structure allows for ease of development and quick testing via **master** or **develop**, but clear isolation and separation between the package distribution via **releases/stable**. 10 | 11 | # Pull requests 12 | Pull requests should be made to the develop branch. The types of pull requests that are highly desirable are generally: 13 | * Bug fixes 14 | * Feature improvements addressing issues discussed on the GitHub repository. This allows for wider discussion of those issues prior to any implementation and has the potential to help filter features or changes that are undesirable before time is spent working on them. 15 | 16 | ## Performance Issues and Pull Requests 17 | For any issues or pull requests regarding performance improvements, at minimum please include details and screenshots describing the issue in as much detail as possible and if relevant showing a before and after profile. Better yet, if you can provide a reproducible example that can be used to demonstrate the issue it will be much more likely that the issue is addressed quickly. 18 | 19 | # Style Guide 20 | 21 | ## Language Usage 22 | * Mark closed types as sealed to enable proper devirtualization (see [here](https://blogs.unity3d.com/2016/07/26/il2cpp-optimizations-devirtualization/) for more info). 23 | * Avoid LINQ usage for runtime usage except where absolutely possible (`ToList` or `ToArray` for example) and avoid using `ForEach`. Using these methods creates easily avoidable garbage (in newer versions of Unity >= 5.6 this is situational to the Collection or if its being used via an interface, but easy to avoid edge cases by not using at all). Editor usage is another story as performance is not as generally important and non-usage of these can be relaxed. 24 | 25 | ## Layout 26 | There is an `.editorconfig` at the root of the repository that can be used by most IDEs to help ensure these settings are automatically applied. 27 | * **Indentation:** 1 tab = 4 spaces (tab character) 28 | * **Desired width:** 120-130 characters max per line 29 | * **Line Endings:** Unix (LF), with a new-line at the end of each file. 30 | * **White Space:** Trim empty whitespace from the ends of lines. 31 | 32 | ## Naming and Formatting 33 | | Object Name | Notation | Example | 34 | | ----------- | -------- | ------- | 35 | | Namespaces | PascalCase | `JCMG.Library.Editor` | 36 | | Classes | PascalCase | `SemVersion` | 37 | | Methods | PascalCase | `ParseVersion` | 38 | | Method arguments | camelCase | `oldValue` | 39 | | Properties | PascalCase | `Value` | 40 | | Public fields | camelCase | `value` | 41 | | Private fields | _camelCase | `_value` | 42 | | Constants | All Upper Caps with Snake case | `DEFAULT_VERSION` | 43 | | Inline variables | camelCase | `value` | 44 | 45 | ## Structure 46 | * Follow good encapsulation principles and try to limit exposing fields directly as public; unless necessary everything should be marked as private/protected unless necessary. Where public access to a field is needed, use a public property instead. 47 | * Always order access from most-accessible to least (i.e, `public` to `private`). 48 | * Where classes or methods are not intended for use by a user, mark these as `internal`. 49 | * Order class structure like so: 50 | * Namespace 51 | * Internal classes 52 | * Properties 53 | * Fields 54 | * Events 55 | * Unity Methods 56 | * Primary Methods 57 | * Helper Methods 58 | * Lines of code that are generally longer than 120-130 characters should generally be broken out into multiple lines. For example, instead of: 59 | 60 | `public bool SomeMethodWithManyParams(int param1, float param2, List param3, out int param4, out int param5)...` 61 | 62 | do 63 | 64 | ``` 65 | public bool SomeMethodWithManyParams( 66 | int param1, 67 | float param2, 68 | List param3, 69 | out int param4, 70 | out int param5)... 71 | ``` 72 | 73 | ## Example Formatting 74 | ``` 75 | using System; 76 | using UnityEngine; 77 | 78 | namespace Example 79 | { 80 | public class Foo : MonoBehavior 81 | { 82 | public int SomeValue { get { return _someValue; } } 83 | 84 | [SerializeField] 85 | private int _someValue; 86 | 87 | private const string WARNING = "Somethings wrong!"; 88 | 89 | private void Update() 90 | { 91 | // Do work 92 | Debug.Log(Warning); 93 | } 94 | } 95 | } 96 | ``` -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Jeff Campbell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # JCMG Curves 2 | [![openupm](https://img.shields.io/npm/v/com.jeffcampbellmakesgames.curves?label=openupm®istry_uri=https://package.openupm.com)](https://openupm.com/packages/com.jeffcampbellmakesgames.curves/) 3 | GitHub issues 4 | GitHub 5 | [![Twitter Follow](https://img.shields.io/badge/twitter-%40stampyturtle-blue.svg?style=flat&label=Follow)](https://twitter.com/stampyturtle) 6 | 7 | ## About 8 | 9 | JCMG Curves is a 3D Bezier curve library focused on ease of use in both its API and Unity Editor integration. 10 | 11 | ![Example Curve](./Images/Example01.gif) 12 | 13 | ## Overview 14 | 15 | JCMG Curves offers a `MonoBehaviour` and `ScriptableObject` curve class which can be modified in the Unity Editor and/or inspector. A Bezier curve can be created as either a `MonoBehaviour` component in the form of `Bezier3DSpline` or as a `ScriptableObject` in the form of `Bezier3DSplineData`. Both have the same common interface as defined by `IBezier3DSplineData` and `IReadOnlySplineData` and offer methods for retreiving the position, rotation, and unit-length local vectors for Up, Left, Right, etc... for a point along the spline based on either a normalized value [0-1] of its total length or on a set distance. 16 | 17 | The primary difference between these two options is that `Bezier3DSpline`' `Transform` is taken into account when accessing its APIs and so the positions, rotations, and vectors it return are transformed based on its `Transform`'s position and rotation, while all similar APIs for `Bezier3DSplineData` do not and are effectively in the World coordinate space. It is easy to copy spline data between these two types or others of the same type by using the Copy and Paste buttonss on their inspector. 18 | 19 | This library was originally cloned from https://github.com/Siccity/Bezier3D and has been refactored and enhanced to include a simpler API, better readability, additional features, and several bug fixes. One of the key features I wanted to maintain that distinguished it from other similar libraries was the way that it cached and stored points along the curve so that it was possible to get a position or rotation along the curve at a set distance of the curve's total length rather than a normalized value of 0-1 over the entire length. This makes it possible to navigate along the spline based on a constant speed and is not affected by Bezier segments of differing lengths. 20 | 21 | ## Installing JCMG Curves 22 | 23 | Using this library in your project can be done in three ways: 24 | 25 | ### Install via OpenUPM 26 | The package is available on the [openupm registry](https://openupm.com/). It's recommended to install it via [openupm-cli](https://github.com/openupm/openupm-cli). 27 | 28 | ``` 29 | openupm add com.jeffcampbellmakesgames.curves 30 | ``` 31 | 32 | ### Install via GIT URL 33 | Using the native Unity Package Manager introduced in 2017.2, you can add this library as a package by modifying your `manifest.json` file found at `/ProjectName/Packages/manifest.json` to include it as a dependency. See the example below on how to reference it. 34 | 35 | ``` 36 | { 37 | "dependencies": { 38 | ... 39 | "com.jeffcampbellmakesgames.curves" : "https://github.com/jeffcampbellmakesgames/unity-curves.git#release/stable", 40 | ... 41 | } 42 | } 43 | ``` 44 | 45 | ### Install via classic `.UnityPackage` 46 | The latest release can be found [here](https://github.com/jeffcampbellmakesgames/unity-curves/releases) as a UnityPackage file that can be downloaded and imported directly into your project's Assets folder. 47 | 48 | ## Usage 49 | 50 | To learn more about how to use JCMG CUrves, see [here](./usage.md) for more information. 51 | 52 | ## Contributing 53 | 54 | For information on how to contribute and code style guidelines, please visit [here](./contributing.md). 55 | 56 | ## Support 57 | If this is useful to you and/or you’d like to see future development and more tools in the future, please consider supporting it either by contributing to the Github projects (submitting bug reports or features and/or creating pull requests) or by buying me coffee using any of the links below. Every little bit helps! 58 | 59 | [![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I3I2W7GX) 60 | -------------------------------------------------------------------------------- /usage.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | ## Creating a Curve as a MonoBehaviour 4 | 5 | To create a Bezier Curve as a Scene object, create a new GameObject and add the `Bezier3DSpline` component (available at the menu path _JCMG/Curves/Bezier3DSpline_). 6 | 7 | ![Adding a Bezier3DSpline component](./Images/CreateBezierSplineComponent01.png) 8 | 9 | Alternatively this can be done by selecting the menu item _GameObject/JCMG/Curves/Bezier3DSpline_ or right-clicking in the Scene Hierarchy window and selecting the menu item _/JCMG/Curves/Bezier3DSpline_. 10 | 11 | ![Creating new Bezier3DSpline GameObject](./Images/CreateBezierSplineComponent02.png) 12 | 13 | After this type of curve has been created, its path can be seen as a Gizmo in the scene view even when unselected. Selecting the curve GameObject will enable you to modify the curve and visualize more information. 14 | 15 | ## Creating a Curve as a ScriptableObject 16 | 17 | To create a Bezier Curve as a `ScriptableObject`, right-click in the Project window and select the menu item `JCMG/Curves/Bezier3DSplineData`. A curve in this form can only be seen and/or modified when selected in the Project window and will not be visible when unselected. 18 | 19 | ![Create new Bezier3DSplineData asset](./Images/CreateBezierSplineDataAsset01.png) 20 | 21 | ## Editing a Curve 22 | 23 | When a curve has been created its initial two control points or `Knot`s as they are designated in code are initialized near the world origin (0,0,0). The primary way to be able to modify a curve is by selecting a `Knot`s in the Scene View and modifying its position and/or rotation via the default `Transform` hotkeys (`W` for Move, `E` for Rotate) or their related fields in the inspector. Other Hotkeys listed below enable additional commands. 24 | 25 | ![Newly-created Bezier3DSpline](./Images/Bezier3DSpline01.png) 26 | 27 | ![Newly-created Bezier3DSpline](./Images/Bezier3DSpline02.png) 28 | 29 | ![Moving a Knot on a Bezier3DSpline](./Images/Bezier3DSpline_Move01.gif) 30 | 31 | ![Rotating a Knot on a Bezier3DSpline](./Images/Bezier3DSpline_Rotate01.gif) 32 | 33 | ### Hotkeys 34 | 35 | | Key | Description | 36 | |-----|-------------| 37 | | Ctrl + I | Pressing Ctrl + I at the same time as the Bezier Curve is selected will flip the direction of the spline to its opposite | 38 | | CMD + Z and CMD + Y (OSX) or Ctrl + Z and Ctrl + Y (Windows)| Bezier Curve operations that modify the curve support undo and redo operations in the Unity Editor and will respond to the bound Undo and Redo buttons for that OS | 39 | | F (while Knot is selected) | Pressing F while a Knot is selected will focus the last active SceneView camera on that Knot's position. | 40 | | Delete (while Knot is selected) | Pressing Delete will remove the selected Knot from the Bezier Curve | 41 | | Escape (while Knot is selected) | Pressing Escape will remove clear the selection state and deselect the selected Knot | 42 | 43 | ## Scene Controls 44 | 45 | When a Bezier curve has been selected, an additional UI appears in the Scene View in the upper-left corner. These options are user-preferences and toggle on or off specific curve modification and visualization options. 46 | 47 | ![Scene View UI](./Images/SceneView_UI01.png) 48 | 49 | ### Mirror Handle Movement 50 | When this option is enabled (green), moving one handle on a Bezier curve's Knot will cause its other handle if present to be automatically set to the opposite direction and length, effectively mirroring its movemennt. This can be useful for creating smooth transitions between two curve segments. When disabled (red), handles can be moved independently. 51 | 52 | ![Mirroring Handle Movement](./Images/Bezier3DSpline_MirrorHandleMovement01.gif) 53 | 54 | ### Visualize Rotation 55 | What is considered `Up` from any point along the spline is determined based on the rotation of the `Knot`s before and after that point along the spline. Toggling this option to be enabled (green) will render the orientation of the point along the spline as a set of lines based on its rotation where the green line indicates `Up`, the blue line indicates `Forward`, and the red line indicates `Right`. This can be useful when objects may need to set their rotation based on the rotation of a point along the spline and so editing the one or more `Knot`'s rotation and visualizing that rotation is essential. When disabled (red), this visualization will not appear. 56 | 57 | ![Mirroring Handle Movement](./Images/Bezier3DSpline_VisualizeRotation01.gif) --------------------------------------------------------------------------------