using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
namespace ProceduralToolkit
{
///
/// Helper class for mesh generation supporting large meshes and submeshes
///
public class CompoundMeshDraft : IEnumerable
{
public string name = "";
public int vertexCount
{
get
{
int count = 0;
foreach (var meshDraft in meshDrafts)
{
count += meshDraft.vertexCount;
}
return count;
}
}
private readonly List meshDrafts = new List();
public IEnumerator GetEnumerator()
{
return meshDrafts.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public CompoundMeshDraft Add(MeshDraft draft)
{
if (draft == null) throw new ArgumentNullException(nameof(draft));
meshDrafts.Add(draft);
return this;
}
public CompoundMeshDraft Add(CompoundMeshDraft compoundDraft)
{
if (compoundDraft == null) throw new ArgumentNullException(nameof(compoundDraft));
meshDrafts.AddRange(compoundDraft.meshDrafts);
return this;
}
///
/// Clears all vertex data and all triangle indices
///
public void Clear()
{
meshDrafts.Clear();
}
///
/// Moves draft vertices by
///
public CompoundMeshDraft Move(Vector3 vector)
{
foreach (var meshDraft in meshDrafts)
{
meshDraft.Move(vector);
}
return this;
}
///
/// Rotates draft vertices by
///
public CompoundMeshDraft Rotate(Quaternion rotation)
{
foreach (var meshDraft in meshDrafts)
{
meshDraft.Rotate(rotation);
}
return this;
}
///
/// Scales draft vertices uniformly by
///
public CompoundMeshDraft Scale(float scale)
{
foreach (var meshDraft in meshDrafts)
{
meshDraft.Scale(scale);
}
return this;
}
///
/// Scales draft vertices non-uniformly by
///
public CompoundMeshDraft Scale(Vector3 scale)
{
foreach (var meshDraft in meshDrafts)
{
meshDraft.Scale(scale);
}
return this;
}
///
/// Paints draft vertices with
///
public CompoundMeshDraft Paint(Color color)
{
foreach (var meshDraft in meshDrafts)
{
meshDraft.Paint(color);
}
return this;
}
///
/// Flips draft faces
///
public CompoundMeshDraft FlipFaces()
{
foreach (var meshDraft in meshDrafts)
{
meshDraft.FlipFaces();
}
return this;
}
///
/// Reverses the winding order of draft triangles
///
public CompoundMeshDraft FlipTriangles()
{
foreach (var meshDraft in meshDrafts)
{
meshDraft.FlipTriangles();
}
return this;
}
///
/// Reverses the direction of draft normals
///
public CompoundMeshDraft FlipNormals()
{
foreach (var meshDraft in meshDrafts)
{
meshDraft.FlipNormals();
}
return this;
}
///
/// Flips the UV map horizontally in the selected
///
public CompoundMeshDraft FlipUVHorizontally(int channel = 0)
{
foreach (var meshDraft in meshDrafts)
{
meshDraft.FlipUVHorizontally(channel);
}
return this;
}
///
/// Flips the UV map vertically in the selected
///
public CompoundMeshDraft FlipUVVertically(int channel = 0)
{
foreach (var meshDraft in meshDrafts)
{
meshDraft.FlipUVVertically(channel);
}
return this;
}
///
/// Projects vertices on a sphere with the given and , recalculates normals
///
public CompoundMeshDraft Spherify(float radius, Vector3 center = default)
{
foreach (var meshDraft in meshDrafts)
{
meshDraft.Spherify(radius, center);
}
return this;
}
public void MergeDraftsWithTheSameName()
{
for (int i = 0; i < meshDrafts.Count; i++)
{
var merged = MergeDraftsWithName(meshDrafts[i].name);
meshDrafts.Insert(i, merged);
}
}
private MeshDraft MergeDraftsWithName(string draftName)
{
var merged = new MeshDraft {name = draftName};
for (int i = 0; i < meshDrafts.Count; i++)
{
var meshDraft = meshDrafts[i];
if (meshDraft.name == draftName)
{
merged.Add(meshDraft);
meshDrafts.RemoveAt(i);
i--;
}
}
return merged;
}
public void SortDraftsByName()
{
meshDrafts.Sort((a, b) => a.name.CompareTo(b.name));
}
public MeshDraft ToMeshDraft()
{
var finalDraft = new MeshDraft();
foreach (var meshDraft in meshDrafts)
{
finalDraft.Add(meshDraft);
}
return finalDraft;
}
///
/// Creates a new mesh from the data in the draft
///
/// Calculate the bounding box of the Mesh after setting the triangles.
/// Use 16 bit or 32 bit index buffers based on vertex count.
public Mesh ToMeshWithSubMeshes(bool calculateBounds = true, bool autoIndexFormat = true)
{
var mesh = new Mesh();
FillMesh(mesh, calculateBounds, autoIndexFormat);
return mesh;
}
///
/// Fills the with the data in the draft
///
/// Resulting mesh. Cleared before use.
/// Calculate the bounding box of the Mesh after setting the triangles.
/// Use 16 bit or 32 bit index buffers based on vertex count.
public void ToMeshWithSubMeshes(Mesh mesh, bool calculateBounds = true, bool autoIndexFormat = true)
{
if (mesh == null)
{
throw new ArgumentNullException(nameof(mesh));
}
mesh.Clear(false);
FillMesh(mesh, calculateBounds, autoIndexFormat);
}
private void FillMesh(Mesh mesh, bool calculateBounds, bool autoIndexFormat)
{
int vCount = vertexCount;
if (vCount > 65535)
{
if (autoIndexFormat)
{
mesh.indexFormat = IndexFormat.UInt32;
}
else
{
Debug.LogError("A mesh can't have more than 65535 vertices with 16 bit index buffer. Vertex count: " + vCount);
mesh.indexFormat = IndexFormat.UInt16;
}
}
else
{
mesh.indexFormat = IndexFormat.UInt16;
}
var finalDraft = new MeshDraft();
foreach (var meshDraft in meshDrafts)
{
finalDraft.Add(meshDraft);
}
mesh.name = name;
mesh.SetVertices(finalDraft.vertices);
mesh.subMeshCount = meshDrafts.Count;
int baseVertex = 0;
for (int i = 0; i < meshDrafts.Count; i++)
{
var draft = meshDrafts[i];
mesh.SetTriangles(draft.triangles, i, false, baseVertex);
baseVertex += draft.vertexCount;
}
if (calculateBounds)
{
mesh.RecalculateBounds();
}
mesh.SetNormals(finalDraft.normals);
mesh.SetTangents(finalDraft.tangents);
mesh.SetUVs(0, finalDraft.uv);
mesh.SetUVs(1, finalDraft.uv2);
mesh.SetUVs(2, finalDraft.uv3);
mesh.SetUVs(3, finalDraft.uv4);
mesh.SetColors(finalDraft.colors);
}
public override string ToString()
{
return name + " (ProceduralToolkit.CompoundMeshDraft)";
}
}
}