Skip to content

Commit 53329cd

Browse files
committed
Separate classes into different files
1 parent 5ca4fe7 commit 53329cd

3 files changed

Lines changed: 273 additions & 254 deletions

File tree

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Elements.Assets;
5+
using Elements.Core;
6+
using Elements.Data;
7+
using FrooxEngine;
8+
using Obsidian.Components.Utility;
9+
10+
namespace Obsidian.Assets.ProceduralMeshes;
11+
12+
[OldTypeName("Obsidian.Components.Tools.EditableMesh")]
13+
[Category("Obsidian/Assets/Procedural Meshes")]
14+
public class EditableMesh : ProceduralMesh
15+
{
16+
private const float EPSILON = 0.001f;
17+
18+
protected readonly AssetRef<Mesh> _sourceMesh;
19+
protected readonly SyncRef<Slot> _controlPointsSlot;
20+
protected readonly SyncRef<MeshCollider> _newCollider;
21+
protected readonly SyncRef<ICollider> _originalCollider;
22+
protected readonly SyncRef<UnlitMaterial> _controlPointMaterial;
23+
24+
private MeshX storedMeshX;
25+
private List<MergedVertexData> mergedVertexData;
26+
27+
private class MergedVertexData
28+
{
29+
public float3 pos;
30+
public HashSet<Vertex> vertices = new();
31+
}
32+
33+
private void DebugLog(string msg)
34+
{
35+
UniLog.Log($"[EditableMesh {this.ReferenceID.ToString()}] {msg}");
36+
}
37+
38+
protected override void OnDestroy()
39+
{
40+
base.OnDestroy();
41+
42+
_controlPointsSlot.Target?.Destroy();
43+
44+
_controlPointMaterial.Target?.Destroy();
45+
46+
// If this ProceduralMesh was baked, nothing should be referencing it anymore
47+
48+
DebugLog($"OnDestroy. AssetReferenceCount: {AssetReferenceCount}");
49+
50+
foreach (var reference in References)
51+
{
52+
DebugLog($"Reference: {reference.Parent.Name}");
53+
}
54+
55+
if (AssetReferenceCount != 0)
56+
{
57+
// EditableMesh wasn't baked.
58+
59+
DebugLog($"Wasn't baked.");
60+
61+
_newCollider.Target?.Destroy();
62+
63+
foreach (var reference in References)
64+
{
65+
reference.Target = _sourceMesh.Target;
66+
}
67+
68+
if (_originalCollider.Target != null)
69+
{
70+
_originalCollider.Target.Enabled = true;
71+
}
72+
}
73+
else
74+
{
75+
// EditableMesh has most likely been baked because nothing references it
76+
77+
DebugLog($"Baked.");
78+
79+
_originalCollider.Target?.Destroy();
80+
81+
if (_sourceMesh.Target != null)
82+
{
83+
var assetSlot = World.AssetsSlot.AddSlot("EditableMesh Original Mesh");
84+
assetSlot.MoveComponent((Component)_sourceMesh.Target);
85+
}
86+
}
87+
}
88+
89+
protected override void OnStart()
90+
{
91+
//_sourceMesh.OnTargetChange += (syncRef) =>
92+
//{
93+
// Handle mesh changes in here?
94+
// Should regen control points and clear mesh data
95+
//};
96+
97+
//if (_sourceMesh.Asset != null && _controlPointsSlot.Target is null)
98+
//{
99+
//InitControlPoints();
100+
//}
101+
}
102+
103+
public void Setup(IAssetProvider<Mesh> meshProvider)
104+
{
105+
if (meshProvider == null)
106+
{
107+
throw new ArgumentNullException(nameof(meshProvider));
108+
}
109+
if (meshProvider.Asset == null)
110+
{
111+
throw new ArgumentException("Provided mesh asset is null!");
112+
}
113+
_sourceMesh.Target = meshProvider;
114+
_controlPointMaterial.Target = Slot.AttachComponent<UnlitMaterial>();
115+
_controlPointMaterial.Target.TintColor.Value = colorX.Green;
116+
InitControlPoints();
117+
}
118+
119+
public void SetColliders(ICollider originalCollider, MeshCollider newCollider)
120+
{
121+
if (originalCollider == null)
122+
{
123+
throw new ArgumentNullException($"{nameof(originalCollider)} is null!");
124+
}
125+
if (newCollider == null)
126+
{
127+
throw new ArgumentNullException($"{nameof(newCollider)} is null!");
128+
}
129+
if (newCollider.Mesh.Target != this)
130+
{
131+
throw new ArgumentException($"{nameof(newCollider)} doesn't target this EditableMesh!");
132+
}
133+
_originalCollider.Target = originalCollider;
134+
_newCollider.Target = newCollider;
135+
}
136+
137+
private void InitControlPoints()
138+
{
139+
var mergedVertexData = CollectMergedVertexData(_sourceMesh.Asset.Data);
140+
141+
_controlPointsSlot.Target = Slot.AddSlot("EditableMesh Control Points");
142+
143+
for (int i = 0; i < mergedVertexData.Count; i++)
144+
{
145+
var data = mergedVertexData[i];
146+
147+
var vertSlot = _controlPointsSlot.Target.AddSlot($"ControlPoint{i}");
148+
vertSlot.ChildIndex = i;
149+
vertSlot.LocalPosition = data.pos;
150+
vertSlot.AttachSphere(0.01f, _controlPointMaterial.Target);
151+
vertSlot.AttachComponent<Slider>();
152+
var controlPointComp = vertSlot.AttachComponent<EditableMeshControlPoint>();
153+
controlPointComp.Setup(this);
154+
}
155+
}
156+
157+
protected override void ClearMeshData()
158+
{
159+
storedMeshX?.Clear();
160+
storedMeshX = null;
161+
mergedVertexData?.Clear();
162+
mergedVertexData = null;
163+
}
164+
165+
private static bool ShouldMerge(float3 p1, float3 p2)
166+
{
167+
return MathX.Approximately(p1, p2, EPSILON);
168+
}
169+
170+
private static List<MergedVertexData> CollectMergedVertexData(MeshX mesh)
171+
{
172+
var result = new List<MergedVertexData>();
173+
for (int i = 0; i < mesh.VertexCount; i++)
174+
{
175+
var vert = mesh.GetVertex(i);
176+
MergedVertexData data = result.FirstOrDefault(d => ShouldMerge(d.pos, vert.Position));
177+
if (data == null)
178+
{
179+
data = new MergedVertexData();
180+
data.pos = vert.Position;
181+
result.Add(data);
182+
}
183+
else
184+
{
185+
continue;
186+
}
187+
data.vertices.Add(vert);
188+
for (int j = 0; j < mesh.VertexCount; j++)
189+
{
190+
var vert2 = mesh.GetVertex(j);
191+
if (vert.Index == vert2.Index) continue;
192+
if (ShouldMerge(vert.Position, vert2.Position))
193+
{
194+
data.vertices.Add(vert2);
195+
}
196+
}
197+
}
198+
return result;
199+
}
200+
201+
protected override void UpdateMeshData(MeshX meshx)
202+
{
203+
if (_sourceMesh.Asset?.Data is null)
204+
{
205+
meshx.Clear();
206+
_sourceMesh.ListenToAssetUpdates = true;
207+
DebugLog($"{nameof(_sourceMesh)} Asset null. Listening for updates...");
208+
return;
209+
}
210+
211+
if (_sourceMesh.ListenToAssetUpdates)
212+
{
213+
DebugLog($"{nameof(_sourceMesh)} Asset loaded. No longer listening for updates.");
214+
_sourceMesh.ListenToAssetUpdates = false;
215+
}
216+
217+
if (storedMeshX != meshx)
218+
{
219+
DebugLog($"Storing new MeshX data.");
220+
storedMeshX = meshx;
221+
storedMeshX.Copy(_sourceMesh.Asset.Data);
222+
mergedVertexData = CollectMergedVertexData(storedMeshX);
223+
}
224+
225+
for (int i = 0; i < mergedVertexData.Count; i++)
226+
{
227+
var data = mergedVertexData[i];
228+
229+
Slot vertSlot = _controlPointsSlot.Target[i]; // Could throw null ref exception but it's probably okay
230+
231+
foreach (var vert in data.vertices)
232+
{
233+
storedMeshX.SetVertex(vert.Index, vertSlot.LocalPosition);
234+
}
235+
}
236+
}
237+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using Elements.Data;
2+
using FrooxEngine;
3+
using Obsidian.Assets.ProceduralMeshes;
4+
5+
namespace Obsidian.Components.Utility;
6+
7+
[OldTypeName("Obsidian.Components.Tools.EditableMeshControlPoint")]
8+
[Category("Obsidian/Utility")]
9+
public class EditableMeshControlPoint : Component
10+
{
11+
protected readonly SyncRef<EditableMesh> _editableMesh;
12+
13+
public EditableMesh EditableMesh => _editableMesh.Target;
14+
15+
public void Setup(EditableMesh editableMesh)
16+
{
17+
_editableMesh.Target = editableMesh;
18+
}
19+
20+
protected override void OnDestroying()
21+
{
22+
base.OnDestroying();
23+
_editableMesh.Target?.Destroy();
24+
}
25+
26+
protected override void OnStart()
27+
{
28+
base.OnStart();
29+
Slot.Position_Field.OnValueChange += (field) =>
30+
{
31+
_editableMesh.Target?.MarkChangeDirty();
32+
};
33+
}
34+
}

0 commit comments

Comments
 (0)