From 88924f9e4126c9acd9111268521c4f7341961514 Mon Sep 17 00:00:00 2001 From: Ben Hopkins Date: Mon, 27 Jun 2016 09:06:20 -0400 Subject: [PATCH 01/16] * Added SceneViewCamera & Editor, for fine-grain movement of scene view camera * Added CylinderCollider, ChainCollider & Editors --- Assets/kode80/UnityTools/Colliders.meta | 9 ++ .../kode80/UnityTools/Colliders/Editor.meta | 9 ++ .../Colliders/Editor/ChainColliderEditor.cs | 89 +++++++++++ .../Editor/ChainColliderEditor.cs.meta | 12 ++ .../Editor/CylinderColliderEditor.cs | 21 +++ .../Editor/CylinderColliderEditor.cs.meta | 12 ++ .../kode80/UnityTools/Colliders/Scripts.meta | 9 ++ .../Colliders/Scripts/ChainCollider.cs | 130 ++++++++++++++++ .../Colliders/Scripts/ChainCollider.cs.meta | 12 ++ .../Colliders/Scripts/CylinderCollider.cs | 142 ++++++++++++++++++ .../Scripts/CylinderCollider.cs.meta | 12 ++ .../Editor/SceneViewCameraEditor.cs | 128 ++++++++++++++++ .../Editor/SceneViewCameraEditor.cs.meta | 12 ++ .../EditorTools/Scripts/SceneViewCamera.cs | 19 +++ .../Scripts/SceneViewCamera.cs.meta | 12 ++ ProjectSettings/ProjectVersion.txt | 2 +- 16 files changed, 629 insertions(+), 1 deletion(-) create mode 100644 Assets/kode80/UnityTools/Colliders.meta create mode 100644 Assets/kode80/UnityTools/Colliders/Editor.meta create mode 100644 Assets/kode80/UnityTools/Colliders/Editor/ChainColliderEditor.cs create mode 100644 Assets/kode80/UnityTools/Colliders/Editor/ChainColliderEditor.cs.meta create mode 100644 Assets/kode80/UnityTools/Colliders/Editor/CylinderColliderEditor.cs create mode 100644 Assets/kode80/UnityTools/Colliders/Editor/CylinderColliderEditor.cs.meta create mode 100644 Assets/kode80/UnityTools/Colliders/Scripts.meta create mode 100644 Assets/kode80/UnityTools/Colliders/Scripts/ChainCollider.cs create mode 100644 Assets/kode80/UnityTools/Colliders/Scripts/ChainCollider.cs.meta create mode 100644 Assets/kode80/UnityTools/Colliders/Scripts/CylinderCollider.cs create mode 100644 Assets/kode80/UnityTools/Colliders/Scripts/CylinderCollider.cs.meta create mode 100644 Assets/kode80/UnityTools/EditorTools/Editor/SceneViewCameraEditor.cs create mode 100644 Assets/kode80/UnityTools/EditorTools/Editor/SceneViewCameraEditor.cs.meta create mode 100644 Assets/kode80/UnityTools/EditorTools/Scripts/SceneViewCamera.cs create mode 100644 Assets/kode80/UnityTools/EditorTools/Scripts/SceneViewCamera.cs.meta diff --git a/Assets/kode80/UnityTools/Colliders.meta b/Assets/kode80/UnityTools/Colliders.meta new file mode 100644 index 0000000..2ebd940 --- /dev/null +++ b/Assets/kode80/UnityTools/Colliders.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c4c9bccd05a074d77bf9d50f576c70e9 +folderAsset: yes +timeCreated: 1467032627 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/kode80/UnityTools/Colliders/Editor.meta b/Assets/kode80/UnityTools/Colliders/Editor.meta new file mode 100644 index 0000000..86e6f2b --- /dev/null +++ b/Assets/kode80/UnityTools/Colliders/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 9daad138e977b46ae861415a7574cdf3 +folderAsset: yes +timeCreated: 1467032639 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/kode80/UnityTools/Colliders/Editor/ChainColliderEditor.cs b/Assets/kode80/UnityTools/Colliders/Editor/ChainColliderEditor.cs new file mode 100644 index 0000000..b0e5344 --- /dev/null +++ b/Assets/kode80/UnityTools/Colliders/Editor/ChainColliderEditor.cs @@ -0,0 +1,89 @@ +using UnityEngine; +using UnityEditor; +using System; +using System.Collections; + +namespace kode80.Colliders +{ + [CustomEditor( typeof(ChainCollider))] + public class ChainColliderEditor : Editor + { + private int selectedPointIndex; + + public override void OnInspectorGUI() + { + DrawDefaultInspector(); + if( GUILayout.Button( "Bake Colliders")) + { + var chain = target as ChainCollider; + chain.CreateColliders( chain.colliderParent == null ? chain.transform : chain.colliderParent); + chain.enabled = false; + } + } + + void OnSceneGUI() + { + var chain = target as ChainCollider; + if( chain.enabled == false) { return; } + + int count = chain.points.Length; + + for( int i=0; i(); + collider.size = size; + collider.transform.localPosition = p0 + delta * 0.5f; + collider.transform.localRotation = rotation; + collider.isTrigger = isTrigger; + collider.material = material; + + return collider; + } + + public void InsertPoint( int index) + { + index = Math.Min( Math.Max( index, 0), points.Length); + + Vector3 before = points[Math.Min( Math.Max( index-1, 0), points.Length-1)]; + Vector3 after = points[Math.Min( Math.Max( index, 0), points.Length-1)]; + Vector3 newPoint = before + ((after - before) * 0.5f); + + var list = points.ToList(); + list.Insert( index, newPoint); + points = list.ToArray(); + } + + public void DeletePoint( int index) + { + index = Math.Min( Math.Max( index, 0), points.Length - 1); + + var list = points.ToList(); + list.RemoveAt( index); + points = list.ToArray(); + } + + public void ApplyParentRotation() + { + int count = points.Length; + for( int i=0; i(); + collider.size = size; + collider.transform.localRotation = Quaternion.Euler( 0.0f, rotationY, 0.0f); + collider.isTrigger = isTrigger; + collider.material = material; + return collider; + } + + private SphereCollider CreateCapCollider( bool isTop) + { + var collider = new GameObject( "Cylinder_Cap_" + (isTop ? "Top" : "Bottom")).AddComponent(); + collider.radius = radius; + collider.center = new Vector3( 0.0f, height * (isTop ? 0.5f : -0.5f), 0.0f); + collider.isTrigger = isTrigger; + collider.material = material; + return collider; + } + + private Vector3 CalculateBoxSize() + { + float circumference = radius * 2.0f * Mathf.PI; + + float width = circumference / boxCount; + width = radius / boxCount * 2.0f * widthScale; + + return new Vector3( width, height, radius * 2.0f); + } + + private float CalculateRotationStep() + { + return 360.0f / boxCount; + } + } +} diff --git a/Assets/kode80/UnityTools/Colliders/Scripts/CylinderCollider.cs.meta b/Assets/kode80/UnityTools/Colliders/Scripts/CylinderCollider.cs.meta new file mode 100644 index 0000000..3aba588 --- /dev/null +++ b/Assets/kode80/UnityTools/Colliders/Scripts/CylinderCollider.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9a3869ef76a684c14a9308c7278c4de1 +timeCreated: 1467032531 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/kode80/UnityTools/EditorTools/Editor/SceneViewCameraEditor.cs b/Assets/kode80/UnityTools/EditorTools/Editor/SceneViewCameraEditor.cs new file mode 100644 index 0000000..d6359e3 --- /dev/null +++ b/Assets/kode80/UnityTools/EditorTools/Editor/SceneViewCameraEditor.cs @@ -0,0 +1,128 @@ +using UnityEngine; +using UnityEditor; +using System.Collections; + +namespace kode80.EditorTools +{ + [CustomEditor(typeof(SceneViewCamera))] + public class SceneViewCameraEditor : Editor + { + private int frameCount; + private bool isForwardsPressed; + private bool isBackwardsPressed; + private bool isLeftPressed; + private bool isRightPressed; + private bool isUpPressed; + private bool isDownPressed; + private bool isRunPressed; + + private Tool previousTool; + private bool cameraControlsEnabled; + private float movementSpeed = 0.005f; + + void OnEnable() + { + frameCount = 0; + EditorApplication.update += EditorUpdate; + + previousTool = Tools.current; + Tools.current = Tool.None; + } + + void OnDisable() + { + EditorApplication.update -= EditorUpdate; + Tools.current = previousTool; + } + + void OnSceneGUI() + { + Tools.current = Tool.None; + + Handles.BeginGUI(); + GUILayout.BeginArea( new Rect( 5, 5, 200, 100)); + var rect = EditorGUILayout.BeginVertical(); + GUI.Box( rect, GUIContent.none, EditorStyles.helpBox); + + bool newCameraEnabled = GUILayout.Toggle( cameraControlsEnabled, "Camera Enabled"); + if( newCameraEnabled != cameraControlsEnabled) + { + cameraControlsEnabled = newCameraEnabled; + if( cameraControlsEnabled) + { + EditorApplication.ExecuteMenuItem( "GameObject/Align With View"); + } + } + movementSpeed = GUILayout.HorizontalSlider( movementSpeed, 0.0f, 0.1f); + + EditorGUILayout.EndVertical(); + GUILayout.EndArea(); + Handles.EndGUI(); + + HandleCameraKeyInput(); + } + + void HandleCameraKeyInput() + { + var currentEvent = Event.current; + + if( currentEvent != null && cameraControlsEnabled) + { + if( currentEvent.type == EventType.KeyDown) + { + if( currentEvent.keyCode == KeyCode.W) { isForwardsPressed = true; } + if( currentEvent.keyCode == KeyCode.S) { isBackwardsPressed = true; } + if( currentEvent.keyCode == KeyCode.A) { isLeftPressed = true; } + if( currentEvent.keyCode == KeyCode.D) { isRightPressed = true; } + if( currentEvent.keyCode == KeyCode.Q) { isDownPressed = true; } + if( currentEvent.keyCode == KeyCode.E) { isUpPressed = true; } + + if( currentEvent.keyCode == KeyCode.C) { isRunPressed = true; } + + currentEvent.Use(); + } + else if( currentEvent.type == EventType.KeyUp) + { + if( currentEvent.keyCode == KeyCode.W) { isForwardsPressed = false; } + if( currentEvent.keyCode == KeyCode.S) { isBackwardsPressed = false; } + if( currentEvent.keyCode == KeyCode.A) { isLeftPressed = false; } + if( currentEvent.keyCode == KeyCode.D) { isRightPressed = false; } + if( currentEvent.keyCode == KeyCode.Q) { isDownPressed = false; } + if( currentEvent.keyCode == KeyCode.E) { isUpPressed = false; } + + if( currentEvent.keyCode == KeyCode.C) { isRunPressed = false; } + + currentEvent.Use(); + } + } + } + + void EditorUpdate() + { + var cameraTransform = (target as SceneViewCamera).transform; + + if( cameraControlsEnabled) + { + if( frameCount % 6 == 0) + { + Vector3 movement = Vector3.zero; + float speed = movementSpeed * (isRunPressed ? 3.0f : 1.0f); + + if( isForwardsPressed) { movement += cameraTransform.forward * speed; } + else if( isBackwardsPressed) { movement -= cameraTransform.forward * speed; } + + if( isLeftPressed) { movement -= cameraTransform.right * speed; } + else if( isRightPressed) { movement += cameraTransform.right * speed; } + + if( isUpPressed) { movement += cameraTransform.up * speed; } + else if( isDownPressed) { movement -= cameraTransform.up * speed; } + + cameraTransform.position += movement; + + EditorApplication.ExecuteMenuItem( "GameObject/Align View to Selected"); + } + frameCount++; + } + } + } +} \ No newline at end of file diff --git a/Assets/kode80/UnityTools/EditorTools/Editor/SceneViewCameraEditor.cs.meta b/Assets/kode80/UnityTools/EditorTools/Editor/SceneViewCameraEditor.cs.meta new file mode 100644 index 0000000..c5308bb --- /dev/null +++ b/Assets/kode80/UnityTools/EditorTools/Editor/SceneViewCameraEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: abf4ce76ad0064e6d98b2ffbe67e6ab9 +timeCreated: 1467032543 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/kode80/UnityTools/EditorTools/Scripts/SceneViewCamera.cs b/Assets/kode80/UnityTools/EditorTools/Scripts/SceneViewCamera.cs new file mode 100644 index 0000000..b18cb61 --- /dev/null +++ b/Assets/kode80/UnityTools/EditorTools/Scripts/SceneViewCamera.cs @@ -0,0 +1,19 @@ +using UnityEngine; +using System.Collections; + +namespace kode80.EditorTools +{ + public class SceneViewCamera : MonoBehaviour + { + + // Use this for initialization + void Start () { + + } + + // Update is called once per frame + void Update () { + + } + } +} \ No newline at end of file diff --git a/Assets/kode80/UnityTools/EditorTools/Scripts/SceneViewCamera.cs.meta b/Assets/kode80/UnityTools/EditorTools/Scripts/SceneViewCamera.cs.meta new file mode 100644 index 0000000..e621bcb --- /dev/null +++ b/Assets/kode80/UnityTools/EditorTools/Scripts/SceneViewCamera.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 96f696ec15e2b40cbadd9ba97d006193 +timeCreated: 1467032531 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt index 3c4cb34..31e0b08 100644 --- a/ProjectSettings/ProjectVersion.txt +++ b/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 5.3.0f4 +m_EditorVersion: 5.4.0b21 m_StandardAssetsVersion: 0 From d1b3446d360cdff8314dc5d0fd94bb1694899e90 Mon Sep 17 00:00:00 2001 From: Ben Hopkins Date: Mon, 27 Jun 2016 09:31:45 -0400 Subject: [PATCH 02/16] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8eaab9f..0eeb038 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ Various editor/GUI tools for Unity3D * Options for super size rendering & framerate * Automatic MP4/GIF export (requires [FFmpeg](http://ffmpeg.org/)) * AssetUpdate: automatic asset update system for non-asset store assets +* SceneViewCamera: hack to gain control of the scene view's camera, allowing for high-precision (1/100th of a Unit) movement +* Composite Colliders: new collider types generated from primitive; Cylinders (with optional caps), Chains Download latest package: [kode80UnityTools.unitypackage](https://raw.github.com/kode80/UnityTools/master/kode80UnityTools.unitypackage) From c705805f8060b7c867918eaec1d69f32f19ba93b Mon Sep 17 00:00:00 2001 From: Ben Hopkins Date: Mon, 27 Jun 2016 09:32:16 -0400 Subject: [PATCH 03/16] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0eeb038..5bca6ac 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Various editor/GUI tools for Unity3D * Options for super size rendering & framerate * Automatic MP4/GIF export (requires [FFmpeg](http://ffmpeg.org/)) * AssetUpdate: automatic asset update system for non-asset store assets -* SceneViewCamera: hack to gain control of the scene view's camera, allowing for high-precision (1/100th of a Unit) movement +* SceneViewCamera: hack to control the scene view's camera, allowing for high-precision (1/100th of a Unit) movement * Composite Colliders: new collider types generated from primitive; Cylinders (with optional caps), Chains Download latest package: [kode80UnityTools.unitypackage](https://raw.github.com/kode80/UnityTools/master/kode80UnityTools.unitypackage) From 324d845fc56445f4b8d49bcda930bb766db4bd08 Mon Sep 17 00:00:00 2001 From: Ben Hopkins Date: Mon, 27 Jun 2016 09:32:47 -0400 Subject: [PATCH 04/16] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5bca6ac..2fe5dab 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Various editor/GUI tools for Unity3D * Automatic MP4/GIF export (requires [FFmpeg](http://ffmpeg.org/)) * AssetUpdate: automatic asset update system for non-asset store assets * SceneViewCamera: hack to control the scene view's camera, allowing for high-precision (1/100th of a Unit) movement -* Composite Colliders: new collider types generated from primitive; Cylinders (with optional caps), Chains +* Composite Colliders: new collider types generated from primitives; Cylinders (with optional caps), Chains Download latest package: [kode80UnityTools.unitypackage](https://raw.github.com/kode80/UnityTools/master/kode80UnityTools.unitypackage) From cb233a9c0c118ada0d31b4afca812ee7bdb67ebf Mon Sep 17 00:00:00 2001 From: Ben Hopkins Date: Mon, 4 Jul 2016 14:13:37 -0400 Subject: [PATCH 05/16] * Added initial generic octree implementation OctreeNode * Added example scene for OctreeNode * Ignore /creative folder --- .gitignore | 1 + Assets/kode80/UnityTools/Common.meta | 9 ++ Assets/kode80/UnityTools/Common/Examples.meta | 9 ++ .../Common/Examples/OctreeTransformTest.cs | 99 +++++++++++++++++ .../Examples/OctreeTransformTest.cs.meta | 12 ++ .../Examples/OctreeTransformTestScene.unity | Bin 0 -> 30556 bytes .../OctreeTransformTestScene.unity.meta | 8 ++ Assets/kode80/UnityTools/Common/Scripts.meta | 9 ++ .../UnityTools/Common/Scripts/Octree.cs | 9 ++ .../UnityTools/Common/Scripts/Octree.cs.meta | 12 ++ .../UnityTools/Common/Scripts/OctreeNode.cs | 103 ++++++++++++++++++ .../Common/Scripts/OctreeNode.cs.meta | 12 ++ ProjectSettings/GraphicsSettings.asset | Bin 4256 -> 4368 bytes ProjectSettings/ProjectSettings.asset | Bin 37461 -> 44073 bytes 14 files changed, 283 insertions(+) create mode 100644 Assets/kode80/UnityTools/Common.meta create mode 100644 Assets/kode80/UnityTools/Common/Examples.meta create mode 100644 Assets/kode80/UnityTools/Common/Examples/OctreeTransformTest.cs create mode 100644 Assets/kode80/UnityTools/Common/Examples/OctreeTransformTest.cs.meta create mode 100644 Assets/kode80/UnityTools/Common/Examples/OctreeTransformTestScene.unity create mode 100644 Assets/kode80/UnityTools/Common/Examples/OctreeTransformTestScene.unity.meta create mode 100644 Assets/kode80/UnityTools/Common/Scripts.meta create mode 100644 Assets/kode80/UnityTools/Common/Scripts/Octree.cs create mode 100644 Assets/kode80/UnityTools/Common/Scripts/Octree.cs.meta create mode 100644 Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs create mode 100644 Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs.meta diff --git a/.gitignore b/.gitignore index d2a4d12..ca78733 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ sysinfo.txt .vscode player_win_development_x86.pdb +Creative diff --git a/Assets/kode80/UnityTools/Common.meta b/Assets/kode80/UnityTools/Common.meta new file mode 100644 index 0000000..b90c725 --- /dev/null +++ b/Assets/kode80/UnityTools/Common.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 70121cfd97c114e3faf677a92dbe7428 +folderAsset: yes +timeCreated: 1467602761 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/kode80/UnityTools/Common/Examples.meta b/Assets/kode80/UnityTools/Common/Examples.meta new file mode 100644 index 0000000..2705724 --- /dev/null +++ b/Assets/kode80/UnityTools/Common/Examples.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c48cdcb93ffd3444999567bf2d21c28f +folderAsset: yes +timeCreated: 1467655802 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTest.cs b/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTest.cs new file mode 100644 index 0000000..b5d6b90 --- /dev/null +++ b/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTest.cs @@ -0,0 +1,99 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using kode80.Common; + +#if UNITY_EDITOR +using UnityEditor; +#endif + +[ExecuteInEditMode] +public class OctreeTransformTest : MonoBehaviour +{ + public bool recreateOctree; + private OctreeNode rootNode; + private List> foundNodes; + + // Use this for initialization + void Start () { + + } + + void Update() + { + RecreateOctree(); + + #if UNITY_EDITOR + if( Selection.activeGameObject != null) { + foundNodes = rootNode.GetNodesContainingItem( Selection.activeGameObject.transform); + } + else { + foundNodes = null; + } + #endif + } + + void OnDrawGizmos() + { + if( rootNode == null) { return; } + + Gizmos.color = Color.red; + DrawOctree( rootNode); + + if( foundNodes != null) + { + Gizmos.color = Color.green; + foreach( var node in foundNodes) { + Gizmos.DrawWireCube( node.Bounds.center, node.Bounds.size); + } + } + } + + private void RecreateOctree() + { + Transform[] transforms = GetComponentsInChildren( true); + Bounds rootBounds = new Bounds(); + List contents = new List(); + + foreach( Transform t in transforms) + { + if( t != transform) + { + rootBounds.Encapsulate(t.position); + contents.Add( t); + } + } + + rootNode = new OctreeNode( rootBounds, HandleItemOverlapsBounds); + rootNode.AddItem( contents); + SubdivideOctree( rootNode, 0, 8); + } + + private bool HandleItemOverlapsBounds(Transform item, Bounds bounds) + { + return bounds.Contains( item.position); + } + + private void DrawOctree( OctreeNode node) + { + if( node.SubNodes == null && node.Contents.Count == 0) { return; } + + Gizmos.DrawWireCube( node.Bounds.center, node.Bounds.size); + if( node.SubNodes != null) + { + foreach( OctreeNode subNode in node.SubNodes) { + DrawOctree( subNode); + } + } + } + + private void SubdivideOctree( OctreeNode node, int currentDepth, int maxDepth) + { + if( node.Contents.Count > 1 && currentDepth < maxDepth) { + node.Subdivide(); + foreach( OctreeNode subNode in node.SubNodes) { + SubdivideOctree( subNode, currentDepth+1, maxDepth); + } + } + } +} diff --git a/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTest.cs.meta b/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTest.cs.meta new file mode 100644 index 0000000..e41f8e9 --- /dev/null +++ b/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTest.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a43da294b534f4a50b4f919309f5f9a0 +timeCreated: 1467648510 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTestScene.unity b/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTestScene.unity new file mode 100644 index 0000000000000000000000000000000000000000..dc9c24ca2570ef8197a9c26d24bd5345d3912025 GIT binary patch literal 30556 zcmeHPdw7+_ng0$Tg7*tmv=vSe6+~`=idK@7giB($?#zt)xF3w-okA@M-}mycMs&e8hqHp zqY-1(x^EnZj{#@D*k>7s4z&9l)9$gr8QgI=PGK6i+vRr>K6T*#5cqKXPaqzs^0B!X zPe$S=5>F5xt;YGos6%;9BCg_SZw1O;i^%-RMLgz_|2)Hg0`VX~olz0~A0nP09_7#P ziK+^>`JYhV)kU8t&B<;N)1xDzX7I7&@?i*Q~7j-Y1|&44;OJgJ`Kood_LmfzsEcx zeg>lFB~-tbp(ocMM>!^$-+@k@&ULlf&aQ06&lE79mL<3NIsC3nwl^1YsZ2Z4^{v?q zelAaLTJGmNq(ptby0wtnMQh4D`y zOWta-S$w2jHQ6j&+T~=k`AfT;Y&QQ!WXYeC%`Pwe)nx01KPQ`AUifpe34a>9tC8iT z0C5+kE0hJf@81b;$EORwz7BHTbdgM%ez4?;8Hv;18@2a|&D%bE{JFqB4{OGCAp`Bl%{qyc z9^1awm0Z*HwXWoMwjG-eB5=V@EPd3QuvHVyVa^?tuMkSbk_Z^ zD`y+osWS}h!)lBazdz@^URTC}j`FBSmjh#8^|~^|Igg3!b!CV*8JxUgUWl(WIPC}V zQTX?5%n!7!+Ew;L(R906Q(oB*3zvDI?1zQtO?hQMEPRW>mHkk7O!X@;xUwG>zTM!o z9}FBHj>FfGW`C8lh5`^@2K?_;8PB8rfR8Pf|1PpDPy4|je4a*{IPC`m#{pv>Jcl%K zerE=bKlS!Cq={?$kx+bIM)_YGoc4o({QrpGV`JJL#0etEqC)hiLSY)Gy%GJ<_Cxa_ z|1-dc?b3cQkU#O62A`^7g>xJ(29E!Gv>yyIK2-*1JNEcA89wI_N09N^U~u|B2H~^C z@R_b*uQu7~=aK_n_QT?&{bX)QI@z9w&8bPYZd{tnc4yjZv*~Qk%X#fyi+g7Li&5hYyp~-J8D6_UX)mG^6I{Z|7N5RX0Tf8-$>WX)zlNsOJ;AB&Nx-FjF z5Z?qY9=LR5+jGgTj#O(T6VIb1w7SUe0&57_olavZwLF>MNGVeV3ftsoU=#s!3!{6i zp_P75p*!buo3k>RYxfHVDCQTX@{n#zF~4{V8>?H?gnt`aThra#C7Ct>H5dGxpRLVi zHu>O|X=P!JHTzx3oHp?ayE`tQHW%2l z=9}@8(Js?3GwlWXyY^+5X@mN*%hX5erE8bZ16Gb*7CvK9k2)s)SNIInE(;&mE(;&q zE_0ql_WP#odoT|#P-#7PkyH{9uQj-`%W6EeeWyJ|RW=!S*4!PE(?FI$G(C5F^J(NN}nT%oV3fP-H4pDpEjTG z89ubj3}R=6k6zbl-0p8&l_jpvk^T*N%2R>J;PMIWviA2fZfr;7*@?csjy(H2RpEi+ zzYO?$rkq~ah4>g$W_{Xaecqz|*;xjsUAA$Y=cw|u%dtd&wDt$ffwNuOWhuWC?XEXC z*Jn0fF!&4$-v;cfh#Uv@&r|%P-(_a8d~_UU6>%-kw+(-;bC5*DY6JR!b3b@g&znOm z;d$JkYAcHM=D-)bwaI*;xg*(@-K;HhtB;Ls2rSQXvAY@`Bb#G^W%Lz|xonHSDxYkp zJ#F$gq(Mfh2)rCeQn^$z%}UMPEqT9CpJ_|A`YO+*b!$zs(AvQzGD@hb)tS}~xGuYq z)!B4+r{4hcolC(kgB6$C^%*5bXR=FG_49silfP;;S=YB`vN>P-y!?`EuC^nYD=hL0 zT0$1UhCf$GW(rH|$j<+w)jeBV3 zFY12vP-FGUG%r8lCr4x`#|_aOaoJ0AMAh*E@`;+G(ZmzPqvnWHf`Rxw#vD(5_@~0bOaQV{>F}VEc>KKS~iqYJ0`p^wA(9CkVb}`bF4TbaP5Xde2>BP_8{<@Tm6jR>=&p`oCuApn-?VuTmT}~&~h!*JYSv5VeO=B zgIJ2*PLx#@E)+3)tt!R!l_phsMW80R(QdkTJdaf<_Pqr~<(^o8x-2%(Em*&9NVfVb zJ94mN*>s!oAJ5(WiywV@$N4w^^IdQ4`OEDGe#(!s7|~Y#`N&J4685zQqhj>62CD## zgHPor4}KIX6&10ZHJI>m*I>eDpldMUL*=jTMII`@#$(<*q$?4rRO}-Kru>{N!iTh& z!R>xg`H9na;9dcyYQUaDX%XvDgZK-9Ja5_y|((l_R$(}p{A@2 zerc^P$FB;39_+q87=`ZZgG~Xgw+}W0csUF2~SKPuh06hYsHNK&=qKV$Jh4X)_B<|FV?UB?^PWa z{kn_2yAYA1&OnWxu9HX+@7o0NEA^$(Q$g!Zqh|syN27(0tI@(|pc*ZF#-n}P1PLEo zqq!asjXN6Usd3faZK>=sER^7u2L8>~qV~6LSl95tAD_P=|K+hiJZ}$m1p!GK5{F>#AxbSgDT=)!h#D$ML;=<=}BVOZoBsZn9-2)%(4)k>YMN^g@ z^VUg~pFi%jXMgef39$vheukl@)C?T$Cw20$`n?P#l*K{$QLIy^=fi5?ocXjmYJE8_ zj<2cLJ#k?C3XCxe7fZSN`uLL?#Wu$~c$L99 z+IIOygHyi+XTR1V%YIQyJ+HK1#{$KMt=M1b7j1!!OTYB^h2^DRY(tmV$J^H-PfS^C zi+>y#`$daw^OtsMv29%1rNy>!X;&X}#6i>Teh%f>u4}R5z}PM=w#`S{)yEvFM3lyefI zy(D@;7xUCH2b6_;*zPO9Sw4=)Ao%Z)CSE}hLGTZdCeD5{5a-?a2{A3tnHmNfm1n9d z%kp~ZDe|0E#5JEuh7ZSy!R2#~!bn;{2K&W% z`WX07Z@FCdytv}C6L=gsjssU^z3J@*4$kky@)tU|=(u0CXcs*X12iD`s!k$Bt?GM4I2PslTA$FOQPbQ_DJ=rM8ENFr|Mm9}Q24MdU0Pch z;X}EFPk#>qg%3SuwW<;2bGY>h+n~ih64sEi(>mCml;g-5N{?wjjNnXT`Qs4nl>k>N z#FfWX9$$NwOAJn4cKJ&UPLHW^ZQ&~oPLIhzIcXU#Lz?{c9w)?`46gP#mZ!MJ;Chdv z%X1&I6_MUgdracm^2<1!3Yu*pZ$y^uvJL~wQ=Y#@nm9csgWz`|O`IN+LGXK#CLVfB z&1aXv`8^rf-(C17-$$C?M0rewYdKktd?qPO^QWa1{ZSrM(e&Q)NmDM4Us(a}NAe{^ z@~=Q-kZ}48&hT`40i-{G!M7yf{!jZgEpyd(04@VsPy-iEI6tYH-(MUTE<16#t-DezC!o z$MgbE9T*SzJO*aXx%dqYAP(u18Fg4stE*3{S)SHc?R)ikzvZmL3xJ5lwaj}>D#>F; zebO!&IIKo>c`V#fVo@%+nWkU&M0p8XS(U)A_LIim_j+3_2j^Wl*+hkEyml>a)^Vk* zOuyY%Eqhb4E!C|q8`R~7?)3E-^8epnM$I?Xnd*Kx^IiV-@@{b5zW@E%w_G;$ieIk3 z>h4Fk#HMgE-#seoENLWF2s||z`Z^G#^PutOqy-BPa~Z!ewbbUMp@F5d#M}WIbq1`% zAb1_p#Eu|{Ah;NDI!gw@(@3+tICYaE>O8aYH)0Sy|Pk^%0tt(WX-#Fv^0rp}Wx4T@bW7-Qu@pYqHrqw;(Hh-kv7Y zwOKrH@O0E}QAZrbI~vb8XD};!Lt7?emtXP2{Cz)^L-bOczp}en^p& z{^JKr;64cvC&hLmfZ23hpO@9r=)V8@|%G(qO$FrpXb{qG^yKG#mz;yx;^KJE=gsQ>80}g z)XM409qm9ZxG9OvW4C(!9&U&1*1~R~F7Feo^Lf8O|E=1$L10Z_g)dp#xJo|`*arpu z`RwDKtl2eY^3~5iF?HETA6UXw`R@^-$0~5Q#J#!-0VhH4yCoWW*5&Gs%CG7NdgAQ_ z5AM@BA(aDA6HhyUYJ-y|6OZMW8(cepkk1-}YX=bGtp?W)AjIzhQ9Y01Qq(j{qkh8V}7U<~@$&vj)=+fMv8nc@;SMtKAZQiPNC` z25HKuc1!p*f6`E#T_#`Cjc3e75X-Ab9xpyJ1+%hJX)}pbx;dTg@;#NTO{Y3rytLoe z?k~z^yJV^*doJt7v}(;|^ZDW%iezhRH(uiTSU9%&G#*}OD%0e*L)p31^IH9MT0g)@ zX1ZZ|B&$@@NKMV8Qd(Ix8=`+HRZzo$e@viFr~N(y4+IE_O2(0X3b8{)P19=Sd2ayg zLgd=!Zc~rL&9DaFX#sxssi^CnckF{o!?uI=72x1GMeH z>Gw`GwAoS*LNx-fR#EeuV`x2~%?DngqNaU%+#i+O-US*rleR3MF|;}e;mUG@q3s6E zmE}gMhhDm}Y%{bSpt-XAY1Nn1et17Bg=n4_*N9~jzh z&|F#07<-IbJ{$zi{YH}v?Iz3}SC+|!b_g_Amblcz{C8!kFth`pxw2F~Sg)22C%`_q z<5Fd44}j*%k}$N1uph20)lv^MSC$$>I|Q05%LU)7ItOav&4KOtq@ynv8rm+<>OkWY zn;Z)xTx4j6KwA$bv-SEXr~OreW!AtxeF49=4*t~8-T=+*-?LH=_RHLwC?~dIvyr=gKvP*7c#%dg~1B70}!l+`hcamu^;rMb&=S~?xN^?;l+i{X6B2_pW09_Jiiia;l+qz?r(TOf<9upt-V~CiP(PTv<*xwB4Y&vYdUe zVf9U^0J{VfX8yj z<$DuOXER6H;$(sVvtU+5ylavS`CbQM^~Sd`tae z>F#-#J$r8bRkaOQ?)t-N7jIwpHT-7@>~Or5!Kncr1mS9Qc6SEX%IjLNox=;^bvOda zCBt%9a1}#3)sjo*w&)7+HhnW2FET2Y>nm|j!t;Vk?4W9#5>?2X7*tW@qh2`kQeEb@ z+RvTx@ycDfj>`M*yb*PSs^@!ty%4m@bLNgy`IBx)EPOIPXW{g<#{&<*hf(j@5}2PR z7(9^>fWK_(M75IDXn-FMt?*Du=btstzFzs_mG4(Rv*6@nTe^s}Ex+KUnI$|gUgPPB zVz`B6MmhY|r{!4(5-ttP1PSb80$Ne?%+pU}93mm{(1Yi?SfqfPu|<=;XN4&w`^IXM zmpvwJ9)s*hnI4bG>-6}vxfj5UsbhsznL-jTDceYQ1N(ZoAp2yL3&I#wOzUc**;q4oDG?Zs5k`oQl{73xxd)h$}UKL}Nyoz*?>ks6CQ;H1bC zsh|c;lOkj6u~WCcK|$+I@MV?$sCj)ejsqloh1Ck)j_WPoxt=&=27^SpASQ8qp6qUlIL~ zvl!72Ik%zwp?+LEZ2BSRNnjs@F{nD~g&!r}T5)I(?B`yw9sETZ6~unfrj-+?Pt{FZ+?f4KaMobiEu5Ju|9y;ZMnov>%y znK!X2CE-(mMQun=a8Zwa%L&|A?KTvKeQhg4x9au zb62nr!Wh7(Jf7G+>FZVV=AGQH{lIZ_SwY$xDf%JuL^?49{SbcT=m*zdV~hY|m*q@Z z&YMZbktP22kpH#2mAPalzXAV&iKDBq& z!LzDv{h^krX))E!We_C|_+h&&PDhoB$AuN?j09#F|0EB$lU4Pwrb(dFLH> zRQ~>*cZz!|-3vYM^G%w>6 zrEqjbDqDSH@D+~*{udFtCx!V*wBln;rTl<{3!?n+m z`&qCL!WdLtxA3S0_c?X1UYY1`pF>?PCrEoE#mpS2l?%VUpaQh)(=_thd!WABCL2I@(qa&i0C&zl;5(a{Rom$F`1s zW#Ml>ydE+#BogYUpSi93R#$_5Jg&?3{jWW5Wq(s)ip$#w42BBwjzZ?GytyFJnz!?Z zYu?IR5U>xzNW1`^A3kx_!fk`iBkD-bk6ZB2Pqc^>GKMSHiEHd28#3>|sSe zK!X2CE-(-X{7X@47@kK!X2CE-(jw<>gZ|y`s z|!9ECMfV=lc zp&t|XzHsls;@d8LW{6SU(}gD?g-uUv!o8QUJ)_U1p}tw!JPLytwJ za)PusQuIUQiS%Iz`XT%Vs~_^FK=ec2(~Ew{+k4Rud8beLL;G>ju-Om!`vI^I!pQrd zTD%S2inHw}`aSP@Efdt$lDds5BVDh(GU512+1a z>c`w+(+~NZ4zLfx$n&w69$S0ssKn%Lr&jl8Kh#j7;y{D6H&XON + { + public delegate bool ItemOverlapsBounds( T item, Bounds bounds); + public ItemOverlapsBounds itemOverlapsBounds; + + private OctreeNode[] subNodes; + public OctreeNode[] SubNodes { get { return subNodes; } } + + private List contents; + public List Contents { get { return contents; } } + + private Bounds bounds; + public Bounds Bounds { get { return bounds; } } + + public OctreeNode( Bounds bounds, ItemOverlapsBounds itemOverlapsBounds) + { + contents = new List(); + this.bounds = bounds; + this.itemOverlapsBounds = itemOverlapsBounds; + } + + public void AddItem( T item) + { + if( itemOverlapsBounds( item, bounds)) + { + if( subNodes == null) { + contents.Add( item); + } + else { + for( int i=0; i<8; i++) { + subNodes[i].AddItem( item); + } + } + } + } + + public void AddItem( IList items) { + foreach( T item in items) { + AddItem( item); + } + } + + public void Subdivide() + { + Bounds bounds = GetSubNodeBounds(); + subNodes = new OctreeNode[8]; + + int index=0; + for( int z=0; z<2; z++) { + for( int y=0; y<2; y++) { + for( int x=0; x<2; x++) { + bounds.center = new Vector3( (bounds.size.x * -0.5f) + (bounds.size.x * x), + (bounds.size.y * -0.5f) + (bounds.size.y * y), + (bounds.size.z * -0.5f) + (bounds.size.z * z)); + bounds.center += this.bounds.center; + subNodes[index] = new OctreeNode( bounds, itemOverlapsBounds); + int count = contents.Count; + for( int i=0; i> GetNodesContainingItem( T item) + { + var nodes = new List>(); + SearchNodesContainingItem( item, nodes); + return nodes; + } + + protected void SearchNodesContainingItem( T item, List> foundNodes) + { + if( itemOverlapsBounds( item, bounds)) + { + foundNodes.Add( this); + + if( subNodes != null) { + foreach( OctreeNode subNode in subNodes) { + subNode.SearchNodesContainingItem( item, foundNodes); + } + } + } + } + + private Bounds GetSubNodeBounds() + { + Bounds subBounds = new Bounds(); + subBounds.size = bounds.size * 0.5f; + return subBounds; + } + } +} \ No newline at end of file diff --git a/Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs.meta b/Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs.meta new file mode 100644 index 0000000..196f977 --- /dev/null +++ b/Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 64116b4da8e1f4db0ae2884bf6de9915 +timeCreated: 1467602886 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/ProjectSettings/GraphicsSettings.asset b/ProjectSettings/GraphicsSettings.asset index 042664c3f7442e4327ca8c8c0496d6c793d1e753..9164da8d7277034714e0428c8739323a6a8e7613 100644 GIT binary patch literal 4368 zcmeH~xpN#v6vlhxmAGWE&1sCqeHmNUWx!yI)nQq(B(v5EVS_=mc3awU&F*Z?%$B5t z+9Dz#B!rZRh@v3j4>PreD!;9+>HhWW_r31vo|zTm;EO^W zJ|u*=PY7OwI5RvkJhCx1D*oQv+jAU{A(ZPUe;S{=_18y@nUmOtKuN=`W0Wyv$jyR0^^C;BoL!mjS{e~E0sM8;zwUM7iZ4PA+ zg?%&!9`t_`b+UfV3?GK>RkZI!8A!O%m1tAf=AGB&7+PNUE`tlYcWd9G?mY=Ny4z?| zmvf-ybq^X`(7iX|+4Xtb@7;h zFN-67!TI_bb)NSVxYD5OjN&}9kiTRwxS7{6jNv&wnc_UxH{j1RaVp`Z%()&0H@YQ} zKG&xcZu0pPZR(CBakBX!FKzjJ_`IQ!^WkOl8P}9No6m&yH9VcqnS?vyI1-*f;j`pr z#_7_(Pb{If2+sN7d8y5E8S__3%f_G2w-3R&Zd@yx_5U>Xf6d^8e;xDJ$;u>YndxK`V&F3OvncVE3TgZp|XP&&P{WJS{A>rBme2E;!{d2U> z>>tKiB#)=PF^@@bo&blEbXOUFWw9PPkp?HS#k3OIr6D z@?qX@C*0BVRp88@?`<0I3w3v6e$8Obd5%7gGn7^0fH)H;O zjt}C)g!!-M_^FtGkmKiLE_3`+%s0r(LR<`FyW!Tts){1FwH1o#j_aXTZOFO`653p! zRhudZR9!UJm;JgDl}Z$xGhUNmriRL#>#2oVR4OuR=!zY=qBcEMi(J1IazHIms#R^v zn&Mc0n{Y{O$=a?R05GfCQRA{7G^NM>WuL>>5XBF)zq{3l=B4NBv8`~O5ks(X@3XT z8)o(P>-P|n0qu>jx$4x$_Q&JEyxa9v8EmO2J14yl_V3AzLJZEnpa3w{iTtLF+#2dj zyirZru10~|ZktT!{H=7;x-2Ty#=^U;)G)GHH<DKlQXS)6)YT}Rzj+~jx60(q-blkqM)6O);^jS40Ha>vj5RUH<8bf#1WNc G2JjD|r6>OY literal 4256 zcmeH~OK%)S5XWomwUa;~Z(adIAWssUkcT1^6b!KqAx7C`qbSN{)tPPY4%(er_0Gz+ zkkE<~pMbL^Brdt2YCZ{j>xu0 zBD*(5WEW;kA{XY*&7WC4FaK_BZ3O|q9LC>&en0d0)cS9CuXT2Q_w)TfE`Z&f5}CnF zxhOJ%|5j#LmKt?q{#<3%iJP!F_!xcTAm3{-xQ%}h zd)Uu?1)C|Oysu-XRO@-e;<0+(EbxcW^LpO$ zyj;&g@aNU@w&#I7g8szW?_icuR*$Sed+IpveOVy4_3uJZ*8eW~XuSUSJTLe25IKZ> zK8YBtpK;zN9Ff=LEA(f{#s9$bnbP$-3?3}de>UrXe!Y&6XJb}wAR^<_KI(a`bY6b{ zY~GpDd5@DX*m~H927)lo3D1KpZxgTv_8~ch{o(g<;P^?4GtM|axHzXO{3pjhs_OyODR7)FAd(B0?s*TYt={3JeT3YJ$)O>2aE`wPO%5v1zR~MnwRocmv zeCJKQ+SOqiCGh~uE4r=1jeHH@^X{737+j6R?y#j>HXa@8Mt2hw<53~=ZDk@Ar&p4$ zi+ow?U6rmTrZ;wg3K$M_BQ#pajlK#s7n3!n-=yA<7|lMYNeFzJBr0Do3+EIE?fUsvqU moSnZ?KYNA7!X>+y?Jek21%0o3SD?>a{@wtcc2R;{0RIDCYVI0dEd|H_s8!-&vbw5)N{{G=Z5a- z4T3Ay34)vU3W8vhAh=>2eg{+bo4nun!HE-sx8Hf^osJHWQ}OuIK82I6UHR~lM?Zel zC;#+7SMA4RgW#$?f?z$~g0z1Sv|#^^d(jGl4*YlBT0!f!j-Uloyow$j!CcrPJIBW0 zcaZb;FM#iem$Y9C4<_o6AAslNd@zwyXNG$o1ZxxKM(vNpOWLA%%4fr$6Y!FLu1nsc z{g{pkc*X}g%hQn~U(4mY9qysd`sD7hR&Y3MkH>?rH&EUYQ2!*nrp|`=ou{bVcQ+j*?~1H!jY@GjvyB={2H?@#by;q0eOQNAY& zALpp&?4K8a1XEzK8Ix1V32#v;?0gygR{<6+S(|PZZ91fGMiC^MudzSot-=XOZW;J?EFZ!0~@D zn;eNc{XB{sDQd?pg&*y)KJML?3eU4gIze?^NR{sR$9RcUry+ywU&V+h1`gM=n z^cyk08vUR1Ec<^``B<|aTLJF<85_j=|4QY4KI)WuUZpyoA1!<}d5&71pCWus!v0d> zABovN2_J6;-xTabwIAcw=l6oMzj58l#QwuL_HE%Od#wCX;in|{4}`ar`|~uhW6k`okII?qU1GnaaJNlO^A?z?q_YJ`9}q zpG}zaobm8TvHv(ZQWR$@!q4&8ar*xWaQgoV@)qrFe>)dA&HwYr-NX9-N#(vjd`|p4 zADk)j{|@07c&z*};TIs5Nbrk=e>TBy5&pRZe@OV1 z3I2@mtH^V{{@G7n24{c1njDGc<-GYfaK?>m93{8&=C#h&^LX6&ymGIz;Rask3mH1s zsr?uef4->P>+B{v*JtS5p!QbhOUk`Yx9HrMp>vbkTb(Z}_c}+4&Q~&YZdQA%bBl7X zvs!d+&Ct0`?XAx3%Dv8|qVv@Zov*3A)wx5t*SSq}?#$4+OYN=B-O9br)1q@vhR(fe zZ*{(|-0Qp|I^W39xliq_&Nr2NosBp2{qX(_od?w3>U>MNpO<%n4&&svM|I4+{Gf6> z?>`jd9AC#{>~Va3N4cGszYFf;s-2g=r`-E9Mf`bKb!^;zM7j0n(HM{W^O$n$&-cO8 z{CQlt_oqkvc|vupKbY%XO0J8Zit)HVPb;_n`~W=7pC2ms@i`BF7~g)RI=(+N!CC)5 zR&L|lGvHp|_J^M+_d4f_&a)XhKUI6H^E2U`j~1aXTqk}$7t`T7=ON+Gt4;@Fb?Xt~ zh~X|VZj-+#{O2*w`Tb3B_S;{Ow^%mYE-wP7&F{Y?cMm(i|4O;9=gm=>tmj|j!4%CS zdxNu{UvkvtYu2B?akiev=aH9%NA=S!`oE3o#OvpGs^jZnso4Ks?L9wL_#a}N^>ZmW z>*p2nmh;Dq>pudg)z7Qs?qTcaPs;tcxJUH=44$U{nsPf%|3Z$$@$w`z7&qwW>x3=x zvF=>=Ezy5N`P#<+H^IIC>$v)l&W-;{?jGxybK|#^k9GTzbvE|(^EYsxuhsv%a;yIj za-3EgHLgtv=6veLY+KwN=OJucO@elg*@_*HwKx zPS;az`^oy`NbD!<&rv_wK<&qxde{)$`?o-K7=k#g%TW9ERqdHc9TjhQqbQbg}y&ZobvEJq)rz?eTpWt5>z5{vA+w*+j0rB(w zYH#adN9DF2#>M#4&|p7#FQj);?&sNG;2PU^=LG+a@Lgh@?fXY?w(qXWeZS&9iaNW2 z^HK*+iQ;j7cjdlcy&?L0sE(g!H+hfO-&48mKYOW;?LT`f_v34K=y3e<{g$-$-AB2t zw|&Wx*sl(RMl`Ugo&IU-%629Jw#=(^B4<?emS_w}|R z^obVmM~=^ZeBMg(?I&-M+j<)SPmBKx$#DzEZ@gTKly|uG$zGzrn8qpkeBae`+b&0t zBT+xTJ~>kDeY-^KlcSW|dOI3CtzC{Gclx$nKCIm9N9&VgY24yHR{uEK=g4il66>~37wAT@%mq?-0L4E`pYu(`TllCu3f*VI<|d}SMKMR zMbICMs##8bR8X{TDGD#eIM-1pi9aLcE!x}imZ_iOPlep+TYsv`eR}= z)v@{w!O#$pHs+N?d{c4Zu{q{s$7d0JajmZf08;W^?yF?bM({J{{^aJ`@@CGeZ8G5_3$a`BeC8%&t3^m zbWwueA^g(`{-p5FkmtM($NNj*^#5Y=7P%eomw>0uFPD~dkp~Ox6ksHmo zF8O|$94YE=7l{2=68u)-H^+3?uO0_yzq*CIMIGC(ZUs+k_uI%_zP8?OSMJ;8MbZB% zjZ^f$M*AGK?6|u_b*%oK%Dw(yME|Y~{kt>t?@=AAf3I?{zt-lye!iZe|BVd&`&7s3 ze^a^F-%|AN&(MD$L;qWhPuT7gB;SX~TjaLgzeAl|d%JvB z^=-c2Q||SYAj{eU{T_ImrF>f3yOq}=CwjpX}d>LW$t`gU-lXZR!MIpgsCV*itb{WD_! zY=XZo{HF=N_7-0MX9>Qo@aM>5`A!69zj{7q&wkYf&Uo?yd5fC1U;P|Bt$uz%j$4xR z)Qie}yDt#^U(z^5|5vond7bz?^=s9!_5YG`U;j&`T)&|{Qq=A%CEu6HTjaJ}zokyD zJ>TD{zRmad%6-14NxpxeK2ntL`I7G|kaB7Mdi9j@_m!M)n2Z@QYY75uD4X*=KDA0KHoaV)|Dt}b-JgGxJALcV+sb`CZ-PTDj*E9_oT49$N!RZnPthNv z-0SZl`fGuw>5t9OUt4vo|LZ9C`iF@Ax*7WGW$3T3I#z!J;zzfp!hKWCj* zKkrfQ^_PkMCK>vhX6SFGI@bTqm3#daqQ6Ck{(Cd@w^SXg|32kj|5VZ6Dnozk4E=3X z$LepZ-0NQ``rBpbZ=a#RgX&oQ_bd1MH;O*api=wixD5TBRLAP?tlaBADEhl(=@dP#-CZW3NfR{9J$9xZ8_5IojLx?cSLalpxW9ft_yGz2gzy6s{CVM>3I2QGA4>4Ig&&mQo4wEb zb8v$1Dg2NGKUnyov@=c55|_N!dXp1dZ!E5=#Rr-8Gcr;)d)W9zvaJguImljD}; z`f7%9KaMUE{h1m1voiE&tB!5Q9_3#DOQL^RhW?xk{kf`R^?Q{|e}F#AIgk2CQ9pTB z`1}NaRd`>5cWmW#4o~o{gfAe^d3~PmjR$AD^poFDZrf#myhU!~0RO&+iJa{ly-&1A z?d|#AVsPKS_Iz&%xzn-ddq*hu_1`Ui9!dTCd5`t;DAl)q9<4gI{*O`a&+FzupXVMQ zralt%&AH#PYH!ayj#KXaJWBk`Q>WGL=OFEK2^Cg+A*mq`uSf@%9XG zj>o0sNKu^sjQF#RyhU#7Z5TYwpCY-_vHl#d+?V$T(O;gSU&_!QQ5~yaR_^uh6#Ytu zel$e+$w7Scd*-8TzNIj@3Uyx!2!Q z^v}%DKPyB3Y}K*)A6M@6r-}YK8Ty~d&_7potp0h*y?(#we=g68?n*e_i->G0u5;?QQ({ z{UUjb`ZoSw51tnPZyFq@YpP@Q?@;db4-@@6GxYDu(7#)Cto}X9z5Y?6e{Y8V*E96L zp*mLoKILBj1kwLyhW`B-`VXj%)&G`q-~Z2nKKuW-sgD%(|IZ44Fvi)RZx(+ZB5$?# z=kHKIM{d_w-z9hY)}QYw_vO7$^dHX9eb#m?HdQ$amzE3Il`hO7pr!(|_kfHxW)v@|NQtr$34=LA=sgD%3{HFxfRPNj5QRs00^(*SMc#nrde^T!2?M*4ypPfGMvGw+v(kuk)i)) zhW=kw$F|E`%Dw)!qW`xH{l91E|3h`G{y&v_{SS)%zcTdyouU7>>RA1ElzaWzqL1oj zH)*T?4)C;o8+{K)a$mL{**OXkNWsX zW|Z&wlJENDt@d)^^MI-4+EDdvz8fj`GLQn~LBcSyP32cA}MThZR>+j4EKI=0@nQSS907X59( z)AaGVo>cwqRmbY@pxn=2zl8o+NWY)@NbC=sr``Z(`FBk4jkfoET!QZ+d?)gp*WtP7 zf#B5NIc85jPxvk|z6g9NI6m4G?CSV9_%J588vGQo-wnJY80Du5-#x)UCVY6Bv9&#l1pJ0d4zk@hT?S22*4A7SMUG)3G)9Pn{_D%zAC5!A_%+kB5C$1UXXad(t*U#{at|7h?u{bOjKq91*aS5p7jg#H@Q zKQ2Q*pP@gfI@bRo2z{2bKz*cWKDthLNS+(z4+vkHu>Ya(Wifl!|L?)sZ->cS z)Uown1n+SAw*HSN$1TbFS+3l-d+>hW?j>+0`hOMjeGfSAA4%|?gqIV1AK{e*?-X7o z&v|{8Yc@E`bpm;d+?LCIADgqc<*LIzty~S|zF#d6{bq*#3fiaWuT&k|?yHo0{Xx-R z4W8!z8rrAme?)bx{)x)Hena$60#DOFnf59Ar>KtAZz=csr;Gln;A#3FrG1M2$5hAa zpQhaFUoQHmgQw}ALHiW_GgZgxpQYUE-z55HgQw|#oc1aD=cta=|Aca{|1Hr!7d%b> zJldz|e^Pa<{`t!NxO)ovVd%fQq0FQu)9cp94?RzmoPT z`d6ur)xTP~*WXk0uK`cfzn1nX`kz-FtN#V%UVnelzYaW2|BJLw(Z61Gto{wky?(do ze+fKI|3=!U=-;F|R{zV&z5X$x{}u2w{hMi@qJN9(Sp8d-d;K+{e;at3{_V6+(f_LI zSpBal_v7wT=#Pc;9pFqHcP}8P+l1d4 zQf}9=-v;l|1Eio-1`4J<<|e-tB&>m4{C4y ze+9fFM}6!6AIXt5d3+!Ds&XGc|2WS3|0i&!D6Vd>ljna<@STOfmf$(ze@XBq!e3AD zWzb|~l1pkHbjS~D{!Z%Lv&3Ezj z$?w}{it2e6;hQA*{=zp+@HxUaOYkFvZ=T>q;aiaBe7@|TYrxq*-%H*ixBYWV<+gvm zj~po(-?mbF+dsDk@5s^K_Rnp|osNwU(f5wCei%Q`6F;|8ee37;s&D<=LG|rA>ix>S z{sW@FV}|~?4E>!{$LjB_-0Qz0`nzQ4@0y{%o9bBo-IaU&ZFcqT$nRwjTC7uBKYP;N z)xWKuy~thtTm8M2d;P<9_4*$G4^s5^p?!+}zT_$T`ziPO=j`hBKL{SA=#Qs;iv9%h z6#a?Hz5Z>xdi_b@L5lul+NbDGAy3hts@&_pysOvWA3R9WKY;cr`UjGy=yxjj`kU_N z^*;n2r05?+`xO1?`}jFdm!aRKI#z$0a_|2UqTijNKRrW#hU!@T znaaI>QS@g~|9;k~?fK~@uucIy!{W;Wcwd>DSZpT+IIZ`rC^4~-7IyO$u z2lwr0<76MX)3I^#aOHlzdcF9$06b{5``NGD`Z++3l=O3<+FL&tfv5SonB3`DKbI)? zem*FE9-;cSy^d6F{XB}?>DzVD(Q0q~JO(_?&kvJ39qVWG?@@5x;r{Cd@$)#t{u|^|MOu^sS#KsJ->G2A<|;o!seIKO4%upL>X(P1U!4 zu263MTuJWqt)HvZ-uk&3Jk8HF`4Q#b&qKve{(C7wi}zSRPf~9EJeeFRIo?lE zd+TQlJk8Hj$(@e%^P|eWpG(BgkEy=(^EBnw&(q1BzOBzQ)ZY4eCU}~kXOTM{>*v|Z zy`L+@&yTCV_46F%*3VCnJALctxoU6yJP$n0&rgy&9qZ@$%DtbT7C$dgee36i%B`QD zB6s@M&x_RF`uS<_G(SH>?sTl57c2LE-YkAzqWad)OO;zcFC%yQ*3Zk;-uih3c$%M| zC3ia3&(A6Mem*RIUa9)l&#RPMKd&Zt`qs~D)ZY4eEqI!rpC@-Z*3T~}_kO-CeqN{g z*3U00w|-tv?)0snH>kb!^Go1qe%?s#bgZ8@DffQzA0p$v^2@4k{rrk@>*vknPT%@@ zi`rX1Zv{{D^EPs)WBt5cx%YE>@$;*yZ~gq5a_i?E`G9ioXP@}_E$ZLTd#s<| zCU22jKOZDVO3p_QslD~{JK$-4ewWUjrrhhV z68-OI=s%vJ|AgvT{U?=s{nJGMsSN$6GxUF;I#&OO%Kf?Dr=ZVz{1Nq$`bzoLVXZ%G zG>YYA^`NUFEH(OvYGGKOUn_>?M!r$3l!HdTwk&K+4_6e2 z!k}3X=a;94Bl&V+L0GReYeQi@$PW#Lkf@A=jj%Se7M{=y%R{S!p~^@#UtT>gKN1Gj zTBXn&YPjc;Q+KmguhfE(V`n1&p6Phfmv0Q?$&kA+yV9svD~(`Puo{>8tEGH>*gMzX zSX~OqhAS%Me;! zj$IIz3tOMsY>hT`5&+{nb3`5{3h6q_4fR{>C1e=nNy0)`6FyYXVZwn*U!~Tl z<%^B~bZud^UMz%ENwb=ZGSr9i)o_7pjg&mpVs5y!;W}l%y1+h*ZaQh=v|?krFUz#% z(xvR;#d?0Q6iyGTjbU{E{sy{fvE(n-qvq|Y&uo@TzNd|{c^C^T(4dnEC zVxy~^FRgAAhw3bYAF^{%`Gfi8>^h}l9mVSn>%-^^ODhQV4^>q{4yiXu^a9qeuPKFdQ15J}u_K>@Z)5$G1_(XEnom zydbEC{`^R_#1fPz73%0stO4|!T3D$MRjS3IMa6KXyXK4DKa935%q`X%^Q(;*U(~<4 zJQOsG3+v&8sqB~Rg3>FC%gSh)u2OY4-(3o&YUh{Zovm7*WMbS3bgD{kI8v#tMju)f z)*9ies2f-7)rox=lQmaWeAP8{LbF&4r_JgORu+p32NuP;F~KYZ=)QcRx4)~)8T2=+ zRgB^Kyk>c5xVhZ0ZiHcUMD3Un`gky%h$MzEZPpFeaab zl8Z2Y_(WZg8H`$WBUUwnu6h-HZUMV;9g$P=M;wat$(@seDV>vp2~#^KjOWh-gZYi& zuvQNS5%19V3Yg=HON%Ik2dGF6FHBY;gB#`QVFMY2D6DT_1l+L7a9?ipl&j4~zncPG z??RJF2k`@7R<((W4r>@M6s^0+(1+^t{bw}tV{UAqG_zzB`gVX}-eV zi)WbGtHo~4;*BC^G|V@1!xdpEs5ffG>WuO-41AYMv2VCi#;^dbqLki9;1FP=8zY;N zBZy5d3x9E1vsfz3YmN+}1<;R&5DhT2%3-4~tc?`W&)|&X{nNYAqhhqX7Gkbh4B0BC ziCWOrH)qBwEH-!xmlO4<4KW}wHP-{@+`=-#VS&+;g@VgvG_D^#-NX5EIV_PQgt{P` zuP;Z}!eGU$>kBwqg&qvJmC^kEsA3x{=J&_ynJ<$j%^p;H&8-(u@k1zJvu6PoOc@>$IJ?o-btFm@kMMnb)%=<<4}2 ze6?B%2NoGWT=R{fPqAI*a+HOM6E0%R;d&(v&gNw-py`L4rla zNOE;Dd0}*Y<`#}YZP{QxX@d@5>cb42$g97&rY-;OX1!4vSyCKyE7imeMN9%|PLsQG zCUfA0q=PA%8UFF^G#|;^{Pf!o87U)f;3B6sifDlz?PBtxe65(rRI$SU9>_0qn-BNW z2R8^TTrjtPXgC}}z>uiu2dwONgvEPF|4<&AkGw3h&y|#5KRk8aY;WR_4}ed93faxQfXs!>rB? z=uiwyUtP|R7!tcNnm)VwdW_44qY8N$zpy$Tp?t719Q4cVfe=eQ%qqAVJ@wrXUB@q5 z28s>0Q+10bY?`W=n*HizWTaB=&#%C09Al2CYiNiI6~pG2RsdsmK^JjG1I4nNKY7Dp zm13FA)Z-UU(MvAkdN~t~<}Vp$d{tq1MEEK4<6sWusoD+Vr#DUb-AIthI4@hVHFEjG%d{i zB4%M7ad~=JcgqjTFTrNOw_m|McL8llxXJ}WUc{bUpU(<0-q01moH3T`rOIl*tc&7H z-Cc=?hS(m%Z#x|5Din$=V7}zC_p3Wsr`&kNmD4sR$?JWUx>F0VC2)G(mGaV}KX?F| zKDXO~fnhAK%K2i+l?@i7@j4<{!j=osi+O!r%R;WJF)Eowtx_FcjX*Vmeu>xfs(juo z^Uwih;%c@!j26HFPh{MO{)M`a1gBLhjqc%aXnAjb6-NU*3`;*}+UPCR>@T_u)ue>u zA8&!v2ieL@T4eS;UClzVLK`0?u?ickV7u$KMT{Npe(bpV`xateSU56R%a2<3Rxnz9 zJS3Er`}9g_aP^GxP{r-YtM$pYKJe02dVh!wY6JHXxGG|)rO1=}um{B9S;@y)7@oGv9Pc_I{IMt*m$Z0 z_s3kI8$e^6I2nz;T5&~wX!Wcn7XIeKyuJp*Ffxra7NEr&?yLlX6yf zARJEUdK^rX(Ql`RgUw|{WN6XyVkKTU2bG0Wo|Utu2D8uvZIF?`oesBMX#)dTZjY+s^3bqvzn;`sAGO9U3LM(0Uz6Sr>`em(--tgphUZ1@r^do*S%q( zn8#UCehB9mP9-@>RwpKB$?C+>5U2%>&y%>t&WsVTvmeXriZ%LX$*7z}&cmBHH6yt3{mnr}P=87oQ|YPKo7}bW@GyqwRT^DOQI-BeY+i}4R#(>jj4A~f zz>Mko!e|i~9U&!?p&iCW5*V@Q&cP89&{JD`EbSJ zD=a=j{|*x0G8pBfBS=mz0=$b6kz%Qsc@Zp_8kM0+X;cZ-T`eM0%#+d528Tnah%#*X z&St#z;v6Ro-VX7YLj&f_%PBj%S$+MZ2b-eVTO49|!3kyj65oPAUCdbJwv}#HC!%Xu z2GqIaEe;_>`u811t>lE2wy=@iA7A+me4o^%yKO~!KDr}Tu4o1w2nRzf{1Y4LGMYmrbd#Rz28#$cA zOBQfIz`|+)^eAH&?$OL?7g05s zdy7l4(n-54K?%E$+G@WgHlm>~1CBGw%@WSEFqz5qc-IrugI?h}w}?ije%&^!Z=pLK z^Jn_eHLUNJ^W6@S@Go67^*c_yKabf6rz5CcH#+dtt?DrH^u)xEm}6y?>d))kB5mYY z-x1`FC=<8TlJf*%ZoUcm!32)09;|2O!sz)pCzX;+^sa{%%MI995yIWa4S3#<2FBag z<*>68@^}vdjlw9x#Vp>npEWm|=ee(pMioYbY_H_5Fgme_7LdY6{JxX15d?z@%k7jr zaOl|C*;T{27vJ;2JFGlZ?dFdR-VC1g$E|F;&=J; z$4d zr7B}KLa^8`tzHxQN|7pN6Jk_jZRZaW#k7eCiFcIn-pJ^pE8Ze;aU5Wo{MpeaO&#CH z5K_`vh6g!Oi>r>_Fw$8ph*;83m*c-V+k_xpUU(We7+7I5ljB&Cx@A6 z?XGpW6yWPSN!(99W8w>z!PyZcld(=-^!JgfnLP111_A!z1%4QDKdF%Y&^G#EL=-KU zu-|yzu4(OX!9f$I&HKYSXWqB+=tocFKNN@WTc+GD!z(4%r62BP< zcdL7z{{Qszd((n|kF50HuG{<2F0QR|sFAPQOaJi|{sBFF(xY!~Pj}Zq&-{6v($C#J z{3gut#9} zj|_wV1!k7<)RGrgzQcV>Mr6lpyW%lp`h=;ICha?~Z^@D=6DCcacv{F!?^Z;Ny$2Vw;JPMxOl;wDGP=dEGcvsW=$#2nv!2rnAbaJ>eSw5 z_oAt@mK5KumfG#<``@|%I0hPr&tki_>RH4V*|%$2_w)%9CrzH>+R8nfy8i(O63>`P zjd=USpYs}HlIz_3os!<|9Kc)OjV=2bA7`Jn-XXW%GX9X~pF8>x-fLgC4y8>pr7?=J zUdFF-1;?{7!I*V}wK#^koOIJCo_m{_Gbhb-RRZ#VPp;11#qEs!_;S+!xT)kEBTJUH z{TaT%F}jwqxAb$A+~2mt+-&sz*e){&@P)_JjTS>~`SQN@{bmq+AmZg(3k+sA9 z4}0HWZ`_x*)y>!d2m8Q2b-SCf3+DWnvERk%O!^KvhkO3ZR=2bBzZmQejrOf?XJO*hGG&$KOZ#zxuAeKYeVeA2|v zga0p|BMTp|GS-?L=Zw86r);_j#6Pmq9@q405a1tyYKw2tWzHpuI2T=Vv81ox#Jj{b z6ZiBQ^Gn9R=pyH*)HoO!;5xoEG$S648nMi6adGr=!0XZvM&niNy3CW&e3oj%awKD0 zB*8XGiE+_o*JdfPPOr1x6Y)*2G2djIi!L&{aW6c7sL8)@Fp1X~OIaxQ4o#)JXo0ct Nb7a>23DfqM{{vRDD_j5o literal 37461 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 Date: Mon, 4 Jul 2016 15:13:24 -0400 Subject: [PATCH 06/16] Removed all foreach style loops in OctreeNode --- .../UnityTools/Common/Scripts/OctreeNode.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs b/Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs index 99a73da..1ac6e29 100644 --- a/Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs +++ b/Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs @@ -40,9 +40,11 @@ public void AddItem( T item) } } - public void AddItem( IList items) { - foreach( T item in items) { - AddItem( item); + public void AddItem( IList items) + { + int count = items.Count; + for( int i=0; i> foundNodes { foundNodes.Add( this); - if( subNodes != null) { - foreach( OctreeNode subNode in subNodes) { - subNode.SearchNodesContainingItem( item, foundNodes); + if( subNodes != null) + { + for( int i=0; i<8; i++) { + subNodes[i].SearchNodesContainingItem( item, foundNodes); } } } From ca28f66e2e86c85f32a0647afbf88f8afca83285 Mon Sep 17 00:00:00 2001 From: Ben Hopkins Date: Mon, 4 Jul 2016 15:25:42 -0400 Subject: [PATCH 07/16] Added GetAllContents & Collapse methods to OctreeNode --- .../UnityTools/Common/Scripts/OctreeNode.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs b/Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs index 1ac6e29..d1068f1 100644 --- a/Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs +++ b/Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs @@ -74,6 +74,19 @@ public void Subdivide() contents.Clear(); } + public List GetAllContents() + { + List allContents = new List(); + CollectContents( this, allContents); + return allContents; + } + + public void Collapse() + { + contents = GetAllContents(); + subNodes = null; + } + public List> GetNodesContainingItem( T item) { var nodes = new List>(); @@ -96,6 +109,18 @@ protected void SearchNodesContainingItem( T item, List> foundNodes } } + protected void CollectContents( OctreeNode node, List allContents) + { + allContents.AddRange( node.contents); + + if( node.SubNodes != null) + { + for( int i=0; i<8; i++) { + CollectContents( node.SubNodes[i], allContents); + } + } + } + private Bounds GetSubNodeBounds() { Bounds subBounds = new Bounds(); From def154d363a0bbb27b98c133a50b2f53e6ae0fd3 Mon Sep 17 00:00:00 2001 From: Ben Hopkins Date: Mon, 4 Jul 2016 15:26:09 -0400 Subject: [PATCH 08/16] Stubbed out generic Octree --- .../UnityTools/Common/Scripts/Octree.cs | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/Assets/kode80/UnityTools/Common/Scripts/Octree.cs b/Assets/kode80/UnityTools/Common/Scripts/Octree.cs index c6daab4..f700f2c 100644 --- a/Assets/kode80/UnityTools/Common/Scripts/Octree.cs +++ b/Assets/kode80/UnityTools/Common/Scripts/Octree.cs @@ -3,7 +3,33 @@ namespace kode80.Common { - public class Octree + public class Octree { + private OctreeNode rootNode; + + private int maxDepth; + public int MaxDepth { + get { return maxDepth; } + set { + if( maxDepth != value) + { + maxDepth = value; + Regenerate(); + } + } + } + + public Bounds Bounds { get { return rootNode.Bounds; } } + + public Octree( Bounds bounds, OctreeNode.ItemOverlapsBounds itemOverlapsBounds, int maxDepth = 1) + { + rootNode = new OctreeNode( bounds, itemOverlapsBounds); + MaxDepth = maxDepth; + } + + private void Regenerate() + { + rootNode.Collapse(); + } } } \ No newline at end of file From 953ef6a1b8ab4f2cf0b6b1c9f9090008a5faa6a5 Mon Sep 17 00:00:00 2001 From: Ben Hopkins Date: Mon, 4 Jul 2016 15:51:24 -0400 Subject: [PATCH 09/16] * Fully implemented Octree (Add methods need optimization, currently regenerates entire tree) * Refactored OctreeTransformTest to use Octree instead of OctreeNode --- .../Common/Examples/OctreeTransformTest.cs | 43 ++++----------- .../Examples/OctreeTransformTestScene.unity | Bin 30556 -> 30556 bytes .../UnityTools/Common/Scripts/Octree.cs | 51 ++++++++++++++++++ .../UnityTools/Common/Scripts/OctreeNode.cs | 5 ++ 4 files changed, 65 insertions(+), 34 deletions(-) diff --git a/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTest.cs b/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTest.cs index b5d6b90..77e847c 100644 --- a/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTest.cs +++ b/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTest.cs @@ -11,7 +11,7 @@ public class OctreeTransformTest : MonoBehaviour { public bool recreateOctree; - private OctreeNode rootNode; + private Octree octree; private List> foundNodes; // Use this for initialization @@ -25,7 +25,7 @@ void Update() #if UNITY_EDITOR if( Selection.activeGameObject != null) { - foundNodes = rootNode.GetNodesContainingItem( Selection.activeGameObject.transform); + foundNodes = octree.GetNodesContainingItem( Selection.activeGameObject.transform); } else { foundNodes = null; @@ -35,16 +35,15 @@ void Update() void OnDrawGizmos() { - if( rootNode == null) { return; } + if( octree == null) { return; } - Gizmos.color = Color.red; - DrawOctree( rootNode); + octree.DrawGizmos( Color.red); if( foundNodes != null) { Gizmos.color = Color.green; foreach( var node in foundNodes) { - Gizmos.DrawWireCube( node.Bounds.center, node.Bounds.size); + node.DrawGizmo(); } } } @@ -52,48 +51,24 @@ void OnDrawGizmos() private void RecreateOctree() { Transform[] transforms = GetComponentsInChildren( true); - Bounds rootBounds = new Bounds(); + Bounds bounds = new Bounds(); List contents = new List(); foreach( Transform t in transforms) { if( t != transform) { - rootBounds.Encapsulate(t.position); + bounds.Encapsulate(t.position); contents.Add( t); } } - rootNode = new OctreeNode( rootBounds, HandleItemOverlapsBounds); - rootNode.AddItem( contents); - SubdivideOctree( rootNode, 0, 8); + octree = new Octree( bounds, HandleItemOverlapsBounds, 8); + octree.Add( contents); } private bool HandleItemOverlapsBounds(Transform item, Bounds bounds) { return bounds.Contains( item.position); } - - private void DrawOctree( OctreeNode node) - { - if( node.SubNodes == null && node.Contents.Count == 0) { return; } - - Gizmos.DrawWireCube( node.Bounds.center, node.Bounds.size); - if( node.SubNodes != null) - { - foreach( OctreeNode subNode in node.SubNodes) { - DrawOctree( subNode); - } - } - } - - private void SubdivideOctree( OctreeNode node, int currentDepth, int maxDepth) - { - if( node.Contents.Count > 1 && currentDepth < maxDepth) { - node.Subdivide(); - foreach( OctreeNode subNode in node.SubNodes) { - SubdivideOctree( subNode, currentDepth+1, maxDepth); - } - } - } } diff --git a/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTestScene.unity b/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTestScene.unity index dc9c24ca2570ef8197a9c26d24bd5345d3912025..4276d7ae557f36a7555e3ebd8a5c203838830c36 100644 GIT binary patch delta 44 zcmV+{0Mq~6?g8BH0k9BG2wabXKbn~tzOxuk;0z169;HC+Q3$|~!gZ6oM;)^uTRa@b C+Y>PW delta 45 zcmccfj`7Yr#ti~~99-8I+dr%l*}qxB?*R`_p)HpKi0APz%3<;zcbUx!(Ka#w(99Ch diff --git a/Assets/kode80/UnityTools/Common/Scripts/Octree.cs b/Assets/kode80/UnityTools/Common/Scripts/Octree.cs index f700f2c..73116d7 100644 --- a/Assets/kode80/UnityTools/Common/Scripts/Octree.cs +++ b/Assets/kode80/UnityTools/Common/Scripts/Octree.cs @@ -1,5 +1,6 @@ using UnityEngine; using System.Collections; +using System.Collections.Generic; namespace kode80.Common { @@ -27,9 +28,59 @@ public Octree( Bounds bounds, OctreeNode.ItemOverlapsBounds itemOverlapsBound MaxDepth = maxDepth; } + public void Add( T item) + { + rootNode.AddItem( item); + Regenerate(); + } + + public void Add( IList items) + { + rootNode.AddItem( items); + Regenerate(); + } + + public List> GetNodesContainingItem( T item) + { + return rootNode.GetNodesContainingItem( item); + } + + public void DrawGizmos( Color color) + { + Color previousColor = Gizmos.color; + Gizmos.color = color; + DrawGizmos( rootNode); + Gizmos.color = previousColor; + } + + private void DrawGizmos( OctreeNode node) + { + if( node.SubNodes == null) { + Gizmos.DrawWireCube( node.Bounds.center, node.Bounds.size); + } + else { + for( int i=0; i<8; i++) { + node.SubNodes[i].DrawGizmo(); + DrawGizmos( node.SubNodes[i]); + } + } + } + private void Regenerate() { rootNode.Collapse(); + SubdivideOctree( rootNode, 0, maxDepth); + } + + private void SubdivideOctree( OctreeNode node, int currentDepth, int maxDepth) + { + if( node.Contents.Count > 1 && currentDepth < maxDepth) + { + node.Subdivide(); + foreach( OctreeNode subNode in node.SubNodes) { + SubdivideOctree( subNode, currentDepth+1, maxDepth); + } + } } } } \ No newline at end of file diff --git a/Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs b/Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs index d1068f1..f2b01cb 100644 --- a/Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs +++ b/Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs @@ -94,6 +94,11 @@ public List> GetNodesContainingItem( T item) return nodes; } + public void DrawGizmo() + { + Gizmos.DrawWireCube( bounds.center, bounds.size); + } + protected void SearchNodesContainingItem( T item, List> foundNodes) { if( itemOverlapsBounds( item, bounds)) From 5abd1ce3c746d6c07c46125fe9cdcf9c544eb42f Mon Sep 17 00:00:00 2001 From: Ben Hopkins Date: Mon, 4 Jul 2016 15:54:39 -0400 Subject: [PATCH 10/16] Renamed OctreeNode.AddItem() to Add() --- Assets/kode80/UnityTools/Common/Scripts/Octree.cs | 4 ++-- Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Assets/kode80/UnityTools/Common/Scripts/Octree.cs b/Assets/kode80/UnityTools/Common/Scripts/Octree.cs index 73116d7..ddfc7bb 100644 --- a/Assets/kode80/UnityTools/Common/Scripts/Octree.cs +++ b/Assets/kode80/UnityTools/Common/Scripts/Octree.cs @@ -30,13 +30,13 @@ public Octree( Bounds bounds, OctreeNode.ItemOverlapsBounds itemOverlapsBound public void Add( T item) { - rootNode.AddItem( item); + rootNode.Add( item); Regenerate(); } public void Add( IList items) { - rootNode.AddItem( items); + rootNode.Add( items); Regenerate(); } diff --git a/Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs b/Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs index f2b01cb..e968467 100644 --- a/Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs +++ b/Assets/kode80/UnityTools/Common/Scripts/OctreeNode.cs @@ -25,7 +25,7 @@ public OctreeNode( Bounds bounds, ItemOverlapsBounds itemOverlapsBounds) this.itemOverlapsBounds = itemOverlapsBounds; } - public void AddItem( T item) + public void Add( T item) { if( itemOverlapsBounds( item, bounds)) { @@ -34,17 +34,17 @@ public void AddItem( T item) } else { for( int i=0; i<8; i++) { - subNodes[i].AddItem( item); + subNodes[i].Add( item); } } } } - public void AddItem( IList items) + public void Add( IList items) { int count = items.Count; for( int i=0; i( bounds, itemOverlapsBounds); int count = contents.Count; for( int i=0; i Date: Mon, 4 Jul 2016 16:05:31 -0400 Subject: [PATCH 11/16] * Added concrete TransformOctree * Refactored OctreeTransformTest to use TransformOctree --- .../Common/Examples/OctreeTransformTest.cs | 9 ++------- .../Common/Scripts/TransformOctree.cs | 17 +++++++++++++++++ .../Common/Scripts/TransformOctree.cs.meta | 12 ++++++++++++ 3 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 Assets/kode80/UnityTools/Common/Scripts/TransformOctree.cs create mode 100644 Assets/kode80/UnityTools/Common/Scripts/TransformOctree.cs.meta diff --git a/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTest.cs b/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTest.cs index 77e847c..d75090c 100644 --- a/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTest.cs +++ b/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTest.cs @@ -11,7 +11,7 @@ public class OctreeTransformTest : MonoBehaviour { public bool recreateOctree; - private Octree octree; + private TransformOctree octree; private List> foundNodes; // Use this for initialization @@ -63,12 +63,7 @@ private void RecreateOctree() } } - octree = new Octree( bounds, HandleItemOverlapsBounds, 8); + octree = new TransformOctree( bounds, 8); octree.Add( contents); } - - private bool HandleItemOverlapsBounds(Transform item, Bounds bounds) - { - return bounds.Contains( item.position); - } } diff --git a/Assets/kode80/UnityTools/Common/Scripts/TransformOctree.cs b/Assets/kode80/UnityTools/Common/Scripts/TransformOctree.cs new file mode 100644 index 0000000..8a74907 --- /dev/null +++ b/Assets/kode80/UnityTools/Common/Scripts/TransformOctree.cs @@ -0,0 +1,17 @@ +using UnityEngine; +using System.Collections; + +namespace kode80.Common +{ + public class TransformOctree : Octree + { + public TransformOctree( Bounds bounds, int maxDepth=1) : base( bounds, HandleItemOverlapsBounds, maxDepth) + { + } + + private static bool HandleItemOverlapsBounds (Transform item, Bounds bounds) + { + return bounds.Contains( item.position); + } + } +} \ No newline at end of file diff --git a/Assets/kode80/UnityTools/Common/Scripts/TransformOctree.cs.meta b/Assets/kode80/UnityTools/Common/Scripts/TransformOctree.cs.meta new file mode 100644 index 0000000..86fd674 --- /dev/null +++ b/Assets/kode80/UnityTools/Common/Scripts/TransformOctree.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5bf5b38f09d134bd08de44abd7a11519 +timeCreated: 1467662220 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 8a519f9b408e1aa8d40789f5794156fcc15d28d3 Mon Sep 17 00:00:00 2001 From: Ben Hopkins Date: Mon, 4 Jul 2016 16:10:30 -0400 Subject: [PATCH 12/16] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2fe5dab..836e4fa 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Various editor/GUI tools for Unity3D * AssetUpdate: automatic asset update system for non-asset store assets * SceneViewCamera: hack to control the scene view's camera, allowing for high-precision (1/100th of a Unit) movement * Composite Colliders: new collider types generated from primitives; Cylinders (with optional caps), Chains +* Generic Octree: simple octree implementation, easily extendable via C# generics and delegates Download latest package: [kode80UnityTools.unitypackage](https://raw.github.com/kode80/UnityTools/master/kode80UnityTools.unitypackage) From 8a76cb2174321eaa9359b98d0c5a52acba90b6c8 Mon Sep 17 00:00:00 2001 From: Ben Hopkins Date: Mon, 4 Jul 2016 16:13:40 -0400 Subject: [PATCH 13/16] Removed foreach style loop from Octree --- Assets/kode80/UnityTools/Common/Scripts/Octree.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/kode80/UnityTools/Common/Scripts/Octree.cs b/Assets/kode80/UnityTools/Common/Scripts/Octree.cs index ddfc7bb..1ff2ef7 100644 --- a/Assets/kode80/UnityTools/Common/Scripts/Octree.cs +++ b/Assets/kode80/UnityTools/Common/Scripts/Octree.cs @@ -77,8 +77,8 @@ private void SubdivideOctree( OctreeNode node, int currentDepth, int maxDepth if( node.Contents.Count > 1 && currentDepth < maxDepth) { node.Subdivide(); - foreach( OctreeNode subNode in node.SubNodes) { - SubdivideOctree( subNode, currentDepth+1, maxDepth); + for( int i=0; i<8; i++) { + SubdivideOctree( node.SubNodes[i], currentDepth+1, maxDepth); } } } From 9851fa1f224366f4d5aae93be0160741743f08e4 Mon Sep 17 00:00:00 2001 From: Ben Hopkins Date: Mon, 4 Jul 2016 16:37:21 -0400 Subject: [PATCH 14/16] * Made rootNode property & Regenerate method protected in Octree * Added concrete MeshOctree (currently uses vertex positions, not triangles) * Added OctreeMeshTest --- .../Common/Examples/OctreeMeshTest.cs | 26 ++++++++++++++++ .../Common/Examples/OctreeMeshTest.cs.meta | 12 ++++++++ .../Common/Examples/OctreeMeshTestScene.unity | Bin 0 -> 17432 bytes .../Examples/OctreeMeshTestScene.unity.meta | 8 +++++ .../Examples/OctreeTransformTestScene.unity | Bin 30556 -> 30556 bytes .../UnityTools/Common/Scripts/MeshOctree.cs | 28 ++++++++++++++++++ .../Common/Scripts/MeshOctree.cs.meta | 12 ++++++++ .../UnityTools/Common/Scripts/Octree.cs | 4 +-- 8 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 Assets/kode80/UnityTools/Common/Examples/OctreeMeshTest.cs create mode 100644 Assets/kode80/UnityTools/Common/Examples/OctreeMeshTest.cs.meta create mode 100644 Assets/kode80/UnityTools/Common/Examples/OctreeMeshTestScene.unity create mode 100644 Assets/kode80/UnityTools/Common/Examples/OctreeMeshTestScene.unity.meta create mode 100644 Assets/kode80/UnityTools/Common/Scripts/MeshOctree.cs create mode 100644 Assets/kode80/UnityTools/Common/Scripts/MeshOctree.cs.meta diff --git a/Assets/kode80/UnityTools/Common/Examples/OctreeMeshTest.cs b/Assets/kode80/UnityTools/Common/Examples/OctreeMeshTest.cs new file mode 100644 index 0000000..d78250d --- /dev/null +++ b/Assets/kode80/UnityTools/Common/Examples/OctreeMeshTest.cs @@ -0,0 +1,26 @@ +using UnityEngine; +using System.Collections; +using kode80.Common; + +public class OctreeMeshTest : MonoBehaviour +{ + public Mesh targetMesh; + [Range( 1, 8)] + public int maxDepth = 1; + private MeshOctree octree; + + void OnValidate() + { + if( targetMesh != null) + { + octree = new MeshOctree( targetMesh, maxDepth); + } + } + + void OnDrawGizmos() + { + if( octree != null) { + octree.DrawGizmos( Color.red); + } + } +} diff --git a/Assets/kode80/UnityTools/Common/Examples/OctreeMeshTest.cs.meta b/Assets/kode80/UnityTools/Common/Examples/OctreeMeshTest.cs.meta new file mode 100644 index 0000000..d0d7402 --- /dev/null +++ b/Assets/kode80/UnityTools/Common/Examples/OctreeMeshTest.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 909e669f180534e57bfefa931e78b532 +timeCreated: 1467664065 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/kode80/UnityTools/Common/Examples/OctreeMeshTestScene.unity b/Assets/kode80/UnityTools/Common/Examples/OctreeMeshTestScene.unity new file mode 100644 index 0000000000000000000000000000000000000000..765cd419ec929aa160ede4ba0bf5155af2c6c509 GIT binary patch literal 17432 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 N!p!Bv+FkGA{|3DDN7w)W literal 0 HcmV?d00001 diff --git a/Assets/kode80/UnityTools/Common/Examples/OctreeMeshTestScene.unity.meta b/Assets/kode80/UnityTools/Common/Examples/OctreeMeshTestScene.unity.meta new file mode 100644 index 0000000..3755477 --- /dev/null +++ b/Assets/kode80/UnityTools/Common/Examples/OctreeMeshTestScene.unity.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5e3619808bd0e4116a9edfd91a8514d9 +timeCreated: 1467664488 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTestScene.unity b/Assets/kode80/UnityTools/Common/Examples/OctreeTransformTestScene.unity index 4276d7ae557f36a7555e3ebd8a5c203838830c36..8b75bfeb5ebe73cb045c8df54425614f0f78809e 100644 GIT binary patch delta 49 zcmV-10M7s1?g8BH0kG6y2(CwQ!1gGdzq8z6cnAmAqX0m0J*u-?X}JssxE>`ykHQ(V H8+JhfZBG^$ delta 49 zcmV-10M7s1?g8BH0kG6y2%4E$KXE;hK(pLncnAj+t_MFKg`=}uX}JssT#o`kAB7jQ H8+JhfCnFO? diff --git a/Assets/kode80/UnityTools/Common/Scripts/MeshOctree.cs b/Assets/kode80/UnityTools/Common/Scripts/MeshOctree.cs new file mode 100644 index 0000000..91e8e80 --- /dev/null +++ b/Assets/kode80/UnityTools/Common/Scripts/MeshOctree.cs @@ -0,0 +1,28 @@ +using UnityEngine; +using System.Collections; + +namespace kode80.Common +{ + public class MeshOctree : Octree + { + private Mesh mesh; + + public MeshOctree( Mesh mesh, int maxDepth = 1) : base( mesh.bounds, null, maxDepth) + { + this.mesh = mesh; + rootNode.itemOverlapsBounds = HandleItemOverlapsBounds; + + int count = mesh.triangles.Length; + for( int i=0; i { - private OctreeNode rootNode; + protected OctreeNode rootNode; private int maxDepth; public int MaxDepth { @@ -66,7 +66,7 @@ private void DrawGizmos( OctreeNode node) } } - private void Regenerate() + protected void Regenerate() { rootNode.Collapse(); SubdivideOctree( rootNode, 0, maxDepth); From 21f333a16edfe187ce68727e20895499320cebff Mon Sep 17 00:00:00 2001 From: Ben Hopkins Date: Sun, 10 Jul 2016 11:13:29 -0400 Subject: [PATCH 15/16] Added early Diff/DiffWindow classes --- .../UnityTools/EditorTools/Editor/Diff.cs | 170 ++++++++++++++++++ .../EditorTools/Editor/Diff.cs.meta | 12 ++ .../EditorTools/Editor/DiffWindow.cs | 124 +++++++++++++ .../EditorTools/Editor/DiffWindow.cs.meta | 12 ++ 4 files changed, 318 insertions(+) create mode 100644 Assets/kode80/UnityTools/EditorTools/Editor/Diff.cs create mode 100644 Assets/kode80/UnityTools/EditorTools/Editor/Diff.cs.meta create mode 100644 Assets/kode80/UnityTools/EditorTools/Editor/DiffWindow.cs create mode 100644 Assets/kode80/UnityTools/EditorTools/Editor/DiffWindow.cs.meta diff --git a/Assets/kode80/UnityTools/EditorTools/Editor/Diff.cs b/Assets/kode80/UnityTools/EditorTools/Editor/Diff.cs new file mode 100644 index 0000000..25fa992 --- /dev/null +++ b/Assets/kode80/UnityTools/EditorTools/Editor/Diff.cs @@ -0,0 +1,170 @@ +using UnityEngine; +using UnityEditor; +using System.Collections; +using System.Collections.Generic; + +namespace kode80.EditorTools +{ + public struct DiffRecord + { + public GameObject gameObjectA; + public GameObject gameObjectB; + public string propertyName; + public string gameObjectPath; + public SerializedPropertyType propertyType; + } + + public class Diff + { + private Vector2 scrollPosition; + + public void Compare( GameObject gameObjectA, GameObject gameObjectB, List diffProperties, string gameObjectPath = "") + { + if( gameObjectPath == "") { + gameObjectPath = gameObjectA.name; + } + else { + gameObjectPath += "." + gameObjectA.name; + } + + var componentsA = gameObjectA.GetComponents(); + var componentsB = gameObjectB.GetComponents(); + + if( componentsA.Length != componentsB.Length) + { + return; + } + + int count = componentsA.Length; + + for( int i=0; i diffs; + private int selectedIndex = -1; + private int stopHighlightCount; + + [MenuItem( "Window/kode80/Editor Tools/Diff")] + public static void Init() + { + EditorWindow.GetWindow( "Diff").Show(); + } + + void OnEnable() + { + } + + void OnDisable() + { + } + + void OnGUI() + { + if( diffs == null) { + diffs = new List(); + } + + bool refresh = false; + var newGameObject = EditorGUILayout.ObjectField( gameObjectA, typeof(GameObject), true) as GameObject; + if( newGameObject != gameObjectA) + { + gameObjectA = newGameObject; + refresh = true; + } + + newGameObject = EditorGUILayout.ObjectField( gameObjectB, typeof(GameObject), true) as GameObject; + if( newGameObject != gameObjectB) + { + gameObjectB = newGameObject; + refresh = true; + } + + if( GUILayout.Button( "Refresh")) { + refresh = true; + } + + if( refresh && + gameObjectA != null && + gameObjectB != null) + { + diffs.Clear(); + selectedIndex = -1; + + var diff = new Diff(); + diff.Compare( gameObjectA, gameObjectB, diffs); + } + + + scrollPosition = EditorGUILayout.BeginScrollView( scrollPosition); + + int count = diffs.Count; + + for( int i=0; i -1) + { + Highlighter.Highlight( "Inspector", diffs[selectedIndex].propertyName); + stopHighlightCount = 20; + } + } + + void Update() + { + if( stopHighlightCount > 0) + { + stopHighlightCount--; + if( stopHighlightCount == 0) + { + Highlighter.Stop(); + } + } + } + } +} \ No newline at end of file diff --git a/Assets/kode80/UnityTools/EditorTools/Editor/DiffWindow.cs.meta b/Assets/kode80/UnityTools/EditorTools/Editor/DiffWindow.cs.meta new file mode 100644 index 0000000..a55c592 --- /dev/null +++ b/Assets/kode80/UnityTools/EditorTools/Editor/DiffWindow.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c24c9be06bff644cba6aca6e63015c0b +timeCreated: 1467947130 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 8203da8d5e54407289efa90220247864cda2083e Mon Sep 17 00:00:00 2001 From: Ben Hopkins Date: Sun, 10 Jul 2016 11:40:09 -0400 Subject: [PATCH 16/16] * DiffRecord now has paths for both game objects * Refactored Diff slightly to allow for both paths * DiffWindow now displays full path for both A/B --- .../UnityTools/EditorTools/Editor/Diff.cs | 37 ++++++++++++------- .../EditorTools/Editor/DiffWindow.cs | 12 ++---- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/Assets/kode80/UnityTools/EditorTools/Editor/Diff.cs b/Assets/kode80/UnityTools/EditorTools/Editor/Diff.cs index 25fa992..63e800f 100644 --- a/Assets/kode80/UnityTools/EditorTools/Editor/Diff.cs +++ b/Assets/kode80/UnityTools/EditorTools/Editor/Diff.cs @@ -10,7 +10,8 @@ public struct DiffRecord public GameObject gameObjectA; public GameObject gameObjectB; public string propertyName; - public string gameObjectPath; + public string gameObjectAPath; + public string gameObjectBPath; public SerializedPropertyType propertyType; } @@ -18,14 +19,22 @@ public class Diff { private Vector2 scrollPosition; - public void Compare( GameObject gameObjectA, GameObject gameObjectB, List diffProperties, string gameObjectPath = "") + public List Compare( GameObject gameObjectA, GameObject gameObjectB) { - if( gameObjectPath == "") { - gameObjectPath = gameObjectA.name; - } - else { - gameObjectPath += "." + gameObjectA.name; - } + var diffs = new List(); + Compare( gameObjectA, gameObjectB, "", "", diffs); + return diffs; + } + + private void Compare( GameObject gameObjectA, GameObject gameObjectB, + string gameObjectAPath, string gameObjectBPath, + List diffs) + { + if( gameObjectAPath == "") { gameObjectAPath = gameObjectA.name; } + else { gameObjectAPath += "." + gameObjectA.name; } + + if( gameObjectBPath == "") { gameObjectBPath = gameObjectB.name; } + else { gameObjectBPath += "." + gameObjectB.name; } var componentsA = gameObjectA.GetComponents(); var componentsB = gameObjectB.GetComponents(); @@ -58,8 +67,9 @@ public void Compare( GameObject gameObjectA, GameObject gameObjectB, List