Added player character and step in/out of dialogue in scene 101

This commit is contained in:
2026-08-15 15:22:47 +02:00
parent a42f25d5fa
commit 38ba2b0eff
2019 changed files with 181227 additions and 265 deletions
@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Unity.ProBuilder")]
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bb4dcd11679b340ee8a7afb51cb0ccfc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,79 @@
namespace UnityEngine.ProBuilder.KdTree
{
struct HyperRect<T>
{
private T[] minPoint;
public T[] MinPoint
{
get
{
return minPoint;
}
set
{
minPoint = new T[value.Length];
value.CopyTo(minPoint, 0);
}
}
private T[] maxPoint;
public T[] MaxPoint
{
get
{
return maxPoint;
}
set
{
maxPoint = new T[value.Length];
value.CopyTo(maxPoint, 0);
}
}
public static HyperRect<T> Infinite(int dimensions, ITypeMath<T> math)
{
var rect = new HyperRect<T>();
rect.MinPoint = new T[dimensions];
rect.MaxPoint = new T[dimensions];
for (var dimension = 0; dimension < dimensions; dimension++)
{
rect.MinPoint[dimension] = math.NegativeInfinity;
rect.MaxPoint[dimension] = math.PositiveInfinity;
}
return rect;
}
public T[] GetClosestPoint(T[] toPoint, ITypeMath<T> math)
{
T[] closest = new T[toPoint.Length];
for (var dimension = 0; dimension < toPoint.Length; dimension++)
{
if (math.Compare(minPoint[dimension], toPoint[dimension]) > 0)
{
closest[dimension] = minPoint[dimension];
}
else if (math.Compare(maxPoint[dimension], toPoint[dimension]) < 0)
{
closest[dimension] = maxPoint[dimension];
}
else
// Point is within rectangle, at least on this dimension
closest[dimension] = toPoint[dimension];
}
return closest;
}
public HyperRect<T> Clone()
{
var rect = new HyperRect<T>();
rect.MinPoint = MinPoint;
rect.MaxPoint = MaxPoint;
return rect;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 518e5a76add435648813be98dd71e2f8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,27 @@
using System.Collections.Generic;
namespace UnityEngine.ProBuilder.KdTree
{
interface IKdTree<TKey, TValue> : IEnumerable<KdTreeNode<TKey, TValue>>
{
bool Add(TKey[] point, TValue value);
bool TryFindValueAt(TKey[] point, out TValue value);
TValue FindValueAt(TKey[] point);
bool TryFindValue(TValue value, out TKey[] point);
TKey[] FindValue(TValue value);
KdTreeNode<TKey, TValue>[] RadialSearch(TKey[] center, TKey radius, int count);
void RemoveAt(TKey[] point);
void Clear();
KdTreeNode<TKey, TValue>[] GetNearestNeighbours(TKey[] point, int count = int.MaxValue);
int Count { get; }
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e8fa221ea996bd7459f869e6d809a95d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,11 @@
namespace UnityEngine.ProBuilder.KdTree
{
interface IPriorityQueue<TItem, TPriority>
{
void Enqueue(TItem item, TPriority priority);
TItem Dequeue();
int Count { get; }
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4c7381a66e715734f82749b2e115722c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,669 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Xml;
namespace UnityEngine.ProBuilder.KdTree
{
enum AddDuplicateBehavior
{
Skip,
Error,
Update,
Collect
}
class DuplicateNodeError : Exception
{
public DuplicateNodeError()
: base("Cannot Add Node With Duplicate Coordinates")
{
}
}
[Serializable]
[DataContract]
class KdTree<TKey, TValue> : IKdTree<TKey, TValue>
{
public KdTree(int dimensions, ITypeMath<TKey> typeMath)
{
this.dimensions = dimensions;
this.typeMath = typeMath;
Count = 0;
}
public KdTree(int dimensions, ITypeMath<TKey> typeMath, AddDuplicateBehavior addDuplicateBehavior)
: this(dimensions, typeMath)
{
AddDuplicateBehavior = addDuplicateBehavior;
}
[DataMember]
private int dimensions;
[DataMember]
private ITypeMath<TKey> typeMath = null;
[DataMember]
private KdTreeNode<TKey, TValue> root = null;
[DataMember]
public AddDuplicateBehavior AddDuplicateBehavior { get; private set; }
public bool Add(TKey[] point, TValue value)
{
var nodeToAdd = new KdTreeNode<TKey, TValue>(point, value);
if (root == null)
{
root = new KdTreeNode<TKey, TValue>(point, value);
}
else
{
int dimension = -1;
KdTreeNode<TKey, TValue> parent = root;
do
{
// Increment the dimension we're searching in
dimension = (dimension + 1) % dimensions;
// Does the node we're adding have the same hyperpoint as this node?
if (typeMath.AreEqual(point, parent.Point))
{
switch (AddDuplicateBehavior)
{
case AddDuplicateBehavior.Skip:
return false;
case AddDuplicateBehavior.Error:
throw new DuplicateNodeError();
case AddDuplicateBehavior.Update:
parent.Value = value;
break;
case AddDuplicateBehavior.Collect:
parent.AddDuplicate(value);
return false;
default:
// Should never happen
throw new Exception("Unexpected AddDuplicateBehavior");
}
}
// Which side does this node sit under in relation to it's parent at this level?
int compare = typeMath.Compare(point[dimension], parent.Point[dimension]);
if (parent[compare] == null)
{
parent[compare] = nodeToAdd;
break;
}
else
{
parent = parent[compare];
}
}
while (true);
}
Count++;
return true;
}
private void ReadChildNodes(KdTreeNode<TKey, TValue> removedNode)
{
if (removedNode.IsLeaf)
return;
// The folllowing code might seem a little redundant but we're using
// 2 queues so we can add the child nodes back in, in (more or less)
// the same order they were added in the first place
var nodesToReadd = new Queue<KdTreeNode<TKey, TValue>>();
var nodesToReaddQueue = new Queue<KdTreeNode<TKey, TValue>>();
if (removedNode.LeftChild != null)
nodesToReaddQueue.Enqueue(removedNode.LeftChild);
if (removedNode.RightChild != null)
nodesToReaddQueue.Enqueue(removedNode.RightChild);
while (nodesToReaddQueue.Count > 0)
{
var nodeToReadd = nodesToReaddQueue.Dequeue();
nodesToReadd.Enqueue(nodeToReadd);
for (int side = -1; side <= 1; side += 2)
{
if (nodeToReadd[side] != null)
{
nodesToReaddQueue.Enqueue(nodeToReadd[side]);
nodeToReadd[side] = null;
}
}
}
while (nodesToReadd.Count > 0)
{
var nodeToReadd = nodesToReadd.Dequeue();
Count--;
Add(nodeToReadd.Point, nodeToReadd.Value);
}
}
public void RemoveAt(TKey[] point)
{
// Is tree empty?
if (root == null)
return;
KdTreeNode<TKey, TValue> node;
if (typeMath.AreEqual(point, root.Point))
{
node = root;
root = null;
Count--;
ReadChildNodes(node);
return;
}
node = root;
int dimension = -1;
do
{
dimension = (dimension + 1) % dimensions;
int compare = typeMath.Compare(point[dimension], node.Point[dimension]);
if (node[compare] == null)
// Can't find node
return;
if (typeMath.AreEqual(point, node[compare].Point))
{
var nodeToRemove = node[compare];
node[compare] = null;
Count--;
ReadChildNodes(nodeToRemove);
}
else
node = node[compare];
}
while (node != null);
}
public KdTreeNode<TKey, TValue>[] GetNearestNeighbours(TKey[] point, int count)
{
if (count > Count)
count = Count;
if (count < 0)
{
throw new ArgumentException("Number of neighbors cannot be negative");
}
if (count == 0)
return new KdTreeNode<TKey, TValue>[0];
var nearestNeighbours = new NearestNeighbourList<KdTreeNode<TKey, TValue>, TKey>(count, typeMath);
var rect = HyperRect<TKey>.Infinite(dimensions, typeMath);
AddNearestNeighbours(root, point, rect, 0, nearestNeighbours, typeMath.MaxValue);
count = nearestNeighbours.Count;
var neighbourArray = new KdTreeNode<TKey, TValue>[count];
for (var index = 0; index < count; index++)
neighbourArray[count - index - 1] = nearestNeighbours.RemoveFurtherest();
return neighbourArray;
}
/*
* 1. Search for the target
*
* 1.1 Start by splitting the specified hyper rect
* on the specified node's point along the current
* dimension so that we end up with 2 sub hyper rects
* (current dimension = depth % dimensions)
*
* 1.2 Check what sub rectangle the the target point resides in
* under the current dimension
*
* 1.3 Set that rect to the nearer rect and also the corresponding
* child node to the nearest rect and node and the other rect
* and child node to the further rect and child node (for use later)
*
* 1.4 Travel into the nearer rect and node by calling function
* recursively with nearer rect and node and incrementing
* the depth
*
* 2. Add leaf to list of nearest neighbours
*
* 3. Walk back up tree and at each level:
*
* 3.1 Add node to nearest neighbours if
* we haven't filled our nearest neighbour
* list yet or if it has a distance to target less
* than any of the distances in our current nearest
* neighbours.
*
* 3.2 If there is any point in the further rectangle that is closer to
* the target than our furtherest nearest neighbour then travel into
* that rect and node
*
* That's it, when it finally finishes traversing the branches
* it needs to we'll have our list!
*/
private void AddNearestNeighbours(
KdTreeNode<TKey, TValue> node,
TKey[] target,
HyperRect<TKey> rect,
int depth,
NearestNeighbourList<KdTreeNode<TKey, TValue>, TKey> nearestNeighbours,
TKey maxSearchRadiusSquared)
{
if (node == null)
return;
// Work out the current dimension
int dimension = depth % dimensions;
// Split our hyper-rect into 2 sub rects along the current
// node's point on the current dimension
var leftRect = rect.Clone();
leftRect.MaxPoint[dimension] = node.Point[dimension];
var rightRect = rect.Clone();
rightRect.MinPoint[dimension] = node.Point[dimension];
// Which side does the target reside in?
int compare = typeMath.Compare(target[dimension], node.Point[dimension]);
var nearerRect = compare <= 0 ? leftRect : rightRect;
var furtherRect = compare <= 0 ? rightRect : leftRect;
var nearerNode = compare <= 0 ? node.LeftChild : node.RightChild;
var furtherNode = compare <= 0 ? node.RightChild : node.LeftChild;
// Let's walk down into the nearer branch
if (nearerNode != null)
{
AddNearestNeighbours(
nearerNode,
target,
nearerRect,
depth + 1,
nearestNeighbours,
maxSearchRadiusSquared);
}
TKey distanceSquaredToTarget;
// Walk down into the further branch but only if our capacity hasn't been reached
// OR if there's a region in the further rect that's closer to the target than our
// current furtherest nearest neighbour
TKey[] closestPointInFurtherRect = furtherRect.GetClosestPoint(target, typeMath);
distanceSquaredToTarget = typeMath.DistanceSquaredBetweenPoints(closestPointInFurtherRect, target);
if (typeMath.Compare(distanceSquaredToTarget, maxSearchRadiusSquared) <= 0)
{
if (nearestNeighbours.IsCapacityReached)
{
if (typeMath.Compare(distanceSquaredToTarget, nearestNeighbours.GetFurtherestDistance()) < 0)
AddNearestNeighbours(
furtherNode,
target,
furtherRect,
depth + 1,
nearestNeighbours,
maxSearchRadiusSquared);
}
else
{
AddNearestNeighbours(
furtherNode,
target,
furtherRect,
depth + 1,
nearestNeighbours,
maxSearchRadiusSquared);
}
}
// Try to add the current node to our nearest neighbours list
distanceSquaredToTarget = typeMath.DistanceSquaredBetweenPoints(node.Point, target);
if (typeMath.Compare(distanceSquaredToTarget, maxSearchRadiusSquared) <= 0)
nearestNeighbours.Add(node, distanceSquaredToTarget);
}
public KdTreeNode<TKey, TValue>[] RadialSearch(TKey[] center, TKey radius, int count)
{
var nearestNeighbours = new NearestNeighbourList<KdTreeNode<TKey, TValue>, TKey>(count, typeMath);
AddNearestNeighbours(
root,
center,
HyperRect<TKey>.Infinite(dimensions, typeMath),
0,
nearestNeighbours,
typeMath.Multiply(radius, radius));
count = nearestNeighbours.Count;
var neighbourArray = new KdTreeNode<TKey, TValue>[count];
for (var index = 0; index < count; index++)
neighbourArray[count - index - 1] = nearestNeighbours.RemoveFurtherest();
return neighbourArray;
}
[DataMember]
public int Count { get; private set; }
public bool TryFindValueAt(TKey[] point, out TValue value)
{
var parent = root;
int dimension = -1;
do
{
if (parent == null)
{
value = default(TValue);
return false;
}
else if (typeMath.AreEqual(point, parent.Point))
{
value = parent.Value;
return true;
}
// Keep searching
dimension = (dimension + 1) % dimensions;
int compare = typeMath.Compare(point[dimension], parent.Point[dimension]);
parent = parent[compare];
}
while (true);
}
public TValue FindValueAt(TKey[] point)
{
TValue value;
if (TryFindValueAt(point, out value))
return value;
else
return default(TValue);
}
public bool TryFindValue(TValue value, out TKey[] point)
{
if (root == null)
{
point = null;
return false;
}
// First-in, First-out list of nodes to search
var nodesToSearch = new Queue<KdTreeNode<TKey, TValue>>();
nodesToSearch.Enqueue(root);
while (nodesToSearch.Count > 0)
{
var nodeToSearch = nodesToSearch.Dequeue();
if (nodeToSearch.Value.Equals(value))
{
point = nodeToSearch.Point;
return true;
}
else
{
for (int side = -1; side <= 1; side += 2)
{
var childNode = nodeToSearch[side];
if (childNode != null)
nodesToSearch.Enqueue(childNode);
}
}
}
point = null;
return false;
}
public TKey[] FindValue(TValue value)
{
TKey[] point;
if (TryFindValue(value, out point))
return point;
else
return null;
}
private void AddNodeToStringBuilder(KdTreeNode<TKey, TValue> node, StringBuilder sb, int depth)
{
sb.AppendLine(node.ToString());
for (var side = -1; side <= 1; side += 2)
{
for (var index = 0; index <= depth; index++)
sb.Append("\t");
sb.Append(side == -1 ? "L " : "R ");
if (node[side] == null)
sb.AppendLine("");
else
AddNodeToStringBuilder(node[side], sb, depth + 1);
}
}
public override string ToString()
{
if (root == null)
return "";
var sb = new StringBuilder();
AddNodeToStringBuilder(root, sb, 0);
return sb.ToString();
}
private void AddNodesToList(KdTreeNode<TKey, TValue> node, List<KdTreeNode<TKey, TValue>> nodes)
{
if (node == null)
return;
nodes.Add(node);
for (var side = -1; side <= 1; side += 2)
{
if (node[side] != null)
{
AddNodesToList(node[side], nodes);
node[side] = null;
}
}
}
private void SortNodesArray(KdTreeNode<TKey, TValue>[] nodes, int byDimension, int fromIndex, int toIndex)
{
for (var index = fromIndex + 1; index <= toIndex; index++)
{
var newIndex = index;
while (true)
{
var a = nodes[newIndex - 1];
var b = nodes[newIndex];
if (typeMath.Compare(b.Point[byDimension], a.Point[byDimension]) < 0)
{
nodes[newIndex - 1] = b;
nodes[newIndex] = a;
}
else
break;
}
}
}
private void AddNodesBalanced(KdTreeNode<TKey, TValue>[] nodes, int byDimension, int fromIndex, int toIndex)
{
if (fromIndex == toIndex)
{
Add(nodes[fromIndex].Point, nodes[fromIndex].Value);
nodes[fromIndex] = null;
return;
}
// Sort the array from the fromIndex to the toIndex
SortNodesArray(nodes, byDimension, fromIndex, toIndex);
// Find the splitting point
int midIndex = fromIndex + (int)System.Math.Round((toIndex + 1 - fromIndex) / 2f) - 1;
// Add the splitting point
Add(nodes[midIndex].Point, nodes[midIndex].Value);
nodes[midIndex] = null;
// Recurse
int nextDimension = (byDimension + 1) % dimensions;
if (fromIndex < midIndex)
AddNodesBalanced(nodes, nextDimension, fromIndex, midIndex - 1);
if (toIndex > midIndex)
AddNodesBalanced(nodes, nextDimension, midIndex + 1, toIndex);
}
public void Balance()
{
var nodeList = new List<KdTreeNode<TKey, TValue>>();
AddNodesToList(root, nodeList);
Clear();
AddNodesBalanced(nodeList.ToArray(), 0, 0, nodeList.Count - 1);
}
private void RemoveChildNodes(KdTreeNode<TKey, TValue> node)
{
for (var side = -1; side <= 1; side += 2)
{
if (node[side] != null)
{
RemoveChildNodes(node[side]);
node[side] = null;
}
}
}
public void Clear()
{
if (root != null)
RemoveChildNodes(root);
}
public void SaveToFile(string filename)
{
var serializer = new DataContractSerializer(typeof(KdTree<TKey, TValue>));
using (FileStream stream = File.Create(filename))
using (var writer = XmlDictionaryWriter.CreateBinaryWriter(stream))
{
serializer.WriteObject(writer, this);
writer.Flush();
}
}
public static KdTree<TKey, TValue> LoadFromFile(string filename)
{
var serializer = new DataContractSerializer(typeof(KdTree<TKey, TValue>));
using (FileStream stream = File.Open(filename, FileMode.Open))
using (var reader = XmlDictionaryReader.CreateBinaryReader(stream, XmlDictionaryReaderQuotas.Max))
{
return (KdTree<TKey, TValue>)serializer.ReadObject(reader);
}
}
public IEnumerator<KdTreeNode<TKey, TValue>> GetEnumerator()
{
var left = new Stack<KdTreeNode<TKey, TValue>>();
var right = new Stack<KdTreeNode<TKey, TValue>>();
Action<KdTreeNode<TKey, TValue>> addLeft = node =>
{
if (node.LeftChild != null)
{
left.Push(node.LeftChild);
}
};
Action<KdTreeNode<TKey, TValue>> addRight = node =>
{
if (node.RightChild != null)
{
right.Push(node.RightChild);
}
};
if (root != null)
{
yield return root;
addLeft(root);
addRight(root);
while (true)
{
if (left.Any())
{
var item = left.Pop();
addLeft(item);
addRight(item);
yield return item;
}
else if (right.Any())
{
var item = right.Pop();
addLeft(item);
addRight(item);
yield return item;
}
else
{
break;
}
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 13a653f5b84336c45b2c00b570775a87
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,86 @@
using System;
using System.Text;
using System.Linq;
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace UnityEngine.ProBuilder.KdTree
{
[Serializable]
[DataContract]
class KdTreeNode<TKey, TValue>
{
public KdTreeNode()
{
}
public KdTreeNode(TKey[] point, TValue value)
{
Point = point;
Value = value;
}
[DataMember]
public TKey[] Point;
[DataMember]
public TValue Value = default(TValue);
[DataMember]
public List<TValue> Duplicates = null;
[DataMember]
internal KdTreeNode<TKey, TValue> LeftChild = null;
[DataMember]
internal KdTreeNode<TKey, TValue> RightChild = null;
internal KdTreeNode<TKey, TValue> this[int compare]
{
get
{
if (compare <= 0)
return LeftChild;
else
return RightChild;
}
set
{
if (compare <= 0)
LeftChild = value;
else
RightChild = value;
}
}
public bool IsLeaf
{
get
{
return (LeftChild == null) && (RightChild == null);
}
}
public void AddDuplicate(TValue value)
{
if (Duplicates == null)
Duplicates = new List<TValue>() { value };
else
Duplicates.Add(value);
}
public override string ToString()
{
var sb = new StringBuilder();
for (var dimension = 0; dimension < Point.Length; dimension++)
{
sb.Append(Point[dimension].ToString());
}
if (Value == null)
sb.Append("null");
else
sb.Append(Value.ToString());
return sb.ToString();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 908a5a36f516c3048abadede5920d5d7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ed05cb2facaa5cc49aab6d1137d15904
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,69 @@
using System;
namespace UnityEngine.ProBuilder.KdTree.Math
{
[Serializable]
class DoubleMath : TypeMath<double>
{
public override int Compare(double a, double b)
{
return a.CompareTo(b);
}
public override bool AreEqual(double a, double b)
{
return a == b;
}
public override double MinValue
{
get { return double.MinValue; }
}
public override double MaxValue
{
get { return double.MaxValue; }
}
public override double Zero
{
get { return 0; }
}
public override double NegativeInfinity { get { return double.NegativeInfinity; } }
public override double PositiveInfinity { get { return double.PositiveInfinity; } }
public override double Add(double a, double b)
{
return a + b;
}
public override double Subtract(double a, double b)
{
return a - b;
}
public override double Multiply(double a, double b)
{
return a * b;
}
public override double DistanceSquaredBetweenPoints(double[] a, double[] b)
{
double distance = Zero;
int dimensions = a.Length;
// Return the absolute distance bewteen 2 hyper points
for (var dimension = 0; dimension < dimensions; dimension++)
{
double distOnThisAxis = Subtract(a[dimension], b[dimension]);
double distOnThisAxisSquared = Multiply(distOnThisAxis, distOnThisAxis);
distance = Add(distance, distOnThisAxisSquared);
}
return distance;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a2c22c8685df2d44b943673a11597711
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,69 @@
using System;
namespace UnityEngine.ProBuilder.KdTree.Math
{
[Serializable]
class FloatMath : TypeMath<float>
{
public override int Compare(float a, float b)
{
return a.CompareTo(b);
}
public override bool AreEqual(float a, float b)
{
return a == b;
}
public override float MinValue
{
get { return float.MinValue; }
}
public override float MaxValue
{
get { return float.MaxValue; }
}
public override float Zero
{
get { return 0; }
}
public override float NegativeInfinity { get { return float.NegativeInfinity; } }
public override float PositiveInfinity { get { return float.PositiveInfinity; } }
public override float Add(float a, float b)
{
return a + b;
}
public override float Subtract(float a, float b)
{
return a - b;
}
public override float Multiply(float a, float b)
{
return a * b;
}
public override float DistanceSquaredBetweenPoints(float[] a, float[] b)
{
float distance = Zero;
int dimensions = a.Length;
// Return the absolute distance bewteen 2 hyper points
for (var dimension = 0; dimension < dimensions; dimension++)
{
float distOnThisAxis = Subtract(a[dimension], b[dimension]);
float distOnThisAxisSquared = Multiply(distOnThisAxis, distOnThisAxis);
distance = Add(distance, distOnThisAxisSquared);
}
return distance;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 483554fdb1324da4ead26f33de2c9990
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,33 @@
namespace UnityEngine.ProBuilder.KdTree
{
interface ITypeMath<T>
{
int Compare(T a, T b);
T MinValue { get; }
T MaxValue { get; }
T Min(T a, T b);
T Max(T a, T b);
bool AreEqual(T a, T b);
bool AreEqual(T[] a, T[] b);
T Add(T a, T b);
T Subtract(T a, T b);
T Multiply(T a, T b);
T Zero { get; }
T NegativeInfinity { get; }
T PositiveInfinity { get; }
T DistanceSquaredBetweenPoints(T[] a, T[] b);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2799d938bc097b0478b150b315487a18
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,64 @@
using System;
namespace UnityEngine.ProBuilder.KdTree.Math
{
[Serializable]
abstract class TypeMath<T> : ITypeMath<T>
{
#region ITypeMath<T> members
public abstract int Compare(T a, T b);
public abstract bool AreEqual(T a, T b);
public virtual bool AreEqual(T[] a, T[] b)
{
if (a.Length != b.Length)
return false;
for (var index = 0; index < a.Length; index++)
{
if (!AreEqual(a[index], b[index]))
return false;
}
return true;
}
public abstract T MinValue { get; }
public abstract T MaxValue { get; }
public T Min(T a, T b)
{
if (Compare(a, b) < 0)
return a;
else
return b;
}
public T Max(T a, T b)
{
if (Compare(a, b) > 0)
return a;
else
return b;
}
public abstract T Zero { get; }
public abstract T NegativeInfinity { get; }
public abstract T PositiveInfinity { get; }
public abstract T Add(T a, T b);
public abstract T Subtract(T a, T b);
public abstract T Multiply(T a, T b);
public abstract T DistanceSquaredBetweenPoints(T[] a, T[] b);
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4daa0ba8c6e93d54a9b542d76b235c55
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,83 @@
using System;
namespace UnityEngine.ProBuilder.KdTree
{
interface INearestNeighbourList<TItem, TDistance>
{
bool Add(TItem item, TDistance distance);
TItem GetFurtherest();
TItem RemoveFurtherest();
int MaxCapacity { get; }
int Count { get; }
}
class NearestNeighbourList<TItem, TDistance> : INearestNeighbourList<TItem, TDistance>
{
public NearestNeighbourList(int maxCapacity, ITypeMath<TDistance> distanceMath)
{
this.maxCapacity = maxCapacity;
this.distanceMath = distanceMath;
queue = new PriorityQueue<TItem, TDistance>(maxCapacity, distanceMath);
}
private PriorityQueue<TItem, TDistance> queue;
private ITypeMath<TDistance> distanceMath;
private int maxCapacity;
public int MaxCapacity { get { return maxCapacity; } }
public int Count { get { return queue.Count; } }
public bool Add(TItem item, TDistance distance)
{
if (queue.Count >= maxCapacity)
{
// If the distance of this item is less than the distance of the last item
// in our neighbour list then pop that neighbour off and push this one on
// otherwise don't even bother adding this item
if (distanceMath.Compare(distance, queue.GetHighestPriority()) < 0)
{
queue.Dequeue();
queue.Enqueue(item, distance);
return true;
}
else
return false;
}
else
{
queue.Enqueue(item, distance);
return true;
}
}
public TItem GetFurtherest()
{
if (Count == 0)
throw new Exception("List is empty");
else
return queue.GetHighest();
}
public TDistance GetFurtherestDistance()
{
if (Count == 0)
throw new Exception("List is empty");
else
return queue.GetHighestPriority();
}
public TItem RemoveFurtherest()
{
return queue.Dequeue();
}
public bool IsCapacityReached
{
get { return Count == MaxCapacity; }
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 601f62929862ecb48956dc2dca0a2498
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,125 @@
using System;
namespace UnityEngine.ProBuilder.KdTree
{
struct ItemPriority<TItem, TPriority>
{
public TItem Item;
public TPriority Priority;
}
class PriorityQueue<TItem, TPriority> : IPriorityQueue<TItem, TPriority>
{
public PriorityQueue(int capacity, ITypeMath<TPriority> priorityMath)
{
if (capacity <= 0)
throw new ArgumentException("Capacity must be greater than zero");
this.capacity = capacity;
queue = new ItemPriority<TItem, TPriority>[capacity];
this.priorityMath = priorityMath;
}
private ITypeMath<TPriority> priorityMath;
private ItemPriority<TItem, TPriority>[] queue;
private int capacity;
private int count;
public int Count { get { return count; } }
// Try to avoid unnecessary slow memory reallocations by creating your queue with an ample capacity
private void ExpandCapacity()
{
// Double our capacity
capacity *= 2;
// Create a new queue
var newQueue = new ItemPriority<TItem, TPriority>[capacity];
// Copy the contents of the original queue to the new one
Array.Copy(queue, newQueue, queue.Length);
// Copy the new queue over the original one
queue = newQueue;
}
public void Enqueue(TItem item, TPriority priority)
{
if (++count > capacity)
ExpandCapacity();
int newItemIndex = count - 1;
queue[newItemIndex] = new ItemPriority<TItem, TPriority> { Item = item, Priority = priority };
ReorderItem(newItemIndex, -1);
}
public TItem Dequeue()
{
TItem item = queue[0].Item;
queue[0].Item = default(TItem);
queue[0].Priority = priorityMath.MinValue;
ReorderItem(0, 1);
count--;
return item;
}
private void ReorderItem(int index, int direction)
{
if ((direction != -1) && (direction != 1))
throw new ArgumentException("Invalid Direction");
var item = queue[index];
int nextIndex = index + direction;
while ((nextIndex >= 0) && (nextIndex < count))
{
var next = queue[nextIndex];
int compare = priorityMath.Compare(item.Priority, next.Priority);
// If we're moving up and our priority is higher than the next priority then swap
// Or if we're moving down and our priority is lower than the next priority then swap
if (
((direction == -1) && (compare > 0))
||
((direction == 1) && (compare < 0))
)
{
queue[index] = next;
queue[nextIndex] = item;
index += direction;
nextIndex += direction;
}
else
break;
}
}
public TItem GetHighest()
{
if (count == 0)
throw new Exception("Queue is empty");
else
return queue[0].Item;
}
public TPriority GetHighestPriority()
{
if (count == 0)
throw new Exception("Queue is empty");
else
return queue[0].Priority;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d9ed04c4f3db58d488f75533eee62283
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: