using UnityEngine; using System.Collections.Generic; #if UNITY_EDITOR using UnityEditor; #endif #if UNITY_5_5_OR_NEWER using UnityEngine.Profiling; #endif namespace IsoTools.Internal { public class IsoScreenSolver { Vector2 _minIsoXY = Vector2.zero; IsoAssocList _oldVisibles = new IsoAssocList(47); IsoAssocList _curVisibles = new IsoAssocList(47); IsoQuadTree _quadTree = new IsoQuadTree(47); IsoQTBoundsLookUpper _qtBoundsLU = new IsoQTBoundsLookUpper(); IsoQTDependsLookUpper _qtDependsLU = new IsoQTDependsLookUpper(); IsoQTVisibilityLookUpper _qtVisibilityLU = new IsoQTVisibilityLookUpper(); IsoIPool _parentInfoPool = new ParentInfoPool(47); IsoAssocList _parentInfoList = new IsoAssocList(47); Dictionary _isoObjectToParent = new Dictionary(47); Dictionary _parentToParentInfo = new Dictionary(47); // --------------------------------------------------------------------- // // IsoQTBoundsLookUpper // // --------------------------------------------------------------------- class IsoQTBoundsLookUpper : IsoQuadTree.IBoundsLookUpper { public void LookUp(IsoRect bounds) { #if UNITY_EDITOR IsoUtils.DrawSolidRect( bounds, IsoUtils.ColorChangeA(Color.red, 0.05f), Color.red); #endif } } // --------------------------------------------------------------------- // // IsoQTDependsLookUpper // // --------------------------------------------------------------------- class IsoQTDependsLookUpper : IsoQuadTree.IContentLookUpper { IsoObject _isoObject; public void LookUp(IsoObject other_iso_object) { LookUpCellForLDepends(_isoObject, other_iso_object); LookUpCellForRDepends(_isoObject, other_iso_object); } public void LookUpForDepends( IsoScreenSolver screen_solver, IsoObject iso_object) { _isoObject = iso_object; if ( iso_object.Internal.QTItem != null ) { screen_solver._quadTree.VisitItemsByItem( iso_object.Internal.QTItem, this); } _isoObject = null; } } // --------------------------------------------------------------------- // // IsoQTVisibilityLookUpper // // --------------------------------------------------------------------- class IsoQTVisibilityLookUpper : IsoQuadTree.IContentLookUpper { Camera[] _tmpCameras = new Camera[8]; IsoScreenSolver _screenSolver = null; // // Public // public void LookUp(IsoObject iso_object) { iso_object.Internal.Placed = false; _screenSolver._oldVisibles.Add(iso_object); } public void LookUpForVisibility(IsoScreenSolver screen_solver, bool include_scene_view) { _screenSolver = screen_solver; _screenSolver._oldVisibles.Clear(); var cam_count = FillLookUpCameras(include_scene_view); for ( var i = 0; i < cam_count; ++i ) { var tmp_cam = _tmpCameras[i]; var vp_rect = tmp_cam.rect; var wrl_min = tmp_cam.ViewportToWorldPoint(new Vector3(vp_rect.xMin, vp_rect.yMin)); var wrl_max = tmp_cam.ViewportToWorldPoint(new Vector3(vp_rect.xMax, vp_rect.yMax)); _screenSolver._quadTree.VisitItemsByBounds(new IsoRect(wrl_min, wrl_max), this); } ResetLookUpCameras(); _screenSolver = null; } // // Private // int FillLookUpCameras(bool include_scene_view) { var camera_count = Camera.allCamerasCount; if ( _tmpCameras.Length < camera_count + 1 ) { _tmpCameras = new Camera[camera_count * 2 + 1]; } Camera.GetAllCameras(_tmpCameras); return include_scene_view ? AddSceneViewCamera(camera_count) : camera_count; } int AddSceneViewCamera(int camera_count) { #if UNITY_EDITOR var scene_view = SceneView.lastActiveSceneView; if ( scene_view && scene_view.camera ) { _tmpCameras[camera_count++] = scene_view.camera; } #endif return camera_count; } void ResetLookUpCameras() { System.Array.Clear(_tmpCameras, 0, _tmpCameras.Length); } } // --------------------------------------------------------------------- // // ParentInfo // // --------------------------------------------------------------------- class ParentInfo { public Transform Parent = null; public Vector3 LastTrans = Vector3.zero; public IsoAssocList IsoObjects = new IsoAssocList(); public ParentInfo Init(Transform parent) { Parent = parent; LastTrans = parent ? parent.position : Vector3.zero; return this; } public ParentInfo Clear() { IsoObjects.Clear(); return Init(null); } } class ParentInfoPool : IsoPool { public ParentInfoPool(int capacity) : base(capacity) { } public override ParentInfo CreateItem() { return new ParentInfo(); } } // --------------------------------------------------------------------- // // Properties // // --------------------------------------------------------------------- public Vector2 minIsoXY { get { return _minIsoXY; } } public IsoAssocList oldVisibles { get { return _oldVisibles; } } public IsoAssocList curVisibles { get { return _curVisibles; } } // --------------------------------------------------------------------- // // Callbacks // // --------------------------------------------------------------------- public void OnAddIsoObject(IsoObject iso_object) { iso_object.Internal.QTItem = _quadTree.AddItem( iso_object.Internal.QTBounds, iso_object); _minIsoXY = IsoUtils.Vec2Min(_minIsoXY, iso_object.position); RegisterIsoObjectParent(iso_object); } public void OnRemoveIsoObject(IsoObject iso_object) { _oldVisibles.Remove(iso_object); _curVisibles.Remove(iso_object); if ( iso_object.Internal.QTItem != null ) { _quadTree.RemoveItem(iso_object.Internal.QTItem); iso_object.Internal.QTItem = null; } ClearIsoObjectDepends(iso_object); UnregisterIsoObjectParent(iso_object); } public bool OnMarkDirtyIsoObject(IsoObject iso_object) { if ( iso_object.Internal.QTItem != null ) { iso_object.Internal.QTItem = _quadTree.MoveItem( iso_object.Internal.QTBounds, iso_object.Internal.QTItem); } else { iso_object.Internal.QTItem = _quadTree.AddItem( iso_object.Internal.QTBounds, iso_object); } _minIsoXY = IsoUtils.Vec2Min(_minIsoXY, iso_object.position); if ( !iso_object.Internal.Dirty ) { iso_object.Internal.Dirty = true; return true; } return false; } public void OnDrawGizmos(IsoWorld iso_world) { if ( iso_world.isShowQuadTree ) { _quadTree.VisitAllBounds(_qtBoundsLU); } } // --------------------------------------------------------------------- // // Public // // --------------------------------------------------------------------- public void StepSortingAction(IsoWorld iso_world) { Profiler.BeginSample("IsoScreenSolver.ProcessParents"); ProcessParents(); Profiler.EndSample(); Profiler.BeginSample("IsoScreenSolver.ProcessVisibles"); ProcessVisibles(iso_world.isSortInSceneView); Profiler.EndSample(); } public void Clear() { _oldVisibles.Clear(); _curVisibles.Clear(); _quadTree.Clear(); } public void SetupIsoObjectDepends(IsoObject iso_object) { ClearIsoObjectDepends(iso_object); _qtDependsLU.LookUpForDepends(this, iso_object); } public void ClearIsoObjectDepends(IsoObject iso_object) { var their_depends = iso_object.Internal.TheirDepends; for ( int i = 0, e = their_depends.Count; i < e; ++i ) { var their_iso_object = their_depends[i]; if ( !their_iso_object.Internal.Dirty ) { their_iso_object.Internal.SelfDepends.Remove(iso_object); } } iso_object.Internal.SelfDepends.Clear(); iso_object.Internal.TheirDepends.Clear(); } // --------------------------------------------------------------------- // // Parents // // --------------------------------------------------------------------- void RegisterIsoObjectParent(IsoObject iso_object) { var parent = iso_object ? iso_object.transform.parent : null; if ( parent ) { ParentInfo parent_info; if ( _parentToParentInfo.TryGetValue(parent, out parent_info) ) { parent_info.IsoObjects.Add(iso_object); } else { parent_info = _parentInfoPool.Take().Init(parent); parent_info.IsoObjects.Add(iso_object); _parentToParentInfo.Add(parent, parent_info); _parentInfoList.Add(parent_info); } _isoObjectToParent.Add(iso_object, parent); } } void UnregisterIsoObjectParent(IsoObject iso_object) { Transform parent; if ( _isoObjectToParent.TryGetValue(iso_object, out parent) ) { ParentInfo parent_info; if ( _parentToParentInfo.TryGetValue(parent, out parent_info) ) { parent_info.IsoObjects.Remove(iso_object); if ( parent_info.IsoObjects.Count == 0 ) { _parentToParentInfo.Remove(parent); _parentInfoList.Remove(parent_info); _parentInfoPool.Release(parent_info.Clear()); } } _isoObjectToParent.Remove(iso_object); } } // --------------------------------------------------------------------- // // Processes // // --------------------------------------------------------------------- void ProcessParents() { for ( int i = 0, ie = _parentInfoList.Count; i < ie; ++i ) { var parent_info = _parentInfoList[i]; var parent_trans = parent_info.Parent.position; if ( parent_info.LastTrans != parent_trans ) { parent_info.LastTrans = parent_trans; for ( int j = 0, je = parent_info.IsoObjects.Count; j < je; ++j ) { var iso_object = parent_info.IsoObjects[j]; iso_object.FixIsoPosition(); } } } } void ProcessVisibles(bool include_scene_view) { _qtVisibilityLU.LookUpForVisibility(this, include_scene_view); SwapCurrentVisibles(); } void SwapCurrentVisibles() { var swap_tmp = _curVisibles; _curVisibles = _oldVisibles; _oldVisibles = swap_tmp; } // --------------------------------------------------------------------- // // LookUpCellForDepends // // --------------------------------------------------------------------- static void LookUpCellForLDepends(IsoObject obj_a, IsoObject obj_b) { if ( !obj_b.Internal.Dirty && obj_a != obj_b && IsIsoObjectDepends(obj_a.position, obj_a.size, obj_b.position, obj_b.size) ) { obj_a.Internal.SelfDepends.Add(obj_b); obj_b.Internal.TheirDepends.Add(obj_a); } } static void LookUpCellForRDepends(IsoObject obj_a, IsoObject obj_b) { if ( !obj_b.Internal.Dirty && obj_a != obj_b && IsIsoObjectDepends(obj_b.position, obj_b.size, obj_a.position, obj_a.size) ) { obj_b.Internal.SelfDepends.Add(obj_a); obj_a.Internal.TheirDepends.Add(obj_b); } } static bool IsIsoObjectDepends(Vector3 a_min, Vector3 a_size, Vector3 b_min, Vector3 b_size) { //var a_max = a_min + a_size; //var b_max = b_min + b_size; var a_min_x = a_min.x; var a_min_y = a_min.y; var a_min_z = a_min.z; var a_size_x = a_size.x; var a_size_y = a_size.y; var a_size_z = a_size.z; var b_min_x = b_min.x; var b_min_y = b_min.y; var b_min_z = b_min.z; var b_size_x = b_size.x; var b_size_y = b_size.y; var b_size_z = b_size.z; var a_max_x = a_min_x + a_size_x; var a_max_y = a_min_y + a_size_y; var a_max_z = a_min_z + a_size_z; var b_max_x = b_min_x + b_size_x; var b_max_y = b_min_y + b_size_y; var b_max_z = b_min_z + b_size_z; var a_yesno = a_max_x > b_min_x && a_max_y > b_min_y && b_max_z > a_min_z; if ( a_yesno ) { var b_yesno = b_max_x > a_min_x && b_max_y > a_min_y && a_max_z > b_min_z; if ( b_yesno ) { //var da_p = new Vector3(a_max.x - b_min.x, a_max.y - b_min.y, b_max.z - a_min.z); //var db_p = new Vector3(b_max.x - a_min.x, b_max.y - a_min.y, a_max.z - b_min.z); //var dp_p = a_size + b_size - IsoUtils.Vec3Abs(da_p - db_p); var dA_x = a_max_x - b_min_x; var dA_y = a_max_y - b_min_y; var dA_z = b_max_z - a_min_z; var dB_x = b_max_x - a_min_x; var dB_y = b_max_y - a_min_y; var dB_z = a_max_z - b_min_z; var dD_x = dB_x - dA_x; var dD_y = dB_y - dA_y; var dD_z = dB_z - dA_z; var dP_x = a_size_x + b_size_x - (dD_x < 0.0f ? -dD_x : dD_x); var dP_y = a_size_y + b_size_y - (dD_y < 0.0f ? -dD_y : dD_y); var dP_z = a_size_z + b_size_z - (dD_z < 0.0f ? -dD_z : dD_z); if ( dP_x <= dP_y && dP_x <= dP_z ) { return dA_x > dB_x; } else if ( dP_y <= dP_x && dP_y <= dP_z ) { return dA_y > dB_y; } else { return dA_z > dB_z; } } } return a_yesno; } } }