diff --git a/Assets/RuntimeGizmo/ExampleScene.unity b/Assets/RuntimeGizmo/ExampleScene.unity deleted file mode 100644 index 0d34cad..0000000 Binary files a/Assets/RuntimeGizmo/ExampleScene.unity and /dev/null differ diff --git a/LICENSE b/LICENSE.md similarity index 100% rename from LICENSE rename to LICENSE.md diff --git a/LICENSE.md.meta b/LICENSE.md.meta new file mode 100644 index 0000000..b3a2ff6 --- /dev/null +++ b/LICENSE.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7b8a3a554baef2846b2c9767f40d342c +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/README.md.meta b/README.md.meta new file mode 100644 index 0000000..1cd3fec --- /dev/null +++ b/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7ce19c001e624ed4bbe664bb5ad2be26 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime.meta b/Runtime.meta new file mode 100644 index 0000000..4096180 --- /dev/null +++ b/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bf9f17300c374b04089410425e9f43c1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Custom.meta b/Runtime/Custom.meta new file mode 100644 index 0000000..1a2a5db --- /dev/null +++ b/Runtime/Custom.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1655c02fb1b2f65428a7c4db5201cb02 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/Custom/TransformGizmoCustomGizmo.cs b/Runtime/Custom/TransformGizmoCustomGizmo.cs similarity index 100% rename from Assets/RuntimeGizmo/Custom/TransformGizmoCustomGizmo.cs rename to Runtime/Custom/TransformGizmoCustomGizmo.cs diff --git a/Runtime/Custom/TransformGizmoCustomGizmo.cs.meta b/Runtime/Custom/TransformGizmoCustomGizmo.cs.meta new file mode 100644 index 0000000..90d2e4b --- /dev/null +++ b/Runtime/Custom/TransformGizmoCustomGizmo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ed0d0164404fcf24b9cb6aceae2839a5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/ExampleScene.unity b/Runtime/ExampleScene.unity new file mode 100644 index 0000000..3f67191 --- /dev/null +++ b/Runtime/ExampleScene.unity @@ -0,0 +1,455 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 1 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 1 + m_BakeBackend: 0 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 512 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 0 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 0 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &343817361 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343817366} + - component: {fileID: 343817365} + - component: {fileID: 343817363} + - component: {fileID: 343817362} + m_Layer: 0 + m_Name: TransformGizmoCamera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &343817362 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343817361} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1c0ad0e8e55c95c4e931911c4b943a64, type: 3} + m_Name: + m_EditorClassIdentifier: + space: 0 + transformType: 0 + pivot: 0 + centerType: 0 + scaleType: 0 + SetMoveType: 119 + SetRotateType: 101 + SetScaleType: 114 + SetAllTransformType: 121 + SetSpaceToggle: 120 + SetPivotModeToggle: 122 + SetCenterTypeToggle: 99 + SetScaleTypeToggle: 115 + translationSnapping: 306 + AddSelection: 304 + RemoveSelection: 306 + ActionKey: 304 + UndoAction: 122 + RedoAction: 121 + xColor: {r: 1, g: 0, b: 0, a: 0.8} + yColor: {r: 0, g: 1, b: 0, a: 0.8} + zColor: {r: 0, g: 0, b: 1, a: 0.8} + allColor: {r: 0.7, g: 0.7, b: 0.7, a: 0.8} + selectedColor: {r: 1, g: 1, b: 0, a: 0.8} + hoverColor: {r: 1, g: 0.75, b: 0, a: 0.8} + planesOpacity: 0.5 + movementSnap: 0.25 + rotationSnap: 15 + scaleSnap: 1 + handleLength: 0.25 + handleWidth: 0.003 + planeSize: 0.035 + triangleSize: 0.03 + boxSize: 0.03 + circleDetail: 40 + allMoveHandleLengthMultiplier: 1 + allRotateHandleLengthMultiplier: 1.4 + allScaleHandleLengthMultiplier: 1.6 + minSelectedDistanceCheck: 0.01 + moveSpeedMultiplier: 1 + scaleSpeedMultiplier: 1 + rotateSpeedMultiplier: 1 + allRotateSpeedMultiplier: 20 + useFirstSelectedAsMain: 1 + circularRotationMethod: 0 + forceUpdatePivotPointOnChange: 1 + maxUndoStored: 100 + manuallyHandleGizmo: 0 + selectionMask: + serializedVersion: 2 + m_Bits: 4294967291 +--- !u!124 &343817363 +Behaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343817361} + m_Enabled: 1 +--- !u!20 &343817365 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343817361} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 0 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &343817366 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343817361} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1138828411 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1138828413} + - component: {fileID: 1138828412} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1138828412 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1138828411} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 0.8 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1138828413 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1138828411} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 15.92, y: -23.72, z: -27.58} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1755359865 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1755359869} + - component: {fileID: 1755359868} + - component: {fileID: 1755359867} + - component: {fileID: 1755359866} + m_Layer: 0 + m_Name: Cube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!23 &1755359866 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1755359865} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!65 &1755359867 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1755359865} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!33 &1755359868 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1755359865} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1755359869 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1755359865} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -2.48, y: 0.3, z: -4.1958246} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Assets/RuntimeGizmo/ExampleScene.unity.meta b/Runtime/ExampleScene.unity.meta similarity index 100% rename from Assets/RuntimeGizmo/ExampleScene.unity.meta rename to Runtime/ExampleScene.unity.meta diff --git a/Runtime/Helpers.meta b/Runtime/Helpers.meta new file mode 100644 index 0000000..433bcca --- /dev/null +++ b/Runtime/Helpers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7b8f4dfcdce6ce14d88c0fa01e36fac5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/Helpers/ExtMathf.cs b/Runtime/Helpers/ExtMathf.cs similarity index 100% rename from Assets/RuntimeGizmo/Helpers/ExtMathf.cs rename to Runtime/Helpers/ExtMathf.cs diff --git a/Runtime/Helpers/ExtMathf.cs.meta b/Runtime/Helpers/ExtMathf.cs.meta new file mode 100644 index 0000000..3efefa5 --- /dev/null +++ b/Runtime/Helpers/ExtMathf.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c19b77cf655524b4fa19c399a806dc69 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/Helpers/ExtTransform.cs b/Runtime/Helpers/ExtTransform.cs similarity index 100% rename from Assets/RuntimeGizmo/Helpers/ExtTransform.cs rename to Runtime/Helpers/ExtTransform.cs diff --git a/Runtime/Helpers/ExtTransform.cs.meta b/Runtime/Helpers/ExtTransform.cs.meta new file mode 100644 index 0000000..e6bd2fb --- /dev/null +++ b/Runtime/Helpers/ExtTransform.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 62f34bc7b87401d44bb0673b87761a4e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/Helpers/ExtTransformType.cs b/Runtime/Helpers/ExtTransformType.cs similarity index 100% rename from Assets/RuntimeGizmo/Helpers/ExtTransformType.cs rename to Runtime/Helpers/ExtTransformType.cs diff --git a/Runtime/Helpers/ExtTransformType.cs.meta b/Runtime/Helpers/ExtTransformType.cs.meta new file mode 100644 index 0000000..6271c1c --- /dev/null +++ b/Runtime/Helpers/ExtTransformType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ab358bd8079be654597ba80944a2f01a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/Helpers/ExtVector3.cs b/Runtime/Helpers/ExtVector3.cs similarity index 96% rename from Assets/RuntimeGizmo/Helpers/ExtVector3.cs rename to Runtime/Helpers/ExtVector3.cs index a643b58..e41a176 100644 --- a/Assets/RuntimeGizmo/Helpers/ExtVector3.cs +++ b/Runtime/Helpers/ExtVector3.cs @@ -1,29 +1,29 @@ -using System; -using UnityEngine; - -namespace RuntimeGizmos -{ - public static class ExtVector3 - { - public static float MagnitudeInDirection(Vector3 vector, Vector3 direction, bool normalizeParameters = true) - { - if(normalizeParameters) direction.Normalize(); - return Vector3.Dot(vector, direction); - } - - public static Vector3 Abs(this Vector3 vector) - { - return new Vector3(Mathf.Abs(vector.x), Mathf.Abs(vector.y), Mathf.Abs(vector.z)); - } - - public static bool IsParallel(Vector3 direction, Vector3 otherDirection, float precision = .0001f) - { - return Vector3.Cross(direction, otherDirection).sqrMagnitude < precision; - } - - public static bool IsInDirection(Vector3 direction, Vector3 otherDirection) - { - return Vector3.Dot(direction, otherDirection) > 0f; - } - } +using System; +using UnityEngine; + +namespace RuntimeGizmos +{ + public static class ExtVector3 + { + public static float MagnitudeInDirection(Vector3 vector, Vector3 direction, bool normalizeParameters = true) + { + if(normalizeParameters) direction.Normalize(); + return Vector3.Dot(vector, direction); + } + + public static Vector3 Abs(this Vector3 vector) + { + return new Vector3(Mathf.Abs(vector.x), Mathf.Abs(vector.y), Mathf.Abs(vector.z)); + } + + public static bool IsParallel(Vector3 direction, Vector3 otherDirection, float precision = .0001f) + { + return Vector3.Cross(direction, otherDirection).sqrMagnitude < precision; + } + + public static bool IsInDirection(Vector3 direction, Vector3 otherDirection) + { + return Vector3.Dot(direction, otherDirection) > 0f; + } + } } \ No newline at end of file diff --git a/Runtime/Helpers/ExtVector3.cs.meta b/Runtime/Helpers/ExtVector3.cs.meta new file mode 100644 index 0000000..3ba8573 --- /dev/null +++ b/Runtime/Helpers/ExtVector3.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 18fe7ab4b11f93d499aa87ec972df874 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/Helpers/Geometry.cs b/Runtime/Helpers/Geometry.cs similarity index 97% rename from Assets/RuntimeGizmo/Helpers/Geometry.cs rename to Runtime/Helpers/Geometry.cs index 04811eb..1350dc9 100644 --- a/Assets/RuntimeGizmo/Helpers/Geometry.cs +++ b/Runtime/Helpers/Geometry.cs @@ -1,101 +1,101 @@ -using System; -using UnityEngine; - -namespace RuntimeGizmos -{ - public static class Geometry - { - public static float LinePlaneDistance(Vector3 linePoint, Vector3 lineVec, Vector3 planePoint, Vector3 planeNormal) - { - //calculate the distance between the linePoint and the line-plane intersection point - float dotNumerator = Vector3.Dot((planePoint - linePoint), planeNormal); - float dotDenominator = Vector3.Dot(lineVec, planeNormal); - - //line and plane are not parallel - if(dotDenominator != 0f) - { - return dotNumerator / dotDenominator; - } - - return 0; - } - - //Note that the line is infinite, this is not a line-segment plane intersect - public static Vector3 LinePlaneIntersect(Vector3 linePoint, Vector3 lineVec, Vector3 planePoint, Vector3 planeNormal) - { - float distance = LinePlaneDistance(linePoint, lineVec, planePoint, planeNormal); - - //line and plane are not parallel - if(distance != 0f) - { - return linePoint + (lineVec * distance); - } - - return Vector3.zero; - } - - //Returns 2 points since on line 1 there will be a closest point to line 2, and on line 2 there will be a closest point to line 1. - public static IntersectPoints ClosestPointsOnTwoLines(Vector3 point1, Vector3 point1Direction, Vector3 point2, Vector3 point2Direction) - { - IntersectPoints intersections = new IntersectPoints(); - - //I dont think we need to normalize - //point1Direction.Normalize(); - //point2Direction.Normalize(); - - float a = Vector3.Dot(point1Direction, point1Direction); - float b = Vector3.Dot(point1Direction, point2Direction); - float e = Vector3.Dot(point2Direction, point2Direction); - - float d = a*e - b*b; - - //This is a check if parallel, howeverm since we are not normalizing the directions, it seems even if they are parallel they will not == 0 - //so they will get past this point, but its seems to be alright since it seems to still give a correct point (although a point very fary away). - //Also, if they are parallel and we dont normalize, the deciding point seems randomly choses on the lines, which while is still correct, - //our ClosestPointsOnTwoLineSegments gets undesireable results when on corners. (for example when using it in our ClosestPointOnTriangleToLine). - if(d != 0f) - { - Vector3 r = point1 - point2; - float c = Vector3.Dot(point1Direction, r); - float f = Vector3.Dot(point2Direction, r); - - float s = (b*f - c*e) / d; - float t = (a*f - c*b) / d; - - intersections.first = point1 + point1Direction * s; - intersections.second = point2 + point2Direction * t; - }else{ - //Lines are parallel, select any points next to eachother - intersections.first = point1; - intersections.second = point2 + Vector3.Project(point1 - point2, point2Direction); - } - - return intersections; - } - - public static IntersectPoints ClosestPointsOnSegmentToLine(Vector3 segment0, Vector3 segment1, Vector3 linePoint, Vector3 lineDirection) - { - IntersectPoints closests = ClosestPointsOnTwoLines(segment0, segment1 - segment0, linePoint, lineDirection); - closests.first = ClampToSegment(closests.first, segment0, segment1); - - return closests; - } - - //Assumes the point is already on the line somewhere - public static Vector3 ClampToSegment(Vector3 point, Vector3 linePoint1, Vector3 linePoint2) - { - Vector3 lineDirection = linePoint2 - linePoint1; - - if(!ExtVector3.IsInDirection(point - linePoint1, lineDirection)) - { - point = linePoint1; - } - else if(ExtVector3.IsInDirection(point - linePoint2, lineDirection)) - { - point = linePoint2; - } - - return point; - } - } +using System; +using UnityEngine; + +namespace RuntimeGizmos +{ + public static class Geometry + { + public static float LinePlaneDistance(Vector3 linePoint, Vector3 lineVec, Vector3 planePoint, Vector3 planeNormal) + { + //calculate the distance between the linePoint and the line-plane intersection point + float dotNumerator = Vector3.Dot((planePoint - linePoint), planeNormal); + float dotDenominator = Vector3.Dot(lineVec, planeNormal); + + //line and plane are not parallel + if(dotDenominator != 0f) + { + return dotNumerator / dotDenominator; + } + + return 0; + } + + //Note that the line is infinite, this is not a line-segment plane intersect + public static Vector3 LinePlaneIntersect(Vector3 linePoint, Vector3 lineVec, Vector3 planePoint, Vector3 planeNormal) + { + float distance = LinePlaneDistance(linePoint, lineVec, planePoint, planeNormal); + + //line and plane are not parallel + if(distance != 0f) + { + return linePoint + (lineVec * distance); + } + + return Vector3.zero; + } + + //Returns 2 points since on line 1 there will be a closest point to line 2, and on line 2 there will be a closest point to line 1. + public static IntersectPoints ClosestPointsOnTwoLines(Vector3 point1, Vector3 point1Direction, Vector3 point2, Vector3 point2Direction) + { + IntersectPoints intersections = new IntersectPoints(); + + //I dont think we need to normalize + //point1Direction.Normalize(); + //point2Direction.Normalize(); + + float a = Vector3.Dot(point1Direction, point1Direction); + float b = Vector3.Dot(point1Direction, point2Direction); + float e = Vector3.Dot(point2Direction, point2Direction); + + float d = a*e - b*b; + + //This is a check if parallel, howeverm since we are not normalizing the directions, it seems even if they are parallel they will not == 0 + //so they will get past this point, but its seems to be alright since it seems to still give a correct point (although a point very fary away). + //Also, if they are parallel and we dont normalize, the deciding point seems randomly choses on the lines, which while is still correct, + //our ClosestPointsOnTwoLineSegments gets undesireable results when on corners. (for example when using it in our ClosestPointOnTriangleToLine). + if(d != 0f) + { + Vector3 r = point1 - point2; + float c = Vector3.Dot(point1Direction, r); + float f = Vector3.Dot(point2Direction, r); + + float s = (b*f - c*e) / d; + float t = (a*f - c*b) / d; + + intersections.first = point1 + point1Direction * s; + intersections.second = point2 + point2Direction * t; + }else{ + //Lines are parallel, select any points next to eachother + intersections.first = point1; + intersections.second = point2 + Vector3.Project(point1 - point2, point2Direction); + } + + return intersections; + } + + public static IntersectPoints ClosestPointsOnSegmentToLine(Vector3 segment0, Vector3 segment1, Vector3 linePoint, Vector3 lineDirection) + { + IntersectPoints closests = ClosestPointsOnTwoLines(segment0, segment1 - segment0, linePoint, lineDirection); + closests.first = ClampToSegment(closests.first, segment0, segment1); + + return closests; + } + + //Assumes the point is already on the line somewhere + public static Vector3 ClampToSegment(Vector3 point, Vector3 linePoint1, Vector3 linePoint2) + { + Vector3 lineDirection = linePoint2 - linePoint1; + + if(!ExtVector3.IsInDirection(point - linePoint1, lineDirection)) + { + point = linePoint1; + } + else if(ExtVector3.IsInDirection(point - linePoint2, lineDirection)) + { + point = linePoint2; + } + + return point; + } + } } \ No newline at end of file diff --git a/Runtime/Helpers/Geometry.cs.meta b/Runtime/Helpers/Geometry.cs.meta new file mode 100644 index 0000000..fa266b4 --- /dev/null +++ b/Runtime/Helpers/Geometry.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7c71d0519379d4f48a1768d3be42bdfa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/HiddenMonk.U3DRTG.asmdef b/Runtime/HiddenMonk.U3DRTG.asmdef new file mode 100644 index 0000000..4be0f09 --- /dev/null +++ b/Runtime/HiddenMonk.U3DRTG.asmdef @@ -0,0 +1,13 @@ +{ + "name": "HiddenMonk.U3DRTG", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} diff --git a/Runtime/Objects.meta b/Runtime/Objects.meta new file mode 100644 index 0000000..5e94b68 --- /dev/null +++ b/Runtime/Objects.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 15d948480b6ae53409c10cd53ac06bcb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/Objects/AxisInfo.cs b/Runtime/Objects/AxisInfo.cs similarity index 95% rename from Assets/RuntimeGizmo/Objects/AxisInfo.cs rename to Runtime/Objects/AxisInfo.cs index 51a739b..c3f1cba 100644 --- a/Assets/RuntimeGizmo/Objects/AxisInfo.cs +++ b/Runtime/Objects/AxisInfo.cs @@ -1,48 +1,48 @@ -using System; -using UnityEngine; - -namespace RuntimeGizmos -{ - public struct AxisInfo - { - public Vector3 pivot; - public Vector3 xDirection; - public Vector3 yDirection; - public Vector3 zDirection; - - public void Set(Transform target, Vector3 pivot, TransformSpace space) - { - if(space == TransformSpace.Global) - { - xDirection = Vector3.right; - yDirection = Vector3.up; - zDirection = Vector3.forward; - } - else if(space == TransformSpace.Local) - { - xDirection = target.right; - yDirection = target.up; - zDirection = target.forward; - } - - this.pivot = pivot; - } - - public Vector3 GetXAxisEnd(float size) - { - return pivot + (xDirection * size); - } - public Vector3 GetYAxisEnd(float size) - { - return pivot + (yDirection * size); - } - public Vector3 GetZAxisEnd(float size) - { - return pivot + (zDirection * size); - } - public Vector3 GetAxisEnd(Vector3 direction, float size) - { - return pivot + (direction * size); - } - } -} +using System; +using UnityEngine; + +namespace RuntimeGizmos +{ + public struct AxisInfo + { + public Vector3 pivot; + public Vector3 xDirection; + public Vector3 yDirection; + public Vector3 zDirection; + + public void Set(Transform target, Vector3 pivot, TransformSpace space) + { + if(space == TransformSpace.Global) + { + xDirection = Vector3.right; + yDirection = Vector3.up; + zDirection = Vector3.forward; + } + else if(space == TransformSpace.Local) + { + xDirection = target.right; + yDirection = target.up; + zDirection = target.forward; + } + + this.pivot = pivot; + } + + public Vector3 GetXAxisEnd(float size) + { + return pivot + (xDirection * size); + } + public Vector3 GetYAxisEnd(float size) + { + return pivot + (yDirection * size); + } + public Vector3 GetZAxisEnd(float size) + { + return pivot + (zDirection * size); + } + public Vector3 GetAxisEnd(Vector3 direction, float size) + { + return pivot + (direction * size); + } + } +} diff --git a/Runtime/Objects/AxisInfo.cs.meta b/Runtime/Objects/AxisInfo.cs.meta new file mode 100644 index 0000000..20f932a --- /dev/null +++ b/Runtime/Objects/AxisInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: aa6fd2a92a4050449b66e44f5a94b84a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/Objects/AxisVectors.cs b/Runtime/Objects/AxisVectors.cs similarity index 95% rename from Assets/RuntimeGizmo/Objects/AxisVectors.cs rename to Runtime/Objects/AxisVectors.cs index 8fcbf4f..4f41741 100644 --- a/Assets/RuntimeGizmo/Objects/AxisVectors.cs +++ b/Runtime/Objects/AxisVectors.cs @@ -1,30 +1,30 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace RuntimeGizmos -{ - public class AxisVectors - { - public List x = new List(); - public List y = new List(); - public List z = new List(); - public List all = new List(); - - public void Add(AxisVectors axisVectors) - { - x.AddRange(axisVectors.x); - y.AddRange(axisVectors.y); - z.AddRange(axisVectors.z); - all.AddRange(axisVectors.all); - } - - public void Clear() - { - x.Clear(); - y.Clear(); - z.Clear(); - all.Clear(); - } - } +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace RuntimeGizmos +{ + public class AxisVectors + { + public List x = new List(); + public List y = new List(); + public List z = new List(); + public List all = new List(); + + public void Add(AxisVectors axisVectors) + { + x.AddRange(axisVectors.x); + y.AddRange(axisVectors.y); + z.AddRange(axisVectors.z); + all.AddRange(axisVectors.all); + } + + public void Clear() + { + x.Clear(); + y.Clear(); + z.Clear(); + all.Clear(); + } + } } \ No newline at end of file diff --git a/Runtime/Objects/AxisVectors.cs.meta b/Runtime/Objects/AxisVectors.cs.meta new file mode 100644 index 0000000..c3ab046 --- /dev/null +++ b/Runtime/Objects/AxisVectors.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c5b9f6e1522940a4481c34a1e2cb61cb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Objects/Commands.meta b/Runtime/Objects/Commands.meta new file mode 100644 index 0000000..fa8003b --- /dev/null +++ b/Runtime/Objects/Commands.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8cff0423ef5f09745a2b8ab76f6d9a2a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/Objects/Commands/SelectCommand.cs b/Runtime/Objects/Commands/SelectCommand.cs similarity index 100% rename from Assets/RuntimeGizmo/Objects/Commands/SelectCommand.cs rename to Runtime/Objects/Commands/SelectCommand.cs diff --git a/Runtime/Objects/Commands/SelectCommand.cs.meta b/Runtime/Objects/Commands/SelectCommand.cs.meta new file mode 100644 index 0000000..ee49b2e --- /dev/null +++ b/Runtime/Objects/Commands/SelectCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4a35275560d01eb42840a13ecb09ba3f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/Objects/Commands/TransformCommand.cs b/Runtime/Objects/Commands/TransformCommand.cs similarity index 100% rename from Assets/RuntimeGizmo/Objects/Commands/TransformCommand.cs rename to Runtime/Objects/Commands/TransformCommand.cs diff --git a/Runtime/Objects/Commands/TransformCommand.cs.meta b/Runtime/Objects/Commands/TransformCommand.cs.meta new file mode 100644 index 0000000..6122cdc --- /dev/null +++ b/Runtime/Objects/Commands/TransformCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 36ed56c6c6b78bd4b9373631584bf2c5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/Objects/Enums.cs b/Runtime/Objects/Enums.cs similarity index 98% rename from Assets/RuntimeGizmo/Objects/Enums.cs rename to Runtime/Objects/Enums.cs index 2e02381..eadfede 100644 --- a/Assets/RuntimeGizmo/Objects/Enums.cs +++ b/Runtime/Objects/Enums.cs @@ -1,18 +1,18 @@ -namespace RuntimeGizmos -{ - public enum TransformSpace {Global, Local} - public enum TransformType {Move, Rotate, Scale /*, RectTool*/, All} - public enum TransformPivot {Pivot, Center} - public enum Axis {None, X, Y, Z, Any} - - //CenterType.All is the center of the current object mesh or pivot if not mesh and all its childrens mesh or pivot if no mesh. - // CenterType.All might give different results than unity I think because unity only counts empty gameobjects a little bit, as if they have less weight. - //CenterType.Solo is the center of the current objects mesh or pivot if no mesh. - //Unity seems to use colliders first to use to find how much weight the object has or something to decide how much it effects the center, - //but for now we only look at the Renderer.bounds.center, so expect some differences between unity. - public enum CenterType {All, Solo} - - //ScaleType.FromPoint acts as if you are using a parent transform as your new pivot and transforming that parent instead of the child. - //ScaleType.FromPointOffset acts as if you are scaling based on a point that is offset from the actual pivot. Its similar to unity editor scaling in Center pivot mode (though a little inaccurate if object is skewed) - public enum ScaleType {FromPoint, FromPointOffset} -} +namespace RuntimeGizmos +{ + public enum TransformSpace {Global, Local} + public enum TransformType {Move, Rotate, Scale /*, RectTool*/, All} + public enum TransformPivot {Pivot, Center} + public enum Axis {None, X, Y, Z, Any} + + //CenterType.All is the center of the current object mesh or pivot if not mesh and all its childrens mesh or pivot if no mesh. + // CenterType.All might give different results than unity I think because unity only counts empty gameobjects a little bit, as if they have less weight. + //CenterType.Solo is the center of the current objects mesh or pivot if no mesh. + //Unity seems to use colliders first to use to find how much weight the object has or something to decide how much it effects the center, + //but for now we only look at the Renderer.bounds.center, so expect some differences between unity. + public enum CenterType {All, Solo} + + //ScaleType.FromPoint acts as if you are using a parent transform as your new pivot and transforming that parent instead of the child. + //ScaleType.FromPointOffset acts as if you are scaling based on a point that is offset from the actual pivot. Its similar to unity editor scaling in Center pivot mode (though a little inaccurate if object is skewed) + public enum ScaleType {FromPoint, FromPointOffset} +} diff --git a/Runtime/Objects/Enums.cs.meta b/Runtime/Objects/Enums.cs.meta new file mode 100644 index 0000000..d19ee22 --- /dev/null +++ b/Runtime/Objects/Enums.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d9a5880deb7a26b4981e7f9c93257aa3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/Objects/IntersectPoints.cs b/Runtime/Objects/IntersectPoints.cs similarity index 94% rename from Assets/RuntimeGizmo/Objects/IntersectPoints.cs rename to Runtime/Objects/IntersectPoints.cs index 95b9d35..52204a2 100644 --- a/Assets/RuntimeGizmo/Objects/IntersectPoints.cs +++ b/Runtime/Objects/IntersectPoints.cs @@ -1,17 +1,17 @@ -using System; -using UnityEngine; - -namespace RuntimeGizmos -{ - public struct IntersectPoints - { - public Vector3 first; - public Vector3 second; - - public IntersectPoints(Vector3 first, Vector3 second) - { - this.first = first; - this.second = second; - } - } +using System; +using UnityEngine; + +namespace RuntimeGizmos +{ + public struct IntersectPoints + { + public Vector3 first; + public Vector3 second; + + public IntersectPoints(Vector3 first, Vector3 second) + { + this.first = first; + this.second = second; + } + } } \ No newline at end of file diff --git a/Runtime/Objects/IntersectPoints.cs.meta b/Runtime/Objects/IntersectPoints.cs.meta new file mode 100644 index 0000000..08e35ec --- /dev/null +++ b/Runtime/Objects/IntersectPoints.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 106288cb550d7664ab244e20aa856fc5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/Objects/Square.cs b/Runtime/Objects/Square.cs similarity index 94% rename from Assets/RuntimeGizmo/Objects/Square.cs rename to Runtime/Objects/Square.cs index 77603e1..ce303ae 100644 --- a/Assets/RuntimeGizmo/Objects/Square.cs +++ b/Runtime/Objects/Square.cs @@ -1,35 +1,35 @@ -using System; -using UnityEngine; - -namespace RuntimeGizmos -{ - public struct Square - { - public Vector3 bottomLeft; - public Vector3 bottomRight; - public Vector3 topLeft; - public Vector3 topRight; - - public Vector3 this[int index] - { - get - { - switch (index) - { - case 0: - return this.bottomLeft; - case 1: - return this.topLeft; - case 2: - return this.topRight; - case 3: - return this.bottomRight; - case 4: - return this.bottomLeft; //so we wrap around back to start - default: - return Vector3.zero; - } - } - } - } -} +using System; +using UnityEngine; + +namespace RuntimeGizmos +{ + public struct Square + { + public Vector3 bottomLeft; + public Vector3 bottomRight; + public Vector3 topLeft; + public Vector3 topRight; + + public Vector3 this[int index] + { + get + { + switch (index) + { + case 0: + return this.bottomLeft; + case 1: + return this.topLeft; + case 2: + return this.topRight; + case 3: + return this.bottomRight; + case 4: + return this.bottomLeft; //so we wrap around back to start + default: + return Vector3.zero; + } + } + } + } +} diff --git a/Runtime/Objects/Square.cs.meta b/Runtime/Objects/Square.cs.meta new file mode 100644 index 0000000..c11d03f --- /dev/null +++ b/Runtime/Objects/Square.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be97ba7ba7259854c9754f6826278109 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/Objects/TargetInfo.cs b/Runtime/Objects/TargetInfo.cs similarity index 100% rename from Assets/RuntimeGizmo/Objects/TargetInfo.cs rename to Runtime/Objects/TargetInfo.cs diff --git a/Runtime/Objects/TargetInfo.cs.meta b/Runtime/Objects/TargetInfo.cs.meta new file mode 100644 index 0000000..6624121 --- /dev/null +++ b/Runtime/Objects/TargetInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0e1a20576a5ea48408d44c986576ad5f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Shader.meta b/Runtime/Shader.meta new file mode 100644 index 0000000..7c3fe93 --- /dev/null +++ b/Runtime/Shader.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dc4932da2f50bec4b931df6d4ff016a6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Shader/Resources.meta b/Runtime/Shader/Resources.meta new file mode 100644 index 0000000..08be983 --- /dev/null +++ b/Runtime/Shader/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 05265a0b951a56b40a659f09b8ccf283 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/Shader/Resources/Lines.shader b/Runtime/Shader/Resources/Lines.shader similarity index 92% rename from Assets/RuntimeGizmo/Shader/Resources/Lines.shader rename to Runtime/Shader/Resources/Lines.shader index f16f99e..56cb4ff 100644 --- a/Assets/RuntimeGizmo/Shader/Resources/Lines.shader +++ b/Runtime/Shader/Resources/Lines.shader @@ -1,20 +1,20 @@ -Shader "Custom/Lines" -{ - SubShader - { - Pass - { - Blend SrcAlpha OneMinusSrcAlpha - ZWrite Off - ZTest Always - Cull Off - Fog { Mode Off } - - BindChannels - { - Bind "vertex", vertex - Bind "color", color - } - } - } +Shader "Custom/Lines" +{ + SubShader + { + Pass + { + Blend SrcAlpha OneMinusSrcAlpha + ZWrite Off + ZTest Always + Cull Off + Fog { Mode Off } + + BindChannels + { + Bind "vertex", vertex + Bind "color", color + } + } + } } \ No newline at end of file diff --git a/Runtime/Shader/Resources/Lines.shader.meta b/Runtime/Shader/Resources/Lines.shader.meta new file mode 100644 index 0000000..2b3aa67 --- /dev/null +++ b/Runtime/Shader/Resources/Lines.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: dff0d28b19790ec4ca1037bb398cb40b +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/Shader/Resources/Outline.shader b/Runtime/Shader/Resources/Outline.shader similarity index 100% rename from Assets/RuntimeGizmo/Shader/Resources/Outline.shader rename to Runtime/Shader/Resources/Outline.shader diff --git a/Runtime/Shader/Resources/Outline.shader.meta b/Runtime/Shader/Resources/Outline.shader.meta new file mode 100644 index 0000000..bf19386 --- /dev/null +++ b/Runtime/Shader/Resources/Outline.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e6dbce706e2548442b17680aa37c3856 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/TransformGizmo.cs b/Runtime/TransformGizmo.cs similarity index 97% rename from Assets/RuntimeGizmo/TransformGizmo.cs rename to Runtime/TransformGizmo.cs index fdf4550..efeb17b 100644 --- a/Assets/RuntimeGizmo/TransformGizmo.cs +++ b/Runtime/TransformGizmo.cs @@ -1,1425 +1,1425 @@ -using System; -using UnityEngine; -using System.Collections.Generic; -using System.Collections; -using CommandUndoRedo; - -namespace RuntimeGizmos -{ - //To be safe, if you are changing any transforms hierarchy, such as parenting an object to something, - //you should call ClearTargets before doing so just to be sure nothing unexpected happens... as well as call UndoRedoManager.Clear() - //For example, if you select an object that has children, move the children elsewhere, deselect the original object, then try to add those old children to the selection, I think it wont work. - - [RequireComponent(typeof(Camera))] - public class TransformGizmo : MonoBehaviour - { - public TransformSpace space = TransformSpace.Global; - public TransformType transformType = TransformType.Move; - public TransformPivot pivot = TransformPivot.Pivot; - public CenterType centerType = CenterType.All; - public ScaleType scaleType = ScaleType.FromPoint; - - //These are the same as the unity editor hotkeys - public KeyCode SetMoveType = KeyCode.W; - public KeyCode SetRotateType = KeyCode.E; - public KeyCode SetScaleType = KeyCode.R; - //public KeyCode SetRectToolType = KeyCode.T; - public KeyCode SetAllTransformType = KeyCode.Y; - public KeyCode SetSpaceToggle = KeyCode.X; - public KeyCode SetPivotModeToggle = KeyCode.Z; - public KeyCode SetCenterTypeToggle = KeyCode.C; - public KeyCode SetScaleTypeToggle = KeyCode.S; - public KeyCode translationSnapping = KeyCode.LeftControl; - public KeyCode AddSelection = KeyCode.LeftShift; - public KeyCode RemoveSelection = KeyCode.LeftControl; - public KeyCode ActionKey = KeyCode.LeftShift; //Its set to shift instead of control so that while in the editor we dont accidentally undo editor changes =/ - public KeyCode UndoAction = KeyCode.Z; - public KeyCode RedoAction = KeyCode.Y; - - public Color xColor = new Color(1, 0, 0, 0.8f); - public Color yColor = new Color(0, 1, 0, 0.8f); - public Color zColor = new Color(0, 0, 1, 0.8f); - public Color allColor = new Color(.7f, .7f, .7f, 0.8f); - public Color selectedColor = new Color(1, 1, 0, 0.8f); - public Color hoverColor = new Color(1, .75f, 0, 0.8f); - public float planesOpacity = .5f; - //public Color rectPivotColor = new Color(0, 0, 1, 0.8f); - //public Color rectCornerColor = new Color(0, 0, 1, 0.8f); - //public Color rectAnchorColor = new Color(.7f, .7f, .7f, 0.8f); - //public Color rectLineColor = new Color(.7f, .7f, .7f, 0.8f); - - public float movementSnap = .25f; - public float rotationSnap = 15f; - public float scaleSnap = 1f; - - public float handleLength = .25f; - public float handleWidth = .003f; - public float planeSize = .035f; - public float triangleSize = .03f; - public float boxSize = .03f; - public int circleDetail = 40; - public float allMoveHandleLengthMultiplier = 1f; - public float allRotateHandleLengthMultiplier = 1.4f; - public float allScaleHandleLengthMultiplier = 1.6f; - public float minSelectedDistanceCheck = .01f; - public float moveSpeedMultiplier = 1f; - public float scaleSpeedMultiplier = 1f; - public float rotateSpeedMultiplier = 1f; - public float allRotateSpeedMultiplier = 20f; - - public bool useFirstSelectedAsMain = true; - - //If circularRotationMethod is true, when rotating you will need to move your mouse around the object as if turning a wheel. - //If circularRotationMethod is false, when rotating you can just click and drag in a line to rotate. - public bool circularRotationMethod; - - //Mainly for if you want the pivot point to update correctly if selected objects are moving outside the transformgizmo. - //Might be poor on performance if lots of objects are selected... - public bool forceUpdatePivotPointOnChange = true; - - public int maxUndoStored = 100; - - public bool manuallyHandleGizmo; - - public LayerMask selectionMask = Physics.DefaultRaycastLayers; - - public Action onCheckForSelectedAxis; - public Action onDrawCustomGizmo; - - public Camera myCamera {get; private set;} - - public bool isTransforming {get; private set;} - public float totalScaleAmount {get; private set;} - public Quaternion totalRotationAmount {get; private set;} - public Axis translatingAxis {get {return nearAxis;}} - public Axis translatingAxisPlane {get {return planeAxis;}} - public bool hasTranslatingAxisPlane {get {return translatingAxisPlane != Axis.None && translatingAxisPlane != Axis.Any;}} - public TransformType transformingType {get {return translatingType;}} - - public Vector3 pivotPoint {get; private set;} - Vector3 totalCenterPivotPoint; - - public Transform mainTargetRoot {get {return (targetRootsOrdered.Count > 0) ? (useFirstSelectedAsMain) ? targetRootsOrdered[0] : targetRootsOrdered[targetRootsOrdered.Count - 1] : null;}} - - AxisInfo axisInfo; - Axis nearAxis = Axis.None; - Axis planeAxis = Axis.None; - TransformType translatingType; - - AxisVectors handleLines = new AxisVectors(); - AxisVectors handlePlanes = new AxisVectors(); - AxisVectors handleTriangles = new AxisVectors(); - AxisVectors handleSquares = new AxisVectors(); - AxisVectors circlesLines = new AxisVectors(); - - //We use a HashSet and a List for targetRoots so that we get fast lookup with the hashset while also keeping track of the order with the list. - List targetRootsOrdered = new List(); - Dictionary targetRoots = new Dictionary(); - HashSet highlightedRenderers = new HashSet(); - HashSet children = new HashSet(); - - List childrenBuffer = new List(); - List renderersBuffer = new List(); - List materialsBuffer = new List(); - - WaitForEndOfFrame waitForEndOFFrame = new WaitForEndOfFrame(); - Coroutine forceUpdatePivotCoroutine; - - static Material lineMaterial; - static Material outlineMaterial; - - void Awake() - { - myCamera = GetComponent(); - SetMaterial(); - } - - void OnEnable() - { - forceUpdatePivotCoroutine = StartCoroutine(ForceUpdatePivotPointAtEndOfFrame()); - } - - void OnDisable() - { - ClearTargets(); //Just so things gets cleaned up, such as removing any materials we placed on objects. - - StopCoroutine(forceUpdatePivotCoroutine); - } - - void OnDestroy() - { - ClearAllHighlightedRenderers(); - } - - void Update() - { - HandleUndoRedo(); - - SetSpaceAndType(); - - if(manuallyHandleGizmo) - { - if(onCheckForSelectedAxis != null) onCheckForSelectedAxis(); - }else{ - SetNearAxis(); - } - - GetTarget(); - - if(mainTargetRoot == null) return; - - TransformSelected(); - } - - void LateUpdate() - { - if(mainTargetRoot == null) return; - - //We run this in lateupdate since coroutines run after update and we want our gizmos to have the updated target transform position after TransformSelected() - SetAxisInfo(); - - if(manuallyHandleGizmo) - { - if(onDrawCustomGizmo != null) onDrawCustomGizmo(); - }else{ - SetLines(); - } - } - - void OnPostRender() - { - if(mainTargetRoot == null || manuallyHandleGizmo) return; - - lineMaterial.SetPass(0); - - Color xColor = (nearAxis == Axis.X) ? (isTransforming) ? selectedColor : hoverColor : this.xColor; - Color yColor = (nearAxis == Axis.Y) ? (isTransforming) ? selectedColor : hoverColor : this.yColor; - Color zColor = (nearAxis == Axis.Z) ? (isTransforming) ? selectedColor : hoverColor : this.zColor; - Color allColor = (nearAxis == Axis.Any) ? (isTransforming) ? selectedColor : hoverColor : this.allColor; - - //Note: The order of drawing the axis decides what gets drawn over what. - - TransformType moveOrScaleType = (transformType == TransformType.Scale || (isTransforming && translatingType == TransformType.Scale)) ? TransformType.Scale : TransformType.Move; - DrawQuads(handleLines.z, GetColor(moveOrScaleType, this.zColor, zColor, hasTranslatingAxisPlane)); - DrawQuads(handleLines.x, GetColor(moveOrScaleType, this.xColor, xColor, hasTranslatingAxisPlane)); - DrawQuads(handleLines.y, GetColor(moveOrScaleType, this.yColor, yColor, hasTranslatingAxisPlane)); - - DrawTriangles(handleTriangles.x, GetColor(TransformType.Move, this.xColor, xColor, hasTranslatingAxisPlane)); - DrawTriangles(handleTriangles.y, GetColor(TransformType.Move, this.yColor, yColor, hasTranslatingAxisPlane)); - DrawTriangles(handleTriangles.z, GetColor(TransformType.Move, this.zColor, zColor, hasTranslatingAxisPlane)); - - DrawQuads(handlePlanes.z, GetColor(TransformType.Move, this.zColor, zColor, planesOpacity, !hasTranslatingAxisPlane)); - DrawQuads(handlePlanes.x, GetColor(TransformType.Move, this.xColor, xColor, planesOpacity, !hasTranslatingAxisPlane)); - DrawQuads(handlePlanes.y, GetColor(TransformType.Move, this.yColor, yColor, planesOpacity, !hasTranslatingAxisPlane)); - - DrawQuads(handleSquares.x, GetColor(TransformType.Scale, this.xColor, xColor)); - DrawQuads(handleSquares.y, GetColor(TransformType.Scale, this.yColor, yColor)); - DrawQuads(handleSquares.z, GetColor(TransformType.Scale, this.zColor, zColor)); - DrawQuads(handleSquares.all, GetColor(TransformType.Scale, this.allColor, allColor)); - - DrawQuads(circlesLines.all, GetColor(TransformType.Rotate, this.allColor, allColor)); - DrawQuads(circlesLines.x, GetColor(TransformType.Rotate, this.xColor, xColor)); - DrawQuads(circlesLines.y, GetColor(TransformType.Rotate, this.yColor, yColor)); - DrawQuads(circlesLines.z, GetColor(TransformType.Rotate, this.zColor, zColor)); - } - - Color GetColor(TransformType type, Color normalColor, Color nearColor, bool forceUseNormal = false) - { - return GetColor(type, normalColor, nearColor, false, 1, forceUseNormal); - } - Color GetColor(TransformType type, Color normalColor, Color nearColor, float alpha, bool forceUseNormal = false) - { - return GetColor(type, normalColor, nearColor, true, alpha, forceUseNormal); - } - Color GetColor(TransformType type, Color normalColor, Color nearColor, bool setAlpha, float alpha, bool forceUseNormal = false) - { - Color color; - if(!forceUseNormal && TranslatingTypeContains(type, false)) - { - color = nearColor; - }else{ - color = normalColor; - } - - if(setAlpha) - { - color.a = alpha; - } - - return color; - } - - void HandleUndoRedo() - { - if(maxUndoStored != UndoRedoManager.maxUndoStored) { UndoRedoManager.maxUndoStored = maxUndoStored; } - - if(Input.GetKey(ActionKey)) - { - if(Input.GetKeyDown(UndoAction)) - { - UndoRedoManager.Undo(); - } - else if(Input.GetKeyDown(RedoAction)) - { - UndoRedoManager.Redo(); - } - } - } - - //We only support scaling in local space. - public TransformSpace GetProperTransformSpace() - { - return transformType == TransformType.Scale ? TransformSpace.Local : space; - } - - public bool TransformTypeContains(TransformType type) - { - return TransformTypeContains(transformType, type); - } - public bool TranslatingTypeContains(TransformType type, bool checkIsTransforming = true) - { - TransformType transType = !checkIsTransforming || isTransforming ? translatingType : transformType; - return TransformTypeContains(transType, type); - } - public bool TransformTypeContains(TransformType mainType, TransformType type) - { - return ExtTransformType.TransformTypeContains(mainType, type, GetProperTransformSpace()); - } - - public float GetHandleLength(TransformType type, Axis axis = Axis.None, bool multiplyDistanceMultiplier = true) - { - float length = handleLength; - if(transformType == TransformType.All) - { - if(type == TransformType.Move) length *= allMoveHandleLengthMultiplier; - if(type == TransformType.Rotate) length *= allRotateHandleLengthMultiplier; - if(type == TransformType.Scale) length *= allScaleHandleLengthMultiplier; - } - - if(multiplyDistanceMultiplier) length *= GetDistanceMultiplier(); - - if(type == TransformType.Scale && isTransforming && (translatingAxis == axis || translatingAxis == Axis.Any)) length += totalScaleAmount; - - return length; - } - - void SetSpaceAndType() - { - if(Input.GetKey(ActionKey)) return; - - if(Input.GetKeyDown(SetMoveType)) transformType = TransformType.Move; - else if(Input.GetKeyDown(SetRotateType)) transformType = TransformType.Rotate; - else if(Input.GetKeyDown(SetScaleType)) transformType = TransformType.Scale; - //else if(Input.GetKeyDown(SetRectToolType)) type = TransformType.RectTool; - else if(Input.GetKeyDown(SetAllTransformType)) transformType = TransformType.All; - - if(!isTransforming) translatingType = transformType; - - if(Input.GetKeyDown(SetPivotModeToggle)) - { - if(pivot == TransformPivot.Pivot) pivot = TransformPivot.Center; - else if(pivot == TransformPivot.Center) pivot = TransformPivot.Pivot; - - SetPivotPoint(); - } - - if(Input.GetKeyDown(SetCenterTypeToggle)) - { - if(centerType == CenterType.All) centerType = CenterType.Solo; - else if(centerType == CenterType.Solo) centerType = CenterType.All; - - SetPivotPoint(); - } - - if(Input.GetKeyDown(SetSpaceToggle)) - { - if(space == TransformSpace.Global) space = TransformSpace.Local; - else if(space == TransformSpace.Local) space = TransformSpace.Global; - } - - if(Input.GetKeyDown(SetScaleTypeToggle)) - { - if(scaleType == ScaleType.FromPoint) scaleType = ScaleType.FromPointOffset; - else if(scaleType == ScaleType.FromPointOffset) scaleType = ScaleType.FromPoint; - } - - if(transformType == TransformType.Scale) - { - if(pivot == TransformPivot.Pivot) scaleType = ScaleType.FromPoint; //FromPointOffset can be inaccurate and should only really be used in Center mode if desired. - } - } - - void TransformSelected() - { - if(mainTargetRoot != null) - { - if(nearAxis != Axis.None && Input.GetMouseButtonDown(0)) - { - StartCoroutine(TransformSelected(translatingType)); - } - } - } - - IEnumerator TransformSelected(TransformType transType) - { - isTransforming = true; - totalScaleAmount = 0; - totalRotationAmount = Quaternion.identity; - - Vector3 originalPivot = pivotPoint; - - Vector3 otherAxis1, otherAxis2; - Vector3 axis = GetNearAxisDirection(out otherAxis1, out otherAxis2); - Vector3 planeNormal = hasTranslatingAxisPlane ? axis : (transform.position - originalPivot).normalized; - Vector3 projectedAxis = Vector3.ProjectOnPlane(axis, planeNormal).normalized; - Vector3 previousMousePosition = Vector3.zero; - - Vector3 currentSnapMovementAmount = Vector3.zero; - float currentSnapRotationAmount = 0; - float currentSnapScaleAmount = 0; - - List transformCommands = new List(); - for(int i = 0; i < targetRootsOrdered.Count; i++) - { - transformCommands.Add(new TransformCommand(this, targetRootsOrdered[i])); - } - - while(!Input.GetMouseButtonUp(0)) - { - Ray mouseRay = myCamera.ScreenPointToRay(Input.mousePosition); - Vector3 mousePosition = Geometry.LinePlaneIntersect(mouseRay.origin, mouseRay.direction, originalPivot, planeNormal); - bool isSnapping = Input.GetKey(translationSnapping); - - if(previousMousePosition != Vector3.zero && mousePosition != Vector3.zero) - { - if(transType == TransformType.Move) - { - Vector3 movement = Vector3.zero; - - if(hasTranslatingAxisPlane) - { - movement = mousePosition - previousMousePosition; - }else{ - float moveAmount = ExtVector3.MagnitudeInDirection(mousePosition - previousMousePosition, projectedAxis) * moveSpeedMultiplier; - movement = axis * moveAmount; - } - - if(isSnapping && movementSnap > 0) - { - currentSnapMovementAmount += movement; - movement = Vector3.zero; - - if(hasTranslatingAxisPlane) - { - float amountInAxis1 = ExtVector3.MagnitudeInDirection(currentSnapMovementAmount, otherAxis1); - float amountInAxis2 = ExtVector3.MagnitudeInDirection(currentSnapMovementAmount, otherAxis2); - - float remainder1; - float snapAmount1 = CalculateSnapAmount(movementSnap, amountInAxis1, out remainder1); - float remainder2; - float snapAmount2 = CalculateSnapAmount(movementSnap, amountInAxis2, out remainder2); - - if(snapAmount1 != 0) - { - Vector3 snapMove = (otherAxis1 * snapAmount1); - movement += snapMove; - currentSnapMovementAmount -= snapMove; - } - if(snapAmount2 != 0) - { - Vector3 snapMove = (otherAxis2 * snapAmount2); - movement += snapMove; - currentSnapMovementAmount -= snapMove; - } - } - else - { - float remainder; - float snapAmount = CalculateSnapAmount(movementSnap, currentSnapMovementAmount.magnitude, out remainder); - - if(snapAmount != 0) - { - movement = currentSnapMovementAmount.normalized * snapAmount; - currentSnapMovementAmount = currentSnapMovementAmount.normalized * remainder; - } - } - } - - for(int i = 0; i < targetRootsOrdered.Count; i++) - { - Transform target = targetRootsOrdered[i]; - - target.Translate(movement, Space.World); - } - - SetPivotPointOffset(movement); - } - else if(transType == TransformType.Scale) - { - Vector3 projected = (nearAxis == Axis.Any) ? transform.right : projectedAxis; - float scaleAmount = ExtVector3.MagnitudeInDirection(mousePosition - previousMousePosition, projected) * scaleSpeedMultiplier; - - if(isSnapping && scaleSnap > 0) - { - currentSnapScaleAmount += scaleAmount; - scaleAmount = 0; - - float remainder; - float snapAmount = CalculateSnapAmount(scaleSnap, currentSnapScaleAmount, out remainder); - - if(snapAmount != 0) - { - scaleAmount = snapAmount; - currentSnapScaleAmount = remainder; - } - } - - //WARNING - There is a bug in unity 5.4 and 5.5 that causes InverseTransformDirection to be affected by scale which will break negative scaling. Not tested, but updating to 5.4.2 should fix it - https://issuetracker.unity3d.com/issues/transformdirection-and-inversetransformdirection-operations-are-affected-by-scale - Vector3 localAxis = (GetProperTransformSpace() == TransformSpace.Local && nearAxis != Axis.Any) ? mainTargetRoot.InverseTransformDirection(axis) : axis; - - Vector3 targetScaleAmount = Vector3.one; - if(nearAxis == Axis.Any) targetScaleAmount = (ExtVector3.Abs(mainTargetRoot.localScale.normalized) * scaleAmount); - else targetScaleAmount = localAxis * scaleAmount; - - for(int i = 0; i < targetRootsOrdered.Count; i++) - { - Transform target = targetRootsOrdered[i]; - - Vector3 targetScale = target.localScale + targetScaleAmount; - - if(pivot == TransformPivot.Pivot) - { - target.localScale = targetScale; - } - else if(pivot == TransformPivot.Center) - { - if(scaleType == ScaleType.FromPoint) - { - target.SetScaleFrom(originalPivot, targetScale); - } - else if(scaleType == ScaleType.FromPointOffset) - { - target.SetScaleFromOffset(originalPivot, targetScale); - } - } - } - - totalScaleAmount += scaleAmount; - } - else if(transType == TransformType.Rotate) - { - float rotateAmount = 0; - Vector3 rotationAxis = axis; - - if(nearAxis == Axis.Any) - { - Vector3 rotation = transform.TransformDirection(new Vector3(Input.GetAxis("Mouse Y"), -Input.GetAxis("Mouse X"), 0)); - Quaternion.Euler(rotation).ToAngleAxis(out rotateAmount, out rotationAxis); - rotateAmount *= allRotateSpeedMultiplier; - }else{ - if(circularRotationMethod) - { - float angle = Vector3.SignedAngle(previousMousePosition - originalPivot, mousePosition - originalPivot, axis); - rotateAmount = angle * rotateSpeedMultiplier; - }else{ - Vector3 projected = (nearAxis == Axis.Any || ExtVector3.IsParallel(axis, planeNormal)) ? planeNormal : Vector3.Cross(axis, planeNormal); - rotateAmount = (ExtVector3.MagnitudeInDirection(mousePosition - previousMousePosition, projected) * (rotateSpeedMultiplier * 100f)) / GetDistanceMultiplier(); - } - } - - if(isSnapping && rotationSnap > 0) - { - currentSnapRotationAmount += rotateAmount; - rotateAmount = 0; - - float remainder; - float snapAmount = CalculateSnapAmount(rotationSnap, currentSnapRotationAmount, out remainder); - - if(snapAmount != 0) - { - rotateAmount = snapAmount; - currentSnapRotationAmount = remainder; - } - } - - for(int i = 0; i < targetRootsOrdered.Count; i++) - { - Transform target = targetRootsOrdered[i]; - - if(pivot == TransformPivot.Pivot) - { - target.Rotate(rotationAxis, rotateAmount, Space.World); - } - else if(pivot == TransformPivot.Center) - { - target.RotateAround(originalPivot, rotationAxis, rotateAmount); - } - } - - totalRotationAmount *= Quaternion.Euler(rotationAxis * rotateAmount); - } - } - - previousMousePosition = mousePosition; - - yield return null; - } - - for(int i = 0; i < transformCommands.Count; i++) - { - ((TransformCommand)transformCommands[i]).StoreNewTransformValues(); - } - CommandGroup commandGroup = new CommandGroup(); - commandGroup.Set(transformCommands); - UndoRedoManager.Insert(commandGroup); - - totalRotationAmount = Quaternion.identity; - totalScaleAmount = 0; - isTransforming = false; - SetTranslatingAxis(transformType, Axis.None); - - SetPivotPoint(); - } - - float CalculateSnapAmount(float snapValue, float currentAmount, out float remainder) - { - remainder = 0; - if(snapValue <= 0) return currentAmount; - - float currentAmountAbs = Mathf.Abs(currentAmount); - if(currentAmountAbs > snapValue) - { - remainder = currentAmountAbs % snapValue; - return snapValue * (Mathf.Sign(currentAmount) * Mathf.Floor(currentAmountAbs / snapValue)); - } - - return 0; - } - - Vector3 GetNearAxisDirection(out Vector3 otherAxis1, out Vector3 otherAxis2) - { - otherAxis1 = otherAxis2 = Vector3.zero; - - if(nearAxis != Axis.None) - { - if(nearAxis == Axis.X) - { - otherAxis1 = axisInfo.yDirection; - otherAxis2 = axisInfo.zDirection; - return axisInfo.xDirection; - } - if(nearAxis == Axis.Y) - { - otherAxis1 = axisInfo.xDirection; - otherAxis2 = axisInfo.zDirection; - return axisInfo.yDirection; - } - if(nearAxis == Axis.Z) - { - otherAxis1 = axisInfo.xDirection; - otherAxis2 = axisInfo.yDirection; - return axisInfo.zDirection; - } - if(nearAxis == Axis.Any) - { - return Vector3.one; - } - } - - return Vector3.zero; - } - - void GetTarget() - { - if(nearAxis == Axis.None && Input.GetMouseButtonDown(0)) - { - bool isAdding = Input.GetKey(AddSelection); - bool isRemoving = Input.GetKey(RemoveSelection); - - RaycastHit hitInfo; - if(Physics.Raycast(myCamera.ScreenPointToRay(Input.mousePosition), out hitInfo, Mathf.Infinity, selectionMask)) - { - Transform target = hitInfo.transform; - - if(isAdding) - { - AddTarget(target); - } - else if(isRemoving) - { - RemoveTarget(target); - } - else if(!isAdding && !isRemoving) - { - ClearAndAddTarget(target); - } - }else{ - if(!isAdding && !isRemoving) - { - ClearTargets(); - } - } - } - } - - public void AddTarget(Transform target, bool addCommand = true) - { - if(target != null) - { - if(targetRoots.ContainsKey(target)) return; - if(children.Contains(target)) return; - - if(addCommand) UndoRedoManager.Insert(new AddTargetCommand(this, target, targetRootsOrdered)); - - AddTargetRoot(target); - AddTargetHighlightedRenderers(target); - - SetPivotPoint(); - } - } - - public void RemoveTarget(Transform target, bool addCommand = true) - { - if(target != null) - { - if(!targetRoots.ContainsKey(target)) return; - - if(addCommand) UndoRedoManager.Insert(new RemoveTargetCommand(this, target)); - - RemoveTargetHighlightedRenderers(target); - RemoveTargetRoot(target); - - SetPivotPoint(); - } - } - - public void ClearTargets(bool addCommand = true) - { - if(addCommand) UndoRedoManager.Insert(new ClearTargetsCommand(this, targetRootsOrdered)); - - ClearAllHighlightedRenderers(); - targetRoots.Clear(); - targetRootsOrdered.Clear(); - children.Clear(); - } - - void ClearAndAddTarget(Transform target) - { - UndoRedoManager.Insert(new ClearAndAddTargetCommand(this, target, targetRootsOrdered)); - - ClearTargets(false); - AddTarget(target, false); - } - - void AddTargetHighlightedRenderers(Transform target) - { - if(target != null) - { - GetTargetRenderers(target, renderersBuffer); - - for(int i = 0; i < renderersBuffer.Count; i++) - { - Renderer render = renderersBuffer[i]; - - if(!highlightedRenderers.Contains(render)) - { - materialsBuffer.Clear(); - materialsBuffer.AddRange(render.sharedMaterials); - - if(!materialsBuffer.Contains(outlineMaterial)) - { - materialsBuffer.Add(outlineMaterial); - render.materials = materialsBuffer.ToArray(); - } - - highlightedRenderers.Add(render); - } - } - - materialsBuffer.Clear(); - } - } - - void GetTargetRenderers(Transform target, List renderers) - { - renderers.Clear(); - if(target != null) - { - target.GetComponentsInChildren(true, renderers); - } - } - - void ClearAllHighlightedRenderers() - { - foreach(var target in targetRoots) - { - RemoveTargetHighlightedRenderers(target.Key); - } - - //In case any are still left, such as if they changed parents or what not when they were highlighted. - renderersBuffer.Clear(); - renderersBuffer.AddRange(highlightedRenderers); - RemoveHighlightedRenderers(renderersBuffer); - } - - void RemoveTargetHighlightedRenderers(Transform target) - { - GetTargetRenderers(target, renderersBuffer); - - RemoveHighlightedRenderers(renderersBuffer); - } - - void RemoveHighlightedRenderers(List renderers) - { - for(int i = 0; i < renderersBuffer.Count; i++) - { - Renderer render = renderersBuffer[i]; - if(render != null) - { - materialsBuffer.Clear(); - materialsBuffer.AddRange(render.sharedMaterials); - - if(materialsBuffer.Contains(outlineMaterial)) - { - materialsBuffer.Remove(outlineMaterial); - render.materials = materialsBuffer.ToArray(); - } - } - - highlightedRenderers.Remove(render); - } - - renderersBuffer.Clear(); - } - - void AddTargetRoot(Transform targetRoot) - { - targetRoots.Add(targetRoot, new TargetInfo()); - targetRootsOrdered.Add(targetRoot); - - AddAllChildren(targetRoot); - } - void RemoveTargetRoot(Transform targetRoot) - { - if(targetRoots.Remove(targetRoot)) - { - targetRootsOrdered.Remove(targetRoot); - - RemoveAllChildren(targetRoot); - } - } - - void AddAllChildren(Transform target) - { - childrenBuffer.Clear(); - target.GetComponentsInChildren(true, childrenBuffer); - childrenBuffer.Remove(target); - - for(int i = 0; i < childrenBuffer.Count; i++) - { - Transform child = childrenBuffer[i]; - children.Add(child); - RemoveTargetRoot(child); //We do this in case we selected child first and then the parent. - } - - childrenBuffer.Clear(); - } - void RemoveAllChildren(Transform target) - { - childrenBuffer.Clear(); - target.GetComponentsInChildren(true, childrenBuffer); - childrenBuffer.Remove(target); - - for(int i = 0; i < childrenBuffer.Count; i++) - { - children.Remove(childrenBuffer[i]); - } - - childrenBuffer.Clear(); - } - - public void SetPivotPoint() - { - if(mainTargetRoot != null) - { - if(pivot == TransformPivot.Pivot) - { - pivotPoint = mainTargetRoot.position; - } - else if(pivot == TransformPivot.Center) - { - totalCenterPivotPoint = Vector3.zero; - - Dictionary.Enumerator targetsEnumerator = targetRoots.GetEnumerator(); //We avoid foreach to avoid garbage. - while(targetsEnumerator.MoveNext()) - { - Transform target = targetsEnumerator.Current.Key; - TargetInfo info = targetsEnumerator.Current.Value; - info.centerPivotPoint = target.GetCenter(centerType); - - totalCenterPivotPoint += info.centerPivotPoint; - } - - totalCenterPivotPoint /= targetRoots.Count; - - if(centerType == CenterType.Solo) - { - pivotPoint = targetRoots[mainTargetRoot].centerPivotPoint; - } - else if(centerType == CenterType.All) - { - pivotPoint = totalCenterPivotPoint; - } - } - } - } - void SetPivotPointOffset(Vector3 offset) - { - pivotPoint += offset; - totalCenterPivotPoint += offset; - } - - - IEnumerator ForceUpdatePivotPointAtEndOfFrame() - { - while(this.enabled) - { - ForceUpdatePivotPointOnChange(); - yield return waitForEndOFFrame; - } - } - - void ForceUpdatePivotPointOnChange() - { - if(forceUpdatePivotPointOnChange) - { - if(mainTargetRoot != null && !isTransforming) - { - bool hasSet = false; - Dictionary.Enumerator targets = targetRoots.GetEnumerator(); - while(targets.MoveNext()) - { - if(!hasSet) - { - if(targets.Current.Value.previousPosition != Vector3.zero && targets.Current.Key.position != targets.Current.Value.previousPosition) - { - SetPivotPoint(); - hasSet = true; - } - } - - targets.Current.Value.previousPosition = targets.Current.Key.position; - } - } - } - } - - public void SetTranslatingAxis(TransformType type, Axis axis, Axis planeAxis = Axis.None) - { - this.translatingType = type; - this.nearAxis = axis; - this.planeAxis = planeAxis; - } - - public AxisInfo GetAxisInfo() - { - AxisInfo currentAxisInfo = axisInfo; - - if(isTransforming && GetProperTransformSpace() == TransformSpace.Global && translatingType == TransformType.Rotate) - { - currentAxisInfo.xDirection = totalRotationAmount * Vector3.right; - currentAxisInfo.yDirection = totalRotationAmount * Vector3.up; - currentAxisInfo.zDirection = totalRotationAmount * Vector3.forward; - } - - return currentAxisInfo; - } - - void SetNearAxis() - { - if(isTransforming) return; - - SetTranslatingAxis(transformType, Axis.None); - - if(mainTargetRoot == null) return; - - float distanceMultiplier = GetDistanceMultiplier(); - float handleMinSelectedDistanceCheck = (this.minSelectedDistanceCheck + handleWidth) * distanceMultiplier; - - if(nearAxis == Axis.None && (TransformTypeContains(TransformType.Move) || TransformTypeContains(TransformType.Scale))) - { - //Important to check scale lines before move lines since in TransformType.All the move planes would block the scales center scale all gizmo. - if(nearAxis == Axis.None && TransformTypeContains(TransformType.Scale)) - { - float tipMinSelectedDistanceCheck = (this.minSelectedDistanceCheck + boxSize) * distanceMultiplier; - HandleNearestPlanes(TransformType.Scale, handleSquares, tipMinSelectedDistanceCheck); - } - - if(nearAxis == Axis.None && TransformTypeContains(TransformType.Move)) - { - //Important to check the planes first before the handle tip since it makes selecting the planes easier. - float planeMinSelectedDistanceCheck = (this.minSelectedDistanceCheck + planeSize) * distanceMultiplier; - HandleNearestPlanes(TransformType.Move, handlePlanes, planeMinSelectedDistanceCheck); - - if(nearAxis != Axis.None) - { - planeAxis = nearAxis; - } - else - { - float tipMinSelectedDistanceCheck = (this.minSelectedDistanceCheck + triangleSize) * distanceMultiplier; - HandleNearestLines(TransformType.Move, handleTriangles, tipMinSelectedDistanceCheck); - } - } - - if(nearAxis == Axis.None) - { - //Since Move and Scale share the same handle line, we give Move the priority. - TransformType transType = transformType == TransformType.All ? TransformType.Move : transformType; - HandleNearestLines(transType, handleLines, handleMinSelectedDistanceCheck); - } - } - - if(nearAxis == Axis.None && TransformTypeContains(TransformType.Rotate)) - { - HandleNearestLines(TransformType.Rotate, circlesLines, handleMinSelectedDistanceCheck); - } - } - - void HandleNearestLines(TransformType type, AxisVectors axisVectors, float minSelectedDistanceCheck) - { - float xClosestDistance = ClosestDistanceFromMouseToLines(axisVectors.x); - float yClosestDistance = ClosestDistanceFromMouseToLines(axisVectors.y); - float zClosestDistance = ClosestDistanceFromMouseToLines(axisVectors.z); - float allClosestDistance = ClosestDistanceFromMouseToLines(axisVectors.all); - - HandleNearest(type, xClosestDistance, yClosestDistance, zClosestDistance, allClosestDistance, minSelectedDistanceCheck); - } - - void HandleNearestPlanes(TransformType type, AxisVectors axisVectors, float minSelectedDistanceCheck) - { - float xClosestDistance = ClosestDistanceFromMouseToPlanes(axisVectors.x); - float yClosestDistance = ClosestDistanceFromMouseToPlanes(axisVectors.y); - float zClosestDistance = ClosestDistanceFromMouseToPlanes(axisVectors.z); - float allClosestDistance = ClosestDistanceFromMouseToPlanes(axisVectors.all); - - HandleNearest(type, xClosestDistance, yClosestDistance, zClosestDistance, allClosestDistance, minSelectedDistanceCheck); - } - - void HandleNearest(TransformType type, float xClosestDistance, float yClosestDistance, float zClosestDistance, float allClosestDistance, float minSelectedDistanceCheck) - { - if(type == TransformType.Scale && allClosestDistance <= minSelectedDistanceCheck) SetTranslatingAxis(type, Axis.Any); - else if(xClosestDistance <= minSelectedDistanceCheck && xClosestDistance <= yClosestDistance && xClosestDistance <= zClosestDistance) SetTranslatingAxis(type, Axis.X); - else if(yClosestDistance <= minSelectedDistanceCheck && yClosestDistance <= xClosestDistance && yClosestDistance <= zClosestDistance) SetTranslatingAxis(type, Axis.Y); - else if(zClosestDistance <= minSelectedDistanceCheck && zClosestDistance <= xClosestDistance && zClosestDistance <= yClosestDistance) SetTranslatingAxis(type, Axis.Z); - else if(type == TransformType.Rotate && mainTargetRoot != null) - { - Ray mouseRay = myCamera.ScreenPointToRay(Input.mousePosition); - Vector3 mousePlaneHit = Geometry.LinePlaneIntersect(mouseRay.origin, mouseRay.direction, pivotPoint, (transform.position - pivotPoint).normalized); - if((pivotPoint - mousePlaneHit).sqrMagnitude <= (GetHandleLength(TransformType.Rotate)).Squared()) SetTranslatingAxis(type, Axis.Any); - } - } - - float ClosestDistanceFromMouseToLines(List lines) - { - Ray mouseRay = myCamera.ScreenPointToRay(Input.mousePosition); - - float closestDistance = float.MaxValue; - for(int i = 0; i + 1 < lines.Count; i++) - { - IntersectPoints points = Geometry.ClosestPointsOnSegmentToLine(lines[i], lines[i + 1], mouseRay.origin, mouseRay.direction); - float distance = Vector3.Distance(points.first, points.second); - if(distance < closestDistance) - { - closestDistance = distance; - } - } - return closestDistance; - } - - float ClosestDistanceFromMouseToPlanes(List planePoints) - { - float closestDistance = float.MaxValue; - - if(planePoints.Count >= 4) - { - Ray mouseRay = myCamera.ScreenPointToRay(Input.mousePosition); - - for(int i = 0; i < planePoints.Count; i += 4) - { - Plane plane = new Plane(planePoints[i], planePoints[i + 1], planePoints[i + 2]); - - float distanceToPlane; - if(plane.Raycast(mouseRay, out distanceToPlane)) - { - Vector3 pointOnPlane = mouseRay.origin + (mouseRay.direction * distanceToPlane); - Vector3 planeCenter = (planePoints[0] + planePoints[1] + planePoints[2] + planePoints[3]) / 4f; - - float distance = Vector3.Distance(planeCenter, pointOnPlane); - if(distance < closestDistance) - { - closestDistance = distance; - } - } - } - } - - return closestDistance; - } - - //float DistanceFromMouseToPlane(List planeLines) - //{ - // if(planeLines.Count >= 4) - // { - // Ray mouseRay = myCamera.ScreenPointToRay(Input.mousePosition); - // Plane plane = new Plane(planeLines[0], planeLines[1], planeLines[2]); - - // float distanceToPlane; - // if(plane.Raycast(mouseRay, out distanceToPlane)) - // { - // Vector3 pointOnPlane = mouseRay.origin + (mouseRay.direction * distanceToPlane); - // Vector3 planeCenter = (planeLines[0] + planeLines[1] + planeLines[2] + planeLines[3]) / 4f; - - // return Vector3.Distance(planeCenter, pointOnPlane); - // } - // } - - // return float.MaxValue; - //} - - void SetAxisInfo() - { - if(mainTargetRoot != null) - { - axisInfo.Set(mainTargetRoot, pivotPoint, GetProperTransformSpace()); - } - } - - //This helps keep the size consistent no matter how far we are from it. - public float GetDistanceMultiplier() - { - if(mainTargetRoot == null) return 0f; - - if(myCamera.orthographic) return Mathf.Max(.01f, myCamera.orthographicSize * 2f); - return Mathf.Max(.01f, Mathf.Abs(ExtVector3.MagnitudeInDirection(pivotPoint - transform.position, myCamera.transform.forward))); - } - - void SetLines() - { - SetHandleLines(); - SetHandlePlanes(); - SetHandleTriangles(); - SetHandleSquares(); - SetCircles(GetAxisInfo(), circlesLines); - } - - void SetHandleLines() - { - handleLines.Clear(); - - if(TranslatingTypeContains(TransformType.Move) || TranslatingTypeContains(TransformType.Scale)) - { - float lineWidth = handleWidth * GetDistanceMultiplier(); - - float xLineLength = 0; - float yLineLength = 0; - float zLineLength = 0; - if(TranslatingTypeContains(TransformType.Move)) - { - xLineLength = yLineLength = zLineLength = GetHandleLength(TransformType.Move); - } - else if(TranslatingTypeContains(TransformType.Scale)) - { - xLineLength = GetHandleLength(TransformType.Scale, Axis.X); - yLineLength = GetHandleLength(TransformType.Scale, Axis.Y); - zLineLength = GetHandleLength(TransformType.Scale, Axis.Z); - } - - AddQuads(pivotPoint, axisInfo.xDirection, axisInfo.yDirection, axisInfo.zDirection, xLineLength, lineWidth, handleLines.x); - AddQuads(pivotPoint, axisInfo.yDirection, axisInfo.xDirection, axisInfo.zDirection, yLineLength, lineWidth, handleLines.y); - AddQuads(pivotPoint, axisInfo.zDirection, axisInfo.xDirection, axisInfo.yDirection, zLineLength, lineWidth, handleLines.z); - } - } - int AxisDirectionMultiplier(Vector3 direction, Vector3 otherDirection) - { - return ExtVector3.IsInDirection(direction, otherDirection) ? 1 : -1; - } - - void SetHandlePlanes() - { - handlePlanes.Clear(); - - if(TranslatingTypeContains(TransformType.Move)) - { - Vector3 pivotToCamera = myCamera.transform.position - pivotPoint; - float cameraXSign = Mathf.Sign(Vector3.Dot(axisInfo.xDirection, pivotToCamera)); - float cameraYSign = Mathf.Sign(Vector3.Dot(axisInfo.yDirection, pivotToCamera)); - float cameraZSign = Mathf.Sign(Vector3.Dot(axisInfo.zDirection, pivotToCamera)); - - float planeSize = this.planeSize; - if(transformType == TransformType.All) { planeSize *= allMoveHandleLengthMultiplier; } - planeSize *= GetDistanceMultiplier(); - - Vector3 xDirection = (axisInfo.xDirection * planeSize) * cameraXSign; - Vector3 yDirection = (axisInfo.yDirection * planeSize) * cameraYSign; - Vector3 zDirection = (axisInfo.zDirection * planeSize) * cameraZSign; - - Vector3 xPlaneCenter = pivotPoint + (yDirection + zDirection); - Vector3 yPlaneCenter = pivotPoint + (xDirection + zDirection); - Vector3 zPlaneCenter = pivotPoint + (xDirection + yDirection); - - AddQuad(xPlaneCenter, axisInfo.yDirection, axisInfo.zDirection, planeSize, handlePlanes.x); - AddQuad(yPlaneCenter, axisInfo.xDirection, axisInfo.zDirection, planeSize, handlePlanes.y); - AddQuad(zPlaneCenter, axisInfo.xDirection, axisInfo.yDirection, planeSize, handlePlanes.z); - } - } - - void SetHandleTriangles() - { - handleTriangles.Clear(); - - if(TranslatingTypeContains(TransformType.Move)) - { - float triangleLength = triangleSize * GetDistanceMultiplier(); - AddTriangles(axisInfo.GetXAxisEnd(GetHandleLength(TransformType.Move)), axisInfo.xDirection, axisInfo.yDirection, axisInfo.zDirection, triangleLength, handleTriangles.x); - AddTriangles(axisInfo.GetYAxisEnd(GetHandleLength(TransformType.Move)), axisInfo.yDirection, axisInfo.xDirection, axisInfo.zDirection, triangleLength, handleTriangles.y); - AddTriangles(axisInfo.GetZAxisEnd(GetHandleLength(TransformType.Move)), axisInfo.zDirection, axisInfo.yDirection, axisInfo.xDirection, triangleLength, handleTriangles.z); - } - } - - void AddTriangles(Vector3 axisEnd, Vector3 axisDirection, Vector3 axisOtherDirection1, Vector3 axisOtherDirection2, float size, List resultsBuffer) - { - Vector3 endPoint = axisEnd + (axisDirection * (size * 2f)); - Square baseSquare = GetBaseSquare(axisEnd, axisOtherDirection1, axisOtherDirection2, size / 2f); - - resultsBuffer.Add(baseSquare.bottomLeft); - resultsBuffer.Add(baseSquare.topLeft); - resultsBuffer.Add(baseSquare.topRight); - resultsBuffer.Add(baseSquare.topLeft); - resultsBuffer.Add(baseSquare.bottomRight); - resultsBuffer.Add(baseSquare.topRight); - - for(int i = 0; i < 4; i++) - { - resultsBuffer.Add(baseSquare[i]); - resultsBuffer.Add(baseSquare[i + 1]); - resultsBuffer.Add(endPoint); - } - } - - void SetHandleSquares() - { - handleSquares.Clear(); - - if(TranslatingTypeContains(TransformType.Scale)) - { - float boxSize = this.boxSize * GetDistanceMultiplier(); - AddSquares(axisInfo.GetXAxisEnd(GetHandleLength(TransformType.Scale, Axis.X)), axisInfo.xDirection, axisInfo.yDirection, axisInfo.zDirection, boxSize, handleSquares.x); - AddSquares(axisInfo.GetYAxisEnd(GetHandleLength(TransformType.Scale, Axis.Y)), axisInfo.yDirection, axisInfo.xDirection, axisInfo.zDirection, boxSize, handleSquares.y); - AddSquares(axisInfo.GetZAxisEnd(GetHandleLength(TransformType.Scale, Axis.Z)), axisInfo.zDirection, axisInfo.xDirection, axisInfo.yDirection, boxSize, handleSquares.z); - AddSquares(pivotPoint - (axisInfo.xDirection * (boxSize * .5f)), axisInfo.xDirection, axisInfo.yDirection, axisInfo.zDirection, boxSize, handleSquares.all); - } - } - - void AddSquares(Vector3 axisStart, Vector3 axisDirection, Vector3 axisOtherDirection1, Vector3 axisOtherDirection2, float size, List resultsBuffer) - { - AddQuads(axisStart, axisDirection, axisOtherDirection1, axisOtherDirection2, size, size * .5f, resultsBuffer); - } - void AddQuads(Vector3 axisStart, Vector3 axisDirection, Vector3 axisOtherDirection1, Vector3 axisOtherDirection2, float length, float width, List resultsBuffer) - { - Vector3 axisEnd = axisStart + (axisDirection * length); - AddQuads(axisStart, axisEnd, axisOtherDirection1, axisOtherDirection2, width, resultsBuffer); - } - void AddQuads(Vector3 axisStart, Vector3 axisEnd, Vector3 axisOtherDirection1, Vector3 axisOtherDirection2, float width, List resultsBuffer) - { - Square baseRectangle = GetBaseSquare(axisStart, axisOtherDirection1, axisOtherDirection2, width); - Square baseRectangleEnd = GetBaseSquare(axisEnd, axisOtherDirection1, axisOtherDirection2, width); - - resultsBuffer.Add(baseRectangle.bottomLeft); - resultsBuffer.Add(baseRectangle.topLeft); - resultsBuffer.Add(baseRectangle.topRight); - resultsBuffer.Add(baseRectangle.bottomRight); - - resultsBuffer.Add(baseRectangleEnd.bottomLeft); - resultsBuffer.Add(baseRectangleEnd.topLeft); - resultsBuffer.Add(baseRectangleEnd.topRight); - resultsBuffer.Add(baseRectangleEnd.bottomRight); - - for(int i = 0; i < 4; i++) - { - resultsBuffer.Add(baseRectangle[i]); - resultsBuffer.Add(baseRectangleEnd[i]); - resultsBuffer.Add(baseRectangleEnd[i + 1]); - resultsBuffer.Add(baseRectangle[i + 1]); - } - } - - void AddQuad(Vector3 axisStart, Vector3 axisOtherDirection1, Vector3 axisOtherDirection2, float width, List resultsBuffer) - { - Square baseRectangle = GetBaseSquare(axisStart, axisOtherDirection1, axisOtherDirection2, width); - - resultsBuffer.Add(baseRectangle.bottomLeft); - resultsBuffer.Add(baseRectangle.topLeft); - resultsBuffer.Add(baseRectangle.topRight); - resultsBuffer.Add(baseRectangle.bottomRight); - } - - Square GetBaseSquare(Vector3 axisEnd, Vector3 axisOtherDirection1, Vector3 axisOtherDirection2, float size) - { - Square square; - Vector3 offsetUp = ((axisOtherDirection1 * size) + (axisOtherDirection2 * size)); - Vector3 offsetDown = ((axisOtherDirection1 * size) - (axisOtherDirection2 * size)); - //These might not really be the proper directions, as in the bottomLeft might not really be at the bottom left... - square.bottomLeft = axisEnd + offsetDown; - square.topLeft = axisEnd + offsetUp; - square.bottomRight = axisEnd - offsetUp; - square.topRight = axisEnd - offsetDown; - return square; - } - - void SetCircles(AxisInfo axisInfo, AxisVectors axisVectors) - { - axisVectors.Clear(); - - if(TranslatingTypeContains(TransformType.Rotate)) - { - float circleLength = GetHandleLength(TransformType.Rotate); - AddCircle(pivotPoint, axisInfo.xDirection, circleLength, axisVectors.x); - AddCircle(pivotPoint, axisInfo.yDirection, circleLength, axisVectors.y); - AddCircle(pivotPoint, axisInfo.zDirection, circleLength, axisVectors.z); - AddCircle(pivotPoint, (pivotPoint - transform.position).normalized, circleLength, axisVectors.all, false); - } - } - - void AddCircle(Vector3 origin, Vector3 axisDirection, float size, List resultsBuffer, bool depthTest = true) - { - Vector3 up = axisDirection.normalized * size; - Vector3 forward = Vector3.Slerp(up, -up, .5f); - Vector3 right = Vector3.Cross(up, forward).normalized * size; - - Matrix4x4 matrix = new Matrix4x4(); - - matrix[0] = right.x; - matrix[1] = right.y; - matrix[2] = right.z; - - matrix[4] = up.x; - matrix[5] = up.y; - matrix[6] = up.z; - - matrix[8] = forward.x; - matrix[9] = forward.y; - matrix[10] = forward.z; - - Vector3 lastPoint = origin + matrix.MultiplyPoint3x4(new Vector3(Mathf.Cos(0), 0, Mathf.Sin(0))); - Vector3 nextPoint = Vector3.zero; - float multiplier = 360f / circleDetail; - - Plane plane = new Plane((transform.position - pivotPoint).normalized, pivotPoint); - - float circleHandleWidth = handleWidth * GetDistanceMultiplier(); - - for(int i = 0; i < circleDetail + 1; i++) - { - nextPoint.x = Mathf.Cos((i * multiplier) * Mathf.Deg2Rad); - nextPoint.z = Mathf.Sin((i * multiplier) * Mathf.Deg2Rad); - nextPoint.y = 0; - - nextPoint = origin + matrix.MultiplyPoint3x4(nextPoint); - - if(!depthTest || plane.GetSide(lastPoint)) - { - Vector3 centerPoint = (lastPoint + nextPoint) * .5f; - Vector3 upDirection = (centerPoint - origin).normalized; - AddQuads(lastPoint, nextPoint, upDirection, axisDirection, circleHandleWidth, resultsBuffer); - } - - lastPoint = nextPoint; - } - } - - void DrawLines(List lines, Color color) - { - if(lines.Count == 0) return; - - GL.Begin(GL.LINES); - GL.Color(color); - - for(int i = 0; i < lines.Count; i += 2) - { - GL.Vertex(lines[i]); - GL.Vertex(lines[i + 1]); - } - - GL.End(); - } - - void DrawTriangles(List lines, Color color) - { - if(lines.Count == 0) return; - - GL.Begin(GL.TRIANGLES); - GL.Color(color); - - for(int i = 0; i < lines.Count; i += 3) - { - GL.Vertex(lines[i]); - GL.Vertex(lines[i + 1]); - GL.Vertex(lines[i + 2]); - } - - GL.End(); - } - - void DrawQuads(List lines, Color color) - { - if(lines.Count == 0) return; - - GL.Begin(GL.QUADS); - GL.Color(color); - - for(int i = 0; i < lines.Count; i += 4) - { - GL.Vertex(lines[i]); - GL.Vertex(lines[i + 1]); - GL.Vertex(lines[i + 2]); - GL.Vertex(lines[i + 3]); - } - - GL.End(); - } - - void DrawFilledCircle(List lines, Color color) - { - if(lines.Count == 0) return; - - Vector3 center = Vector3.zero; - for(int i = 0; i < lines.Count; i++) - { - center += lines[i]; - } - center /= lines.Count; - - GL.Begin(GL.TRIANGLES); - GL.Color(color); - - for(int i = 0; i + 1 < lines.Count; i++) - { - GL.Vertex(lines[i]); - GL.Vertex(lines[i + 1]); - GL.Vertex(center); - } - - GL.End(); - } - - void SetMaterial() - { - if(lineMaterial == null) - { - lineMaterial = new Material(Shader.Find("Custom/Lines")); - outlineMaterial = new Material(Shader.Find("Custom/Outline")); - } - } - } -} +using System; +using UnityEngine; +using System.Collections.Generic; +using System.Collections; +using CommandUndoRedo; + +namespace RuntimeGizmos +{ + //To be safe, if you are changing any transforms hierarchy, such as parenting an object to something, + //you should call ClearTargets before doing so just to be sure nothing unexpected happens... as well as call UndoRedoManager.Clear() + //For example, if you select an object that has children, move the children elsewhere, deselect the original object, then try to add those old children to the selection, I think it wont work. + + [RequireComponent(typeof(Camera))] + public class TransformGizmo : MonoBehaviour + { + public TransformSpace space = TransformSpace.Global; + public TransformType transformType = TransformType.Move; + public TransformPivot pivot = TransformPivot.Pivot; + public CenterType centerType = CenterType.All; + public ScaleType scaleType = ScaleType.FromPoint; + + //These are the same as the unity editor hotkeys + public KeyCode SetMoveType = KeyCode.W; + public KeyCode SetRotateType = KeyCode.E; + public KeyCode SetScaleType = KeyCode.R; + //public KeyCode SetRectToolType = KeyCode.T; + public KeyCode SetAllTransformType = KeyCode.Y; + public KeyCode SetSpaceToggle = KeyCode.X; + public KeyCode SetPivotModeToggle = KeyCode.Z; + public KeyCode SetCenterTypeToggle = KeyCode.C; + public KeyCode SetScaleTypeToggle = KeyCode.S; + public KeyCode translationSnapping = KeyCode.LeftControl; + public KeyCode AddSelection = KeyCode.LeftShift; + public KeyCode RemoveSelection = KeyCode.LeftControl; + public KeyCode ActionKey = KeyCode.LeftShift; //Its set to shift instead of control so that while in the editor we dont accidentally undo editor changes =/ + public KeyCode UndoAction = KeyCode.Z; + public KeyCode RedoAction = KeyCode.Y; + + public Color xColor = new Color(1, 0, 0, 0.8f); + public Color yColor = new Color(0, 1, 0, 0.8f); + public Color zColor = new Color(0, 0, 1, 0.8f); + public Color allColor = new Color(.7f, .7f, .7f, 0.8f); + public Color selectedColor = new Color(1, 1, 0, 0.8f); + public Color hoverColor = new Color(1, .75f, 0, 0.8f); + public float planesOpacity = .5f; + //public Color rectPivotColor = new Color(0, 0, 1, 0.8f); + //public Color rectCornerColor = new Color(0, 0, 1, 0.8f); + //public Color rectAnchorColor = new Color(.7f, .7f, .7f, 0.8f); + //public Color rectLineColor = new Color(.7f, .7f, .7f, 0.8f); + + public float movementSnap = .25f; + public float rotationSnap = 15f; + public float scaleSnap = 1f; + + public float handleLength = .25f; + public float handleWidth = .003f; + public float planeSize = .035f; + public float triangleSize = .03f; + public float boxSize = .03f; + public int circleDetail = 40; + public float allMoveHandleLengthMultiplier = 1f; + public float allRotateHandleLengthMultiplier = 1.4f; + public float allScaleHandleLengthMultiplier = 1.6f; + public float minSelectedDistanceCheck = .01f; + public float moveSpeedMultiplier = 1f; + public float scaleSpeedMultiplier = 1f; + public float rotateSpeedMultiplier = 1f; + public float allRotateSpeedMultiplier = 20f; + + public bool useFirstSelectedAsMain = true; + + //If circularRotationMethod is true, when rotating you will need to move your mouse around the object as if turning a wheel. + //If circularRotationMethod is false, when rotating you can just click and drag in a line to rotate. + public bool circularRotationMethod; + + //Mainly for if you want the pivot point to update correctly if selected objects are moving outside the transformgizmo. + //Might be poor on performance if lots of objects are selected... + public bool forceUpdatePivotPointOnChange = true; + + public int maxUndoStored = 100; + + public bool manuallyHandleGizmo; + + public LayerMask selectionMask = Physics.DefaultRaycastLayers; + + public Action onCheckForSelectedAxis; + public Action onDrawCustomGizmo; + + public Camera myCamera {get; private set;} + + public bool isTransforming {get; private set;} + public float totalScaleAmount {get; private set;} + public Quaternion totalRotationAmount {get; private set;} + public Axis translatingAxis {get {return nearAxis;}} + public Axis translatingAxisPlane {get {return planeAxis;}} + public bool hasTranslatingAxisPlane {get {return translatingAxisPlane != Axis.None && translatingAxisPlane != Axis.Any;}} + public TransformType transformingType {get {return translatingType;}} + + public Vector3 pivotPoint {get; private set;} + Vector3 totalCenterPivotPoint; + + public Transform mainTargetRoot {get {return (targetRootsOrdered.Count > 0) ? (useFirstSelectedAsMain) ? targetRootsOrdered[0] : targetRootsOrdered[targetRootsOrdered.Count - 1] : null;}} + + AxisInfo axisInfo; + Axis nearAxis = Axis.None; + Axis planeAxis = Axis.None; + TransformType translatingType; + + AxisVectors handleLines = new AxisVectors(); + AxisVectors handlePlanes = new AxisVectors(); + AxisVectors handleTriangles = new AxisVectors(); + AxisVectors handleSquares = new AxisVectors(); + AxisVectors circlesLines = new AxisVectors(); + + //We use a HashSet and a List for targetRoots so that we get fast lookup with the hashset while also keeping track of the order with the list. + List targetRootsOrdered = new List(); + Dictionary targetRoots = new Dictionary(); + HashSet highlightedRenderers = new HashSet(); + HashSet children = new HashSet(); + + List childrenBuffer = new List(); + List renderersBuffer = new List(); + List materialsBuffer = new List(); + + WaitForEndOfFrame waitForEndOFFrame = new WaitForEndOfFrame(); + Coroutine forceUpdatePivotCoroutine; + + static Material lineMaterial; + static Material outlineMaterial; + + void Awake() + { + myCamera = GetComponent(); + SetMaterial(); + } + + void OnEnable() + { + forceUpdatePivotCoroutine = StartCoroutine(ForceUpdatePivotPointAtEndOfFrame()); + } + + void OnDisable() + { + ClearTargets(); //Just so things gets cleaned up, such as removing any materials we placed on objects. + + StopCoroutine(forceUpdatePivotCoroutine); + } + + void OnDestroy() + { + ClearAllHighlightedRenderers(); + } + + void Update() + { + HandleUndoRedo(); + + SetSpaceAndType(); + + if(manuallyHandleGizmo) + { + if(onCheckForSelectedAxis != null) onCheckForSelectedAxis(); + }else{ + SetNearAxis(); + } + + GetTarget(); + + if(mainTargetRoot == null) return; + + TransformSelected(); + } + + void LateUpdate() + { + if(mainTargetRoot == null) return; + + //We run this in lateupdate since coroutines run after update and we want our gizmos to have the updated target transform position after TransformSelected() + SetAxisInfo(); + + if(manuallyHandleGizmo) + { + if(onDrawCustomGizmo != null) onDrawCustomGizmo(); + }else{ + SetLines(); + } + } + + void OnPostRender() + { + if(mainTargetRoot == null || manuallyHandleGizmo) return; + + lineMaterial.SetPass(0); + + Color xColor = (nearAxis == Axis.X) ? (isTransforming) ? selectedColor : hoverColor : this.xColor; + Color yColor = (nearAxis == Axis.Y) ? (isTransforming) ? selectedColor : hoverColor : this.yColor; + Color zColor = (nearAxis == Axis.Z) ? (isTransforming) ? selectedColor : hoverColor : this.zColor; + Color allColor = (nearAxis == Axis.Any) ? (isTransforming) ? selectedColor : hoverColor : this.allColor; + + //Note: The order of drawing the axis decides what gets drawn over what. + + TransformType moveOrScaleType = (transformType == TransformType.Scale || (isTransforming && translatingType == TransformType.Scale)) ? TransformType.Scale : TransformType.Move; + DrawQuads(handleLines.z, GetColor(moveOrScaleType, this.zColor, zColor, hasTranslatingAxisPlane)); + DrawQuads(handleLines.x, GetColor(moveOrScaleType, this.xColor, xColor, hasTranslatingAxisPlane)); + DrawQuads(handleLines.y, GetColor(moveOrScaleType, this.yColor, yColor, hasTranslatingAxisPlane)); + + DrawTriangles(handleTriangles.x, GetColor(TransformType.Move, this.xColor, xColor, hasTranslatingAxisPlane)); + DrawTriangles(handleTriangles.y, GetColor(TransformType.Move, this.yColor, yColor, hasTranslatingAxisPlane)); + DrawTriangles(handleTriangles.z, GetColor(TransformType.Move, this.zColor, zColor, hasTranslatingAxisPlane)); + + DrawQuads(handlePlanes.z, GetColor(TransformType.Move, this.zColor, zColor, planesOpacity, !hasTranslatingAxisPlane)); + DrawQuads(handlePlanes.x, GetColor(TransformType.Move, this.xColor, xColor, planesOpacity, !hasTranslatingAxisPlane)); + DrawQuads(handlePlanes.y, GetColor(TransformType.Move, this.yColor, yColor, planesOpacity, !hasTranslatingAxisPlane)); + + DrawQuads(handleSquares.x, GetColor(TransformType.Scale, this.xColor, xColor)); + DrawQuads(handleSquares.y, GetColor(TransformType.Scale, this.yColor, yColor)); + DrawQuads(handleSquares.z, GetColor(TransformType.Scale, this.zColor, zColor)); + DrawQuads(handleSquares.all, GetColor(TransformType.Scale, this.allColor, allColor)); + + DrawQuads(circlesLines.all, GetColor(TransformType.Rotate, this.allColor, allColor)); + DrawQuads(circlesLines.x, GetColor(TransformType.Rotate, this.xColor, xColor)); + DrawQuads(circlesLines.y, GetColor(TransformType.Rotate, this.yColor, yColor)); + DrawQuads(circlesLines.z, GetColor(TransformType.Rotate, this.zColor, zColor)); + } + + Color GetColor(TransformType type, Color normalColor, Color nearColor, bool forceUseNormal = false) + { + return GetColor(type, normalColor, nearColor, false, 1, forceUseNormal); + } + Color GetColor(TransformType type, Color normalColor, Color nearColor, float alpha, bool forceUseNormal = false) + { + return GetColor(type, normalColor, nearColor, true, alpha, forceUseNormal); + } + Color GetColor(TransformType type, Color normalColor, Color nearColor, bool setAlpha, float alpha, bool forceUseNormal = false) + { + Color color; + if(!forceUseNormal && TranslatingTypeContains(type, false)) + { + color = nearColor; + }else{ + color = normalColor; + } + + if(setAlpha) + { + color.a = alpha; + } + + return color; + } + + void HandleUndoRedo() + { + if(maxUndoStored != UndoRedoManager.maxUndoStored) { UndoRedoManager.maxUndoStored = maxUndoStored; } + + if(Input.GetKey(ActionKey)) + { + if(Input.GetKeyDown(UndoAction)) + { + UndoRedoManager.Undo(); + } + else if(Input.GetKeyDown(RedoAction)) + { + UndoRedoManager.Redo(); + } + } + } + + //We only support scaling in local space. + public TransformSpace GetProperTransformSpace() + { + return transformType == TransformType.Scale ? TransformSpace.Local : space; + } + + public bool TransformTypeContains(TransformType type) + { + return TransformTypeContains(transformType, type); + } + public bool TranslatingTypeContains(TransformType type, bool checkIsTransforming = true) + { + TransformType transType = !checkIsTransforming || isTransforming ? translatingType : transformType; + return TransformTypeContains(transType, type); + } + public bool TransformTypeContains(TransformType mainType, TransformType type) + { + return ExtTransformType.TransformTypeContains(mainType, type, GetProperTransformSpace()); + } + + public float GetHandleLength(TransformType type, Axis axis = Axis.None, bool multiplyDistanceMultiplier = true) + { + float length = handleLength; + if(transformType == TransformType.All) + { + if(type == TransformType.Move) length *= allMoveHandleLengthMultiplier; + if(type == TransformType.Rotate) length *= allRotateHandleLengthMultiplier; + if(type == TransformType.Scale) length *= allScaleHandleLengthMultiplier; + } + + if(multiplyDistanceMultiplier) length *= GetDistanceMultiplier(); + + if(type == TransformType.Scale && isTransforming && (translatingAxis == axis || translatingAxis == Axis.Any)) length += totalScaleAmount; + + return length; + } + + void SetSpaceAndType() + { + if(Input.GetKey(ActionKey)) return; + + if(Input.GetKeyDown(SetMoveType)) transformType = TransformType.Move; + else if(Input.GetKeyDown(SetRotateType)) transformType = TransformType.Rotate; + else if(Input.GetKeyDown(SetScaleType)) transformType = TransformType.Scale; + //else if(Input.GetKeyDown(SetRectToolType)) type = TransformType.RectTool; + else if(Input.GetKeyDown(SetAllTransformType)) transformType = TransformType.All; + + if(!isTransforming) translatingType = transformType; + + if(Input.GetKeyDown(SetPivotModeToggle)) + { + if(pivot == TransformPivot.Pivot) pivot = TransformPivot.Center; + else if(pivot == TransformPivot.Center) pivot = TransformPivot.Pivot; + + SetPivotPoint(); + } + + if(Input.GetKeyDown(SetCenterTypeToggle)) + { + if(centerType == CenterType.All) centerType = CenterType.Solo; + else if(centerType == CenterType.Solo) centerType = CenterType.All; + + SetPivotPoint(); + } + + if(Input.GetKeyDown(SetSpaceToggle)) + { + if(space == TransformSpace.Global) space = TransformSpace.Local; + else if(space == TransformSpace.Local) space = TransformSpace.Global; + } + + if(Input.GetKeyDown(SetScaleTypeToggle)) + { + if(scaleType == ScaleType.FromPoint) scaleType = ScaleType.FromPointOffset; + else if(scaleType == ScaleType.FromPointOffset) scaleType = ScaleType.FromPoint; + } + + if(transformType == TransformType.Scale) + { + if(pivot == TransformPivot.Pivot) scaleType = ScaleType.FromPoint; //FromPointOffset can be inaccurate and should only really be used in Center mode if desired. + } + } + + void TransformSelected() + { + if(mainTargetRoot != null) + { + if(nearAxis != Axis.None && Input.GetMouseButtonDown(0)) + { + StartCoroutine(TransformSelected(translatingType)); + } + } + } + + IEnumerator TransformSelected(TransformType transType) + { + isTransforming = true; + totalScaleAmount = 0; + totalRotationAmount = Quaternion.identity; + + Vector3 originalPivot = pivotPoint; + + Vector3 otherAxis1, otherAxis2; + Vector3 axis = GetNearAxisDirection(out otherAxis1, out otherAxis2); + Vector3 planeNormal = hasTranslatingAxisPlane ? axis : (transform.position - originalPivot).normalized; + Vector3 projectedAxis = Vector3.ProjectOnPlane(axis, planeNormal).normalized; + Vector3 previousMousePosition = Vector3.zero; + + Vector3 currentSnapMovementAmount = Vector3.zero; + float currentSnapRotationAmount = 0; + float currentSnapScaleAmount = 0; + + List transformCommands = new List(); + for(int i = 0; i < targetRootsOrdered.Count; i++) + { + transformCommands.Add(new TransformCommand(this, targetRootsOrdered[i])); + } + + while(!Input.GetMouseButtonUp(0)) + { + Ray mouseRay = myCamera.ScreenPointToRay(Input.mousePosition); + Vector3 mousePosition = Geometry.LinePlaneIntersect(mouseRay.origin, mouseRay.direction, originalPivot, planeNormal); + bool isSnapping = Input.GetKey(translationSnapping); + + if(previousMousePosition != Vector3.zero && mousePosition != Vector3.zero) + { + if(transType == TransformType.Move) + { + Vector3 movement = Vector3.zero; + + if(hasTranslatingAxisPlane) + { + movement = mousePosition - previousMousePosition; + }else{ + float moveAmount = ExtVector3.MagnitudeInDirection(mousePosition - previousMousePosition, projectedAxis) * moveSpeedMultiplier; + movement = axis * moveAmount; + } + + if(isSnapping && movementSnap > 0) + { + currentSnapMovementAmount += movement; + movement = Vector3.zero; + + if(hasTranslatingAxisPlane) + { + float amountInAxis1 = ExtVector3.MagnitudeInDirection(currentSnapMovementAmount, otherAxis1); + float amountInAxis2 = ExtVector3.MagnitudeInDirection(currentSnapMovementAmount, otherAxis2); + + float remainder1; + float snapAmount1 = CalculateSnapAmount(movementSnap, amountInAxis1, out remainder1); + float remainder2; + float snapAmount2 = CalculateSnapAmount(movementSnap, amountInAxis2, out remainder2); + + if(snapAmount1 != 0) + { + Vector3 snapMove = (otherAxis1 * snapAmount1); + movement += snapMove; + currentSnapMovementAmount -= snapMove; + } + if(snapAmount2 != 0) + { + Vector3 snapMove = (otherAxis2 * snapAmount2); + movement += snapMove; + currentSnapMovementAmount -= snapMove; + } + } + else + { + float remainder; + float snapAmount = CalculateSnapAmount(movementSnap, currentSnapMovementAmount.magnitude, out remainder); + + if(snapAmount != 0) + { + movement = currentSnapMovementAmount.normalized * snapAmount; + currentSnapMovementAmount = currentSnapMovementAmount.normalized * remainder; + } + } + } + + for(int i = 0; i < targetRootsOrdered.Count; i++) + { + Transform target = targetRootsOrdered[i]; + + target.Translate(movement, Space.World); + } + + SetPivotPointOffset(movement); + } + else if(transType == TransformType.Scale) + { + Vector3 projected = (nearAxis == Axis.Any) ? transform.right : projectedAxis; + float scaleAmount = ExtVector3.MagnitudeInDirection(mousePosition - previousMousePosition, projected) * scaleSpeedMultiplier; + + if(isSnapping && scaleSnap > 0) + { + currentSnapScaleAmount += scaleAmount; + scaleAmount = 0; + + float remainder; + float snapAmount = CalculateSnapAmount(scaleSnap, currentSnapScaleAmount, out remainder); + + if(snapAmount != 0) + { + scaleAmount = snapAmount; + currentSnapScaleAmount = remainder; + } + } + + //WARNING - There is a bug in unity 5.4 and 5.5 that causes InverseTransformDirection to be affected by scale which will break negative scaling. Not tested, but updating to 5.4.2 should fix it - https://issuetracker.unity3d.com/issues/transformdirection-and-inversetransformdirection-operations-are-affected-by-scale + Vector3 localAxis = (GetProperTransformSpace() == TransformSpace.Local && nearAxis != Axis.Any) ? mainTargetRoot.InverseTransformDirection(axis) : axis; + + Vector3 targetScaleAmount = Vector3.one; + if(nearAxis == Axis.Any) targetScaleAmount = (ExtVector3.Abs(mainTargetRoot.localScale.normalized) * scaleAmount); + else targetScaleAmount = localAxis * scaleAmount; + + for(int i = 0; i < targetRootsOrdered.Count; i++) + { + Transform target = targetRootsOrdered[i]; + + Vector3 targetScale = target.localScale + targetScaleAmount; + + if(pivot == TransformPivot.Pivot) + { + target.localScale = targetScale; + } + else if(pivot == TransformPivot.Center) + { + if(scaleType == ScaleType.FromPoint) + { + target.SetScaleFrom(originalPivot, targetScale); + } + else if(scaleType == ScaleType.FromPointOffset) + { + target.SetScaleFromOffset(originalPivot, targetScale); + } + } + } + + totalScaleAmount += scaleAmount; + } + else if(transType == TransformType.Rotate) + { + float rotateAmount = 0; + Vector3 rotationAxis = axis; + + if(nearAxis == Axis.Any) + { + Vector3 rotation = transform.TransformDirection(new Vector3(Input.GetAxis("Mouse Y"), -Input.GetAxis("Mouse X"), 0)); + Quaternion.Euler(rotation).ToAngleAxis(out rotateAmount, out rotationAxis); + rotateAmount *= allRotateSpeedMultiplier; + }else{ + if(circularRotationMethod) + { + float angle = Vector3.SignedAngle(previousMousePosition - originalPivot, mousePosition - originalPivot, axis); + rotateAmount = angle * rotateSpeedMultiplier; + }else{ + Vector3 projected = (nearAxis == Axis.Any || ExtVector3.IsParallel(axis, planeNormal)) ? planeNormal : Vector3.Cross(axis, planeNormal); + rotateAmount = (ExtVector3.MagnitudeInDirection(mousePosition - previousMousePosition, projected) * (rotateSpeedMultiplier * 100f)) / GetDistanceMultiplier(); + } + } + + if(isSnapping && rotationSnap > 0) + { + currentSnapRotationAmount += rotateAmount; + rotateAmount = 0; + + float remainder; + float snapAmount = CalculateSnapAmount(rotationSnap, currentSnapRotationAmount, out remainder); + + if(snapAmount != 0) + { + rotateAmount = snapAmount; + currentSnapRotationAmount = remainder; + } + } + + for(int i = 0; i < targetRootsOrdered.Count; i++) + { + Transform target = targetRootsOrdered[i]; + + if(pivot == TransformPivot.Pivot) + { + target.Rotate(rotationAxis, rotateAmount, Space.World); + } + else if(pivot == TransformPivot.Center) + { + target.RotateAround(originalPivot, rotationAxis, rotateAmount); + } + } + + totalRotationAmount *= Quaternion.Euler(rotationAxis * rotateAmount); + } + } + + previousMousePosition = mousePosition; + + yield return null; + } + + for(int i = 0; i < transformCommands.Count; i++) + { + ((TransformCommand)transformCommands[i]).StoreNewTransformValues(); + } + CommandGroup commandGroup = new CommandGroup(); + commandGroup.Set(transformCommands); + UndoRedoManager.Insert(commandGroup); + + totalRotationAmount = Quaternion.identity; + totalScaleAmount = 0; + isTransforming = false; + SetTranslatingAxis(transformType, Axis.None); + + SetPivotPoint(); + } + + float CalculateSnapAmount(float snapValue, float currentAmount, out float remainder) + { + remainder = 0; + if(snapValue <= 0) return currentAmount; + + float currentAmountAbs = Mathf.Abs(currentAmount); + if(currentAmountAbs > snapValue) + { + remainder = currentAmountAbs % snapValue; + return snapValue * (Mathf.Sign(currentAmount) * Mathf.Floor(currentAmountAbs / snapValue)); + } + + return 0; + } + + Vector3 GetNearAxisDirection(out Vector3 otherAxis1, out Vector3 otherAxis2) + { + otherAxis1 = otherAxis2 = Vector3.zero; + + if(nearAxis != Axis.None) + { + if(nearAxis == Axis.X) + { + otherAxis1 = axisInfo.yDirection; + otherAxis2 = axisInfo.zDirection; + return axisInfo.xDirection; + } + if(nearAxis == Axis.Y) + { + otherAxis1 = axisInfo.xDirection; + otherAxis2 = axisInfo.zDirection; + return axisInfo.yDirection; + } + if(nearAxis == Axis.Z) + { + otherAxis1 = axisInfo.xDirection; + otherAxis2 = axisInfo.yDirection; + return axisInfo.zDirection; + } + if(nearAxis == Axis.Any) + { + return Vector3.one; + } + } + + return Vector3.zero; + } + + void GetTarget() + { + if(nearAxis == Axis.None && Input.GetMouseButtonDown(0)) + { + bool isAdding = Input.GetKey(AddSelection); + bool isRemoving = Input.GetKey(RemoveSelection); + + RaycastHit hitInfo; + if(Physics.Raycast(myCamera.ScreenPointToRay(Input.mousePosition), out hitInfo, Mathf.Infinity, selectionMask)) + { + Transform target = hitInfo.transform; + + if(isAdding) + { + AddTarget(target); + } + else if(isRemoving) + { + RemoveTarget(target); + } + else if(!isAdding && !isRemoving) + { + ClearAndAddTarget(target); + } + }else{ + if(!isAdding && !isRemoving) + { + ClearTargets(); + } + } + } + } + + public void AddTarget(Transform target, bool addCommand = true) + { + if(target != null) + { + if(targetRoots.ContainsKey(target)) return; + if(children.Contains(target)) return; + + if(addCommand) UndoRedoManager.Insert(new AddTargetCommand(this, target, targetRootsOrdered)); + + AddTargetRoot(target); + AddTargetHighlightedRenderers(target); + + SetPivotPoint(); + } + } + + public void RemoveTarget(Transform target, bool addCommand = true) + { + if(target != null) + { + if(!targetRoots.ContainsKey(target)) return; + + if(addCommand) UndoRedoManager.Insert(new RemoveTargetCommand(this, target)); + + RemoveTargetHighlightedRenderers(target); + RemoveTargetRoot(target); + + SetPivotPoint(); + } + } + + public void ClearTargets(bool addCommand = true) + { + if(addCommand) UndoRedoManager.Insert(new ClearTargetsCommand(this, targetRootsOrdered)); + + ClearAllHighlightedRenderers(); + targetRoots.Clear(); + targetRootsOrdered.Clear(); + children.Clear(); + } + + void ClearAndAddTarget(Transform target) + { + UndoRedoManager.Insert(new ClearAndAddTargetCommand(this, target, targetRootsOrdered)); + + ClearTargets(false); + AddTarget(target, false); + } + + void AddTargetHighlightedRenderers(Transform target) + { + if(target != null) + { + GetTargetRenderers(target, renderersBuffer); + + for(int i = 0; i < renderersBuffer.Count; i++) + { + Renderer render = renderersBuffer[i]; + + if(!highlightedRenderers.Contains(render)) + { + materialsBuffer.Clear(); + materialsBuffer.AddRange(render.sharedMaterials); + + if(!materialsBuffer.Contains(outlineMaterial)) + { + materialsBuffer.Add(outlineMaterial); + render.materials = materialsBuffer.ToArray(); + } + + highlightedRenderers.Add(render); + } + } + + materialsBuffer.Clear(); + } + } + + void GetTargetRenderers(Transform target, List renderers) + { + renderers.Clear(); + if(target != null) + { + target.GetComponentsInChildren(true, renderers); + } + } + + void ClearAllHighlightedRenderers() + { + foreach(var target in targetRoots) + { + RemoveTargetHighlightedRenderers(target.Key); + } + + //In case any are still left, such as if they changed parents or what not when they were highlighted. + renderersBuffer.Clear(); + renderersBuffer.AddRange(highlightedRenderers); + RemoveHighlightedRenderers(renderersBuffer); + } + + void RemoveTargetHighlightedRenderers(Transform target) + { + GetTargetRenderers(target, renderersBuffer); + + RemoveHighlightedRenderers(renderersBuffer); + } + + void RemoveHighlightedRenderers(List renderers) + { + for(int i = 0; i < renderersBuffer.Count; i++) + { + Renderer render = renderersBuffer[i]; + if(render != null) + { + materialsBuffer.Clear(); + materialsBuffer.AddRange(render.sharedMaterials); + + if(materialsBuffer.Contains(outlineMaterial)) + { + materialsBuffer.Remove(outlineMaterial); + render.materials = materialsBuffer.ToArray(); + } + } + + highlightedRenderers.Remove(render); + } + + renderersBuffer.Clear(); + } + + void AddTargetRoot(Transform targetRoot) + { + targetRoots.Add(targetRoot, new TargetInfo()); + targetRootsOrdered.Add(targetRoot); + + AddAllChildren(targetRoot); + } + void RemoveTargetRoot(Transform targetRoot) + { + if(targetRoots.Remove(targetRoot)) + { + targetRootsOrdered.Remove(targetRoot); + + RemoveAllChildren(targetRoot); + } + } + + void AddAllChildren(Transform target) + { + childrenBuffer.Clear(); + target.GetComponentsInChildren(true, childrenBuffer); + childrenBuffer.Remove(target); + + for(int i = 0; i < childrenBuffer.Count; i++) + { + Transform child = childrenBuffer[i]; + children.Add(child); + RemoveTargetRoot(child); //We do this in case we selected child first and then the parent. + } + + childrenBuffer.Clear(); + } + void RemoveAllChildren(Transform target) + { + childrenBuffer.Clear(); + target.GetComponentsInChildren(true, childrenBuffer); + childrenBuffer.Remove(target); + + for(int i = 0; i < childrenBuffer.Count; i++) + { + children.Remove(childrenBuffer[i]); + } + + childrenBuffer.Clear(); + } + + public void SetPivotPoint() + { + if(mainTargetRoot != null) + { + if(pivot == TransformPivot.Pivot) + { + pivotPoint = mainTargetRoot.position; + } + else if(pivot == TransformPivot.Center) + { + totalCenterPivotPoint = Vector3.zero; + + Dictionary.Enumerator targetsEnumerator = targetRoots.GetEnumerator(); //We avoid foreach to avoid garbage. + while(targetsEnumerator.MoveNext()) + { + Transform target = targetsEnumerator.Current.Key; + TargetInfo info = targetsEnumerator.Current.Value; + info.centerPivotPoint = target.GetCenter(centerType); + + totalCenterPivotPoint += info.centerPivotPoint; + } + + totalCenterPivotPoint /= targetRoots.Count; + + if(centerType == CenterType.Solo) + { + pivotPoint = targetRoots[mainTargetRoot].centerPivotPoint; + } + else if(centerType == CenterType.All) + { + pivotPoint = totalCenterPivotPoint; + } + } + } + } + void SetPivotPointOffset(Vector3 offset) + { + pivotPoint += offset; + totalCenterPivotPoint += offset; + } + + + IEnumerator ForceUpdatePivotPointAtEndOfFrame() + { + while(this.enabled) + { + ForceUpdatePivotPointOnChange(); + yield return waitForEndOFFrame; + } + } + + void ForceUpdatePivotPointOnChange() + { + if(forceUpdatePivotPointOnChange) + { + if(mainTargetRoot != null && !isTransforming) + { + bool hasSet = false; + Dictionary.Enumerator targets = targetRoots.GetEnumerator(); + while(targets.MoveNext()) + { + if(!hasSet) + { + if(targets.Current.Value.previousPosition != Vector3.zero && targets.Current.Key.position != targets.Current.Value.previousPosition) + { + SetPivotPoint(); + hasSet = true; + } + } + + targets.Current.Value.previousPosition = targets.Current.Key.position; + } + } + } + } + + public void SetTranslatingAxis(TransformType type, Axis axis, Axis planeAxis = Axis.None) + { + this.translatingType = type; + this.nearAxis = axis; + this.planeAxis = planeAxis; + } + + public AxisInfo GetAxisInfo() + { + AxisInfo currentAxisInfo = axisInfo; + + if(isTransforming && GetProperTransformSpace() == TransformSpace.Global && translatingType == TransformType.Rotate) + { + currentAxisInfo.xDirection = totalRotationAmount * Vector3.right; + currentAxisInfo.yDirection = totalRotationAmount * Vector3.up; + currentAxisInfo.zDirection = totalRotationAmount * Vector3.forward; + } + + return currentAxisInfo; + } + + void SetNearAxis() + { + if(isTransforming) return; + + SetTranslatingAxis(transformType, Axis.None); + + if(mainTargetRoot == null) return; + + float distanceMultiplier = GetDistanceMultiplier(); + float handleMinSelectedDistanceCheck = (this.minSelectedDistanceCheck + handleWidth) * distanceMultiplier; + + if(nearAxis == Axis.None && (TransformTypeContains(TransformType.Move) || TransformTypeContains(TransformType.Scale))) + { + //Important to check scale lines before move lines since in TransformType.All the move planes would block the scales center scale all gizmo. + if(nearAxis == Axis.None && TransformTypeContains(TransformType.Scale)) + { + float tipMinSelectedDistanceCheck = (this.minSelectedDistanceCheck + boxSize) * distanceMultiplier; + HandleNearestPlanes(TransformType.Scale, handleSquares, tipMinSelectedDistanceCheck); + } + + if(nearAxis == Axis.None && TransformTypeContains(TransformType.Move)) + { + //Important to check the planes first before the handle tip since it makes selecting the planes easier. + float planeMinSelectedDistanceCheck = (this.minSelectedDistanceCheck + planeSize) * distanceMultiplier; + HandleNearestPlanes(TransformType.Move, handlePlanes, planeMinSelectedDistanceCheck); + + if(nearAxis != Axis.None) + { + planeAxis = nearAxis; + } + else + { + float tipMinSelectedDistanceCheck = (this.minSelectedDistanceCheck + triangleSize) * distanceMultiplier; + HandleNearestLines(TransformType.Move, handleTriangles, tipMinSelectedDistanceCheck); + } + } + + if(nearAxis == Axis.None) + { + //Since Move and Scale share the same handle line, we give Move the priority. + TransformType transType = transformType == TransformType.All ? TransformType.Move : transformType; + HandleNearestLines(transType, handleLines, handleMinSelectedDistanceCheck); + } + } + + if(nearAxis == Axis.None && TransformTypeContains(TransformType.Rotate)) + { + HandleNearestLines(TransformType.Rotate, circlesLines, handleMinSelectedDistanceCheck); + } + } + + void HandleNearestLines(TransformType type, AxisVectors axisVectors, float minSelectedDistanceCheck) + { + float xClosestDistance = ClosestDistanceFromMouseToLines(axisVectors.x); + float yClosestDistance = ClosestDistanceFromMouseToLines(axisVectors.y); + float zClosestDistance = ClosestDistanceFromMouseToLines(axisVectors.z); + float allClosestDistance = ClosestDistanceFromMouseToLines(axisVectors.all); + + HandleNearest(type, xClosestDistance, yClosestDistance, zClosestDistance, allClosestDistance, minSelectedDistanceCheck); + } + + void HandleNearestPlanes(TransformType type, AxisVectors axisVectors, float minSelectedDistanceCheck) + { + float xClosestDistance = ClosestDistanceFromMouseToPlanes(axisVectors.x); + float yClosestDistance = ClosestDistanceFromMouseToPlanes(axisVectors.y); + float zClosestDistance = ClosestDistanceFromMouseToPlanes(axisVectors.z); + float allClosestDistance = ClosestDistanceFromMouseToPlanes(axisVectors.all); + + HandleNearest(type, xClosestDistance, yClosestDistance, zClosestDistance, allClosestDistance, minSelectedDistanceCheck); + } + + void HandleNearest(TransformType type, float xClosestDistance, float yClosestDistance, float zClosestDistance, float allClosestDistance, float minSelectedDistanceCheck) + { + if(type == TransformType.Scale && allClosestDistance <= minSelectedDistanceCheck) SetTranslatingAxis(type, Axis.Any); + else if(xClosestDistance <= minSelectedDistanceCheck && xClosestDistance <= yClosestDistance && xClosestDistance <= zClosestDistance) SetTranslatingAxis(type, Axis.X); + else if(yClosestDistance <= minSelectedDistanceCheck && yClosestDistance <= xClosestDistance && yClosestDistance <= zClosestDistance) SetTranslatingAxis(type, Axis.Y); + else if(zClosestDistance <= minSelectedDistanceCheck && zClosestDistance <= xClosestDistance && zClosestDistance <= yClosestDistance) SetTranslatingAxis(type, Axis.Z); + else if(type == TransformType.Rotate && mainTargetRoot != null) + { + Ray mouseRay = myCamera.ScreenPointToRay(Input.mousePosition); + Vector3 mousePlaneHit = Geometry.LinePlaneIntersect(mouseRay.origin, mouseRay.direction, pivotPoint, (transform.position - pivotPoint).normalized); + if((pivotPoint - mousePlaneHit).sqrMagnitude <= (GetHandleLength(TransformType.Rotate)).Squared()) SetTranslatingAxis(type, Axis.Any); + } + } + + float ClosestDistanceFromMouseToLines(List lines) + { + Ray mouseRay = myCamera.ScreenPointToRay(Input.mousePosition); + + float closestDistance = float.MaxValue; + for(int i = 0; i + 1 < lines.Count; i++) + { + IntersectPoints points = Geometry.ClosestPointsOnSegmentToLine(lines[i], lines[i + 1], mouseRay.origin, mouseRay.direction); + float distance = Vector3.Distance(points.first, points.second); + if(distance < closestDistance) + { + closestDistance = distance; + } + } + return closestDistance; + } + + float ClosestDistanceFromMouseToPlanes(List planePoints) + { + float closestDistance = float.MaxValue; + + if(planePoints.Count >= 4) + { + Ray mouseRay = myCamera.ScreenPointToRay(Input.mousePosition); + + for(int i = 0; i < planePoints.Count; i += 4) + { + Plane plane = new Plane(planePoints[i], planePoints[i + 1], planePoints[i + 2]); + + float distanceToPlane; + if(plane.Raycast(mouseRay, out distanceToPlane)) + { + Vector3 pointOnPlane = mouseRay.origin + (mouseRay.direction * distanceToPlane); + Vector3 planeCenter = (planePoints[0] + planePoints[1] + planePoints[2] + planePoints[3]) / 4f; + + float distance = Vector3.Distance(planeCenter, pointOnPlane); + if(distance < closestDistance) + { + closestDistance = distance; + } + } + } + } + + return closestDistance; + } + + //float DistanceFromMouseToPlane(List planeLines) + //{ + // if(planeLines.Count >= 4) + // { + // Ray mouseRay = myCamera.ScreenPointToRay(Input.mousePosition); + // Plane plane = new Plane(planeLines[0], planeLines[1], planeLines[2]); + + // float distanceToPlane; + // if(plane.Raycast(mouseRay, out distanceToPlane)) + // { + // Vector3 pointOnPlane = mouseRay.origin + (mouseRay.direction * distanceToPlane); + // Vector3 planeCenter = (planeLines[0] + planeLines[1] + planeLines[2] + planeLines[3]) / 4f; + + // return Vector3.Distance(planeCenter, pointOnPlane); + // } + // } + + // return float.MaxValue; + //} + + void SetAxisInfo() + { + if(mainTargetRoot != null) + { + axisInfo.Set(mainTargetRoot, pivotPoint, GetProperTransformSpace()); + } + } + + //This helps keep the size consistent no matter how far we are from it. + public float GetDistanceMultiplier() + { + if(mainTargetRoot == null) return 0f; + + if(myCamera.orthographic) return Mathf.Max(.01f, myCamera.orthographicSize * 2f); + return Mathf.Max(.01f, Mathf.Abs(ExtVector3.MagnitudeInDirection(pivotPoint - transform.position, myCamera.transform.forward))); + } + + void SetLines() + { + SetHandleLines(); + SetHandlePlanes(); + SetHandleTriangles(); + SetHandleSquares(); + SetCircles(GetAxisInfo(), circlesLines); + } + + void SetHandleLines() + { + handleLines.Clear(); + + if(TranslatingTypeContains(TransformType.Move) || TranslatingTypeContains(TransformType.Scale)) + { + float lineWidth = handleWidth * GetDistanceMultiplier(); + + float xLineLength = 0; + float yLineLength = 0; + float zLineLength = 0; + if(TranslatingTypeContains(TransformType.Move)) + { + xLineLength = yLineLength = zLineLength = GetHandleLength(TransformType.Move); + } + else if(TranslatingTypeContains(TransformType.Scale)) + { + xLineLength = GetHandleLength(TransformType.Scale, Axis.X); + yLineLength = GetHandleLength(TransformType.Scale, Axis.Y); + zLineLength = GetHandleLength(TransformType.Scale, Axis.Z); + } + + AddQuads(pivotPoint, axisInfo.xDirection, axisInfo.yDirection, axisInfo.zDirection, xLineLength, lineWidth, handleLines.x); + AddQuads(pivotPoint, axisInfo.yDirection, axisInfo.xDirection, axisInfo.zDirection, yLineLength, lineWidth, handleLines.y); + AddQuads(pivotPoint, axisInfo.zDirection, axisInfo.xDirection, axisInfo.yDirection, zLineLength, lineWidth, handleLines.z); + } + } + int AxisDirectionMultiplier(Vector3 direction, Vector3 otherDirection) + { + return ExtVector3.IsInDirection(direction, otherDirection) ? 1 : -1; + } + + void SetHandlePlanes() + { + handlePlanes.Clear(); + + if(TranslatingTypeContains(TransformType.Move)) + { + Vector3 pivotToCamera = myCamera.transform.position - pivotPoint; + float cameraXSign = Mathf.Sign(Vector3.Dot(axisInfo.xDirection, pivotToCamera)); + float cameraYSign = Mathf.Sign(Vector3.Dot(axisInfo.yDirection, pivotToCamera)); + float cameraZSign = Mathf.Sign(Vector3.Dot(axisInfo.zDirection, pivotToCamera)); + + float planeSize = this.planeSize; + if(transformType == TransformType.All) { planeSize *= allMoveHandleLengthMultiplier; } + planeSize *= GetDistanceMultiplier(); + + Vector3 xDirection = (axisInfo.xDirection * planeSize) * cameraXSign; + Vector3 yDirection = (axisInfo.yDirection * planeSize) * cameraYSign; + Vector3 zDirection = (axisInfo.zDirection * planeSize) * cameraZSign; + + Vector3 xPlaneCenter = pivotPoint + (yDirection + zDirection); + Vector3 yPlaneCenter = pivotPoint + (xDirection + zDirection); + Vector3 zPlaneCenter = pivotPoint + (xDirection + yDirection); + + AddQuad(xPlaneCenter, axisInfo.yDirection, axisInfo.zDirection, planeSize, handlePlanes.x); + AddQuad(yPlaneCenter, axisInfo.xDirection, axisInfo.zDirection, planeSize, handlePlanes.y); + AddQuad(zPlaneCenter, axisInfo.xDirection, axisInfo.yDirection, planeSize, handlePlanes.z); + } + } + + void SetHandleTriangles() + { + handleTriangles.Clear(); + + if(TranslatingTypeContains(TransformType.Move)) + { + float triangleLength = triangleSize * GetDistanceMultiplier(); + AddTriangles(axisInfo.GetXAxisEnd(GetHandleLength(TransformType.Move)), axisInfo.xDirection, axisInfo.yDirection, axisInfo.zDirection, triangleLength, handleTriangles.x); + AddTriangles(axisInfo.GetYAxisEnd(GetHandleLength(TransformType.Move)), axisInfo.yDirection, axisInfo.xDirection, axisInfo.zDirection, triangleLength, handleTriangles.y); + AddTriangles(axisInfo.GetZAxisEnd(GetHandleLength(TransformType.Move)), axisInfo.zDirection, axisInfo.yDirection, axisInfo.xDirection, triangleLength, handleTriangles.z); + } + } + + void AddTriangles(Vector3 axisEnd, Vector3 axisDirection, Vector3 axisOtherDirection1, Vector3 axisOtherDirection2, float size, List resultsBuffer) + { + Vector3 endPoint = axisEnd + (axisDirection * (size * 2f)); + Square baseSquare = GetBaseSquare(axisEnd, axisOtherDirection1, axisOtherDirection2, size / 2f); + + resultsBuffer.Add(baseSquare.bottomLeft); + resultsBuffer.Add(baseSquare.topLeft); + resultsBuffer.Add(baseSquare.topRight); + resultsBuffer.Add(baseSquare.topLeft); + resultsBuffer.Add(baseSquare.bottomRight); + resultsBuffer.Add(baseSquare.topRight); + + for(int i = 0; i < 4; i++) + { + resultsBuffer.Add(baseSquare[i]); + resultsBuffer.Add(baseSquare[i + 1]); + resultsBuffer.Add(endPoint); + } + } + + void SetHandleSquares() + { + handleSquares.Clear(); + + if(TranslatingTypeContains(TransformType.Scale)) + { + float boxSize = this.boxSize * GetDistanceMultiplier(); + AddSquares(axisInfo.GetXAxisEnd(GetHandleLength(TransformType.Scale, Axis.X)), axisInfo.xDirection, axisInfo.yDirection, axisInfo.zDirection, boxSize, handleSquares.x); + AddSquares(axisInfo.GetYAxisEnd(GetHandleLength(TransformType.Scale, Axis.Y)), axisInfo.yDirection, axisInfo.xDirection, axisInfo.zDirection, boxSize, handleSquares.y); + AddSquares(axisInfo.GetZAxisEnd(GetHandleLength(TransformType.Scale, Axis.Z)), axisInfo.zDirection, axisInfo.xDirection, axisInfo.yDirection, boxSize, handleSquares.z); + AddSquares(pivotPoint - (axisInfo.xDirection * (boxSize * .5f)), axisInfo.xDirection, axisInfo.yDirection, axisInfo.zDirection, boxSize, handleSquares.all); + } + } + + void AddSquares(Vector3 axisStart, Vector3 axisDirection, Vector3 axisOtherDirection1, Vector3 axisOtherDirection2, float size, List resultsBuffer) + { + AddQuads(axisStart, axisDirection, axisOtherDirection1, axisOtherDirection2, size, size * .5f, resultsBuffer); + } + void AddQuads(Vector3 axisStart, Vector3 axisDirection, Vector3 axisOtherDirection1, Vector3 axisOtherDirection2, float length, float width, List resultsBuffer) + { + Vector3 axisEnd = axisStart + (axisDirection * length); + AddQuads(axisStart, axisEnd, axisOtherDirection1, axisOtherDirection2, width, resultsBuffer); + } + void AddQuads(Vector3 axisStart, Vector3 axisEnd, Vector3 axisOtherDirection1, Vector3 axisOtherDirection2, float width, List resultsBuffer) + { + Square baseRectangle = GetBaseSquare(axisStart, axisOtherDirection1, axisOtherDirection2, width); + Square baseRectangleEnd = GetBaseSquare(axisEnd, axisOtherDirection1, axisOtherDirection2, width); + + resultsBuffer.Add(baseRectangle.bottomLeft); + resultsBuffer.Add(baseRectangle.topLeft); + resultsBuffer.Add(baseRectangle.topRight); + resultsBuffer.Add(baseRectangle.bottomRight); + + resultsBuffer.Add(baseRectangleEnd.bottomLeft); + resultsBuffer.Add(baseRectangleEnd.topLeft); + resultsBuffer.Add(baseRectangleEnd.topRight); + resultsBuffer.Add(baseRectangleEnd.bottomRight); + + for(int i = 0; i < 4; i++) + { + resultsBuffer.Add(baseRectangle[i]); + resultsBuffer.Add(baseRectangleEnd[i]); + resultsBuffer.Add(baseRectangleEnd[i + 1]); + resultsBuffer.Add(baseRectangle[i + 1]); + } + } + + void AddQuad(Vector3 axisStart, Vector3 axisOtherDirection1, Vector3 axisOtherDirection2, float width, List resultsBuffer) + { + Square baseRectangle = GetBaseSquare(axisStart, axisOtherDirection1, axisOtherDirection2, width); + + resultsBuffer.Add(baseRectangle.bottomLeft); + resultsBuffer.Add(baseRectangle.topLeft); + resultsBuffer.Add(baseRectangle.topRight); + resultsBuffer.Add(baseRectangle.bottomRight); + } + + Square GetBaseSquare(Vector3 axisEnd, Vector3 axisOtherDirection1, Vector3 axisOtherDirection2, float size) + { + Square square; + Vector3 offsetUp = ((axisOtherDirection1 * size) + (axisOtherDirection2 * size)); + Vector3 offsetDown = ((axisOtherDirection1 * size) - (axisOtherDirection2 * size)); + //These might not really be the proper directions, as in the bottomLeft might not really be at the bottom left... + square.bottomLeft = axisEnd + offsetDown; + square.topLeft = axisEnd + offsetUp; + square.bottomRight = axisEnd - offsetUp; + square.topRight = axisEnd - offsetDown; + return square; + } + + void SetCircles(AxisInfo axisInfo, AxisVectors axisVectors) + { + axisVectors.Clear(); + + if(TranslatingTypeContains(TransformType.Rotate)) + { + float circleLength = GetHandleLength(TransformType.Rotate); + AddCircle(pivotPoint, axisInfo.xDirection, circleLength, axisVectors.x); + AddCircle(pivotPoint, axisInfo.yDirection, circleLength, axisVectors.y); + AddCircle(pivotPoint, axisInfo.zDirection, circleLength, axisVectors.z); + AddCircle(pivotPoint, (pivotPoint - transform.position).normalized, circleLength, axisVectors.all, false); + } + } + + void AddCircle(Vector3 origin, Vector3 axisDirection, float size, List resultsBuffer, bool depthTest = true) + { + Vector3 up = axisDirection.normalized * size; + Vector3 forward = Vector3.Slerp(up, -up, .5f); + Vector3 right = Vector3.Cross(up, forward).normalized * size; + + Matrix4x4 matrix = new Matrix4x4(); + + matrix[0] = right.x; + matrix[1] = right.y; + matrix[2] = right.z; + + matrix[4] = up.x; + matrix[5] = up.y; + matrix[6] = up.z; + + matrix[8] = forward.x; + matrix[9] = forward.y; + matrix[10] = forward.z; + + Vector3 lastPoint = origin + matrix.MultiplyPoint3x4(new Vector3(Mathf.Cos(0), 0, Mathf.Sin(0))); + Vector3 nextPoint = Vector3.zero; + float multiplier = 360f / circleDetail; + + Plane plane = new Plane((transform.position - pivotPoint).normalized, pivotPoint); + + float circleHandleWidth = handleWidth * GetDistanceMultiplier(); + + for(int i = 0; i < circleDetail + 1; i++) + { + nextPoint.x = Mathf.Cos((i * multiplier) * Mathf.Deg2Rad); + nextPoint.z = Mathf.Sin((i * multiplier) * Mathf.Deg2Rad); + nextPoint.y = 0; + + nextPoint = origin + matrix.MultiplyPoint3x4(nextPoint); + + if(!depthTest || plane.GetSide(lastPoint)) + { + Vector3 centerPoint = (lastPoint + nextPoint) * .5f; + Vector3 upDirection = (centerPoint - origin).normalized; + AddQuads(lastPoint, nextPoint, upDirection, axisDirection, circleHandleWidth, resultsBuffer); + } + + lastPoint = nextPoint; + } + } + + void DrawLines(List lines, Color color) + { + if(lines.Count == 0) return; + + GL.Begin(GL.LINES); + GL.Color(color); + + for(int i = 0; i < lines.Count; i += 2) + { + GL.Vertex(lines[i]); + GL.Vertex(lines[i + 1]); + } + + GL.End(); + } + + void DrawTriangles(List lines, Color color) + { + if(lines.Count == 0) return; + + GL.Begin(GL.TRIANGLES); + GL.Color(color); + + for(int i = 0; i < lines.Count; i += 3) + { + GL.Vertex(lines[i]); + GL.Vertex(lines[i + 1]); + GL.Vertex(lines[i + 2]); + } + + GL.End(); + } + + void DrawQuads(List lines, Color color) + { + if(lines.Count == 0) return; + + GL.Begin(GL.QUADS); + GL.Color(color); + + for(int i = 0; i < lines.Count; i += 4) + { + GL.Vertex(lines[i]); + GL.Vertex(lines[i + 1]); + GL.Vertex(lines[i + 2]); + GL.Vertex(lines[i + 3]); + } + + GL.End(); + } + + void DrawFilledCircle(List lines, Color color) + { + if(lines.Count == 0) return; + + Vector3 center = Vector3.zero; + for(int i = 0; i < lines.Count; i++) + { + center += lines[i]; + } + center /= lines.Count; + + GL.Begin(GL.TRIANGLES); + GL.Color(color); + + for(int i = 0; i + 1 < lines.Count; i++) + { + GL.Vertex(lines[i]); + GL.Vertex(lines[i + 1]); + GL.Vertex(center); + } + + GL.End(); + } + + void SetMaterial() + { + if(lineMaterial == null) + { + lineMaterial = new Material(Shader.Find("Custom/Lines")); + outlineMaterial = new Material(Shader.Find("Custom/Outline")); + } + } + } +} diff --git a/Assets/RuntimeGizmo/TransformGizmo.cs.meta b/Runtime/TransformGizmo.cs.meta similarity index 100% rename from Assets/RuntimeGizmo/TransformGizmo.cs.meta rename to Runtime/TransformGizmo.cs.meta diff --git a/Runtime/UndoRedo.meta b/Runtime/UndoRedo.meta new file mode 100644 index 0000000..9c19f97 --- /dev/null +++ b/Runtime/UndoRedo.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d68646dea12c62644ab7da6a5348ef14 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/UndoRedo/CommandGroup.cs b/Runtime/UndoRedo/CommandGroup.cs similarity index 100% rename from Assets/RuntimeGizmo/UndoRedo/CommandGroup.cs rename to Runtime/UndoRedo/CommandGroup.cs diff --git a/Runtime/UndoRedo/CommandGroup.cs.meta b/Runtime/UndoRedo/CommandGroup.cs.meta new file mode 100644 index 0000000..73bde37 --- /dev/null +++ b/Runtime/UndoRedo/CommandGroup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ffd4d2c126badea45a2effbf6da29a70 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/UndoRedo/DropoutStack.cs b/Runtime/UndoRedo/DropoutStack.cs similarity index 100% rename from Assets/RuntimeGizmo/UndoRedo/DropoutStack.cs rename to Runtime/UndoRedo/DropoutStack.cs diff --git a/Runtime/UndoRedo/DropoutStack.cs.meta b/Runtime/UndoRedo/DropoutStack.cs.meta new file mode 100644 index 0000000..2b832ce --- /dev/null +++ b/Runtime/UndoRedo/DropoutStack.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 62b3fa3a942a40145960a0c3acb537bc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/UndoRedo/ICommand.cs b/Runtime/UndoRedo/ICommand.cs similarity index 100% rename from Assets/RuntimeGizmo/UndoRedo/ICommand.cs rename to Runtime/UndoRedo/ICommand.cs diff --git a/Runtime/UndoRedo/ICommand.cs.meta b/Runtime/UndoRedo/ICommand.cs.meta new file mode 100644 index 0000000..5551cba --- /dev/null +++ b/Runtime/UndoRedo/ICommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d75dc835398d5434e9cba37786e24b5a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/UndoRedo/UndoRedo.cs b/Runtime/UndoRedo/UndoRedo.cs similarity index 100% rename from Assets/RuntimeGizmo/UndoRedo/UndoRedo.cs rename to Runtime/UndoRedo/UndoRedo.cs diff --git a/Runtime/UndoRedo/UndoRedo.cs.meta b/Runtime/UndoRedo/UndoRedo.cs.meta new file mode 100644 index 0000000..7a3dda3 --- /dev/null +++ b/Runtime/UndoRedo/UndoRedo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6e16e82867a10644688dc2898ee05a61 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RuntimeGizmo/UndoRedo/UndoRedoManager.cs b/Runtime/UndoRedo/UndoRedoManager.cs similarity index 100% rename from Assets/RuntimeGizmo/UndoRedo/UndoRedoManager.cs rename to Runtime/UndoRedo/UndoRedoManager.cs diff --git a/Runtime/UndoRedo/UndoRedoManager.cs.meta b/Runtime/UndoRedo/UndoRedoManager.cs.meta new file mode 100644 index 0000000..085cba3 --- /dev/null +++ b/Runtime/UndoRedo/UndoRedoManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 58151c496a56b2a4f828cbdd8db7fe2e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/hiddenmonk.U3DRTG.asmdef.meta b/Runtime/hiddenmonk.U3DRTG.asmdef.meta new file mode 100644 index 0000000..2d896bc --- /dev/null +++ b/Runtime/hiddenmonk.U3DRTG.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 99dd42aa5d1431f49bc323220378000e +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package.json b/package.json new file mode 100644 index 0000000..9d70543 --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "com.hiddenmonk.u3drtg", + "displayName": "Unity 3D Runtime Transform Gizmo", + "version": "1.0.0", + "unity": "2017.2", + "description": "A runtime transform gizmo similar to unitys editor so you can translate (move, rotate, scale) objects at runtime.", + "repository": { + "type": "git", + "url": "https://github.com/HiddenMonk/Unity3DRuntimeTransformGizmo.git" + }, + "author": "HiddenMonk", + "hideInEditor": false, + "homepage": "https://github.com/HiddenMonk/Unity3DRuntimeTransformGizmo.git", + "license": "MIT" +} diff --git a/package.json.meta b/package.json.meta new file mode 100644 index 0000000..6ffced9 --- /dev/null +++ b/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 510794f0f0dff234f8ebaebdae87a5e4 +PackageManifestImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: