using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System;
namespace SplineMesh {
///
/// This class returns a transformed version of a given source mesh, plus others
/// informations to help bending the mesh along a curve.
/// It is imutable to ensure better performances.
///
/// To obtain an instance, call the static method .
/// The building is made in a fluent way.
///
public struct SourceMesh {
private Vector3 translation;
private Quaternion rotation;
private Vector3 scale;
internal Mesh Mesh { get; }
private List vertices;
internal List Vertices {
get {
if (vertices == null) BuildData();
return vertices;
}
}
private int[] triangles;
internal int[] Triangles {
get {
if (vertices == null) BuildData();
return triangles;
}
}
private float minX;
internal float MinX {
get {
if (vertices == null) BuildData();
return minX;
}
}
private float length;
internal float Length {
get {
if (vertices == null) BuildData();
return length;
}
}
///
/// constructor is private to enable fluent builder pattern.
/// Use to obtain an instance.
///
///
private SourceMesh(Mesh mesh) {
Mesh = mesh;
translation = default(Vector3);
rotation = default(Quaternion);
scale = default(Vector3);
vertices = null;
triangles = null;
minX = 0;
length = 0;
}
///
/// copy constructor
///
///
private SourceMesh(SourceMesh other) {
Mesh = other.Mesh;
translation = other.translation;
rotation = other.rotation;
scale = other.scale;
vertices = null;
triangles = null;
minX = 0;
length = 0;
}
public static SourceMesh Build(Mesh mesh) {
return new SourceMesh(mesh);
}
public SourceMesh Translate(Vector3 translation) {
var res = new SourceMesh(this) {
translation = translation
};
return res;
}
public SourceMesh Translate(float x, float y, float z) {
return Translate(new Vector3(x, y, z));
}
public SourceMesh Rotate(Quaternion rotation) {
var res = new SourceMesh(this) {
rotation = rotation
};
return res;
}
public SourceMesh Scale(Vector3 scale) {
var res = new SourceMesh(this) {
scale = scale
};
return res;
}
public SourceMesh Scale(float x, float y, float z) {
return Scale(new Vector3(x, y, z));
}
private void BuildData() {
// if the mesh is reversed by scale, we must change the culling of the faces by inversing all triangles.
// the mesh is reverse only if the number of resersing axes is impair.
bool reversed = scale.x < 0;
if (scale.y < 0) reversed = !reversed;
if (scale.z < 0) reversed = !reversed;
triangles = reversed ? MeshUtility.GetReversedTriangles(Mesh) : Mesh.triangles;
// we transform the source mesh vertices according to rotation/translation/scale
int i = 0;
vertices = new List(Mesh.vertexCount);
foreach (Vector3 vert in Mesh.vertices) {
var transformed = new MeshVertex(vert, Mesh.normals[i++]);
// application of rotation
if (rotation != Quaternion.identity) {
transformed.position = rotation * transformed.position;
transformed.normal = rotation * transformed.normal;
}
if (scale != Vector3.one) {
transformed.position = Vector3.Scale(transformed.position, scale);
transformed.normal = Vector3.Scale(transformed.normal, scale);
}
if (translation != Vector3.zero) {
transformed.position += translation;
}
vertices.Add(transformed);
}
// find the bounds along x
minX = float.MaxValue;
float maxX = float.MinValue;
foreach (var vert in vertices) {
Vector3 p = vert.position;
maxX = Math.Max(maxX, p.x);
minX = Math.Min(minX, p.x);
}
length = Math.Abs(maxX - minX);
}
public override bool Equals(object obj) {
if (obj == null || GetType() != obj.GetType()) {
return false;
}
var other = (SourceMesh)obj;
return Mesh == other.Mesh &&
translation == other.translation &&
rotation == other.rotation &&
scale == other.scale;
}
public override int GetHashCode() {
return base.GetHashCode();
}
public static bool operator ==(SourceMesh sm1, SourceMesh sm2) {
return sm1.Equals(sm2);
}
public static bool operator !=(SourceMesh sm1, SourceMesh sm2) {
return sm1.Equals(sm2);
}
}
}