Removed old KD-tree implementation, added summaries to PSXTexture2D
This commit is contained in:
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 5d9bff9b871f6052f9cb0cea865b5608
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,211 +0,0 @@
|
|||||||
/*MIT License
|
|
||||||
|
|
||||||
Copyright(c) 2018 Vili Volčini / viliwonka
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace DataStructures.ViliWonka.Heap {
|
|
||||||
|
|
||||||
// array start at index 1, optimisation reason
|
|
||||||
public abstract class BaseHeap {
|
|
||||||
|
|
||||||
protected int nodesCount;
|
|
||||||
protected int maxSize;
|
|
||||||
|
|
||||||
protected float[] heap;
|
|
||||||
|
|
||||||
protected BaseHeap(int initialSize) {
|
|
||||||
|
|
||||||
maxSize = initialSize;
|
|
||||||
heap = new float[initialSize + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count { get { return nodesCount; } }
|
|
||||||
|
|
||||||
public float HeadValue { get { return heap[1]; } }
|
|
||||||
|
|
||||||
public void Clear() {
|
|
||||||
nodesCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int Parent(int index) { return (index >> 1); }
|
|
||||||
protected int Left (int index) { return (index << 1); }
|
|
||||||
protected int Right (int index) { return (index << 1) | 1; }
|
|
||||||
|
|
||||||
// bubble down, MaxHeap version
|
|
||||||
protected void BubbleDownMax(int index) {
|
|
||||||
|
|
||||||
int L = Left(index);
|
|
||||||
int R = Right(index);
|
|
||||||
|
|
||||||
// bubbling down, 2 kids
|
|
||||||
while (R <= nodesCount) {
|
|
||||||
|
|
||||||
// if heap property is violated between index and Left child
|
|
||||||
if(heap[index] < heap[L]) {
|
|
||||||
|
|
||||||
if (heap[L] < heap[R]) {
|
|
||||||
|
|
||||||
Swap(index, R); // left has bigger priority
|
|
||||||
index = R;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
Swap(index, L); // right has bigger priority
|
|
||||||
index = L;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// if heap property is violated between index and R
|
|
||||||
if (heap[index] < heap[R]) {
|
|
||||||
|
|
||||||
Swap(index, R);
|
|
||||||
index = R;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
index = L;
|
|
||||||
L = Left(index);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
L = Left(index);
|
|
||||||
R = Right(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// only left & last children available to test and swap
|
|
||||||
if (L <= nodesCount && heap[index] < heap[L]) {
|
|
||||||
Swap(index, L);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// bubble up, MaxHeap version
|
|
||||||
protected void BubbleUpMax(int index) {
|
|
||||||
|
|
||||||
int P = Parent(index);
|
|
||||||
|
|
||||||
//swap, until Heap property isn't violated anymore
|
|
||||||
while (P > 0 && heap[P] < heap[index]) {
|
|
||||||
|
|
||||||
Swap(P, index);
|
|
||||||
|
|
||||||
index = P;
|
|
||||||
P = Parent(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// bubble down, MinHeap version
|
|
||||||
protected void BubbleDownMin(int index) {
|
|
||||||
|
|
||||||
int L = Left(index);
|
|
||||||
int R = Right(index);
|
|
||||||
|
|
||||||
// bubbling down, 2 kids
|
|
||||||
while(R <= nodesCount) {
|
|
||||||
|
|
||||||
// if heap property is violated between index and Left child
|
|
||||||
if(heap[index] > heap[L]) {
|
|
||||||
|
|
||||||
if(heap[L] > heap[R]) {
|
|
||||||
|
|
||||||
Swap(index, R); // right has smaller priority
|
|
||||||
index = R;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
Swap(index, L); // left has smaller priority
|
|
||||||
index = L;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// if heap property is violated between index and R
|
|
||||||
if(heap[index] > heap[R]) {
|
|
||||||
|
|
||||||
Swap(index, R);
|
|
||||||
index = R;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
index = L;
|
|
||||||
L = Left(index);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
L = Left(index);
|
|
||||||
R = Right(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// only left & last children available to test and swap
|
|
||||||
if(L <= nodesCount && heap[index] > heap[L]) {
|
|
||||||
Swap(index, L);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// bubble up, MinHeap version
|
|
||||||
protected void BubbleUpMin(int index) {
|
|
||||||
|
|
||||||
int P = Parent(index);
|
|
||||||
|
|
||||||
//swap, until Heap property isn't violated anymore
|
|
||||||
while(P > 0 && heap[P] > heap[index]) {
|
|
||||||
|
|
||||||
Swap(P, index);
|
|
||||||
|
|
||||||
index = P;
|
|
||||||
P = Parent(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected float tempHeap;
|
|
||||||
protected virtual void Swap(int A, int B) {
|
|
||||||
|
|
||||||
tempHeap = heap[A];
|
|
||||||
heap[A] = heap[B];
|
|
||||||
heap[B] = tempHeap;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void UpsizeHeap() {
|
|
||||||
|
|
||||||
maxSize *= 2;
|
|
||||||
System.Array.Resize(ref heap, maxSize + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void PushValue(float h) {
|
|
||||||
throw new System.NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual float PopValue() {
|
|
||||||
throw new System.NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void FlushHeapResult(List<float> heapList) {
|
|
||||||
|
|
||||||
for(int i = 1; i < Count; i++) {
|
|
||||||
heapList.Add(heap[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 0a58014cb612f86d1ab500d7c5f6360d
|
|
||||||
@@ -1,229 +0,0 @@
|
|||||||
/*MIT License
|
|
||||||
|
|
||||||
Copyright(c) 2018 Vili Volčini / viliwonka
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace DataStructures.ViliWonka.Heap {
|
|
||||||
|
|
||||||
public class KSmallestHeap : BaseHeap {
|
|
||||||
|
|
||||||
public KSmallestHeap(int maxEntries) : base(maxEntries) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Full {
|
|
||||||
get {
|
|
||||||
return maxSize == nodesCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// in lots of cases, max head gets removed
|
|
||||||
public override void PushValue(float h) {
|
|
||||||
|
|
||||||
// if heap full
|
|
||||||
if(nodesCount == maxSize) {
|
|
||||||
|
|
||||||
// if Heads priority is smaller than input priority, then ignore that item
|
|
||||||
if(HeadValue < h) {
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
heap[1] = h; // remove top element
|
|
||||||
BubbleDownMax(1); // bubble it down
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
nodesCount++;
|
|
||||||
heap[nodesCount] = h;
|
|
||||||
BubbleUpMax(nodesCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override float PopValue() {
|
|
||||||
|
|
||||||
if(nodesCount == 0)
|
|
||||||
throw new System.ArgumentException("Heap is empty!");
|
|
||||||
|
|
||||||
float result = heap[1];
|
|
||||||
|
|
||||||
heap[1] = heap[nodesCount];
|
|
||||||
nodesCount--;
|
|
||||||
BubbleDownMax(1);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Print() {
|
|
||||||
|
|
||||||
UnityEngine.Debug.Log("HeapPropertyHolds? " + HeapPropertyHolds(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
//should remove
|
|
||||||
public bool HeapPropertyHolds(int index, int depth = 0) {
|
|
||||||
|
|
||||||
if (index > nodesCount)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
UnityEngine.Debug.Log(heap[index]);
|
|
||||||
|
|
||||||
int L = Left(index);
|
|
||||||
int R = Right(index);
|
|
||||||
|
|
||||||
bool bothHold = true;
|
|
||||||
|
|
||||||
if(L <= nodesCount) {
|
|
||||||
|
|
||||||
UnityEngine.Debug.Log(heap[index] + " => " + heap[L]);
|
|
||||||
|
|
||||||
if (heap[index] < heap[L])
|
|
||||||
bothHold = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if L <= nodesCount, then R <= nodesCount can also happen
|
|
||||||
if (R <= nodesCount) {
|
|
||||||
|
|
||||||
UnityEngine.Debug.Log(heap[index] + " => " + heap[R]);
|
|
||||||
|
|
||||||
if (bothHold && heap[index] < heap[R])
|
|
||||||
bothHold = false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return bothHold & HeapPropertyHolds(L, depth + 1) & HeapPropertyHolds(R, depth + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// array start at index 1
|
|
||||||
// generic version
|
|
||||||
public class KSmallestHeap<T> : KSmallestHeap {
|
|
||||||
|
|
||||||
T[] objs; //objects
|
|
||||||
|
|
||||||
public KSmallestHeap(int maxEntries) : base(maxEntries) {
|
|
||||||
objs = new T[maxEntries + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
public T HeadHeapObject { get { return objs[1]; } }
|
|
||||||
|
|
||||||
T tempObjs;
|
|
||||||
protected override void Swap(int A, int B) {
|
|
||||||
|
|
||||||
tempHeap = heap[A];
|
|
||||||
tempObjs = objs[A];
|
|
||||||
|
|
||||||
heap[A] = heap[B];
|
|
||||||
objs[A] = objs[B];
|
|
||||||
|
|
||||||
heap[B] = tempHeap;
|
|
||||||
objs[B] = tempObjs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void PushValue(float h) {
|
|
||||||
throw new System.ArgumentException("Use Push(T, float)!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PushObj(T obj, float h) {
|
|
||||||
|
|
||||||
// if heap full
|
|
||||||
if(nodesCount == maxSize) {
|
|
||||||
|
|
||||||
// if Heads priority is smaller than input priority, then ignore that item
|
|
||||||
if(HeadValue < h) {
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
heap[1] = h; // remove top element
|
|
||||||
objs[1] = obj;
|
|
||||||
BubbleDownMax(1); // bubble it down
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
nodesCount++;
|
|
||||||
heap[nodesCount] = h;
|
|
||||||
objs[nodesCount] = obj;
|
|
||||||
BubbleUpMax(nodesCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override float PopValue() {
|
|
||||||
throw new System.ArgumentException("Use PopObj()!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public T PopObj() {
|
|
||||||
|
|
||||||
if(nodesCount == 0)
|
|
||||||
throw new System.ArgumentException("Heap is empty!");
|
|
||||||
|
|
||||||
T result = objs[1];
|
|
||||||
|
|
||||||
heap[1] = heap[nodesCount];
|
|
||||||
objs[1] = objs[nodesCount];
|
|
||||||
|
|
||||||
nodesCount--;
|
|
||||||
BubbleDownMax(1);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T PopObj(ref float heapValue) {
|
|
||||||
|
|
||||||
if(nodesCount == 0)
|
|
||||||
throw new System.ArgumentException("Heap is empty!");
|
|
||||||
|
|
||||||
heapValue = heap[1];
|
|
||||||
T result = PopObj();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//flush internal results, returns ordered data
|
|
||||||
public void FlushResult(List<T> resultList, List<float> heapList = null) {
|
|
||||||
|
|
||||||
int count = nodesCount + 1;
|
|
||||||
|
|
||||||
|
|
||||||
if(heapList == null) {
|
|
||||||
|
|
||||||
for(int i = 1; i < count; i++) {
|
|
||||||
resultList.Add(PopObj());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
float h = 0f;
|
|
||||||
|
|
||||||
for(int i = 1; i < count; i++) {
|
|
||||||
resultList.Add(PopObj(ref h));
|
|
||||||
heapList.Add(h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 902305de5cb00eb74a5d1d6b430ab942
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
/*MIT License
|
|
||||||
|
|
||||||
Copyright(c) 2018 Vili Volčini / viliwonka
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace DataStructures.ViliWonka.Heap {
|
|
||||||
|
|
||||||
public class MaxHeap : BaseHeap {
|
|
||||||
|
|
||||||
public MaxHeap(int initialSize = 2048) : base(initialSize) {
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void PushValue(float h) {
|
|
||||||
|
|
||||||
// if heap array is full
|
|
||||||
if(nodesCount == maxSize) {
|
|
||||||
|
|
||||||
UpsizeHeap();
|
|
||||||
}
|
|
||||||
|
|
||||||
nodesCount++;
|
|
||||||
heap[nodesCount] = h;
|
|
||||||
BubbleUpMax(nodesCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override float PopValue() {
|
|
||||||
|
|
||||||
if(nodesCount == 0)
|
|
||||||
throw new System.ArgumentException("Heap is empty!");
|
|
||||||
|
|
||||||
float result = heap[1];
|
|
||||||
|
|
||||||
heap[1] = heap[nodesCount];
|
|
||||||
nodesCount--;
|
|
||||||
BubbleDownMax(1);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// generic version
|
|
||||||
public class MaxHeap<T> : MaxHeap {
|
|
||||||
|
|
||||||
T[] objs; // objects
|
|
||||||
|
|
||||||
public MaxHeap(int maxNodes) : base(maxNodes) {
|
|
||||||
objs = new T[maxNodes + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
public T HeadHeapObject { get { return objs[1]; } }
|
|
||||||
|
|
||||||
T tempObjs;
|
|
||||||
protected override void Swap(int A, int B) {
|
|
||||||
|
|
||||||
tempHeap = heap[A];
|
|
||||||
tempObjs = objs[A];
|
|
||||||
|
|
||||||
heap[A] = heap[B];
|
|
||||||
objs[A] = objs[B];
|
|
||||||
|
|
||||||
heap[B] = tempHeap;
|
|
||||||
objs[B] = tempObjs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void PushValue(float h) {
|
|
||||||
throw new System.ArgumentException("Use PushObj(T, float)!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public override float PopValue() {
|
|
||||||
throw new System.ArgumentException("Use Push(T, float)!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PushObj(T obj, float h) {
|
|
||||||
|
|
||||||
// if heap array is full
|
|
||||||
if(nodesCount == maxSize) {
|
|
||||||
UpsizeHeap();
|
|
||||||
}
|
|
||||||
|
|
||||||
nodesCount++;
|
|
||||||
heap[nodesCount] = h;
|
|
||||||
objs[nodesCount] = obj;
|
|
||||||
|
|
||||||
BubbleUpMin(nodesCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T PopObj() {
|
|
||||||
|
|
||||||
if(nodesCount == 0)
|
|
||||||
throw new System.ArgumentException("Heap is empty!");
|
|
||||||
|
|
||||||
T result = objs[1];
|
|
||||||
|
|
||||||
heap[1] = heap[nodesCount];
|
|
||||||
objs[1] = objs[nodesCount];
|
|
||||||
|
|
||||||
objs[nodesCount] = default(T);
|
|
||||||
|
|
||||||
nodesCount--;
|
|
||||||
BubbleDownMin(1);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public T PopObj(ref float heapValue) {
|
|
||||||
|
|
||||||
if(nodesCount == 0)
|
|
||||||
throw new System.ArgumentException("Heap is empty!");
|
|
||||||
|
|
||||||
heapValue = heap[1];
|
|
||||||
T result = PopObj();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void UpsizeHeap() {
|
|
||||||
|
|
||||||
maxSize *= 2;
|
|
||||||
System.Array.Resize(ref heap, maxSize + 1);
|
|
||||||
System.Array.Resize(ref objs, maxSize + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//flush internal results, returns ordered data
|
|
||||||
public void FlushResult(List<T> resultList, List<float> heapList = null) {
|
|
||||||
|
|
||||||
int count = nodesCount + 1;
|
|
||||||
|
|
||||||
if(heapList == null) {
|
|
||||||
|
|
||||||
for(int i = 1; i < count; i++) {
|
|
||||||
resultList.Add(PopObj());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
float h = 0f;
|
|
||||||
|
|
||||||
for(int i = 1; i < count; i++) {
|
|
||||||
resultList.Add(PopObj(ref h));
|
|
||||||
heapList.Add(h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 4de1738443a82f33b9102bb09da91d2f
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
/*MIT License
|
|
||||||
|
|
||||||
Copyright(c) 2018 Vili Volčini / viliwonka
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace DataStructures.ViliWonka.Heap {
|
|
||||||
|
|
||||||
public class MinHeap : BaseHeap {
|
|
||||||
|
|
||||||
public MinHeap(int initialSize = 2048) : base(initialSize) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void PushValue(float h) {
|
|
||||||
|
|
||||||
// if heap array is full
|
|
||||||
if(nodesCount == maxSize) {
|
|
||||||
|
|
||||||
UpsizeHeap();
|
|
||||||
}
|
|
||||||
|
|
||||||
nodesCount++;
|
|
||||||
heap[nodesCount] = h;
|
|
||||||
BubbleUpMin(nodesCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override float PopValue() {
|
|
||||||
|
|
||||||
if(nodesCount == 0)
|
|
||||||
throw new System.ArgumentException("Heap is empty!");
|
|
||||||
|
|
||||||
float result = heap[1];
|
|
||||||
|
|
||||||
heap[1] = heap[nodesCount];
|
|
||||||
|
|
||||||
nodesCount--;
|
|
||||||
|
|
||||||
if(nodesCount != 0)
|
|
||||||
BubbleDownMin(1);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// generic version
|
|
||||||
public class MinHeap<T> : MinHeap {
|
|
||||||
|
|
||||||
T[] objs; // objects
|
|
||||||
|
|
||||||
public MinHeap(int maxNodes = 2048) : base(maxNodes) {
|
|
||||||
objs = new T[maxNodes + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
public T HeadHeapObject { get { return objs[1]; } }
|
|
||||||
|
|
||||||
T tempObjs;
|
|
||||||
protected override void Swap(int A, int B) {
|
|
||||||
|
|
||||||
tempHeap = heap[A];
|
|
||||||
tempObjs = objs[A];
|
|
||||||
|
|
||||||
heap[A] = heap[B];
|
|
||||||
objs[A] = objs[B];
|
|
||||||
|
|
||||||
heap[B] = tempHeap;
|
|
||||||
objs[B] = tempObjs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void PushValue(float h) {
|
|
||||||
throw new System.ArgumentException("Use Push(T, float)!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public override float PopValue() {
|
|
||||||
throw new System.ArgumentException("Use Push(T, float)!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PushObj(T obj, float h) {
|
|
||||||
|
|
||||||
// if heap array is full
|
|
||||||
if(nodesCount == maxSize) {
|
|
||||||
UpsizeHeap();
|
|
||||||
}
|
|
||||||
|
|
||||||
nodesCount++;
|
|
||||||
heap[nodesCount] = h;
|
|
||||||
objs[nodesCount] = obj;
|
|
||||||
|
|
||||||
BubbleUpMin(nodesCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T PopObj() {
|
|
||||||
|
|
||||||
if(nodesCount == 0)
|
|
||||||
throw new System.ArgumentException("Heap is empty!");
|
|
||||||
|
|
||||||
T result = objs[1];
|
|
||||||
|
|
||||||
heap[1] = heap[nodesCount];
|
|
||||||
objs[1] = objs[nodesCount];
|
|
||||||
|
|
||||||
objs[nodesCount] = default(T);
|
|
||||||
|
|
||||||
nodesCount--;
|
|
||||||
|
|
||||||
if(nodesCount != 0)
|
|
||||||
BubbleDownMin(1);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T PopObj(ref float heapValue) {
|
|
||||||
|
|
||||||
if(nodesCount == 0)
|
|
||||||
throw new System.ArgumentException("Heap is empty!");
|
|
||||||
|
|
||||||
heapValue = heap[1];
|
|
||||||
T result = PopObj();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void UpsizeHeap() {
|
|
||||||
|
|
||||||
maxSize *= 2;
|
|
||||||
System.Array.Resize(ref heap, maxSize + 1);
|
|
||||||
System.Array.Resize(ref objs, maxSize + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//flush internal array, returns ordered data
|
|
||||||
public void FlushResult(List<T> resultList, List<float> heapList = null) {
|
|
||||||
|
|
||||||
int count = nodesCount + 1;
|
|
||||||
|
|
||||||
if(heapList == null) {
|
|
||||||
|
|
||||||
for(int i = 1; i < count; i++) {
|
|
||||||
resultList.Add(PopObj());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
float h = 0f;
|
|
||||||
|
|
||||||
for(int i = 1; i < count; i++) {
|
|
||||||
resultList.Add(PopObj(ref h));
|
|
||||||
heapList.Add(h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 9ebf0e20ba274e5a59101ce360358b04
|
|
||||||
@@ -1,298 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!29 &1
|
|
||||||
OcclusionCullingSettings:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
serializedVersion: 2
|
|
||||||
m_OcclusionBakeSettings:
|
|
||||||
smallestOccluder: 5
|
|
||||||
smallestHole: 0.25
|
|
||||||
backfaceThreshold: 100
|
|
||||||
m_SceneGUID: 00000000000000000000000000000000
|
|
||||||
m_OcclusionCullingData: {fileID: 0}
|
|
||||||
--- !u!104 &2
|
|
||||||
RenderSettings:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
serializedVersion: 9
|
|
||||||
m_Fog: 0
|
|
||||||
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
|
||||||
m_FogMode: 3
|
|
||||||
m_FogDensity: 0.01
|
|
||||||
m_LinearFogStart: 0
|
|
||||||
m_LinearFogEnd: 300
|
|
||||||
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
|
|
||||||
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
|
|
||||||
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
|
|
||||||
m_AmbientIntensity: 1
|
|
||||||
m_AmbientMode: 0
|
|
||||||
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
|
|
||||||
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
m_HaloStrength: 0.5
|
|
||||||
m_FlareStrength: 1
|
|
||||||
m_FlareFadeSpeed: 3
|
|
||||||
m_HaloTexture: {fileID: 0}
|
|
||||||
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
|
|
||||||
m_DefaultReflectionMode: 0
|
|
||||||
m_DefaultReflectionResolution: 128
|
|
||||||
m_ReflectionBounces: 1
|
|
||||||
m_ReflectionIntensity: 1
|
|
||||||
m_CustomReflection: {fileID: 0}
|
|
||||||
m_Sun: {fileID: 0}
|
|
||||||
m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1}
|
|
||||||
m_UseRadianceAmbientProbe: 0
|
|
||||||
--- !u!157 &3
|
|
||||||
LightmapSettings:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
serializedVersion: 11
|
|
||||||
m_GIWorkflowMode: 0
|
|
||||||
m_GISettings:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_BounceScale: 1
|
|
||||||
m_IndirectOutputScale: 1
|
|
||||||
m_AlbedoBoost: 1
|
|
||||||
m_TemporalCoherenceThreshold: 1
|
|
||||||
m_EnvironmentLightingMode: 0
|
|
||||||
m_EnableBakedLightmaps: 1
|
|
||||||
m_EnableRealtimeLightmaps: 1
|
|
||||||
m_LightmapEditorSettings:
|
|
||||||
serializedVersion: 10
|
|
||||||
m_Resolution: 2
|
|
||||||
m_BakeResolution: 40
|
|
||||||
m_AtlasSize: 1024
|
|
||||||
m_AO: 0
|
|
||||||
m_AOMaxDistance: 1
|
|
||||||
m_CompAOExponent: 1
|
|
||||||
m_CompAOExponentDirect: 0
|
|
||||||
m_Padding: 2
|
|
||||||
m_LightmapParameters: {fileID: 0}
|
|
||||||
m_LightmapsBakeMode: 1
|
|
||||||
m_TextureCompression: 1
|
|
||||||
m_FinalGather: 0
|
|
||||||
m_FinalGatherFiltering: 1
|
|
||||||
m_FinalGatherRayCount: 256
|
|
||||||
m_ReflectionCompression: 2
|
|
||||||
m_MixedBakeMode: 2
|
|
||||||
m_BakeBackend: 1
|
|
||||||
m_PVRSampling: 1
|
|
||||||
m_PVRDirectSampleCount: 32
|
|
||||||
m_PVRSampleCount: 500
|
|
||||||
m_PVRBounces: 2
|
|
||||||
m_PVRFilterTypeDirect: 0
|
|
||||||
m_PVRFilterTypeIndirect: 0
|
|
||||||
m_PVRFilterTypeAO: 0
|
|
||||||
m_PVRFilteringMode: 1
|
|
||||||
m_PVRCulling: 1
|
|
||||||
m_PVRFilteringGaussRadiusDirect: 1
|
|
||||||
m_PVRFilteringGaussRadiusIndirect: 5
|
|
||||||
m_PVRFilteringGaussRadiusAO: 2
|
|
||||||
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
|
||||||
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
|
||||||
m_PVRFilteringAtrousPositionSigmaAO: 1
|
|
||||||
m_ShowResolutionOverlay: 1
|
|
||||||
m_LightingDataAsset: {fileID: 0}
|
|
||||||
m_UseShadowmask: 1
|
|
||||||
--- !u!196 &4
|
|
||||||
NavMeshSettings:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_BuildSettings:
|
|
||||||
serializedVersion: 2
|
|
||||||
agentTypeID: 0
|
|
||||||
agentRadius: 0.5
|
|
||||||
agentHeight: 2
|
|
||||||
agentSlope: 45
|
|
||||||
agentClimb: 0.4
|
|
||||||
ledgeDropHeight: 0
|
|
||||||
maxJumpAcrossDistance: 0
|
|
||||||
minRegionArea: 2
|
|
||||||
manualCellSize: 0
|
|
||||||
cellSize: 0.16666667
|
|
||||||
manualTileSize: 0
|
|
||||||
tileSize: 256
|
|
||||||
accuratePlacement: 0
|
|
||||||
debug:
|
|
||||||
m_Flags: 0
|
|
||||||
m_NavMeshData: {fileID: 0}
|
|
||||||
--- !u!1 &653832527
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInternal: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 653832530}
|
|
||||||
- component: {fileID: 653832529}
|
|
||||||
- component: {fileID: 653832528}
|
|
||||||
m_Layer: 0
|
|
||||||
m_Name: Main Camera
|
|
||||||
m_TagString: MainCamera
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!81 &653832528
|
|
||||||
AudioListener:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInternal: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 653832527}
|
|
||||||
m_Enabled: 1
|
|
||||||
--- !u!20 &653832529
|
|
||||||
Camera:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInternal: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 653832527}
|
|
||||||
m_Enabled: 1
|
|
||||||
serializedVersion: 2
|
|
||||||
m_ClearFlags: 1
|
|
||||||
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
|
|
||||||
m_projectionMatrixMode: 1
|
|
||||||
m_SensorSize: {x: 36, y: 24}
|
|
||||||
m_LensShift: {x: 0, y: 0}
|
|
||||||
m_FocalLength: 50
|
|
||||||
m_NormalizedViewPortRect:
|
|
||||||
serializedVersion: 2
|
|
||||||
x: 0
|
|
||||||
y: 0
|
|
||||||
width: 1
|
|
||||||
height: 1
|
|
||||||
near clip plane: 0.3
|
|
||||||
far clip plane: 1000
|
|
||||||
field of view: 60
|
|
||||||
orthographic: 0
|
|
||||||
orthographic size: 5
|
|
||||||
m_Depth: -1
|
|
||||||
m_CullingMask:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Bits: 4294967295
|
|
||||||
m_RenderingPath: -1
|
|
||||||
m_TargetTexture: {fileID: 0}
|
|
||||||
m_TargetDisplay: 0
|
|
||||||
m_TargetEye: 3
|
|
||||||
m_HDR: 1
|
|
||||||
m_AllowMSAA: 1
|
|
||||||
m_AllowDynamicResolution: 0
|
|
||||||
m_ForceIntoRT: 0
|
|
||||||
m_OcclusionCulling: 1
|
|
||||||
m_StereoConvergence: 10
|
|
||||||
m_StereoSeparation: 0.022
|
|
||||||
--- !u!4 &653832530
|
|
||||||
Transform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInternal: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 653832527}
|
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
|
||||||
m_LocalPosition: {x: 0, y: 1, z: -10}
|
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
|
||||||
m_Children: []
|
|
||||||
m_Father: {fileID: 0}
|
|
||||||
m_RootOrder: 0
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
--- !u!1 &1730864583
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInternal: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 1730864585}
|
|
||||||
- component: {fileID: 1730864584}
|
|
||||||
m_Layer: 0
|
|
||||||
m_Name: Directional Light
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!108 &1730864584
|
|
||||||
Light:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInternal: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 1730864583}
|
|
||||||
m_Enabled: 1
|
|
||||||
serializedVersion: 8
|
|
||||||
m_Type: 1
|
|
||||||
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
|
|
||||||
m_Intensity: 1
|
|
||||||
m_Range: 10
|
|
||||||
m_SpotAngle: 30
|
|
||||||
m_CookieSize: 10
|
|
||||||
m_Shadows:
|
|
||||||
m_Type: 2
|
|
||||||
m_Resolution: -1
|
|
||||||
m_CustomResolution: -1
|
|
||||||
m_Strength: 1
|
|
||||||
m_Bias: 0.05
|
|
||||||
m_NormalBias: 0.4
|
|
||||||
m_NearPlane: 0.2
|
|
||||||
m_Cookie: {fileID: 0}
|
|
||||||
m_DrawHalo: 0
|
|
||||||
m_Flare: {fileID: 0}
|
|
||||||
m_RenderMode: 0
|
|
||||||
m_CullingMask:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Bits: 4294967295
|
|
||||||
m_Lightmapping: 4
|
|
||||||
m_LightShadowCasterMode: 0
|
|
||||||
m_AreaSize: {x: 1, y: 1}
|
|
||||||
m_BounceIntensity: 1
|
|
||||||
m_ColorTemperature: 6570
|
|
||||||
m_UseColorTemperature: 0
|
|
||||||
m_ShadowRadius: 0
|
|
||||||
m_ShadowAngle: 0
|
|
||||||
--- !u!4 &1730864585
|
|
||||||
Transform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInternal: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 1730864583}
|
|
||||||
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
|
|
||||||
m_LocalPosition: {x: 0, y: 3, z: 0}
|
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
|
||||||
m_Children: []
|
|
||||||
m_Father: {fileID: 0}
|
|
||||||
m_RootOrder: 1
|
|
||||||
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
|
|
||||||
--- !u!1 &1883466098
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInternal: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 1883466100}
|
|
||||||
- component: {fileID: 1883466099}
|
|
||||||
m_Layer: 0
|
|
||||||
m_Name: GameObject
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!114 &1883466099
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInternal: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 1883466098}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: e3f22e25c6d555d45b86d62ecaaf8895, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
--- !u!4 &1883466100
|
|
||||||
Transform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInternal: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 1883466098}
|
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
|
||||||
m_LocalPosition: {x: 1.6106011, y: 0.41596547, z: 1.608385}
|
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
|
||||||
m_Children: []
|
|
||||||
m_Father: {fileID: 0}
|
|
||||||
m_RootOrder: 2
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 57dce109462253f30bda1904173334b8
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: ec47b0ae95f0bc9ac90d793b3b8192e9
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
/*MIT License
|
|
||||||
|
|
||||||
Copyright(c) 2018 Vili Volčini / viliwonka
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEditor;
|
|
||||||
|
|
||||||
namespace DataStructures.ViliWonka.KDTree {
|
|
||||||
|
|
||||||
public struct KDBounds {
|
|
||||||
|
|
||||||
public Vector3 min;
|
|
||||||
public Vector3 max;
|
|
||||||
|
|
||||||
public Vector3 size {
|
|
||||||
|
|
||||||
get {
|
|
||||||
return max - min;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns unity bounds
|
|
||||||
public Bounds Bounds {
|
|
||||||
|
|
||||||
get {
|
|
||||||
return new Bounds(
|
|
||||||
(min + max) / 2,
|
|
||||||
(max - min)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Vector3 ClosestPoint(Vector3 point) {
|
|
||||||
|
|
||||||
// X axis
|
|
||||||
if(point.x < min.x) point.x = min.x;
|
|
||||||
else
|
|
||||||
if(point.x > max.x) point.x = max.x;
|
|
||||||
|
|
||||||
// Y axis
|
|
||||||
if(point.y < min.y) point.y = min.y;
|
|
||||||
else
|
|
||||||
if(point.y > max.y) point.y = max.y;
|
|
||||||
|
|
||||||
// Z axis
|
|
||||||
if(point.z < min.z) point.z = min.z;
|
|
||||||
else
|
|
||||||
if(point.z > max.z) point.z = max.z;
|
|
||||||
|
|
||||||
return point;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 8d2bf691fd08219d89c9c4d729a8d6d7
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
/*MIT License
|
|
||||||
|
|
||||||
Copyright(c) 2018 Vili Volčini / viliwonka
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace DataStructures.ViliWonka.KDTree {
|
|
||||||
|
|
||||||
public class KDNode {
|
|
||||||
|
|
||||||
public float partitionCoordinate;
|
|
||||||
public int partitionAxis = -1;
|
|
||||||
|
|
||||||
public KDNode negativeChild;
|
|
||||||
public KDNode positiveChild;
|
|
||||||
|
|
||||||
public int start;
|
|
||||||
public int end;
|
|
||||||
|
|
||||||
public int Count { get { return end - start; } }
|
|
||||||
|
|
||||||
public bool Leaf { get { return partitionAxis == -1; } }
|
|
||||||
|
|
||||||
public KDBounds bounds;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: f0f1ff21a62e87ca0a4a847161f67fbd
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 9065ed313aead20618eb497fa6c25bc9
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 59c04f18f4c9203109233947fa24b400
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
/*MIT License
|
|
||||||
|
|
||||||
Copyright(c) 2018 Vili Volčini / viliwonka
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
The object used for querying. This object should be persistent - re-used for querying.
|
|
||||||
Contains internal array for pooling, so that it doesn't generate (too much) garbage.
|
|
||||||
The array never down-sizes, only up-sizes, so the more you use this object, less garbage will it make over time.
|
|
||||||
|
|
||||||
Should be used only by 1 thread,
|
|
||||||
which means each thread should have it's own KDQuery object in order for querying to be thread safe.
|
|
||||||
|
|
||||||
KDQuery can query different KDTrees.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace DataStructures.ViliWonka.KDTree {
|
|
||||||
|
|
||||||
public partial class KDQuery {
|
|
||||||
|
|
||||||
protected KDQueryNode[] queueArray; // queue array
|
|
||||||
protected Heap.MinHeap<KDQueryNode> minHeap; //heap for k-nearest
|
|
||||||
protected int count = 0; // size of queue
|
|
||||||
protected int queryIndex = 0; // current index at stack
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns initialized node from stack that also acts as a pool
|
|
||||||
/// The returned reference to node stays in stack
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Reference to pooled node</returns>
|
|
||||||
private KDQueryNode PushGetQueue() {
|
|
||||||
|
|
||||||
KDQueryNode node = null;
|
|
||||||
|
|
||||||
if (count < queueArray.Length) {
|
|
||||||
|
|
||||||
if (queueArray[count] == null)
|
|
||||||
queueArray[count] = node = new KDQueryNode();
|
|
||||||
else
|
|
||||||
node = queueArray[count];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
// automatic resize of pool
|
|
||||||
Array.Resize(ref queueArray, queueArray.Length * 2);
|
|
||||||
node = queueArray[count] = new KDQueryNode();
|
|
||||||
}
|
|
||||||
|
|
||||||
count++;
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void PushToQueue(KDNode node, Vector3 tempClosestPoint) {
|
|
||||||
|
|
||||||
var queryNode = PushGetQueue();
|
|
||||||
queryNode.node = node;
|
|
||||||
queryNode.tempClosestPoint = tempClosestPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void PushToHeap(KDNode node, Vector3 tempClosestPoint, Vector3 queryPosition) {
|
|
||||||
|
|
||||||
var queryNode = PushGetQueue();
|
|
||||||
queryNode.node = node;
|
|
||||||
queryNode.tempClosestPoint = tempClosestPoint;
|
|
||||||
|
|
||||||
float sqrDist = Vector3.SqrMagnitude(tempClosestPoint - queryPosition);
|
|
||||||
queryNode.distance = sqrDist;
|
|
||||||
minHeap.PushObj(queryNode, sqrDist);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int LeftToProcess {
|
|
||||||
|
|
||||||
get {
|
|
||||||
return count - queryIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// just gets unprocessed node from stack
|
|
||||||
// increases queryIndex
|
|
||||||
protected KDQueryNode PopFromQueue() {
|
|
||||||
|
|
||||||
var node = queueArray[queryIndex];
|
|
||||||
queryIndex++;
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected KDQueryNode PopFromHeap() {
|
|
||||||
|
|
||||||
KDQueryNode heapNode = minHeap.PopObj();
|
|
||||||
|
|
||||||
queueArray[queryIndex]= heapNode;
|
|
||||||
queryIndex++;
|
|
||||||
|
|
||||||
return heapNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void Reset() {
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
queryIndex = 0;
|
|
||||||
minHeap.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public KDQuery(int queryNodesContainersInitialSize = 2048) {
|
|
||||||
queueArray = new KDQueryNode[queryNodesContainersInitialSize];
|
|
||||||
minHeap = new Heap.MinHeap<KDQueryNode>(queryNodesContainersInitialSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 7967af123067d1622a5c5fbc948b1f19
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
/*MIT License
|
|
||||||
|
|
||||||
Copyright(c) 2018 Vili Volčini / viliwonka
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define KDTREE_VISUAL_DEBUG
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace DataStructures.ViliWonka.KDTree {
|
|
||||||
|
|
||||||
public partial class KDQuery {
|
|
||||||
|
|
||||||
// uses gizmos
|
|
||||||
public void DrawLastQuery() {
|
|
||||||
|
|
||||||
Color start = Color.red;
|
|
||||||
Color end = Color.green;
|
|
||||||
|
|
||||||
start.a = 0.25f;
|
|
||||||
end.a = 0.25f;
|
|
||||||
|
|
||||||
for(int i = 0; i < queryIndex; i++) {
|
|
||||||
|
|
||||||
float val = i / (float)queryIndex;
|
|
||||||
|
|
||||||
Gizmos.color = Color.Lerp(end, start, val);
|
|
||||||
|
|
||||||
Bounds b = queueArray[i].node.bounds.Bounds;
|
|
||||||
|
|
||||||
Gizmos.DrawWireCube(b.center, b.size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: e2a2d436a25ed2ea89df09bc3572fb7d
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/*MIT License
|
|
||||||
|
|
||||||
Copyright(c) 2018 Vili Volčini / viliwonka
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEditor;
|
|
||||||
|
|
||||||
namespace DataStructures.ViliWonka.KDTree {
|
|
||||||
|
|
||||||
public class KDQueryNode {
|
|
||||||
|
|
||||||
public KDNode node;
|
|
||||||
public Vector3 tempClosestPoint;
|
|
||||||
public float distance;
|
|
||||||
|
|
||||||
public KDQueryNode() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public KDQueryNode(KDNode node, Vector3 tempClosestPoint) {
|
|
||||||
this.node = node;
|
|
||||||
this.tempClosestPoint = tempClosestPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 0db79addaf1dc6c12939c505533a7fe7
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
/*MIT License
|
|
||||||
|
|
||||||
Copyright(c) 2018 Vili Volčini / viliwonka
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace DataStructures.ViliWonka.KDTree {
|
|
||||||
|
|
||||||
using Heap;
|
|
||||||
|
|
||||||
public partial class KDQuery {
|
|
||||||
|
|
||||||
public void ClosestPoint(KDTree tree, Vector3 queryPosition, List<int> resultIndices, List<float> resultDistances = null) {
|
|
||||||
|
|
||||||
Reset();
|
|
||||||
|
|
||||||
Vector3[] points = tree.Points;
|
|
||||||
int[] permutation = tree.Permutation;
|
|
||||||
|
|
||||||
if (points.Length == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int smallestIndex = 0;
|
|
||||||
/// Smallest Squared Radius
|
|
||||||
float SSR = Single.PositiveInfinity;
|
|
||||||
|
|
||||||
|
|
||||||
var rootNode = tree.RootNode;
|
|
||||||
|
|
||||||
Vector3 rootClosestPoint = rootNode.bounds.ClosestPoint(queryPosition);
|
|
||||||
|
|
||||||
PushToHeap(rootNode, rootClosestPoint, queryPosition);
|
|
||||||
|
|
||||||
KDQueryNode queryNode = null;
|
|
||||||
KDNode node = null;
|
|
||||||
|
|
||||||
int partitionAxis;
|
|
||||||
float partitionCoord;
|
|
||||||
|
|
||||||
Vector3 tempClosestPoint;
|
|
||||||
|
|
||||||
// searching
|
|
||||||
while(minHeap.Count > 0) {
|
|
||||||
|
|
||||||
queryNode = PopFromHeap();
|
|
||||||
|
|
||||||
if(queryNode.distance > SSR)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
node = queryNode.node;
|
|
||||||
|
|
||||||
if(!node.Leaf) {
|
|
||||||
|
|
||||||
partitionAxis = node.partitionAxis;
|
|
||||||
partitionCoord = node.partitionCoordinate;
|
|
||||||
|
|
||||||
tempClosestPoint = queryNode.tempClosestPoint;
|
|
||||||
|
|
||||||
if((tempClosestPoint[partitionAxis] - partitionCoord) < 0) {
|
|
||||||
|
|
||||||
// we already know we are on the side of negative bound/node,
|
|
||||||
// so we don't need to test for distance
|
|
||||||
// push to stack for later querying
|
|
||||||
|
|
||||||
PushToHeap(node.negativeChild, tempClosestPoint, queryPosition);
|
|
||||||
// project the tempClosestPoint to other bound
|
|
||||||
tempClosestPoint[partitionAxis] = partitionCoord;
|
|
||||||
|
|
||||||
if(node.positiveChild.Count != 0) {
|
|
||||||
|
|
||||||
PushToHeap(node.positiveChild, tempClosestPoint, queryPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
// we already know we are on the side of positive bound/node,
|
|
||||||
// so we don't need to test for distance
|
|
||||||
// push to stack for later querying
|
|
||||||
|
|
||||||
PushToHeap(node.positiveChild, tempClosestPoint, queryPosition);
|
|
||||||
// project the tempClosestPoint to other bound
|
|
||||||
tempClosestPoint[partitionAxis] = partitionCoord;
|
|
||||||
|
|
||||||
if(node.positiveChild.Count != 0) {
|
|
||||||
|
|
||||||
PushToHeap(node.negativeChild, tempClosestPoint, queryPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
float sqrDist;
|
|
||||||
// LEAF
|
|
||||||
for(int i = node.start; i < node.end; i++) {
|
|
||||||
|
|
||||||
int index = permutation[i];
|
|
||||||
|
|
||||||
sqrDist = Vector3.SqrMagnitude(points[index] - queryPosition);
|
|
||||||
|
|
||||||
if(sqrDist <= SSR) {
|
|
||||||
|
|
||||||
SSR = sqrDist;
|
|
||||||
smallestIndex = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resultIndices.Add(smallestIndex);
|
|
||||||
|
|
||||||
if(resultDistances != null) {
|
|
||||||
resultDistances.Add(SSR);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 0c02618e93fdf8299bc09f6285de4d5e
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
/*MIT License
|
|
||||||
|
|
||||||
Copyright(c) 2018 Vili Volčini / viliwonka
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace DataStructures.ViliWonka.KDTree {
|
|
||||||
|
|
||||||
public partial class KDQuery {
|
|
||||||
|
|
||||||
public void Interval(KDTree tree, Vector3 min, Vector3 max, List<int> resultIndices) {
|
|
||||||
|
|
||||||
Reset();
|
|
||||||
|
|
||||||
Vector3[] points = tree.Points;
|
|
||||||
int[] permutation = tree.Permutation;
|
|
||||||
|
|
||||||
var rootNode = tree.RootNode;
|
|
||||||
|
|
||||||
PushToQueue(
|
|
||||||
|
|
||||||
rootNode,
|
|
||||||
rootNode.bounds.ClosestPoint((min + max) / 2)
|
|
||||||
);
|
|
||||||
|
|
||||||
KDQueryNode queryNode = null;
|
|
||||||
KDNode node = null;
|
|
||||||
|
|
||||||
|
|
||||||
// KD search with pruning (don't visit areas which distance is more away than range)
|
|
||||||
// Recursion done on Stack
|
|
||||||
while(LeftToProcess > 0) {
|
|
||||||
|
|
||||||
queryNode = PopFromQueue();
|
|
||||||
node = queryNode.node;
|
|
||||||
|
|
||||||
if(!node.Leaf) {
|
|
||||||
|
|
||||||
int partitionAxis = node.partitionAxis;
|
|
||||||
float partitionCoord = node.partitionCoordinate;
|
|
||||||
|
|
||||||
Vector3 tempClosestPoint = queryNode.tempClosestPoint;
|
|
||||||
|
|
||||||
if((tempClosestPoint[partitionAxis] - partitionCoord) < 0) {
|
|
||||||
|
|
||||||
// we already know we are inside negative bound/node,
|
|
||||||
// so we don't need to test for distance
|
|
||||||
// push to stack for later querying
|
|
||||||
|
|
||||||
// tempClosestPoint is inside negative side
|
|
||||||
// assign it to negativeChild
|
|
||||||
PushToQueue(node.negativeChild, tempClosestPoint);
|
|
||||||
|
|
||||||
tempClosestPoint[partitionAxis] = partitionCoord;
|
|
||||||
|
|
||||||
// testing other side
|
|
||||||
if(node.positiveChild.Count != 0
|
|
||||||
&& tempClosestPoint[partitionAxis] <= max[partitionAxis]) {
|
|
||||||
|
|
||||||
PushToQueue(node.positiveChild, tempClosestPoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
// we already know we are inside positive bound/node,
|
|
||||||
// so we don't need to test for distance
|
|
||||||
// push to stack for later querying
|
|
||||||
|
|
||||||
// tempClosestPoint is inside positive side
|
|
||||||
// assign it to positiveChild
|
|
||||||
PushToQueue(node.positiveChild, tempClosestPoint);
|
|
||||||
|
|
||||||
// project the tempClosestPoint to other bound
|
|
||||||
tempClosestPoint[partitionAxis] = partitionCoord;
|
|
||||||
|
|
||||||
// testing other side
|
|
||||||
if(node.negativeChild.Count != 0
|
|
||||||
&& tempClosestPoint[partitionAxis] >= min[partitionAxis]) {
|
|
||||||
|
|
||||||
PushToQueue(node.negativeChild, tempClosestPoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
// LEAF
|
|
||||||
|
|
||||||
// testing if node bounds are inside the query interval
|
|
||||||
if(node.bounds.min[0] >= min[0]
|
|
||||||
&& node.bounds.min[1] >= min[1]
|
|
||||||
&& node.bounds.min[2] >= min[2]
|
|
||||||
|
|
||||||
&& node.bounds.max[0] <= max[0]
|
|
||||||
&& node.bounds.max[1] <= max[1]
|
|
||||||
&& node.bounds.max[2] <= max[2]) {
|
|
||||||
|
|
||||||
for(int i = node.start; i < node.end; i++) {
|
|
||||||
|
|
||||||
resultIndices.Add(permutation[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
// node is not inside query interval, need to do test on each point separately
|
|
||||||
else {
|
|
||||||
|
|
||||||
for(int i = node.start; i < node.end; i++) {
|
|
||||||
|
|
||||||
int index = permutation[i];
|
|
||||||
|
|
||||||
Vector3 v = points[index];
|
|
||||||
|
|
||||||
if(v[0] >= min[0]
|
|
||||||
&& v[1] >= min[1]
|
|
||||||
&& v[2] >= min[2]
|
|
||||||
|
|
||||||
&& v[0] <= max[0]
|
|
||||||
&& v[1] <= max[1]
|
|
||||||
&& v[2] <= max[2]) {
|
|
||||||
|
|
||||||
resultIndices.Add(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 201cd9cbfb7b7005285e57eb971698cf
|
|
||||||
@@ -1,160 +0,0 @@
|
|||||||
/*MIT License
|
|
||||||
|
|
||||||
Copyright(c) 2018 Vili Volčini / viliwonka
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define KDTREE_VISUAL_DEBUG
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace DataStructures.ViliWonka.KDTree {
|
|
||||||
|
|
||||||
using Heap;
|
|
||||||
|
|
||||||
public partial class KDQuery {
|
|
||||||
|
|
||||||
SortedList<int, KSmallestHeap<int>> _heaps = new SortedList<int, KSmallestHeap<int>>();
|
|
||||||
/// <summary>
|
|
||||||
/// Returns indices to k closest points, and optionaly can return distances
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tree">Tree to do search on</param>
|
|
||||||
/// <param name="queryPosition">Position</param>
|
|
||||||
/// <param name="k">Max number of points</param>
|
|
||||||
/// <param name="resultIndices">List where resulting indices will be stored</param>
|
|
||||||
/// <param name="resultDistances">Optional list where resulting distances will be stored</param>
|
|
||||||
public void KNearest(KDTree tree, Vector3 queryPosition, int k, List<int> resultIndices, List<float> resultDistances = null) {
|
|
||||||
|
|
||||||
// pooled heap arrays
|
|
||||||
KSmallestHeap<int> kHeap;
|
|
||||||
|
|
||||||
_heaps.TryGetValue(k, out kHeap);
|
|
||||||
|
|
||||||
if(kHeap == null) {
|
|
||||||
|
|
||||||
kHeap = new KSmallestHeap<int>(k);
|
|
||||||
_heaps.Add(k, kHeap);
|
|
||||||
}
|
|
||||||
|
|
||||||
kHeap.Clear();
|
|
||||||
Reset();
|
|
||||||
|
|
||||||
Vector3[] points = tree.Points;
|
|
||||||
int[] permutation = tree.Permutation;
|
|
||||||
|
|
||||||
///Biggest Smallest Squared Radius
|
|
||||||
float BSSR = Single.PositiveInfinity;
|
|
||||||
|
|
||||||
var rootNode = tree.RootNode;
|
|
||||||
|
|
||||||
Vector3 rootClosestPoint = rootNode.bounds.ClosestPoint(queryPosition);
|
|
||||||
|
|
||||||
PushToHeap(rootNode, rootClosestPoint, queryPosition);
|
|
||||||
|
|
||||||
KDQueryNode queryNode = null;
|
|
||||||
KDNode node = null;
|
|
||||||
|
|
||||||
int partitionAxis;
|
|
||||||
float partitionCoord;
|
|
||||||
|
|
||||||
Vector3 tempClosestPoint;
|
|
||||||
|
|
||||||
// searching
|
|
||||||
while(minHeap.Count > 0) {
|
|
||||||
|
|
||||||
queryNode = PopFromHeap();
|
|
||||||
|
|
||||||
if(queryNode.distance > BSSR)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
node = queryNode.node;
|
|
||||||
|
|
||||||
if(!node.Leaf) {
|
|
||||||
|
|
||||||
partitionAxis = node.partitionAxis;
|
|
||||||
partitionCoord = node.partitionCoordinate;
|
|
||||||
|
|
||||||
tempClosestPoint = queryNode.tempClosestPoint;
|
|
||||||
|
|
||||||
if((tempClosestPoint[partitionAxis] - partitionCoord) < 0) {
|
|
||||||
|
|
||||||
// we already know we are on the side of negative bound/node,
|
|
||||||
// so we don't need to test for distance
|
|
||||||
// push to stack for later querying
|
|
||||||
|
|
||||||
PushToHeap(node.negativeChild, tempClosestPoint, queryPosition);
|
|
||||||
// project the tempClosestPoint to other bound
|
|
||||||
tempClosestPoint[partitionAxis] = partitionCoord;
|
|
||||||
|
|
||||||
if(node.positiveChild.Count != 0) {
|
|
||||||
|
|
||||||
PushToHeap(node.positiveChild, tempClosestPoint, queryPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
// we already know we are on the side of positive bound/node,
|
|
||||||
// so we don't need to test for distance
|
|
||||||
// push to stack for later querying
|
|
||||||
|
|
||||||
PushToHeap(node.positiveChild, tempClosestPoint, queryPosition);
|
|
||||||
// project the tempClosestPoint to other bound
|
|
||||||
tempClosestPoint[partitionAxis] = partitionCoord;
|
|
||||||
|
|
||||||
if(node.positiveChild.Count != 0) {
|
|
||||||
|
|
||||||
PushToHeap(node.negativeChild, tempClosestPoint, queryPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
float sqrDist;
|
|
||||||
// LEAF
|
|
||||||
for(int i = node.start; i < node.end; i++) {
|
|
||||||
|
|
||||||
int index = permutation[i];
|
|
||||||
|
|
||||||
sqrDist = Vector3.SqrMagnitude(points[index] - queryPosition);
|
|
||||||
|
|
||||||
if(sqrDist <= BSSR) {
|
|
||||||
|
|
||||||
kHeap.PushObj(index, sqrDist);
|
|
||||||
|
|
||||||
if(kHeap.Full) {
|
|
||||||
BSSR = kHeap.HeadValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
kHeap.FlushResult(resultIndices, resultDistances);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: b3a3e4ea20ad993c68c63d2dccd56e56
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
/*MIT License
|
|
||||||
|
|
||||||
Copyright(c) 2018 Vili Volčini / viliwonka
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace DataStructures.ViliWonka.KDTree {
|
|
||||||
|
|
||||||
public partial class KDQuery {
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Search by radius method.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tree">Tree to do search on</param>
|
|
||||||
/// <param name="queryPosition">Position</param>
|
|
||||||
/// <param name="queryRadius">Radius</param>
|
|
||||||
/// <param name="resultIndices">Initialized list, cleared.</param>
|
|
||||||
public void Radius(KDTree tree, Vector3 queryPosition, float queryRadius, List<int> resultIndices) {
|
|
||||||
|
|
||||||
Reset();
|
|
||||||
|
|
||||||
Vector3[] points = tree.Points;
|
|
||||||
int[] permutation = tree.Permutation;
|
|
||||||
|
|
||||||
float squaredRadius = queryRadius * queryRadius;
|
|
||||||
|
|
||||||
var rootNode = tree.RootNode;
|
|
||||||
|
|
||||||
PushToQueue(rootNode, rootNode.bounds.ClosestPoint(queryPosition));
|
|
||||||
|
|
||||||
KDQueryNode queryNode = null;
|
|
||||||
KDNode node = null;
|
|
||||||
|
|
||||||
// KD search with pruning (don't visit areas which distance is more away than range)
|
|
||||||
// Recursion done on Stack
|
|
||||||
while(LeftToProcess > 0) {
|
|
||||||
|
|
||||||
queryNode = PopFromQueue();
|
|
||||||
node = queryNode.node;
|
|
||||||
|
|
||||||
if(!node.Leaf) {
|
|
||||||
|
|
||||||
int partitionAxis = node.partitionAxis;
|
|
||||||
float partitionCoord = node.partitionCoordinate;
|
|
||||||
|
|
||||||
Vector3 tempClosestPoint = queryNode.tempClosestPoint;
|
|
||||||
|
|
||||||
if((tempClosestPoint[partitionAxis] - partitionCoord) < 0) {
|
|
||||||
|
|
||||||
// we already know we are inside negative bound/node,
|
|
||||||
// so we don't need to test for distance
|
|
||||||
// push to stack for later querying
|
|
||||||
|
|
||||||
// tempClosestPoint is inside negative side
|
|
||||||
// assign it to negativeChild
|
|
||||||
PushToQueue(node.negativeChild, tempClosestPoint);
|
|
||||||
|
|
||||||
tempClosestPoint[partitionAxis] = partitionCoord;
|
|
||||||
|
|
||||||
float sqrDist = Vector3.SqrMagnitude(tempClosestPoint - queryPosition);
|
|
||||||
|
|
||||||
// testing other side
|
|
||||||
if(node.positiveChild.Count != 0
|
|
||||||
&& sqrDist <= squaredRadius) {
|
|
||||||
|
|
||||||
PushToQueue(node.positiveChild, tempClosestPoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
// we already know we are inside positive bound/node,
|
|
||||||
// so we don't need to test for distance
|
|
||||||
// push to stack for later querying
|
|
||||||
|
|
||||||
// tempClosestPoint is inside positive side
|
|
||||||
// assign it to positiveChild
|
|
||||||
PushToQueue(node.positiveChild, tempClosestPoint);
|
|
||||||
|
|
||||||
// project the tempClosestPoint to other bound
|
|
||||||
tempClosestPoint[partitionAxis] = partitionCoord;
|
|
||||||
|
|
||||||
float sqrDist = Vector3.SqrMagnitude(tempClosestPoint - queryPosition);
|
|
||||||
|
|
||||||
// testing other side
|
|
||||||
if(node.negativeChild.Count != 0
|
|
||||||
&& sqrDist <= squaredRadius) {
|
|
||||||
|
|
||||||
PushToQueue(node.negativeChild, tempClosestPoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
// LEAF
|
|
||||||
for(int i = node.start; i < node.end; i++) {
|
|
||||||
|
|
||||||
int index = permutation[i];
|
|
||||||
|
|
||||||
if(Vector3.SqrMagnitude(points[index] - queryPosition) <= squaredRadius) {
|
|
||||||
|
|
||||||
resultIndices.Add(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 9ac26aab538b2e7b3934a1ef1e96549a
|
|
||||||
@@ -1,459 +0,0 @@
|
|||||||
/*MIT License
|
|
||||||
|
|
||||||
Copyright(c) 2018 Vili Volčini / viliwonka
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// change to !KDTREE_DUPLICATES
|
|
||||||
// if you know for sure you will not use duplicate coordinates (all unique)
|
|
||||||
#define KDTREE_DUPLICATES
|
|
||||||
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace DataStructures.ViliWonka.KDTree {
|
|
||||||
|
|
||||||
public class KDTree {
|
|
||||||
|
|
||||||
public KDNode RootNode { get; private set; }
|
|
||||||
|
|
||||||
public Vector3[] Points { get { return points; } } // points on which kd-tree will build on. This array will stay unchanged when re/building kdtree!
|
|
||||||
private Vector3[] points;
|
|
||||||
|
|
||||||
public int[] Permutation { get { return permutation; } } // index aray, that will be permuted
|
|
||||||
private int[] permutation;
|
|
||||||
|
|
||||||
public int Count { get; private set; }
|
|
||||||
|
|
||||||
private int maxPointsPerLeafNode = 32;
|
|
||||||
|
|
||||||
private KDNode[] kdNodesStack;
|
|
||||||
private int kdNodesCount = 0;
|
|
||||||
|
|
||||||
public KDTree(int maxPointsPerLeafNode = 32) {
|
|
||||||
|
|
||||||
Count = 0;
|
|
||||||
points = new Vector3[0];
|
|
||||||
permutation = new int[0];
|
|
||||||
|
|
||||||
kdNodesStack = new KDNode[64];
|
|
||||||
|
|
||||||
this.maxPointsPerLeafNode = maxPointsPerLeafNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public KDTree(Vector3[] points, int maxPointsPerLeafNode = 32) {
|
|
||||||
|
|
||||||
this.points = points;
|
|
||||||
this.permutation = new int[points.Length];
|
|
||||||
|
|
||||||
Count = points.Length;
|
|
||||||
kdNodesStack = new KDNode[64];
|
|
||||||
|
|
||||||
this.maxPointsPerLeafNode = maxPointsPerLeafNode;
|
|
||||||
|
|
||||||
Rebuild();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Build(Vector3[] newPoints, int maxPointsPerLeafNode = -1) {
|
|
||||||
|
|
||||||
SetCount(newPoints.Length);
|
|
||||||
|
|
||||||
for(int i = 0; i < Count; i++) {
|
|
||||||
points[i] = newPoints[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
Rebuild(maxPointsPerLeafNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Build(List<Vector3> newPoints, int maxPointsPerLeafNode = -1) {
|
|
||||||
|
|
||||||
SetCount(newPoints.Count);
|
|
||||||
|
|
||||||
for(int i = 0; i < Count; i++) {
|
|
||||||
points[i] = newPoints[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
Rebuild(maxPointsPerLeafNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Rebuild(int maxPointsPerLeafNode = -1) {
|
|
||||||
|
|
||||||
for(int i = 0; i < Count; i++) {
|
|
||||||
permutation[i] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(maxPointsPerLeafNode > 0) {
|
|
||||||
this.maxPointsPerLeafNode = maxPointsPerLeafNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
BuildTree();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetCount(int newSize) {
|
|
||||||
|
|
||||||
Count = newSize;
|
|
||||||
// upsize internal arrays
|
|
||||||
if(Count > points.Length) {
|
|
||||||
|
|
||||||
Array.Resize(ref points, Count);
|
|
||||||
Array.Resize(ref permutation, Count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuildTree() {
|
|
||||||
|
|
||||||
ResetKDNodeStack();
|
|
||||||
|
|
||||||
RootNode = GetKDNode();
|
|
||||||
RootNode.bounds = MakeBounds();
|
|
||||||
RootNode.start = 0;
|
|
||||||
RootNode.end = Count;
|
|
||||||
|
|
||||||
SplitNode(RootNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
KDNode GetKDNode() {
|
|
||||||
|
|
||||||
KDNode node = null;
|
|
||||||
|
|
||||||
if(kdNodesCount < kdNodesStack.Length) {
|
|
||||||
|
|
||||||
if(kdNodesStack[kdNodesCount] == null) {
|
|
||||||
kdNodesStack[kdNodesCount] = node = new KDNode();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
node = kdNodesStack[kdNodesCount];
|
|
||||||
node.partitionAxis = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
// automatic resize of KDNode pool array
|
|
||||||
Array.Resize(ref kdNodesStack, kdNodesStack.Length * 2);
|
|
||||||
node = kdNodesStack[kdNodesCount] = new KDNode();
|
|
||||||
}
|
|
||||||
|
|
||||||
kdNodesCount++;
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResetKDNodeStack() {
|
|
||||||
kdNodesCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// For calculating root node bounds
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Boundary of all Vector3 points</returns>
|
|
||||||
KDBounds MakeBounds() {
|
|
||||||
|
|
||||||
Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
|
|
||||||
Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
|
|
||||||
|
|
||||||
int even = Count & ~1; // calculate even Length
|
|
||||||
|
|
||||||
// min, max calculations
|
|
||||||
// 3n/2 calculations instead of 2n
|
|
||||||
for (int i0 = 0; i0 < even; i0 += 2) {
|
|
||||||
|
|
||||||
int i1 = i0 + 1;
|
|
||||||
|
|
||||||
// X Coords
|
|
||||||
if (points[i0].x > points[i1].x) {
|
|
||||||
// i0 is bigger, i1 is smaller
|
|
||||||
if (points[i1].x < min.x)
|
|
||||||
min.x = points[i1].x;
|
|
||||||
|
|
||||||
if (points[i0].x > max.x)
|
|
||||||
max.x = points[i0].x;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// i1 is smaller, i0 is bigger
|
|
||||||
if (points[i0].x < min.x)
|
|
||||||
min.x = points[i0].x;
|
|
||||||
|
|
||||||
if (points[i1].x > max.x)
|
|
||||||
max.x = points[i1].x;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Y Coords
|
|
||||||
if (points[i0].y > points[i1].y) {
|
|
||||||
// i0 is bigger, i1 is smaller
|
|
||||||
if (points[i1].y < min.y)
|
|
||||||
min.y = points[i1].y;
|
|
||||||
|
|
||||||
if (points[i0].y > max.y)
|
|
||||||
max.y = points[i0].y;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// i1 is smaller, i0 is bigger
|
|
||||||
if (points[i0].y < min.y)
|
|
||||||
min.y = points[i0].y;
|
|
||||||
|
|
||||||
if (points[i1].y > max.y)
|
|
||||||
max.y = points[i1].y;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Z Coords
|
|
||||||
if (points[i0].z > points[i1].z) {
|
|
||||||
// i0 is bigger, i1 is smaller
|
|
||||||
if (points[i1].z < min.z)
|
|
||||||
min.z = points[i1].z;
|
|
||||||
|
|
||||||
if (points[i0].z > max.z)
|
|
||||||
max.z = points[i0].z;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// i1 is smaller, i0 is bigger
|
|
||||||
if (points[i0].z < min.z)
|
|
||||||
min.z = points[i0].z;
|
|
||||||
|
|
||||||
if (points[i1].z > max.z)
|
|
||||||
max.z = points[i1].z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if array was odd, calculate also min/max for the last element
|
|
||||||
if(even != Count) {
|
|
||||||
// X
|
|
||||||
if (min.x > points[even].x)
|
|
||||||
min.x = points[even].x;
|
|
||||||
|
|
||||||
if (max.x < points[even].x)
|
|
||||||
max.x = points[even].x;
|
|
||||||
// Y
|
|
||||||
if (min.y > points[even].y)
|
|
||||||
min.y = points[even].y;
|
|
||||||
|
|
||||||
if (max.y < points[even].y)
|
|
||||||
max.y = points[even].y;
|
|
||||||
// Z
|
|
||||||
if (min.z > points[even].z)
|
|
||||||
min.z = points[even].z;
|
|
||||||
|
|
||||||
if (max.z < points[even].z)
|
|
||||||
max.z = points[even].z;
|
|
||||||
}
|
|
||||||
|
|
||||||
KDBounds b = new KDBounds();
|
|
||||||
b.min = min;
|
|
||||||
b.max = max;
|
|
||||||
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Recursive splitting procedure
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="parent">This is where root node goes</param>
|
|
||||||
/// <param name="depth"></param>
|
|
||||||
///
|
|
||||||
void SplitNode(KDNode parent) {
|
|
||||||
|
|
||||||
// center of bounding box
|
|
||||||
KDBounds parentBounds = parent.bounds;
|
|
||||||
Vector3 parentBoundsSize = parentBounds.size;
|
|
||||||
|
|
||||||
// Find axis where bounds are largest
|
|
||||||
int splitAxis = 0;
|
|
||||||
float axisSize = parentBoundsSize.x;
|
|
||||||
|
|
||||||
if (axisSize < parentBoundsSize.y) {
|
|
||||||
splitAxis = 1;
|
|
||||||
axisSize = parentBoundsSize.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (axisSize < parentBoundsSize.z) {
|
|
||||||
splitAxis = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Our axis min-max bounds
|
|
||||||
float boundsStart = parentBounds.min[splitAxis];
|
|
||||||
float boundsEnd = parentBounds.max[splitAxis];
|
|
||||||
|
|
||||||
// Calculate the spliting coords
|
|
||||||
float splitPivot = CalculatePivot(parent.start, parent.end, boundsStart, boundsEnd, splitAxis);
|
|
||||||
|
|
||||||
parent.partitionAxis = splitAxis;
|
|
||||||
parent.partitionCoordinate = splitPivot;
|
|
||||||
|
|
||||||
// 'Spliting' array to two subarrays
|
|
||||||
int splittingIndex = Partition(parent.start, parent.end, splitPivot, splitAxis);
|
|
||||||
|
|
||||||
// Negative / Left node
|
|
||||||
Vector3 negMax = parentBounds.max;
|
|
||||||
negMax[splitAxis] = splitPivot;
|
|
||||||
|
|
||||||
KDNode negNode = GetKDNode();
|
|
||||||
negNode.bounds = parentBounds;
|
|
||||||
negNode.bounds.max = negMax;
|
|
||||||
negNode.start = parent.start;
|
|
||||||
negNode.end = splittingIndex;
|
|
||||||
parent.negativeChild = negNode;
|
|
||||||
|
|
||||||
// Positive / Right node
|
|
||||||
Vector3 posMin = parentBounds.min;
|
|
||||||
posMin[splitAxis] = splitPivot;
|
|
||||||
|
|
||||||
KDNode posNode = GetKDNode();
|
|
||||||
posNode.bounds = parentBounds;
|
|
||||||
posNode.bounds.min = posMin;
|
|
||||||
posNode.start = splittingIndex;
|
|
||||||
posNode.end = parent.end;
|
|
||||||
parent.positiveChild = posNode;
|
|
||||||
|
|
||||||
// check if we are actually splitting it anything
|
|
||||||
// this if check enables duplicate coordinates, but makes construction a bit slower
|
|
||||||
#if KDTREE_DUPLICATES
|
|
||||||
if(negNode.Count != 0 && posNode.Count != 0) {
|
|
||||||
#endif
|
|
||||||
// Constraint function deciding if split should be continued
|
|
||||||
if(ContinueSplit(negNode))
|
|
||||||
SplitNode(negNode);
|
|
||||||
|
|
||||||
|
|
||||||
if(ContinueSplit(posNode))
|
|
||||||
SplitNode(posNode);
|
|
||||||
|
|
||||||
#if KDTREE_DUPLICATES
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sliding midpoint splitting pivot calculation
|
|
||||||
/// 1. First splits node to two equal parts (midPoint)
|
|
||||||
/// 2. Checks if elements are in both sides of splitted bounds
|
|
||||||
/// 3a. If they are, just return midPoint
|
|
||||||
/// 3b. If they are not, then points are only on left or right bound.
|
|
||||||
/// 4. Move the splitting pivot so that it shrinks part with points completely (calculate min or max dependent) and return.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="start"></param>
|
|
||||||
/// <param name="end"></param>
|
|
||||||
/// <param name="boundsStart"></param>
|
|
||||||
/// <param name="boundsEnd"></param>
|
|
||||||
/// <param name="axis"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
float CalculatePivot(int start, int end, float boundsStart, float boundsEnd, int axis) {
|
|
||||||
|
|
||||||
//! sliding midpoint rule
|
|
||||||
float midPoint = (boundsStart + boundsEnd) / 2f;
|
|
||||||
|
|
||||||
bool negative = false;
|
|
||||||
bool positive = false;
|
|
||||||
|
|
||||||
float negMax = Single.MinValue;
|
|
||||||
float posMin = Single.MaxValue;
|
|
||||||
|
|
||||||
// this for loop section is used both for sorted and unsorted data
|
|
||||||
for (int i = start; i < end; i++) {
|
|
||||||
|
|
||||||
if (points[permutation[i]][axis] < midPoint)
|
|
||||||
negative = true;
|
|
||||||
else
|
|
||||||
positive = true;
|
|
||||||
|
|
||||||
if (negative == true && positive == true)
|
|
||||||
return midPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (negative) {
|
|
||||||
|
|
||||||
for (int i = start; i < end; i++)
|
|
||||||
if (negMax < points[permutation[i]][axis])
|
|
||||||
negMax = points[permutation[i]][axis];
|
|
||||||
|
|
||||||
return negMax;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
for (int i = start; i < end; i++)
|
|
||||||
if (posMin > points[permutation[i]][axis])
|
|
||||||
posMin = points[permutation[i]][axis];
|
|
||||||
|
|
||||||
return posMin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Similar to Hoare partitioning algorithm (used in Quick Sort)
|
|
||||||
/// Modification: pivot is not left-most element but is instead argument of function
|
|
||||||
/// Calculates splitting index and partially sorts elements (swaps them until they are on correct side - depending on pivot)
|
|
||||||
/// Complexity: O(n)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="start">Start index</param>
|
|
||||||
/// <param name="end">End index</param>
|
|
||||||
/// <param name="partitionPivot">Pivot that decides boundary between left and right</param>
|
|
||||||
/// <param name="axis">Axis of this pivoting</param>
|
|
||||||
/// <returns>
|
|
||||||
/// Returns splitting index that subdivides array into 2 smaller arrays
|
|
||||||
/// left = [start, pivot),
|
|
||||||
/// right = [pivot, end)
|
|
||||||
/// </returns>
|
|
||||||
int Partition(int start, int end, float partitionPivot, int axis) {
|
|
||||||
|
|
||||||
// note: increasing right pointer is actually decreasing!
|
|
||||||
int LP = start - 1; // left pointer (negative side)
|
|
||||||
int RP = end; // right pointer (positive side)
|
|
||||||
|
|
||||||
int temp; // temporary var for swapping permutation indexes
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
|
|
||||||
do {
|
|
||||||
// move from left to the right until "out of bounds" value is found
|
|
||||||
LP++;
|
|
||||||
}
|
|
||||||
while (LP < RP && points[permutation[LP]][axis] < partitionPivot);
|
|
||||||
|
|
||||||
do {
|
|
||||||
// move from right to the left until "out of bounds" value found
|
|
||||||
RP--;
|
|
||||||
}
|
|
||||||
while (LP < RP && points[permutation[RP]][axis] >= partitionPivot);
|
|
||||||
|
|
||||||
if (LP < RP) {
|
|
||||||
// swap
|
|
||||||
temp = permutation[LP];
|
|
||||||
permutation[LP] = permutation[RP];
|
|
||||||
permutation[RP] = temp;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
return LP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constraint function. You can add custom constraints here - if you have some other data/classes binded to Vector3 points
|
|
||||||
/// Can hardcode it into
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="node"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
bool ContinueSplit(KDNode node) {
|
|
||||||
|
|
||||||
return (node.Count > maxPointsPerLeafNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: cb2a53f24c1d57ed6adef63d87b95550
|
|
||||||
@@ -6,6 +6,9 @@ using static PSXSplash.RuntimeCode.TextureQuantizer;
|
|||||||
namespace PSXSplash.RuntimeCode
|
namespace PSXSplash.RuntimeCode
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the bit depth of a PSX texture.
|
||||||
|
/// </summary>
|
||||||
public enum PSXBPP
|
public enum PSXBPP
|
||||||
{
|
{
|
||||||
TEX_4BIT = 4,
|
TEX_4BIT = 4,
|
||||||
@@ -13,38 +16,61 @@ namespace PSXSplash.RuntimeCode
|
|||||||
TEX_16BIT = 15
|
TEX_16BIT = 15
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a pixel in VRAM with RGB components and a semi-transparency flag.
|
||||||
|
/// </summary>
|
||||||
public struct VRAMPixel
|
public struct VRAMPixel
|
||||||
{
|
{
|
||||||
private ushort r; // 0-4 bits
|
private ushort r; // 0-4 bits
|
||||||
private ushort g; // 5-9 bits
|
private ushort g; // 5-9 bits
|
||||||
private ushort b; // 10-14 bits
|
private ushort b; // 10-14 bits
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Red component (0-4 bits).
|
||||||
|
/// </summary>
|
||||||
public ushort R
|
public ushort R
|
||||||
{
|
{
|
||||||
get => r;
|
get => r;
|
||||||
set => r = (ushort)(value & 0b11111);
|
set => r = (ushort)(value & 0b11111);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Green component (0-4 bits).
|
||||||
|
/// </summary>
|
||||||
public ushort G
|
public ushort G
|
||||||
{
|
{
|
||||||
get => g;
|
get => g;
|
||||||
set => g = (ushort)(value & 0b11111);
|
set => g = (ushort)(value & 0b11111);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Blue component (0-4 bits).
|
||||||
|
/// </summary>
|
||||||
public ushort B
|
public ushort B
|
||||||
{
|
{
|
||||||
get => b;
|
get => b;
|
||||||
set => b = (ushort)(value & 0b11111);
|
set => b = (ushort)(value & 0b11111);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether the pixel is semi-transparent (15th bit).
|
||||||
|
/// </summary>
|
||||||
public bool SemiTransparent { get; set; } // 15th bit
|
public bool SemiTransparent { get; set; } // 15th bit
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Packs the RGB components and semi-transparency flag into a single ushort value.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The packed ushort value.</returns>
|
||||||
public ushort Pack()
|
public ushort Pack()
|
||||||
{
|
{
|
||||||
return (ushort)((r << 11) | (g << 6) | (b << 1) | (SemiTransparent ? 1 : 0));
|
return (ushort)((r << 11) | (g << 6) | (b << 1) | (SemiTransparent ? 1 : 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unpacks the RGB components and semi-transparency flag from a packed ushort value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="packedValue">The packed ushort value.</param>
|
||||||
public void Unpack(ushort packedValue)
|
public void Unpack(ushort packedValue)
|
||||||
{
|
{
|
||||||
r = (ushort)((packedValue >> 11) & 0b11111);
|
r = (ushort)((packedValue >> 11) & 0b11111);
|
||||||
@@ -54,12 +80,14 @@ namespace PSXSplash.RuntimeCode
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a PSX texture with various bit depths and provides methods to create and manipulate the texture.
|
||||||
|
/// </summary>
|
||||||
public class PSXTexture2D
|
public class PSXTexture2D
|
||||||
{
|
{
|
||||||
public int Width { get; set; }
|
public int Width { get; set; }
|
||||||
public int Height { get; set; }
|
public int Height { get; set; }
|
||||||
public int[] Pixels { get; set; }
|
public int[] PixelIndices { get; set; }
|
||||||
public List<VRAMPixel> ColorPalette = new List<VRAMPixel>();
|
public List<VRAMPixel> ColorPalette = new List<VRAMPixel>();
|
||||||
public PSXBPP BitDepth { get; set; }
|
public PSXBPP BitDepth { get; set; }
|
||||||
private int _maxColors;
|
private int _maxColors;
|
||||||
@@ -67,7 +95,12 @@ namespace PSXSplash.RuntimeCode
|
|||||||
// Used only for 16bpp
|
// Used only for 16bpp
|
||||||
public ushort[] ImageData { get; set; }
|
public ushort[] ImageData { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a PSX texture from a given Texture2D with the specified bit depth.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="inputTexture">The input Texture2D.</param>
|
||||||
|
/// <param name="bitDepth">The desired bit depth for the PSX texture.</param>
|
||||||
|
/// <returns>The created PSXTexture2D.</returns>
|
||||||
public static PSXTexture2D CreateFromTexture2D(Texture2D inputTexture, PSXBPP bitDepth)
|
public static PSXTexture2D CreateFromTexture2D(Texture2D inputTexture, PSXBPP bitDepth)
|
||||||
{
|
{
|
||||||
PSXTexture2D psxTex = new PSXTexture2D();
|
PSXTexture2D psxTex = new PSXTexture2D();
|
||||||
@@ -76,6 +109,7 @@ namespace PSXSplash.RuntimeCode
|
|||||||
psxTex.Height = inputTexture.height;
|
psxTex.Height = inputTexture.height;
|
||||||
psxTex.BitDepth = bitDepth;
|
psxTex.BitDepth = bitDepth;
|
||||||
|
|
||||||
|
|
||||||
if (bitDepth == PSXBPP.TEX_16BIT)
|
if (bitDepth == PSXBPP.TEX_16BIT)
|
||||||
{
|
{
|
||||||
psxTex.ImageData = new ushort[inputTexture.width * inputTexture.height];
|
psxTex.ImageData = new ushort[inputTexture.width * inputTexture.height];
|
||||||
@@ -101,12 +135,12 @@ namespace PSXSplash.RuntimeCode
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
psxTex.Pixels = new int[psxTex.Width * psxTex.Height];
|
psxTex.PixelIndices = new int[psxTex.Width * psxTex.Height];
|
||||||
for (int x = 0; x < psxTex.Width; x++)
|
for (int x = 0; x < psxTex.Width; x++)
|
||||||
{
|
{
|
||||||
for (int y = 0; y < psxTex.Height; y++)
|
for (int y = 0; y < psxTex.Height; y++)
|
||||||
{
|
{
|
||||||
psxTex.Pixels[x + y * psxTex.Width] = result.Indices[x, y];
|
psxTex.PixelIndices[x + y * psxTex.Width] = result.Indices[x, y];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +148,11 @@ namespace PSXSplash.RuntimeCode
|
|||||||
return psxTex;
|
return psxTex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a preview Texture2D from the PSX texture.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The generated preview Texture2D.</returns>
|
||||||
public Texture2D GeneratePreview()
|
public Texture2D GeneratePreview()
|
||||||
{
|
{
|
||||||
Texture2D tex = new Texture2D(Width, Height);
|
Texture2D tex = new Texture2D(Width, Height);
|
||||||
@@ -144,7 +183,7 @@ namespace PSXSplash.RuntimeCode
|
|||||||
{
|
{
|
||||||
for (int x = 0; x < Width; x++)
|
for (int x = 0; x < Width; x++)
|
||||||
{
|
{
|
||||||
int pixel = Pixels[y * Width + x];
|
int pixel = PixelIndices[y * Width + x];
|
||||||
VRAMPixel color = ColorPalette[pixel];
|
VRAMPixel color = ColorPalette[pixel];
|
||||||
|
|
||||||
float r = color.R / 31f;
|
float r = color.R / 31f;
|
||||||
@@ -159,6 +198,10 @@ namespace PSXSplash.RuntimeCode
|
|||||||
return tex;
|
return tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a VRAM preview Texture2D from the PSX texture.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The generated VRAM preview Texture2D.</returns>
|
||||||
public Texture2D GenerateVramPreview()
|
public Texture2D GenerateVramPreview()
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -184,17 +227,17 @@ namespace PSXSplash.RuntimeCode
|
|||||||
|
|
||||||
if (BitDepth == PSXBPP.TEX_4BIT)
|
if (BitDepth == PSXBPP.TEX_4BIT)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < Pixels.Length; i += 4)
|
for (int i = 0; i < PixelIndices.Length; i += 4)
|
||||||
{
|
{
|
||||||
ushort packed = (ushort)((Pixels[i] << 12) | (Pixels[i + 1] << 8) | (Pixels[i + 2] << 4) | Pixels[i + 3]);
|
ushort packed = (ushort)((PixelIndices[i] << 12) | (PixelIndices[i + 1] << 8) | (PixelIndices[i + 2] << 4) | PixelIndices[i + 3]);
|
||||||
packedValues.Add(packed);
|
packedValues.Add(packed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (BitDepth == PSXBPP.TEX_8BIT)
|
else if (BitDepth == PSXBPP.TEX_8BIT)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < Pixels.Length; i += 2)
|
for (int i = 0; i < PixelIndices.Length; i += 2)
|
||||||
{
|
{
|
||||||
ushort packed = (ushort)((Pixels[i] << 8) | Pixels[i + 1]);
|
ushort packed = (ushort)((PixelIndices[i] << 8) | PixelIndices[i + 1]);
|
||||||
packedValues.Add(packed);
|
packedValues.Add(packed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user