IMHOTEP Framework
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Pages
MeshLoader.cs
1 using UnityEngine;
2 using BlenderMeshReader;
3 using System;
4 using System.Threading;
5 using System.Collections.Generic;
6 using System.ComponentModel;
7 using System.Collections;
8 using System.IO;
9 using LitJson;
10 
14 public class MeshLoader : MonoBehaviour {
15 
17  public GameObject meshNode;
18 
19  //List of lists of UnityMeshes with max. 2^16 vertices per mesh
20  private volatile List<List<UnityMesh>> unityMeshes = new List<List<UnityMesh>>();
21  //List of blender objects, witch conatins name, location and rotation of all blender objects
22  private volatile List<BlenderObjectBlock> blenderObjects = new List<BlenderObjectBlock>();
23  //True if file is loaded
24  private bool loaded = false;
25  private bool triggerEvent = false;
26  private volatile string Path = "";
27 
28  private MeshJson meshJson = null;
29 
30  //Contains a list of game objects. This game objects are parents of actual meshs.
31  public List<GameObject> MeshGameObjectContainers { get; set; }
32 
33  public MeshLoader () {
34  MeshGameObjectContainers = new List<GameObject>();
35  }
36 
37  void OnEnable()
38  {
39  // Register event callbacks:
40  PatientEventSystem.startListening(PatientEventSystem.Event.PATIENT_Closed, RemoveMesh);
41  }
42 
43  void OnDisable()
44  {
45  // Unregister myself:
46  PatientEventSystem.stopListening(PatientEventSystem.Event.PATIENT_Closed, RemoveMesh);
47  }
48 
49  // Update is called once per frame
50  void Update () {
51 
52  if (loaded)
53  {
54  StartCoroutine("LoadFileExecute");
55  unityMeshes = new List<List<UnityMesh>>();
56  loaded = false;
57  Path = "";
58  }
59  if(triggerEvent){
60  blenderObjects = new List<BlenderObjectBlock>();
61  meshJson = null;
62  triggerEvent = false;
63 
64  // Let loading screen know what we're currently doing:
65  PatientEventSystem.triggerEvent (PatientEventSystem.Event.LOADING_RemoveLoadingJob, "Mesh");
66  PatientEventSystem.triggerEvent(PatientEventSystem.Event.MESH_LoadedAll);
67  }
68  }
69 
72  public void LoadFile(string pathToMeshJson)
73  {
74  //Check if mesh.json exists
75  if (!File.Exists(pathToMeshJson))
76  {
77  Debug.LogWarning("Could not load mesh from: " + pathToMeshJson + ", file not found.");
78  return;
79  }
80 
81  // Read mesh.json
82  string fileContent = "";
83  string line;
84  System.IO.StreamReader file = new System.IO.StreamReader(pathToMeshJson);
85  while ((line = file.ReadLine()) != null)
86  {
87  fileContent += line;
88  }
89  file.Close();
90  meshJson = JsonMapper.ToObject<MeshJson>(fileContent);
91  if(meshJson == null)
92  {
93  Debug.LogWarning("Error while parsing mesh.json");
94  return;
95  }
96  Patient currentPatient = Patient.getLoadedPatient();
97  string path = currentPatient.path + "/" + meshJson.pathToBlendFile;
98 
99  //Loading blend file
100  if (File.Exists (path)) {
101 
102  // Let loading screen know what we're currently doing:
103  PatientEventSystem.triggerEvent (PatientEventSystem.Event.LOADING_AddLoadingJob, "Mesh");
104  this.RemoveMesh();
105  this.Path = path;
106  MeshGameObjectContainers = new List<GameObject>();
107 
108  // Reset scale, rotation, position:
109  meshNode.transform.localScale = new Vector3 (0.007f, 0.007f, 0.007f);
110  meshNode.transform.parent.localScale = new Vector3 (1.0f, 1.0f, 1.0f);
111  meshNode.transform.parent.localRotation = Quaternion.identity;
112  //meshNode.transform.parent.Rotate (90, 0, 0);
113  meshNode.transform.parent.GetComponent<ModelRotator>().setTargetOrientation( Quaternion.Euler(90,0,0) );
114 
115  ThreadUtil t = new ThreadUtil (this.LoadFileWorker, this.LoadFileCallback);
116  t.Run ();
117  } else {
118  Debug.LogWarning ("Could not load mesh from: '" + path + "', file not found.");
119  }
120  }
121 
125  private void LoadFileWorker(object sender, DoWorkEventArgs e)
126  {
127  BlenderFile b = new BlenderFile(Path);
128  List<BlenderMesh> blenderMeshes = new List<BlenderMesh>();
129  blenderObjects = b.readObject();
130  blenderMeshes = b.readMesh();
131  unityMeshes = BlenderFile.createSubmeshesForUnity(blenderMeshes);
132  return;
133  }
134 
136  private void LoadFileCallback(object sender, RunWorkerCompletedEventArgs e)
137  {
138  //BackgroundWorker worker = sender as BackgroundWorker;
139  if (e.Cancelled)
140  {
141  Debug.Log("Loading cancelled");
142  }else if (e.Error != null)
143  {
144  Debug.LogError("[MeshLoader.cs] Loading error");
145  Debug.LogError(e.Error);
146  }
147  else
148  {
149  loaded = true;
150  }
151  return;
152  }
153 
156  private IEnumerator LoadFileExecute()
157  {
158  Bounds bounds = new Bounds ();
159  bool boundsInitialized = false; // set to true when bounds is first set
160 
161  // meshNode
162  // | - containerObject
163  // | - actual mesh
164  // | - actual mesh
165  // | - actual mesh
166  // | - ...
167  // | - containerObject
168  // | - actual mesh
169  // | - actual mesh
170  // | - actual mesh
171  // | - ...
172  // | ...
173 
174  foreach (List<UnityMesh> um in unityMeshes) {
175  GameObject containerObject = new GameObject(um[0].Name);
176  containerObject.layer = meshNode.layer; //Set same layer as parent
177  containerObject.transform.SetParent( meshNode.transform, false );
178  //containerObject.transform.localScale = new Vector3 (400.0f, 400.0f, 400.0f);
179  containerObject.transform.localPosition = new Vector3(0, 0, 0);
180  MeshMaterialControl matControl = containerObject.AddComponent<MeshMaterialControl> ();
181  Color col = matColorForMeshName (um[0].Name);
182  matControl.setColor (col);
183  MeshGameObjectContainers.Add(containerObject);
184 
185  //attach BlenderObject to containerObject
186  foreach(BlenderObjectBlock b in blenderObjects)
187  {
188  if (b.uniqueIdentifier == um[0].UniqueIdentifier)
189  {
190  BlenderObject attachedObject = containerObject.AddComponent<BlenderObject>(); //TODO Remove... maybe
191  attachedObject.objectName = b.objectName;
192  attachedObject.location = b.location;
193  attachedObject.rotation = b.rotation;
194 
195  //Convert to left-handed soordinate systems
196  containerObject.transform.localPosition = new Vector3(b.location.x, b.location.y, -b.location.z);
197 
198  /* TODO
199  Quaternion rot = Quaternion.Inverse(b.rotation);
200  rot = new Quaternion(-rot.x, -rot.z, rot.y, -rot.w);
201  containerObject.transform.localRotation = rot;
202  */
203 
204  }
205  }
206 
207  foreach (UnityMesh unityMesh in um)
208  {
209  //Spawn object
210  GameObject objToSpawn = new GameObject(unityMesh.Name);
211  objToSpawn.layer = meshNode.layer; //Set same layer as parent
212 
213  objToSpawn.transform.SetParent (containerObject.transform, false);
214 
215  //Add Components
216  objToSpawn.AddComponent<MeshFilter>();
217  objToSpawn.AddComponent<MeshCollider>(); //TODO need to much time --> own thread?? Dont work in Unity!!
218  objToSpawn.AddComponent<MeshRenderer>();
219 
220  //Create Mesh
221  Mesh mesh = new Mesh();
222  mesh.name = unityMesh.Name;
223  mesh.vertices = unityMesh.VertexList;
224  mesh.normals = unityMesh.NormalList;
225  mesh.triangles = unityMesh.TriangleList;
226 
227  objToSpawn.GetComponent<MeshFilter>().mesh = mesh;
228  objToSpawn.GetComponent<MeshCollider>().sharedMesh = mesh; //TODO Reduce mesh??
229 
230  objToSpawn.transform.localPosition = new Vector3(0, 0, 0);
231 
232  unityMeshes = new List<List<UnityMesh>>();
233  loaded = false;
234  Path = "";
235 
236 
237  // Increase the common bounding box to contain this object:
238  // Calculate bounds in
239  Bounds worldBounds = TransformUtil.TransformBounds( objToSpawn.transform.parent, mesh.bounds );
240  Bounds localBounds = TransformUtil.InverseTransformBounds (containerObject.transform.parent, worldBounds);
241  if (!boundsInitialized) {
242  bounds = localBounds;
243  boundsInitialized = true;
244  } else {
245  bounds.Encapsulate (localBounds);
246  }
247 
248  // Make sure the color of the material is set correctly:
249  matControl.changeOpactiyOfChildren (1f);
250 
251  // Let others know that a new mesh has been loaded:
252  PatientEventSystem.triggerEvent (PatientEventSystem.Event.MESH_LoadedSingle, objToSpawn);
253 
254  // Deactivate for now, let someone else activate the mesh when needed:
255  objToSpawn.SetActive( false );
256 
257  yield return null;
258  }
259 
260  // Once all sub-meshes have been loaded, start the loading effect:
261  matControl.startLoadingEffect ();
262  }
263 
264  // Move the object by half the size of all of the meshes.
265  // This makes sure the object will rotate around its actual center:
266  //containerObject.transform.localPosition = -bounds.center;
267  meshNode.GetComponent<ModelMover> ().targetPosition = Vector3.Scale(-bounds.center, meshNode.transform.localScale);
268 
269  triggerEvent = true;
270 
271  yield return null;
272  }
273 
275  public void RemoveMesh(object obj = null)
276  {
277  //Destroy current game objects attached to mesh node
278  for (int i = 0; i < meshNode.transform.childCount; i++)
279  {
280  if (meshNode.transform.GetChild (i).name != "DICOMBounds" &&
281  meshNode.transform.GetChild (i).name != "DICOMVolume" ) {
282  Destroy (meshNode.transform.GetChild (i).gameObject);
283  }
284  }
285  }
286 
287  public Color matColorForMeshName( string meshName )
288  {
289  foreach(MeshListElement mle in meshJson.meshList)
290  {
291  if(mle.name == meshName)
292  {
293  return HexToColor (mle.color);
294  }
295  }
296  return new Color (0.7f, 0.5f, 0.2f);
297  }
298 
299  // Adopted from the Unity Wiki:
300  // http://wiki.unity3d.com/index.php?title=HexConverter
301  public static string ColorToHex(Color32 color)
302  {
303  string hex = color.r.ToString("X2") + color.g.ToString("X2") + color.b.ToString("X2");
304  return hex;
305  }
306 
307  // Adopted from the Unity Wiki:
308  // http://wiki.unity3d.com/index.php?title=HexConverter
309  public static Color HexToColor(string hex)
310  {
311  //Debug.LogWarning(hex);
312  byte r = byte.Parse(hex.Substring(1,2), System.Globalization.NumberStyles.HexNumber);
313  byte g = byte.Parse(hex.Substring(3,2), System.Globalization.NumberStyles.HexNumber);
314  byte b = byte.Parse(hex.Substring(5,2), System.Globalization.NumberStyles.HexNumber);
315  return new Color32(r,g,b, 255);
316  }
317 
318  /*public List<BlenderObject> getBlenderObjects()
319  {
320  return blenderObjects;
321  }*/
322 
323 
324 }
List< MeshListElement > meshList
Definition: MeshJson.cs:18
void LoadFile(string pathToMeshJson)
Definition: MeshLoader.cs:72
GameObject meshNode
Definition: MeshLoader.cs:17
void RemoveMesh(object obj=null)
Definition: MeshLoader.cs:275