using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
[SelectionBase]
public class IsoHandler : MonoBehaviour {
private HashSet<IsoItem> items = new HashSet<IsoItem>();
private List<IsoItem> spriteList = new List<IsoItem>();
private List<IsoItem> objectList = new List<IsoItem>();
private List<IsoItem> allList = new List<IsoItem>();
private Camera mainCamera;
public int ChunksX = 40;
public int ChunksY = 40;
private int numChunks;
private List<List<IsoItem>> chunks;
// Use this for initialization
void Start()
{
numChunks = ChunksX * ChunksY;
mainCamera = GameObject.Find("Main Camera").GetComponent<Camera>();
mainCamera.transparencySortMode = TransparencySortMode.Orthographic;
chunks = new List<List<IsoItem>>();
for (int i = 0; i < numChunks; i++)
{
chunks.Add(new List<IsoItem>());
}
}
public void AddIsoItem(IsoItem item)
{
if (items.Add(item))
{
if (item.IsoType == IsoItem.IsoTypes.Sprite)
{
spriteList.Add(item);
}
else
{
objectList.Add(item);
}
allList.Add(item);
}
}
public void RemoveIsoItem(IsoItem item)
{
if (items.Remove(item))
{
if (item.IsoType == IsoItem.IsoTypes.Sprite)
{
spriteList.Remove(item);
}
else
{
objectList.Remove(item);
}
allList.Remove(item);
}
}
int ItemSort(IsoItem a, IsoItem b)
{
float diff = b.CameraSpace.z - a.CameraSpace.z;
if (diff > 0) return 1;
if (diff < 0) return -1;
return 0;
}
private float nextDepth = 0;
private Vector3 camForward;
private Vector3 camRight;
private Vector3 camUp;
private Vector3 camPos;
private List<IsoItem> ordered = new List<IsoItem>();
//private HashSet<int> usedChunks = new HashSet<int>();
void LateUpdate()
{
camForward = mainCamera.transform.forward;
camRight = mainCamera.transform.right;
camUp = mainCamera.transform.up;
camPos = mainCamera.transform.position;
float worldSizeH = mainCamera.orthographicSize * 2;
float worldSizeW = worldSizeH * mainCamera.aspect;
Vector3 worldBottomLeft = mainCamera.ViewportToWorldPoint(new Vector3());
//remaining.Clear();
ordered.Clear();
nextDepth = 10;
for (int i = 0; i < spriteList.Count; i++)
{
spriteList[i].Behind.Clear();
spriteList[i].MarkTemp = false;
spriteList[i].MarkPerm = false;
//remaining.Add(spriteList[i]);
}
for (int i = 0; i < objectList.Count; i++)
{
objectList[i].Behind.Clear();
objectList[i].MarkTemp = false;
objectList[i].MarkPerm = false;
//remaining.Add(objectList[i]);
}
Ray outRay = new Ray();
outRay.direction = camForward;
Ray inRay = new Ray();
inRay.direction = -camForward;
int layerIn = LayerMask.GetMask("iso_piece", "leaf", "player_controller", "iso_piece_no_collide");
int layerOut = LayerMask.GetMask("iso_piece", "iso_piece_no_collide");
//usedChunks.Clear();
int count = spriteList.Count;
for (int i = 0; i < count; i++)
{
IsoItem item = spriteList[i];
Vector3 screenSpace = mainCamera.WorldToViewportPoint(item.transform.position);
//item.CameraSpace.x = worldBottomLeft.x + screenSpace.x * worldSizeW;
//item.CameraSpace.y = worldBottomLeft.y + screenSpace.y * worldSizeH;
//item.CameraSpace.z = screenSpace.z;
item.CameraSpace = screenSpace;
/*
if (item.IsoRadius > 0)
{
float scale = 1; // Mathf.Max(item.LinkedImage.transform.lossyScale.x, Mathf.Max(item.LinkedImage.transform.lossyScale.y, item.LinkedImage.transform.lossyScale.z));
float radiusCamX = item.IsoRadius / worldSizeW * scale;
float radiusCamY = item.IsoRadius / worldSizeH * scale;
int leftBucket = Mathf.Max(0, Mathf.Min(ChunksX - 1, (int)Mathf.Floor((screenSpace.x - radiusCamX) * ChunksX)));
int rightBucket = Mathf.Max(0, Mathf.Min(ChunksX - 1, (int)Mathf.Ceil((screenSpace.x + radiusCamX) * ChunksX)));
int bottomBucket = Mathf.Max(0, Mathf.Min(ChunksY - 1, (int)Mathf.Floor((screenSpace.y - radiusCamY) * ChunksY)));
int topBucket = Mathf.Max(0, Mathf.Min(ChunksY - 1, (int)Mathf.Ceil((screenSpace.y + radiusCamY) * ChunksY)));
for (int x = leftBucket; x <= rightBucket; x++)
{
for (int y = bottomBucket; y <= topBucket; y++)
{
int chunkIndex = y * ChunksX + x;
List<IsoItem> chunk = chunks[chunkIndex];
bool placed = false;
for (var j = 0; j < chunk.Count; j++)
{
if (item.CameraSpace.z > chunk[j].CameraSpace.z)
{
chunk.Insert(j, item);
placed = true;
break;
}
}
if (!placed)
{
chunk.Add(item);
}
//usedChunks.Add(chunkIndex);
}
}
}
*/
//if (item.Moved)
//{
outRay.origin = inRay.origin = item.transform.position;
DepthHitCheck(item, inRay, item.CameraSpace.z, layerIn, false);
//if (otherItem != null)
//{
// item.Behind.Add(otherItem);
//}
DepthHitCheck(item, outRay, 50, layerIn, true);
//if (otherItem != null)
//{
// otherItem.Behind.Add(item);
//}
}
/*
//foreach (int i in usedChunks)
//{
for (int i = 0; i < numChunks; i++)
{
List<IsoItem> chunk = chunks[i];
for (int j = 0; j < chunk.Count - 1; j++)
{
chunk[j].Behind.Add(chunk[j + 1]);/
}
chunk.Clear();
}
*/
for (int i = 0; i < objectList.Count; i++)
{
IsoItem item = objectList[i];
item.CameraSpace = mainCamera.WorldToViewportPoint(item.LinkedImage.transform.position);
}
objectList.Sort((a, b) => b.ObjectManualDepth - a.ObjectManualDepth);
for (int i = 0; i < objectList.Count - 1; i++)
{
objectList[i].Behind.Add(objectList[i + 1]);
}
int nextUnmarked = 0;
int total = allList.Count;
while (nextUnmarked < total)
{
IsoItem item = allList[nextUnmarked];
Visit(item);
nextUnmarked++;
while (nextUnmarked < total && allList[nextUnmarked].MarkPerm)
{
nextUnmarked++;
}
}
}
private RaycastHit hitInfo = new RaycastHit();
private void DepthHitCheck(IsoItem item, Ray ray, float dist, int layer, bool itemInFront)
{
IsoItem found = null;
switch (item.Custom)
{
case IsoItem.CustomSort.None:
bool hit = Physics.Raycast(ray, out hitInfo, dist, layer);
if (hit)
{
IsoItem otherItem = hitInfo.collider.GetComponentInParent<IsoItem>();
if (otherItem != null)
{
found = otherItem;
}
}
break;
case IsoItem.CustomSort.Capsule:
{
Vector3 p1 = ray.origin + Vector3.up * item.CustomCapsuleHeight * 0.25f;
Vector3 p2 = ray.origin + Vector3.up * item.CustomCapsuleHeight * 0.75f;
float closestDist = 0;
foreach (RaycastHit hitInfo in Physics.CapsuleCastAll(p1, p2, item.CustomCapsuleHeight * 0.25f, ray.direction, dist, layer))
{
IsoItem otherItem = hitInfo.collider.GetComponentInParent<IsoItem>();
if (otherItem != null && otherItem != item)
{
if (otherItem.IsoType == IsoItem.IsoTypes.Sprite)
{
var otherDist = Vector3.Dot(otherItem.transform.position - ray.origin, ray.direction);
if (otherDist > 0 && (found == null || otherDist < closestDist))
{
closestDist = hitInfo.distance;
found = otherItem;
}
}
else
{
if (itemInFront || otherItem.ObjectManualDepth == 100)
{
if (!item.Behind.Contains(otherItem)) otherItem.Behind.Add(item);
}
else
{
if (!otherItem.Behind.Contains(item)) item.Behind.Add(otherItem);
}
}
}
}
break;
}
case IsoItem.CustomSort.Sphere:
{
Vector3 o = ray.origin + Vector3.up * item.CustomSphereHeight;
float closestDist = 0;
foreach (RaycastHit hitInfo in Physics.SphereCastAll(o, item.CustomSphereRadius, ray.direction, dist, layer))
{
IsoItem otherItem = hitInfo.collider.GetComponentInParent<IsoItem>();
if (otherItem != null && otherItem != item)
{
if (otherItem.IsoType == IsoItem.IsoTypes.Sprite)
{
var otherDist = Vector3.Dot(otherItem.transform.position - ray.origin, ray.direction);
if (otherDist > 0 && (found == null || otherDist < closestDist))
{
closestDist = hitInfo.distance;
found = otherItem;
}
}
else
{
if (itemInFront || otherItem.ObjectManualDepth == 100)
{
if (!item.Behind.Contains(otherItem)) otherItem.Behind.Add(item);
}
else
{
if (!otherItem.Behind.Contains(item)) item.Behind.Add(otherItem);
}
}
}
}
break;
}
}
if (found != null)
{
if (itemInFront || found.ObjectManualDepth == 100)
{
if (!item.Behind.Contains(found)) found.Behind.Add(item);
}
else
{
if (!found.Behind.Contains(item)) item.Behind.Add(found);
}
}
}
private void Visit(IsoItem item)
{
if (item.MarkPerm) return;
if (item.MarkTemp)
{
//Debug.LogError("CYCLICAL RENDER GRAPH");
item.MarkTemp = false;
item.MarkPerm = true;
//remaining.Remove(item);
return;
}
item.MarkTemp = true;
//for (int i = 0; i < item.Behind.Count; i++)
//{
// Visit(item.Behind[i]);
//}
foreach (IsoItem nextItem in item.Behind)
{
Visit(nextItem);
}
item.MarkTemp = false;
item.MarkPerm = true;
//remaining.Remove(item);
item.SetDepth = nextDepth + item.Thickness;
Vector3 camPos = item.CameraSpace;
camPos.z = nextDepth + item.Thickness;
item.LinkedImage.transform.position = mainCamera.ViewportToWorldPoint(camPos);
nextDepth += 0.01f + item.Thickness * 2;
}
}