mirror of
https://gitgud.io/AbstractConcept/rimworld-animation-studio.git
synced 2024-08-15 00:43:27 +00:00
Initial commit
This commit is contained in:
commit
3c7cc0c973
8391 changed files with 704313 additions and 0 deletions
|
@ -0,0 +1,20 @@
|
|||
// -----------------------------------------------------------------------
|
||||
// <copyright file="ISmoother.cs">
|
||||
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace UnityEngine.U2D.Animation.TriangleNet
|
||||
.Smoothing
|
||||
{
|
||||
using Animation.TriangleNet.Meshing;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for mesh smoothers.
|
||||
/// </summary>
|
||||
internal interface ISmoother
|
||||
{
|
||||
void Smooth(IMesh mesh);
|
||||
void Smooth(IMesh mesh, int limit);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 35740bedfbcef470ab44b7b96930602b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,175 @@
|
|||
// -----------------------------------------------------------------------
|
||||
// <copyright file="SimpleSmoother.cs" company="">
|
||||
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace UnityEngine.U2D.Animation.TriangleNet
|
||||
.Smoothing
|
||||
{
|
||||
using System.Linq;
|
||||
using Animation.TriangleNet.Geometry;
|
||||
using Animation.TriangleNet.Meshing;
|
||||
using Animation.TriangleNet.Topology.DCEL;
|
||||
using Animation.TriangleNet.Voronoi;
|
||||
|
||||
/// <summary>
|
||||
/// Simple mesh smoother implementation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Vertices wich should not move (e.g. segment vertices) MUST have a
|
||||
/// boundary mark greater than 0.
|
||||
/// </remarks>
|
||||
internal class SimpleSmoother : ISmoother
|
||||
{
|
||||
TrianglePool pool;
|
||||
Configuration config;
|
||||
|
||||
IVoronoiFactory factory;
|
||||
|
||||
ConstraintOptions options;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SimpleSmoother" /> class.
|
||||
/// </summary>
|
||||
public SimpleSmoother()
|
||||
: this(new VoronoiFactory())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SimpleSmoother" /> class.
|
||||
/// </summary>
|
||||
public SimpleSmoother(IVoronoiFactory factory)
|
||||
{
|
||||
this.factory = factory;
|
||||
this.pool = new TrianglePool();
|
||||
|
||||
this.config = new Configuration(
|
||||
() => RobustPredicates.Default,
|
||||
() => pool.Restart());
|
||||
|
||||
this.options = new ConstraintOptions() { ConformingDelaunay = true };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SimpleSmoother" /> class.
|
||||
/// </summary>
|
||||
/// <param name="factory">Voronoi object factory.</param>
|
||||
/// <param name="config">Configuration.</param>
|
||||
public SimpleSmoother(IVoronoiFactory factory, Configuration config)
|
||||
{
|
||||
this.factory = factory;
|
||||
this.config = config;
|
||||
|
||||
this.options = new ConstraintOptions() { ConformingDelaunay = true };
|
||||
}
|
||||
|
||||
public void Smooth(IMesh mesh)
|
||||
{
|
||||
Smooth(mesh, 10);
|
||||
}
|
||||
|
||||
public void Smooth(IMesh mesh, int limit)
|
||||
{
|
||||
var smoothedMesh = (Mesh)mesh;
|
||||
|
||||
var mesher = new GenericMesher(config);
|
||||
var predicates = config.Predicates();
|
||||
|
||||
// The smoother should respect the mesh segment splitting behavior.
|
||||
this.options.SegmentSplitting = smoothedMesh.behavior.NoBisect;
|
||||
|
||||
// Take a few smoothing rounds (Lloyd's algorithm).
|
||||
for (int i = 0; i < limit; i++)
|
||||
{
|
||||
Step(smoothedMesh, factory, predicates);
|
||||
|
||||
// Actually, we only want to rebuild, if the mesh is no longer
|
||||
// Delaunay. Flipping edges could be the right choice instead
|
||||
// of re-triangulating...
|
||||
smoothedMesh = (Mesh)mesher.Triangulate(Rebuild(smoothedMesh), options);
|
||||
|
||||
factory.Reset();
|
||||
}
|
||||
|
||||
smoothedMesh.CopyTo((Mesh)mesh);
|
||||
}
|
||||
|
||||
private void Step(Mesh mesh, IVoronoiFactory factory, IPredicates predicates)
|
||||
{
|
||||
var voronoi = new BoundedVoronoi(mesh, factory, predicates);
|
||||
|
||||
if (!voronoi.IsConsistent())
|
||||
return;
|
||||
|
||||
double x, y;
|
||||
|
||||
foreach (var face in voronoi.Faces)
|
||||
{
|
||||
if (face.generator.label == 0)
|
||||
{
|
||||
Centroid(face, out x, out y);
|
||||
|
||||
face.generator.x = x;
|
||||
face.generator.y = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the centroid of a polygon.
|
||||
/// </summary>
|
||||
private void Centroid(Face face, out double x, out double y)
|
||||
{
|
||||
double ai, atmp = 0, xtmp = 0, ytmp = 0;
|
||||
|
||||
var edge = face.Edge;
|
||||
var first = edge.Next.ID;
|
||||
|
||||
Point p, q;
|
||||
|
||||
do
|
||||
{
|
||||
p = edge.Origin;
|
||||
q = edge.Twin.Origin;
|
||||
|
||||
ai = p.x * q.y - q.x * p.y;
|
||||
atmp += ai;
|
||||
xtmp += (q.x + p.x) * ai;
|
||||
ytmp += (q.y + p.y) * ai;
|
||||
|
||||
edge = edge.Next;
|
||||
}
|
||||
while (edge.Next.ID != first);
|
||||
|
||||
x = xtmp / (3 * atmp);
|
||||
y = ytmp / (3 * atmp);
|
||||
|
||||
//area = atmp / 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rebuild the input geometry.
|
||||
/// </summary>
|
||||
private Polygon Rebuild(Mesh mesh)
|
||||
{
|
||||
var data = new Polygon(mesh.vertices.Count);
|
||||
|
||||
foreach (var v in mesh.vertices.Values)
|
||||
{
|
||||
// Reset to input vertex.
|
||||
v.type = VertexType.InputVertex;
|
||||
|
||||
data.Points.Add(v);
|
||||
}
|
||||
|
||||
data.Segments.AddRange(mesh.subsegs.Values.Cast<ISegment>());
|
||||
|
||||
data.Holes.AddRange(mesh.holes);
|
||||
data.Regions.AddRange(mesh.regions);
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d0481896be8a94a678efd967e5309d04
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,201 @@
|
|||
namespace UnityEngine.U2D.Animation.TriangleNet
|
||||
.Smoothing
|
||||
{
|
||||
using System;
|
||||
using Animation.TriangleNet.Topology.DCEL;
|
||||
using Animation.TriangleNet.Voronoi;
|
||||
|
||||
/// <summary>
|
||||
/// Factory which re-uses objects in the smoothing loop to enhance performance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See <see cref="SimpleSmoother"/>.
|
||||
/// </remarks>
|
||||
class VoronoiFactory : IVoronoiFactory
|
||||
{
|
||||
ObjectPool<Vertex> vertices;
|
||||
ObjectPool<HalfEdge> edges;
|
||||
ObjectPool<Face> faces;
|
||||
|
||||
public VoronoiFactory()
|
||||
{
|
||||
vertices = new ObjectPool<Vertex>();
|
||||
edges = new ObjectPool<HalfEdge>();
|
||||
faces = new ObjectPool<Face>();
|
||||
}
|
||||
|
||||
public void Initialize(int vertexCount, int edgeCount, int faceCount)
|
||||
{
|
||||
vertices.Capacity = vertexCount;
|
||||
edges.Capacity = edgeCount;
|
||||
faces.Capacity = faceCount;
|
||||
|
||||
for (int i = vertices.Count; i < vertexCount; i++)
|
||||
{
|
||||
vertices.Put(new Vertex(0, 0));
|
||||
}
|
||||
|
||||
|
||||
for (int i = edges.Count; i < edgeCount; i++)
|
||||
{
|
||||
edges.Put(new HalfEdge(null));
|
||||
}
|
||||
|
||||
for (int i = faces.Count; i < faceCount; i++)
|
||||
{
|
||||
faces.Put(new Face(null));
|
||||
}
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
vertices.Release();
|
||||
edges.Release();
|
||||
faces.Release();
|
||||
}
|
||||
|
||||
public Vertex CreateVertex(double x, double y)
|
||||
{
|
||||
Vertex vertex;
|
||||
|
||||
if (vertices.TryGet(out vertex))
|
||||
{
|
||||
vertex.x = x;
|
||||
vertex.y = y;
|
||||
vertex.leaving = null;
|
||||
|
||||
return vertex;
|
||||
}
|
||||
|
||||
vertex = new Vertex(x, y);
|
||||
|
||||
vertices.Put(vertex);
|
||||
|
||||
return vertex;
|
||||
}
|
||||
|
||||
public HalfEdge CreateHalfEdge(Vertex origin, Face face)
|
||||
{
|
||||
HalfEdge edge;
|
||||
|
||||
if (edges.TryGet(out edge))
|
||||
{
|
||||
edge.origin = origin;
|
||||
edge.face = face;
|
||||
edge.next = null;
|
||||
edge.twin = null;
|
||||
|
||||
if (face != null && face.edge == null)
|
||||
{
|
||||
face.edge = edge;
|
||||
}
|
||||
|
||||
return edge;
|
||||
}
|
||||
|
||||
edge = new HalfEdge(origin, face);
|
||||
|
||||
edges.Put(edge);
|
||||
|
||||
return edge;
|
||||
}
|
||||
|
||||
public Face CreateFace(Geometry.Vertex vertex)
|
||||
{
|
||||
Face face;
|
||||
|
||||
if (faces.TryGet(out face))
|
||||
{
|
||||
face.id = vertex.id;
|
||||
face.generator = vertex;
|
||||
face.edge = null;
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
face = new Face(vertex);
|
||||
|
||||
faces.Put(face);
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
class ObjectPool<T> where T : class
|
||||
{
|
||||
int index, count;
|
||||
|
||||
T[] pool;
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return count; }
|
||||
}
|
||||
|
||||
|
||||
public int Capacity
|
||||
{
|
||||
get { return this.pool.Length; }
|
||||
set { Resize(value); }
|
||||
}
|
||||
|
||||
public ObjectPool(int capacity = 3)
|
||||
{
|
||||
this.index = 0;
|
||||
this.count = 0;
|
||||
|
||||
this.pool = new T[capacity];
|
||||
}
|
||||
|
||||
public ObjectPool(T[] pool)
|
||||
{
|
||||
this.index = 0;
|
||||
this.count = 0;
|
||||
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
public bool TryGet(out T obj)
|
||||
{
|
||||
if (this.index < this.count)
|
||||
{
|
||||
obj = this.pool[this.index++];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
obj = null;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Put(T obj)
|
||||
{
|
||||
var capacity = this.pool.Length;
|
||||
|
||||
if (capacity <= this.count)
|
||||
{
|
||||
Resize(2 * capacity);
|
||||
}
|
||||
|
||||
this.pool[this.count++] = obj;
|
||||
|
||||
this.index++;
|
||||
}
|
||||
|
||||
public void Release()
|
||||
{
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
private void Resize(int size)
|
||||
{
|
||||
if (size > this.count)
|
||||
{
|
||||
Array.Resize(ref this.pool, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fc487a3a8092e46c0879d9e74ba443aa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue