mirror of
https://github.com/simtactics/mysimulation.git
synced 2025-07-07 07:00:33 -04:00
Removed NioTSO client and server
- NioTSO client isn't needed because we're using RayLib - Added FreeSO's API server to handle most backend operations
This commit is contained in:
parent
f12ba1502b
commit
22191ce648
591 changed files with 53264 additions and 3362 deletions
253
server/tso.common/WorldGeometry/MeshProjector.cs
Executable file
253
server/tso.common/WorldGeometry/MeshProjector.cs
Executable file
|
@ -0,0 +1,253 @@
|
|||
using FSO.SimAntics.Model.Routing;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace FSO.Common.WorldGeometry
|
||||
{
|
||||
/// <summary>
|
||||
/// Projects one mesh onto another mesh on a given axis, potentially with an offset from the surface.
|
||||
/// Example use case: Projecting a road onto a terrain mesh
|
||||
/// </summary>
|
||||
public class MeshProjector
|
||||
{
|
||||
public MeshProjector(IEnumerable<BaseMeshTriangle> baseMesh, IEnumerable<MeshTriangle> projMesh)
|
||||
{
|
||||
foreach (var tri in baseMesh) tri.GenBounds();
|
||||
foreach (var tri in projMesh) tri.GenBounds();
|
||||
|
||||
BaseMesh = baseMesh;
|
||||
ProjectMesh = projMesh;
|
||||
|
||||
BaseSet = BaseTriangleSet.RoughBalanced(baseMesh.ToList());
|
||||
}
|
||||
|
||||
IEnumerable<BaseMeshTriangle> BaseMesh;
|
||||
BaseTriangleSet BaseSet;
|
||||
IEnumerable<MeshTriangle> ProjectMesh;
|
||||
|
||||
public List<int> Indices;
|
||||
public List<MeshPoint> Vertices;
|
||||
|
||||
public void Project()
|
||||
{
|
||||
Indices = new List<int>();
|
||||
Vertices = new List<MeshPoint>();
|
||||
//find list of potential intersect tris for a projtri
|
||||
//build clipping edges for projtri
|
||||
|
||||
foreach (var projTri in ProjectMesh)
|
||||
{
|
||||
//find candidate baseTris
|
||||
var candidates = BaseSet.AllIntersect(projTri);
|
||||
foreach (var baseTri in candidates)
|
||||
{
|
||||
//if (projTri.RoughIntersects(baseTri))
|
||||
//{
|
||||
ClipTriangles(baseTri, projTri, Vertices, Indices);
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ClipTriangles(BaseMeshTriangle baseTri, MeshTriangle projTri, List<MeshPoint> outverts, List<int> inds)
|
||||
{
|
||||
//Sutherland–Hodgman algorithm
|
||||
//clip a triangle against another by iteratively clipping each edge of the second one
|
||||
|
||||
//we want to clip against base tri
|
||||
var outputList = new MeshPolygon(projTri);
|
||||
var basePlane = new Plane(baseTri.Vertices[0], baseTri.Vertices[1], baseTri.Vertices[2]);
|
||||
|
||||
for (int i=0; i<3; i++)
|
||||
{
|
||||
if (outputList.Points.Count == 0) return;
|
||||
var inputList = outputList;
|
||||
var edge = new ClipEdge(baseTri.Vertices[i], baseTri.Vertices[(i + 1) % 3]);
|
||||
outputList = new MeshPolygon();
|
||||
var lastPoint = inputList.Points.Last();
|
||||
int j = inputList.Points.Count-1;
|
||||
foreach (var point in inputList.Points)
|
||||
{
|
||||
if (!edge.ShouldClip(point.Position))
|
||||
{
|
||||
if (edge.ShouldClip(lastPoint.Position))
|
||||
{
|
||||
outputList.Points.Add(edge.IntersectLine(inputList, j));
|
||||
}
|
||||
//we still need to project the point onto the surface...
|
||||
var ray = new Ray(point.Position, new Vector3(0, -1, 0));
|
||||
var intersect2 = ray.Intersects(basePlane);
|
||||
if (intersect2 == null) {
|
||||
ray.Direction *= -1;
|
||||
intersect2 = ray.Intersects(basePlane);
|
||||
if (intersect2 == null) { }
|
||||
intersect2 = -(intersect2 ?? 0f);
|
||||
}
|
||||
point.Position.Y -= intersect2.Value;
|
||||
outputList.Points.Add(point);
|
||||
} else
|
||||
{
|
||||
if (!edge.ShouldClip(lastPoint.Position))
|
||||
{
|
||||
outputList.Points.Add(edge.IntersectLine(inputList, j));
|
||||
}
|
||||
}
|
||||
j = (j + 1) % inputList.Points.Count;
|
||||
lastPoint = point;
|
||||
}
|
||||
}
|
||||
|
||||
if (outputList.Points.Count < 3) return; //?
|
||||
|
||||
outputList.Triangulate(outverts, inds);
|
||||
}
|
||||
}
|
||||
|
||||
public class ClipEdge
|
||||
{
|
||||
Vector3 EdgeVec;
|
||||
Vector2 DotVec;
|
||||
Vector3 EdgePos;
|
||||
Vector2 EdgePos2;
|
||||
|
||||
public ClipEdge(Vector3 from, Vector3 to)
|
||||
{
|
||||
//xz
|
||||
//we assume the triangle is winding clockwise, so points on the left should be clipped
|
||||
|
||||
EdgeVec = to - from;
|
||||
EdgePos = from;
|
||||
EdgePos2 = new Vector2(from.X, from.Z);
|
||||
DotVec = new Vector2(-EdgeVec.Z, EdgeVec.X);
|
||||
}
|
||||
|
||||
public bool ShouldClip(Vector3 pos)
|
||||
{
|
||||
return (Vector2.Dot(DotVec, new Vector2(pos.X, pos.Z) - EdgePos2) < 0);
|
||||
}
|
||||
|
||||
public MeshPoint IntersectLine(MeshPolygon tri, int lineInd)
|
||||
{
|
||||
var points = tri.Points;
|
||||
var lineInd2 = (lineInd + 1) % points.Count;
|
||||
var pt1 = tri.Points[lineInd];
|
||||
var pt2 = tri.Points[lineInd2];
|
||||
|
||||
Vector3 a = EdgeVec; //line 1
|
||||
Vector3 b = pt2.Position - pt1.Position; //line 2
|
||||
Vector3 c = EdgePos - pt1.Position; //vec between starts
|
||||
|
||||
//percent of line 1 where we intersect with line 2
|
||||
float ip = 1 / (-b.X * a.Z + a.X * b.Z); //projection
|
||||
float t = (b.X * c.Z - b.Z * c.X) * ip;
|
||||
|
||||
//percent of line 2 where we intersect line 1
|
||||
float ip2 = 1 / (-a.X * b.Z + b.X * a.Z);
|
||||
float s = (a.X * (-c.Z) - a.Z * (-c.X)) * ip2;
|
||||
|
||||
//pos + vec * t = pos2 + vec2 * s
|
||||
//vec * t - vec2 * s = pos2 - pos1
|
||||
float[] newTC = new float[pt1.TexCoords.Length];
|
||||
float ms = 1 - s;
|
||||
for (int i=0; i<newTC.Length; i++)
|
||||
{
|
||||
newTC[i] = pt1.TexCoords[i] * ms + pt2.TexCoords[i] * s;
|
||||
}
|
||||
|
||||
return new MeshPoint(
|
||||
//position from the clip triangle (use t)
|
||||
EdgePos + EdgeVec * t,
|
||||
//texcoords from the two points in the poly (use s)
|
||||
newTC
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class BaseMeshTriangle
|
||||
{
|
||||
public float x1;
|
||||
public float y1;
|
||||
public float x2;
|
||||
public float y2;
|
||||
|
||||
public Vector3[] Vertices;
|
||||
|
||||
public void GenBounds()
|
||||
{
|
||||
x1 = Vertices[0].X;
|
||||
y1 = Vertices[0].Z;
|
||||
x2 = x1;
|
||||
y2 = y1;
|
||||
for (int i=1; i<Vertices.Length; i++)
|
||||
{
|
||||
var v = Vertices[i];
|
||||
if (v.X < x1) x1 = v.X;
|
||||
if (v.Z < y1) y1 = v.Z;
|
||||
if (v.X > x2) x2 = v.X;
|
||||
if (v.Z > y2) y2 = v.Z;
|
||||
}
|
||||
}
|
||||
|
||||
public bool RoughIntersects(BaseMeshTriangle other)
|
||||
{
|
||||
return !(x1 > other.x2 || x2 < other.x1 || y1 > other.y2 || y2 < other.y1);
|
||||
}
|
||||
}
|
||||
|
||||
public class MeshTriangle : BaseMeshTriangle
|
||||
{
|
||||
public float[][] TexCoords;
|
||||
}
|
||||
|
||||
public class MeshPoint
|
||||
{
|
||||
public Vector3 Position;
|
||||
public float[] TexCoords;
|
||||
|
||||
public MeshPoint(Vector3 pos, float[] texCoords)
|
||||
{
|
||||
Position = pos;
|
||||
TexCoords = texCoords;
|
||||
}
|
||||
|
||||
public MeshPoint(Vector3 pos, Vector2 texCoords)
|
||||
{
|
||||
Position = pos;
|
||||
TexCoords = new float[] { texCoords.X, texCoords.Y };
|
||||
}
|
||||
}
|
||||
|
||||
public class MeshPolygon {
|
||||
public List<MeshPoint> Points;
|
||||
|
||||
public MeshPolygon()
|
||||
{
|
||||
Points = new List<MeshPoint>();
|
||||
}
|
||||
|
||||
public MeshPolygon(MeshTriangle tri)
|
||||
{
|
||||
Points = new List<MeshPoint>();
|
||||
for (int i=0; i<3; i++)
|
||||
{
|
||||
Points.Add(new MeshPoint(tri.Vertices[i], tri.TexCoords[i]));
|
||||
}
|
||||
}
|
||||
|
||||
public void Triangulate(List<MeshPoint> outverts, List<int> inds)
|
||||
{
|
||||
//simple fan triangle fill
|
||||
var baseInd = outverts.Count;
|
||||
outverts.AddRange(Points);
|
||||
|
||||
for (int i=2; i<Points.Count; i++)
|
||||
{
|
||||
inds.Add(baseInd);
|
||||
inds.Add(baseInd+i-1);
|
||||
inds.Add(baseInd+i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue