From febfef8e7e6cb14a6892055671a22fecd4c4a31a Mon Sep 17 00:00:00 2001 From: Julian Ahlmark Date: Tue, 2 Jun 2026 05:52:43 +0200 Subject: [PATCH] Vp jlep ErnygvzrPFT oehfu bs CbyltbaZrfu --- .../Scene/RealtimeCSGTarget.FixedExtrude.cs | 8 +- .../RealtimeCSGTarget.LinearStaircase.cs | 8 +- .../Scene/RealtimeCSGTarget.RevolveChopped.cs | 8 +- .../Scene/RealtimeCSGTarget.RevolveExtrude.cs | 8 +- .../Scene/RealtimeCSGTarget.ScaledExtrude.cs | 8 +- .../Scene/RealtimeCSGTarget.SplineExtrude.cs | 8 +- Scripts/Editor/Scene/RealtimeCSGTarget.cs | 16 +- Scripts/Utilities/ExternalRealtimeCSG.cs | 420 +++++++++++++++++- 8 files changed, 446 insertions(+), 38 deletions(-) diff --git a/Scripts/Editor/Scene/RealtimeCSGTarget.FixedExtrude.cs b/Scripts/Editor/Scene/RealtimeCSGTarget.FixedExtrude.cs index 966ea68..91eb543 100644 --- a/Scripts/Editor/Scene/RealtimeCSGTarget.FixedExtrude.cs +++ b/Scripts/Editor/Scene/RealtimeCSGTarget.FixedExtrude.cs @@ -22,11 +22,7 @@ private void FixedExtrude_Rebuild() for (int i = 0; i < polygonMeshesCount; i++) { var polygonMesh = polygonMeshes[i]; - var planes = polygonMesh.ToMaterialPlanes(); - - var brush = ExternalRealtimeCSG.CreateBrushFromPlanes("Shape Editor Brush", planes.planes, GetMaterials(planes.materials), polygonMesh.booleanOperator); - if (brush != null) - brush.transform.SetParent(parent, false); + CreateBrushFromPolygonMesh(parent, polygonMesh); } ExternalRealtimeCSG.AddCSGOperationComponent(gameObject); @@ -35,4 +31,4 @@ private void FixedExtrude_Rebuild() } } -#endif \ No newline at end of file +#endif diff --git a/Scripts/Editor/Scene/RealtimeCSGTarget.LinearStaircase.cs b/Scripts/Editor/Scene/RealtimeCSGTarget.LinearStaircase.cs index db1a563..1459162 100644 --- a/Scripts/Editor/Scene/RealtimeCSGTarget.LinearStaircase.cs +++ b/Scripts/Editor/Scene/RealtimeCSGTarget.LinearStaircase.cs @@ -33,11 +33,7 @@ private void LinearStaircase_Rebuild() for (int i = 0; i < polygonMeshesCount; i++) { var polygonMesh = polygonMeshes[i]; - var planes = polygonMesh.ToMaterialPlanes(); - - var brush = ExternalRealtimeCSG.CreateBrushFromPlanes("Shape Editor Brush", planes.planes, GetMaterials(planes.materials), polygonMesh.booleanOperator); - if (brush != null) - brush.transform.SetParent(parent, false); + CreateBrushFromPolygonMesh(parent, polygonMesh); } ExternalRealtimeCSG.AddCSGOperationComponent(gameObject); @@ -46,4 +42,4 @@ private void LinearStaircase_Rebuild() } } -#endif \ No newline at end of file +#endif diff --git a/Scripts/Editor/Scene/RealtimeCSGTarget.RevolveChopped.cs b/Scripts/Editor/Scene/RealtimeCSGTarget.RevolveChopped.cs index a6a5f4e..673a708 100644 --- a/Scripts/Editor/Scene/RealtimeCSGTarget.RevolveChopped.cs +++ b/Scripts/Editor/Scene/RealtimeCSGTarget.RevolveChopped.cs @@ -35,11 +35,7 @@ private void RevolveChopped_Rebuild() for (int i = 0; i < polygonMeshesCount; i++) { var polygonMesh = polygonMeshes[i]; - var planes = polygonMesh.ToMaterialPlanes(); - - var brush = ExternalRealtimeCSG.CreateBrushFromPlanes("Shape Editor Brush", planes.planes, GetMaterials(planes.materials), polygonMesh.booleanOperator); - if (brush != null) - brush.transform.SetParent(parent, false); + CreateBrushFromPolygonMesh(parent, polygonMesh); } ExternalRealtimeCSG.AddCSGOperationComponent(gameObject); @@ -48,4 +44,4 @@ private void RevolveChopped_Rebuild() } } -#endif \ No newline at end of file +#endif diff --git a/Scripts/Editor/Scene/RealtimeCSGTarget.RevolveExtrude.cs b/Scripts/Editor/Scene/RealtimeCSGTarget.RevolveExtrude.cs index bbdf6e6..3fbbbeb 100644 --- a/Scripts/Editor/Scene/RealtimeCSGTarget.RevolveExtrude.cs +++ b/Scripts/Editor/Scene/RealtimeCSGTarget.RevolveExtrude.cs @@ -42,11 +42,7 @@ private void RevolveExtrude_Rebuild() for (int i = 0; i < polygonMeshesCount; i++) { var polygonMesh = polygonMeshes[i]; - var planes = polygonMesh.ToMaterialPlanes(); - - var brush = ExternalRealtimeCSG.CreateBrushFromPlanes("Shape Editor Brush", planes.planes, GetMaterials(planes.materials), polygonMesh.booleanOperator); - if (brush != null) - brush.transform.SetParent(parent, false); + CreateBrushFromPolygonMesh(parent, polygonMesh); } ExternalRealtimeCSG.AddCSGOperationComponent(gameObject); @@ -55,4 +51,4 @@ private void RevolveExtrude_Rebuild() } } -#endif \ No newline at end of file +#endif diff --git a/Scripts/Editor/Scene/RealtimeCSGTarget.ScaledExtrude.cs b/Scripts/Editor/Scene/RealtimeCSGTarget.ScaledExtrude.cs index 28b33f1..d2923d8 100644 --- a/Scripts/Editor/Scene/RealtimeCSGTarget.ScaledExtrude.cs +++ b/Scripts/Editor/Scene/RealtimeCSGTarget.ScaledExtrude.cs @@ -30,11 +30,7 @@ private void ScaledExtrude_Rebuild() for (int i = 0; i < polygonMeshesCount; i++) { var polygonMesh = polygonMeshes[i]; - var planes = polygonMesh.ToMaterialPlanes(); - - var brush = ExternalRealtimeCSG.CreateBrushFromPlanes("Shape Editor Brush", planes.planes, GetMaterials(planes.materials), polygonMesh.booleanOperator); - if (brush != null) - brush.transform.SetParent(parent, false); + CreateBrushFromPolygonMesh(parent, polygonMesh); } ExternalRealtimeCSG.AddCSGOperationComponent(gameObject); @@ -43,4 +39,4 @@ private void ScaledExtrude_Rebuild() } } -#endif \ No newline at end of file +#endif diff --git a/Scripts/Editor/Scene/RealtimeCSGTarget.SplineExtrude.cs b/Scripts/Editor/Scene/RealtimeCSGTarget.SplineExtrude.cs index 86125ed..3ae8dff 100644 --- a/Scripts/Editor/Scene/RealtimeCSGTarget.SplineExtrude.cs +++ b/Scripts/Editor/Scene/RealtimeCSGTarget.SplineExtrude.cs @@ -30,11 +30,7 @@ private void SplineExtrude_Rebuild() for (int i = 0; i < polygonMeshesCount; i++) { var polygonMesh = polygonMeshes[i]; - var planes = polygonMesh.ToMaterialPlanes(); - - var brush = ExternalRealtimeCSG.CreateBrushFromPlanes("Shape Editor Brush", planes.planes, GetMaterials(planes.materials), polygonMesh.booleanOperator); - if (brush != null) - brush.transform.SetParent(parent, false); + CreateBrushFromPolygonMesh(parent, polygonMesh); } ExternalRealtimeCSG.AddCSGOperationComponent(gameObject); @@ -61,4 +57,4 @@ private Vector3[] GetLocalChildPoints() } } -#endif \ No newline at end of file +#endif diff --git a/Scripts/Editor/Scene/RealtimeCSGTarget.cs b/Scripts/Editor/Scene/RealtimeCSGTarget.cs index cd2097e..7288364 100644 --- a/Scripts/Editor/Scene/RealtimeCSGTarget.cs +++ b/Scripts/Editor/Scene/RealtimeCSGTarget.cs @@ -140,6 +140,20 @@ private Material[] GetMaterials(int[] materialIndices) return result; } + private void CreateBrushFromPolygonMesh(Transform parent, PolygonMesh polygonMesh) + { + var materialPlanes = polygonMesh.ToMaterialPlanes(); + var materials = GetMaterials(materialPlanes.materials); + var brush = ExternalRealtimeCSG.CreateBrushFromPolygonMesh(parent, "Shape Editor Brush", polygonMesh, materials); + + if (brush == null) + { + brush = ExternalRealtimeCSG.CreateBrushFromPlanes("Shape Editor Brush", materialPlanes.planes, materials, polygonMesh.booleanOperator); + if (brush != null) + brush.transform.SetParent(parent, false); + } + } + private void OnDrawGizmosSelected() { if (targetMode == RealtimeCSGTargetMode.SplineExtrude) @@ -197,4 +211,4 @@ private Vector3[] GetChildPointsAndDrawGizmos(out int hash) } } -#endif \ No newline at end of file +#endif diff --git a/Scripts/Utilities/ExternalRealtimeCSG.cs b/Scripts/Utilities/ExternalRealtimeCSG.cs index a984837..462563f 100644 --- a/Scripts/Utilities/ExternalRealtimeCSG.cs +++ b/Scripts/Utilities/ExternalRealtimeCSG.cs @@ -15,6 +15,50 @@ namespace AeternumGames.ShapeEditor /// public class ExternalRealtimeCSG { + private class RealtimePolygonData + { + public int[] vertexIndices; + public int[] edgeIndices; + public int sourcePolygonIndex; + } + + private struct RealtimeHalfEdgeData + { + public int polygonIndex; + public int endVertexIndex; + public int twinIndex; + } + + private struct RealtimeEdgeKey : IEquatable + { + private readonly int startVertexIndex; + private readonly int endVertexIndex; + + public RealtimeEdgeKey(int startVertexIndex, int endVertexIndex) + { + this.startVertexIndex = startVertexIndex; + this.endVertexIndex = endVertexIndex; + } + + public bool Equals(RealtimeEdgeKey other) + { + return startVertexIndex == other.startVertexIndex && endVertexIndex == other.endVertexIndex; + } + + public override bool Equals(object obj) + { + return obj is RealtimeEdgeKey && Equals((RealtimeEdgeKey)obj); + } + + public override int GetHashCode() + { + unchecked + { + return (startVertexIndex * 397) ^ endVertexIndex; + } + } + } + /// /// The cached RealtimeCSG.Legacy.BrushFactory type after initialization. /// @@ -30,6 +74,45 @@ public class ExternalRealtimeCSG /// private static MethodInfo createBrushMethod = null; + private static Type controlMesh = null; + private static ConstructorInfo controlMeshConstructorMethod = null; + private static FieldInfo controlMeshVerticesField = null; + private static FieldInfo controlMeshEdgesField = null; + private static FieldInfo controlMeshPolygonsField = null; + private static PropertyInfo controlMeshValidProperty = null; + private static Type controlMeshPolygon = null; + private static ConstructorInfo controlMeshPolygonConstructorMethod = null; + private static Type halfEdge = null; + private static FieldInfo halfEdgeTwinIndexField = null; + private static FieldInfo halfEdgePolygonIndexField = null; + private static FieldInfo halfEdgeHardEdgeField = null; + private static FieldInfo halfEdgeVertexIndexField = null; + private static Type shape = null; + private static ConstructorInfo shapeConstructorMethod = null; + private static FieldInfo shapeSurfacesField = null; + private static FieldInfo shapeTexGensField = null; + private static FieldInfo shapeTexGenFlagsField = null; + private static Type surface = null; + private static FieldInfo surfacePlaneField = null; + private static FieldInfo surfaceTangentField = null; + private static FieldInfo surfaceBiNormalField = null; + private static FieldInfo surfaceTexGenIndexField = null; + private static Type texGen = null; + private static FieldInfo texGenScaleField = null; + private static FieldInfo texGenRenderMaterialField = null; + private static Type texGenFlags = null; + private static PropertyInfo csgPlaneNormalProperty = null; + private static Type geometryUtility = null; + private static MethodInfo calcPolygonPlaneMethod = null; + private static MethodInfo calculateTangentsMethod = null; + private static Type shapeUtility = null; + private static MethodInfo shapeUtilityEnsureInitializedMethod = null; + private static Type controlMeshUtility = null; + private static MethodInfo controlMeshUtilityValidateMethod = null; + private static Type csgSettings = null; + private static FieldInfo csgSettingsDefaultMaterialField = null; + private static FieldInfo csgSettingsDefaultTexGenFlagsField = null; + /// /// The cached RealtimeCSG.ShapePolygonUtility type after initialization. /// @@ -171,6 +254,120 @@ public static bool IsAvailable() csgPlaneConstructorMethod = csgPlane.GetConstructor(new Type[] { typeof(Plane) }); if (csgPlaneConstructorMethod == null) { initializationError = true; return false; } + csgPlaneNormalProperty = csgPlane.GetProperty("normal"); + if (csgPlaneNormalProperty == null) { initializationError = true; return false; } + + controlMesh = GetType("RealtimeCSG.Legacy.ControlMesh"); + if (controlMesh == null) { initializationError = true; return false; } + + controlMeshConstructorMethod = controlMesh.GetConstructor(Type.EmptyTypes); + if (controlMeshConstructorMethod == null) { initializationError = true; return false; } + + controlMeshVerticesField = controlMesh.GetField("Vertices"); + if (controlMeshVerticesField == null) { initializationError = true; return false; } + + controlMeshEdgesField = controlMesh.GetField("Edges"); + if (controlMeshEdgesField == null) { initializationError = true; return false; } + + controlMeshPolygonsField = controlMesh.GetField("Polygons"); + if (controlMeshPolygonsField == null) { initializationError = true; return false; } + + controlMeshValidProperty = controlMesh.GetProperty("Valid"); + if (controlMeshValidProperty == null) { initializationError = true; return false; } + + controlMeshPolygon = GetType("RealtimeCSG.Legacy.Polygon"); + if (controlMeshPolygon == null) { initializationError = true; return false; } + + controlMeshPolygonConstructorMethod = controlMeshPolygon.GetConstructor(new Type[] { typeof(int[]), typeof(int) }); + if (controlMeshPolygonConstructorMethod == null) { initializationError = true; return false; } + + halfEdge = GetType("RealtimeCSG.Legacy.HalfEdge"); + if (halfEdge == null) { initializationError = true; return false; } + + halfEdgeTwinIndexField = halfEdge.GetField("TwinIndex"); + if (halfEdgeTwinIndexField == null) { initializationError = true; return false; } + + halfEdgePolygonIndexField = halfEdge.GetField("PolygonIndex"); + if (halfEdgePolygonIndexField == null) { initializationError = true; return false; } + + halfEdgeHardEdgeField = halfEdge.GetField("HardEdge"); + if (halfEdgeHardEdgeField == null) { initializationError = true; return false; } + + halfEdgeVertexIndexField = halfEdge.GetField("VertexIndex"); + if (halfEdgeVertexIndexField == null) { initializationError = true; return false; } + + shape = GetType("RealtimeCSG.Legacy.Shape"); + if (shape == null) { initializationError = true; return false; } + + shapeConstructorMethod = shape.GetConstructor(Type.EmptyTypes); + if (shapeConstructorMethod == null) { initializationError = true; return false; } + + shapeSurfacesField = shape.GetField("Surfaces"); + if (shapeSurfacesField == null) { initializationError = true; return false; } + + shapeTexGensField = shape.GetField("TexGens"); + if (shapeTexGensField == null) { initializationError = true; return false; } + + shapeTexGenFlagsField = shape.GetField("TexGenFlags"); + if (shapeTexGenFlagsField == null) { initializationError = true; return false; } + + surface = GetType("RealtimeCSG.Legacy.Surface"); + if (surface == null) { initializationError = true; return false; } + + surfacePlaneField = surface.GetField("Plane"); + if (surfacePlaneField == null) { initializationError = true; return false; } + + surfaceTangentField = surface.GetField("Tangent"); + if (surfaceTangentField == null) { initializationError = true; return false; } + + surfaceBiNormalField = surface.GetField("BiNormal"); + if (surfaceBiNormalField == null) { initializationError = true; return false; } + + surfaceTexGenIndexField = surface.GetField("TexGenIndex"); + if (surfaceTexGenIndexField == null) { initializationError = true; return false; } + + texGen = GetType("RealtimeCSG.Legacy.TexGen"); + if (texGen == null) { initializationError = true; return false; } + + texGenScaleField = texGen.GetField("Scale"); + if (texGenScaleField == null) { initializationError = true; return false; } + + texGenRenderMaterialField = texGen.GetField("RenderMaterial"); + if (texGenRenderMaterialField == null) { initializationError = true; return false; } + + texGenFlags = GetType("RealtimeCSG.Legacy.TexGenFlags"); + if (texGenFlags == null) { initializationError = true; return false; } + + geometryUtility = GetType("RealtimeCSG.GeometryUtility"); + if (geometryUtility == null) { initializationError = true; return false; } + + calcPolygonPlaneMethod = geometryUtility.GetMethod("CalcPolygonPlane", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { controlMesh, typeof(short) }, null); + if (calcPolygonPlaneMethod == null) { initializationError = true; return false; } + + calculateTangentsMethod = geometryUtility.GetMethod("CalculateTangents", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(Vector3), typeof(Vector3).MakeByRefType(), typeof(Vector3).MakeByRefType() }, null); + if (calculateTangentsMethod == null) { initializationError = true; return false; } + + shapeUtility = GetType("RealtimeCSG.ShapeUtility"); + if (shapeUtility == null) { initializationError = true; return false; } + + shapeUtilityEnsureInitializedMethod = shapeUtility.GetMethod("EnsureInitialized", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { shape }, null); + if (shapeUtilityEnsureInitializedMethod == null) { initializationError = true; return false; } + + controlMeshUtility = GetType("RealtimeCSG.ControlMeshUtility"); + if (controlMeshUtility == null) { initializationError = true; return false; } + + controlMeshUtilityValidateMethod = controlMeshUtility.GetMethod("Validate", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { controlMesh, shape }, null); + if (controlMeshUtilityValidateMethod == null) { initializationError = true; return false; } + + csgSettings = GetType("RealtimeCSG.CSGSettings"); + if (csgSettings == null) { initializationError = true; return false; } + + csgSettingsDefaultMaterialField = csgSettings.GetField("DefaultMaterial", BindingFlags.Public | BindingFlags.Static); + if (csgSettingsDefaultMaterialField == null) { initializationError = true; return false; } + + csgSettingsDefaultTexGenFlagsField = csgSettings.GetField("DefaultTexGenFlags", BindingFlags.Public | BindingFlags.Static); + if (csgSettingsDefaultTexGenFlagsField == null) { initializationError = true; return false; } + csgOperation = GetType("RealtimeCSG.Components.CSGOperation"); if (csgOperation == null) { initializationError = true; return false; } @@ -237,6 +434,213 @@ public static Material WallMaterial } } + private static int GetOrAddRealtimeVertex(List vertices, Vector3 position) + { + var count = vertices.Count; + for (int i = 0; i < count; i++) + if (vertices[i].EqualsWithEpsilon5(position)) + return i; + + vertices.Add(position); + return count; + } + + private static bool HasRealtimePolygonArea(List vertices, List vertexIndices) + { + var normal = Vector3.zero; + var previous = vertices[vertexIndices[vertexIndices.Count - 1]]; + var count = vertexIndices.Count; + + for (int i = 0; i < count; i++) + { + var current = vertices[vertexIndices[i]]; + normal.x += (previous.y - current.y) * (previous.z + current.z); + normal.y += (previous.z - current.z) * (previous.x + current.x); + normal.z += (previous.x - current.x) * (previous.y + current.y); + previous = current; + } + + return normal.sqrMagnitude > MathEx.EPSILON_5 * MathEx.EPSILON_5; + } + + private static bool TryCreateRealtimePolygonData(PolygonMesh mesh, out Vector3[] vertices, out List polygons, out List halfEdges) + { + vertices = null; + polygons = new List(); + halfEdges = new List(); + + if (mesh == null || mesh.Count < 4) + return false; + + var uniqueVertices = new List(); + var meshCount = mesh.Count; + for (int i = 0; i < meshCount; i++) + { + var sourcePolygon = mesh[i]; + if (sourcePolygon == null || sourcePolygon.Count < 3) + continue; + + var vertexIndices = new List(sourcePolygon.Count); + for (int j = sourcePolygon.Count - 1; j >= 0; j--) + { + var vertexIndex = GetOrAddRealtimeVertex(uniqueVertices, sourcePolygon[j].position); + if (!vertexIndices.Contains(vertexIndex)) + vertexIndices.Add(vertexIndex); + } + + if (vertexIndices.Count < 3 || !HasRealtimePolygonArea(uniqueVertices, vertexIndices)) + continue; + + polygons.Add(new RealtimePolygonData + { + vertexIndices = vertexIndices.ToArray(), + sourcePolygonIndex = i + }); + } + + if (polygons.Count < 4 || uniqueVertices.Count > short.MaxValue || polygons.Count > short.MaxValue) + return false; + + var openEdges = new Dictionary(); + var polygonCount = polygons.Count; + for (int i = 0; i < polygonCount; i++) + { + var polygon = polygons[i]; + var vertexIndices = polygon.vertexIndices; + var vertexCount = vertexIndices.Length; + polygon.edgeIndices = new int[vertexCount]; + + for (int j = 0; j < vertexCount; j++) + { + var currentVertexIndex = vertexIndices[j]; + var previousVertexIndex = vertexIndices[j == 0 ? vertexCount - 1 : j - 1]; + var edgeIndex = halfEdges.Count; + + var halfEdgeInfo = new RealtimeHalfEdgeData + { + polygonIndex = i, + endVertexIndex = currentVertexIndex, + twinIndex = -1 + }; + + var reverseKey = new RealtimeEdgeKey(currentVertexIndex, previousVertexIndex); + if (openEdges.TryGetValue(reverseKey, out var twinIndex)) + { + var twin = halfEdges[twinIndex]; + twin.twinIndex = edgeIndex; + halfEdges[twinIndex] = twin; + + halfEdgeInfo.twinIndex = twinIndex; + openEdges.Remove(reverseKey); + } + else + { + var key = new RealtimeEdgeKey(previousVertexIndex, currentVertexIndex); + if (openEdges.ContainsKey(key)) + return false; + + openEdges.Add(key, edgeIndex); + } + + polygon.edgeIndices[j] = edgeIndex; + halfEdges.Add(halfEdgeInfo); + } + } + + if (openEdges.Count > 0) + return false; + + vertices = uniqueVertices.ToArray(); + return true; + } + + private static Material GetRealtimePolygonMaterial(Material[] materials, int sourcePolygonIndex) + { + if (materials != null && sourcePolygonIndex >= 0 && sourcePolygonIndex < materials.Length && materials[sourcePolygonIndex] != null) + return materials[sourcePolygonIndex]; + + return (Material)csgSettingsDefaultMaterialField.GetValue(null); + } + + private static object NewRealtimeHalfEdge(RealtimeHalfEdgeData halfEdgeInfo) + { + var result = Activator.CreateInstance(halfEdge); + halfEdgePolygonIndexField.SetValue(result, (short)halfEdgeInfo.polygonIndex); + halfEdgeTwinIndexField.SetValue(result, halfEdgeInfo.twinIndex); + halfEdgeHardEdgeField.SetValue(result, true); + halfEdgeVertexIndexField.SetValue(result, (short)halfEdgeInfo.endVertexIndex); + return result; + } + + private static bool TryCreateRealtimeControlMesh(PolygonMesh mesh, Material[] materials, out object resultControlMesh, out object resultShape) + { + resultControlMesh = null; + resultShape = null; + + if (!TryCreateRealtimePolygonData(mesh, out var vertices, out var polygons, out var halfEdges)) + return false; + + resultControlMesh = controlMeshConstructorMethod.Invoke(new object[0]); + + var realtimeHalfEdges = Array.CreateInstance(halfEdge, halfEdges.Count); + var halfEdgeCount = halfEdges.Count; + for (int i = 0; i < halfEdgeCount; i++) + realtimeHalfEdges.SetValue(NewRealtimeHalfEdge(halfEdges[i]), i); + + var realtimePolygons = Array.CreateInstance(controlMeshPolygon, polygons.Count); + var polygonCount = polygons.Count; + for (int i = 0; i < polygonCount; i++) + realtimePolygons.SetValue(controlMeshPolygonConstructorMethod.Invoke(new object[] { polygons[i].edgeIndices, i }), i); + + controlMeshVerticesField.SetValue(resultControlMesh, vertices); + controlMeshEdgesField.SetValue(resultControlMesh, realtimeHalfEdges); + controlMeshPolygonsField.SetValue(resultControlMesh, realtimePolygons); + + resultShape = shapeConstructorMethod.Invoke(new object[0]); + + var realtimeSurfaces = Array.CreateInstance(surface, polygonCount); + var realtimeTexGens = Array.CreateInstance(texGen, polygonCount); + var realtimeTexGenFlags = Array.CreateInstance(texGenFlags, polygonCount); + var defaultTexGenFlags = csgSettingsDefaultTexGenFlagsField.GetValue(null); + + for (int i = 0; i < polygonCount; i++) + { + var realtimeSurface = Activator.CreateInstance(surface); + var plane = calcPolygonPlaneMethod.Invoke(null, new object[] { resultControlMesh, (short)i }); + var normal = (Vector3)csgPlaneNormalProperty.GetValue(plane); + var tangentArgs = new object[] { normal, Vector3.zero, Vector3.zero }; + + calculateTangentsMethod.Invoke(null, tangentArgs); + + surfacePlaneField.SetValue(realtimeSurface, plane); + surfaceTangentField.SetValue(realtimeSurface, (Vector3)tangentArgs[1]); + surfaceBiNormalField.SetValue(realtimeSurface, (Vector3)tangentArgs[2]); + surfaceTexGenIndexField.SetValue(realtimeSurface, i); + realtimeSurfaces.SetValue(realtimeSurface, i); + + var realtimeTexGen = Activator.CreateInstance(texGen); + texGenScaleField.SetValue(realtimeTexGen, Vector2.one); + texGenRenderMaterialField.SetValue(realtimeTexGen, GetRealtimePolygonMaterial(materials, polygons[i].sourcePolygonIndex)); + realtimeTexGens.SetValue(realtimeTexGen, i); + + realtimeTexGenFlags.SetValue(defaultTexGenFlags, i); + } + + shapeSurfacesField.SetValue(resultShape, realtimeSurfaces); + shapeTexGensField.SetValue(resultShape, realtimeTexGens); + shapeTexGenFlagsField.SetValue(resultShape, realtimeTexGenFlags); + + shapeUtilityEnsureInitializedMethod.Invoke(null, new object[] { resultShape }); + var valid = (bool)controlMeshUtilityValidateMethod.Invoke(null, new object[] { resultControlMesh, resultShape }); + controlMeshValidProperty.SetValue(resultControlMesh, valid, null); + if (valid) + return true; + + resultControlMesh = null; + resultShape = null; + return false; + } + public static void CreateExtrudedBrushesFromPolygon(Transform parent, string brushName, Vector2[] vertices, float distance, PolygonBooleanOperator booleanOperator) { if (!IsAvailable()) return; @@ -286,6 +690,20 @@ public static MonoBehaviour CreateBrushFromPlanes(string brushName, Plane[] plan return (MonoBehaviour)brush; } + public static MonoBehaviour CreateBrushFromPolygonMesh(Transform parent, string brushName, PolygonMesh mesh, Material[] materials) + { + if (!IsAvailable()) return null; + if (!TryCreateRealtimeControlMesh(mesh, materials, out var controlMesh, out var shape)) return null; + + var brush = createBrushMethod.Invoke(null, new object[] { parent, brushName, controlMesh, shape }); + if (brush == null) return null; + + if (mesh.booleanOperator == PolygonBooleanOperator.Difference) + csgBrushOperationType.SetValue(brush, csgOperationTypeSubtractive); + + return (MonoBehaviour)brush; + } + private static void DestroyCSGNodeComponent(GameObject gameObject) { var component = gameObject.GetComponent(csgNode); @@ -325,4 +743,4 @@ public static void UpdateSelection() } } -#endif \ No newline at end of file +#endif