View difference between Paste ID: 7sLteqNw and K6Y9MD31
SHOW: | | - or go back to the newest paste.
1
public enum SaveFormat {
2
	OBJ,
3
	QMO
4
}
5
public enum LoadFormat {
6
	Auto,
7
	OBJ,
8
	QMO
9
}
10
11
public static class ImportExport {
12
13-
	public static string SaveToText (this Mesh mesh, SaveFormat sFormat = SaveFormat.OBJ) {
13+
// NEW CODE (more complex but can load .obj from "anywhere" (normally) and generated files are lighter)
14
	/// <summary>
15
	/// Save a Mesh to a file.
16
	/// path : the path were the mesh will be created WITHOUT THE EXTENSION.
17
	/// format : format of the file (obj/qmo).
18-
				
18+
	/// overwrite : if the file already exists, should it overwrite ?
19
	/// </summary>
20
	public static void SaveToFile (this Mesh mesh, string path, SaveFormat format, bool overwrite) {
21
		path = path + '.' + format.ToString ().ToLower ();
22
23
		try {
24
			if (!File.Exists (path) || overwrite) {
25-
			foreach (Vector3 u in mesh.uv) {
25+
				File.WriteAllText (path, mesh.SaveToText (format));
26
			}
27
			else {
28
				Debug.LogWarning ("This file already exists, can't save mesh : " + mesh.name + ", or set overwrite to true.\n@" + path);
29
			}
30
		}
31
		catch (Exception ex) {
32
			Debug.LogWarning ("Exception while saving mesh : " + mesh.name + "\n@ " + path + "\nex: " + ex);
33
		}
34-
				
34+
35-
			text.Append ("\ns off\n\n"); // smoothing group, but unity doesn't support it
35+
36-
				
36+
	/// <summary>
37
	/// Save a Mesh to a text.
38
	/// </summary>
39
	public static string SaveToText (this Mesh mesh, SaveFormat format) {
40
		StringBuilder text = new StringBuilder ();
41
42
		if (format == SaveFormat.OBJ) {
43
			text.AppendFormat ("# ModelisaTools exported obj file\n\no {0}\n\n", mesh.name);
44
45
			List<Vector3> vertices = new List<Vector3> ();
46
			List<int> veIndex = new List<int> ();
47
			List<Vector3> uv = new List<Vector3> ();
48
			List<int> uvIndex = new List<int> ();
49-
	// path = the path where the file will be created, WITHOUT THE EXTENSION
49+
			List<Vector3> normals = new List<Vector3> ();
50-
	public static void SaveToFile (this Mesh mesh, string path, SaveFormat sFormat = SaveFormat.OBJ, bool overwrite = false) {
50+
			List<int> noIndex = new List<int> ();
51
52
			Vector3 tempV3;
53
			Vector2 tempV2;
54
55-
				File.WriteAllText (path, mesh.SaveToText (sFormat));
55+
			for (int i = 0; i < mesh.vertices.Length; i++) {
56
				if (!vertices.Contains (mesh.vertices[i])) {
57
					vertices.Add (mesh.vertices[i]);
58
					veIndex.Add (vertices.Count - 1);
59
				}
60
				else {
61
					veIndex.Add (vertices.IndexOf (mesh.vertices[i]));
62
				}
63
			}
64
65
			for (int i = 0; i < mesh.uv.Length; i++) {
66-
	// path = the path were the mesh will be loaded, WITH THE EXTENSION if lFormat is AUTO, and WITHOUT if lFormat is : OBJ, QMO
66+
				if (!uv.Contains (mesh.uv[i])) {
67-
	public static void LoadFromFile (this Mesh mesh, string path, LoadFormat lFormat = LoadFormat.Auto) {
67+
					uv.Add (mesh.uv[i]);
68
					uvIndex.Add (uv.Count - 1);
69
				}
70
				else {
71
					uvIndex.Add (uv.IndexOf (mesh.uv[i]));
72
				}
73
			}
74
75
			for (int i = 0; i < mesh.normals.Length; i++) {
76
				if (!normals.Contains (mesh.normals[i])) {
77
					normals.Add (mesh.normals[i]);
78
					noIndex.Add (normals.Count - 1);
79
				}
80
				else {
81
					noIndex.Add (normals.IndexOf (mesh.normals[i]));
82
				}
83
			}
84
85
			for (int i = 0; i < vertices.Count; i++) {
86
				tempV3 = vertices[i];
87
				text.AppendFormat ("v {0} {1} {2}\n", tempV3.x, tempV3.y, tempV3.z);
88
			}
89
90
			text.Append ("\n");
91
92
			for (int i = 0; i < uv.Count; i++) {
93
				tempV2 = uv[i];
94
				text.AppendFormat ("vt {0} {1}\n", tempV2.x, tempV2.y);
95
			}
96-
	public static void LoadFromStream (this Mesh mesh, TextReader reader, LoadFormat lFormat) {
96+
97
			text.Append ("\n");
98
99
			for (int i = 0; i < normals.Count; i++) {
100
				tempV3 = normals[i];
101
				text.AppendFormat ("vn {0} {1} {2}\n", tempV3.x, tempV3.y, tempV3.z);
102
			}
103
104
			text.Append ("\ns off\n\n"); // smoothing group, but unity doesn't support it :/
105
106
			for (int i = 0; i < mesh.triangles.Length; i += 3) {
107
				text.AppendFormat ("f {0}/{1}/{2} {3}/{4}/{5} {6}/{7}/{8}\n",
108
									veIndex[ mesh.triangles[ i ] ] + 1,
109
									uvIndex[ mesh.triangles[ i ] ] + 1,
110
									noIndex[ mesh.triangles[ i ] ] + 1,
111
112
									veIndex[ mesh.triangles[ i + 1 ] ] + 1,
113
									uvIndex[ mesh.triangles[ i + 1 ] ] + 1,
114
									noIndex[ mesh.triangles[ i + 1 ] ] + 1,
115
116
									veIndex[ mesh.triangles[ i + 2 ] ] + 1,
117
									uvIndex[ mesh.triangles[ i + 2 ] ] + 1,
118
									noIndex[ mesh.triangles[ i + 2 ] ] + 1
119
									);
120
			}
121
		}
122
123-
				else if (line.StartsWith ("v ")) {
123+
		if (format == SaveFormat.QMO) {
124
			throw new NotImplementedException ();
125
		}
126
127
		return text.ToString ();
128-
							
128+
129
130
	/// <summary>
131
	/// Load a Mesh from a file.
132
	/// path : the path were the mesh will be loaded, WITHOUT THE EXTENSION.
133
	/// format : format of mesh (obj/qmo).
134
	/// </summary>
135
136
	public static void LoadFromFile (this Mesh mesh, string path, LoadFormat format) {
137
		path = path + '.' + format.ToString ().ToLower ();
138-
				else if (line.StartsWith ("vt")) {
138+
139
		try {
140
			if (File.Exists (path)) {
141
				mesh.LoadFromStream (File.OpenText (path), format);
142-
							
142+
143
			else {
144
				Debug.LogWarning ("This file doesn't exists, can't load mesh @ " + path);
145
			}
146
		}
147
		catch (Exception ex) {
148
			Debug.LogWarning ("Exception while loading mesh : " + ((mesh == null) ? "NULL_MESH" : mesh.name) + "\n@ " + path + "\nex: " + ex);
149
		}
150
	}
151
152-
				else if (line.StartsWith ("vn")) {
152+
	/// <summary>
153
	/// Load a Mesh from a TextReader (StringReader or StreamReader).
154
	/// </summary>
155
156
	public static void LoadFromStream (this Mesh mesh, TextReader reader, LoadFormat format) {
157-
							
157+
158
		int lineNumber = 0;
159
160
		string[] datas;
161
		string[] v0Datas;
162
		string[] v1Datas;
163
		string[] v2Datas;
164
		string[] v3Datas;
165
166
		Vector3 tempV3;
167-
				else if (line.StartsWith ("f")) {
167+
		Vector2 tempV2;
168
169
		// "raw" data
170
		List<Vector3> tempVertices = new List<Vector3> ();
171
		List<Vector2> tempUV = new List<Vector2> ();
172
		List<Vector3> tempNormals = new List<Vector3> ();
173
174
		// ordered data
175
		List<Vector3> vertices = new List<Vector3> ();
176
		List<Vector2> uv = new List<Vector2> ();
177-
						triangles.Add (3); // beurk beurk mais je vois pas comment faire autrement :/
177+
178
		List<int> triangles = new List<int> ();
179
180
		if (format == LoadFormat.OBJ) {
181
			while ((line = reader.ReadLine()) != null) {
182
				lineNumber++;
183
				line = line.Replace ('\t', ' ');
184
				datas = line.Split (' ');
185
186
				if (datas.Length == 0) continue;
187
188
				// mesh name
189
				if (datas[0] == "o") {
190
					try {
191
						mesh.name = datas[1];
192
					}
193
					catch (Exception ex) {
194
						mesh.name = "undefined";
195
						Debug.LogWarning ("PARSE ERROR (name) : line " + lineNumber + " while loading mesh : " + mesh.name + "\n" + ex);
196
					}
197
				}
198
199
				// vertex
200
				if (datas[0] == "v") {
201
					try {
202
						tempV3.x = float.Parse (datas[1]);
203-
	public static void LoadFromText (this Mesh mesh, string text, LoadFormat lFormat) {
203+
						tempV3.y = float.Parse (datas[2]);
204-
		mesh.LoadFromStream (new StringReader (text), lFormat);
204+
						tempV3.z = float.Parse (datas[3]);
205
206
						tempVertices.Add (tempV3);
207
					}
208
					catch (Exception ex) {
209
						tempVertices.Add (Vector3.zero);
210
						Debug.LogWarning ("PARSE ERROR (vertex) : line " + lineNumber + " while loading mesh : " + mesh.name + "\n" + ex);
211
					}
212
				}
213
214
				// uv (vt = vertex texture)
215
				if (datas[0] == "vt") {
216
					try  {
217
						tempV2.x = float.Parse (datas[1]);
218
						tempV2.y = float.Parse (datas[2]);
219
220
						tempUV.Add (tempV2);
221
					}
222
					catch (Exception ex) {
223
						tempUV.Add (Vector2.zero);
224
						Debug.LogWarning ("PARSE ERROR (uv) : line " + lineNumber + " while loading mesh : " + mesh.name + "\n" + ex);
225
					}
226
				}
227
228
				// normal
229
				if (datas[0] == "vn") {
230
					try {
231
						tempV3.x = float.Parse (datas[1]);
232
						tempV3.y = float.Parse (datas[2]);
233
						tempV3.z = float.Parse (datas[3]);
234
235
						tempNormals.Add (tempV3);
236
					}
237
					catch (Exception ex) {
238
						tempNormals.Add (Vector3.zero);
239
						Debug.LogWarning ("PARSE ERROR (normal) : line " + lineNumber + " while loading mesh : " + mesh.name + "\n" + ex);
240
					}
241
				}
242
243
				// face
244
				if (datas[0] == "f") {
245
246
					// triangle or quad
247
					if (datas.Length >= 4) {
248
						try {
249
							v0Datas = datas[1].Split ('/');
250
							v1Datas = datas[2].Split ('/');
251
							v2Datas = datas[3].Split ('/');
252
253
							vertices.Add ( tempVertices[ int.Parse (v0Datas[0]) - 1 ] );
254
							vertices.Add ( tempVertices[ int.Parse (v1Datas[0]) - 1 ] );
255
							vertices.Add ( tempVertices[ int.Parse (v2Datas[0]) - 1 ] );
256
257
							uv.Add ( tempUV[ int.Parse (v0Datas[1]) - 1 ] );
258
							uv.Add ( tempUV[ int.Parse (v1Datas[1]) - 1 ] );
259
							uv.Add ( tempUV[ int.Parse (v2Datas[1]) - 1 ] );
260
261
							normals.Add ( tempNormals[ int.Parse (v0Datas[2]) - 1 ] );
262
							normals.Add ( tempNormals[ int.Parse (v1Datas[2]) - 1 ] );
263
							normals.Add ( tempNormals[ int.Parse (v2Datas[2]) - 1 ] );
264
265
							int i = triangles.Count;
266
							triangles.Add (i);
267
							triangles.Add (i + 1);
268
							triangles.Add (i + 2);
269
270
							if (datas.Length >= 5) {
271
								v3Datas = datas[4].Split ('/');
272
273
								vertices.Add ( tempVertices[ int.Parse (v3Datas[0]) ] );
274
								uv.Add ( tempUV[ int.Parse (v3Datas[1]) ] );
275
								normals.Add ( tempNormals[ int.Parse (v3Datas[2]) ] );
276
277
								triangles.Add (i + 1);
278
								triangles.Add (i + 2);
279
								triangles.Add (i + 3);
280
							}
281
						}
282
						catch (Exception ex) {
283
							Debug.LogWarning ("PARSE ERROR (face:" + (datas.Length-1) + ") : line " + lineNumber + " while loading mesh : " + mesh.name + "\n" + ex);
284
						}
285
					}
286
				}
287
288
				// else it's :
289
				// - a comment (#)
290
				// - a smoothing group (s on or s off), but unity doesn't support it
291
				// - a unsupported instruction (ex : mtl)
292
			}
293
294
			mesh.Clear ();
295
			mesh.vertices = vertices.ToArray ();
296
			mesh.uv = uv.ToArray ();
297
			mesh.normals = normals.ToArray ();
298
			mesh.triangles = triangles.ToArray ();
299
		}
300
301
		if (format == LoadFormat.QMO) {
302
			throw new NotImplementedException ();
303
		}
304
305
		reader.Close ();
306
	}
307
// NEW CODE
308
	
309
// OLD CODE (simpler but surely faster, WARNING : can load only .obj saved with this code (can have issue when loading .obj from other softwares))
310
	public static string SimpleSaveToText (this Mesh mesh) { return mesh.SimpleSaveToText (SaveFormat.OBJ); }
311
	
312
	/// <summary>
313
	/// Save a Mesh to a text.
314
	/// sFormat : format of the text (obj/qmo). Optional : default .obj.
315
	/// </summary>
316
317
	public static string SimpleSaveToText (this Mesh mesh, SaveFormat sFormat) {
318
		StringBuilder text = new StringBuilder ();
319
		
320
		if (sFormat == SaveFormat.OBJ) {
321
			text.AppendFormat("# ModelisaTools exported obj file\n\no {0}\n\n", mesh.name);
322
			
323
			foreach (Vector3 v in mesh.vertices) {
324
				text.AppendFormat ("v {0} {1} {2}\n", v.x, v.y, v.z);
325
			}
326
327
			text.Append ("\n");
328
329
			foreach (Vector2 u in mesh.uv) {
330
				text.AppendFormat ("vt {0} {1}\n", u.x, u.y);
331
			}
332
333
			text.Append ("\n");
334
335
			foreach (Vector3 n in mesh.normals) {
336
				text.AppendFormat ("vn {0} {1} {2}\n", n.x, n.y, n.z);
337
			}
338
			
339
			text.Append ("\ns off\n\n"); // smoothing group, but unity doesn't support it :/
340
			
341
			for (int i = 0; i < mesh.triangles.Length; i += 3) {
342
				text.AppendFormat ("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", mesh.triangles[i]+1, mesh.triangles[i+1]+1, mesh.triangles[i+2]+1);
343
			}
344
		}
345
		
346
		if (sFormat == SaveFormat.QMO) {
347
			throw new NotImplementedException ();
348
		}
349
		
350
		return text.ToString ();
351
	}
352
	
353
	public static void SimpleSaveToFile (this Mesh mesh, string path) { mesh.SimpleSaveToFile (path, SaveFormat.OBJ, false); }
354
	public static void SimpleSaveToFile (this Mesh mesh, string path, SaveFormat sFormat) { mesh.SimpleSaveToFile (path, sFormat, false); }
355
	public static void SimpleSaveToFile (this Mesh mesh, string path, bool overwrite) { mesh.SimpleSaveToFile (path, SaveFormat.OBJ, overwrite); }
356
	
357
	/// <summary>
358
	/// Save a Mesh to a file.
359
	/// path : the path were the mesh will be created WITHOUT THE EXTENSION.
360
	/// sFormat : format of the file (obj/qmo). Optional : default .obj.
361
	/// overwrite : if the file already exists, should it overwrite ? Optional : default false.
362
	/// </summary>
363
364
	public static void SimpleSaveToFile (this Mesh mesh, string path, SaveFormat sFormat, bool overwrite) {
365
		path = path + '.' + sFormat.ToString ().ToLower ();
366
367
		try {
368
			if (!File.Exists (path) || overwrite) {
369
				File.WriteAllText (path, mesh.SimpleSaveToText (sFormat));
370
			}
371
			else {
372
				Debug.LogWarning ("This file already exists, can't save mesh : " + mesh.name + ", or set overwrite to true.\n@" + path);
373
			}
374
		}
375
		catch (Exception ex) {
376
			Debug.LogWarning ("Exception while saving mesh : " + mesh.name + "\n@ " + path + "\nex: " + ex);
377
		}
378
	}
379
380
	public static void SimpleLoadFromFile (this Mesh mesh, string path) { mesh.SimpleLoadFromFile (path, LoadFormat.Auto); }
381
382
	/// <summary>
383
	/// Load a Mesh from a file.
384
	/// path : the path were the mesh will be loaded, WITH THE EXTENSION if lFormat is AUTO, and WITHOUT if lFormat is : OBJ, QMO.
385
	/// lFormat : format of mesh (obj/qmo). Optional : default AUTO
386
	/// </summary>
387
388
	public static void SimpleLoadFromFile (this Mesh mesh, string path, LoadFormat lFormat) {
389
		if (lFormat != LoadFormat.Auto) {
390
			path = path + '.' + lFormat.ToString ().ToLower ();
391
		}
392
393
		try {
394
			if (File.Exists (path)) {
395
				string extension = Path.GetExtension (path);
396
				LoadFormat format;
397
				if (extension == ".obj") {
398
					format = LoadFormat.OBJ;
399
				}
400
				else if (extension == ".qmo") {
401
					format = LoadFormat.QMO;
402
				}
403
				else {
404
					format = LoadFormat.Auto;
405
				}
406
				mesh.SimpleLoadFromStream (File.OpenText (path), format);
407
			}
408
			else {
409
				Debug.LogWarning ("This file doesn't exists, can't load mesh @ " + path);
410
			}
411
		}
412
		catch (Exception ex) {
413
			Debug.LogWarning ("Exception while loading mesh : " + mesh.name + "\n@ " + path + "\nex: " + ex);
414
		}
415
	}
416
417
	/// <summary>
418
	/// Load a Mesh from a TextReader (StringReader or StreamReader).
419
	/// </summary>
420
421
	public static void SimpleLoadFromStream (this Mesh mesh, TextReader reader, LoadFormat lFormat) {
422
		string line;
423
		int lineNumber = 0;
424
		string[] datas;
425
		Vector3 tempVector3;
426
		Vector2 tempVector2;
427
		List<Vector3> vertices = new List<Vector3> ();
428
		List<Vector2> uv = new List<Vector2> ();
429
		List<Vector3> normals = new List<Vector3> ();
430
		List<int> triangles = new List<int> ();
431
432
		if (lFormat == LoadFormat.Auto) {
433
			Debug.LogWarning ("Can't load mesh : " + mesh.name + ", format is not supported.");
434
			return;
435
		}
436
437
		if (lFormat == LoadFormat.OBJ) {
438
			while ((line = reader.ReadLine()) != null) {
439
440
				datas = line.Split (' '); // so datas[0] == o || v || vt || vn || f || ...
441
442
				// mesh name
443
				if (line.StartsWith ("o")) {
444
					mesh.name = datas[1];
445
				}
446
447
				// vertex
448
				if (line.StartsWith ("v ")) {
449
					try {
450
						tempVector3.x = float.Parse (datas[1]);
451
						tempVector3.y = float.Parse (datas[2]);
452
						tempVector3.z = float.Parse (datas[3]);
453
						
454
						vertices.Add (tempVector3);
455
					}
456
					catch (Exception ex) {
457
						Debug.LogWarning ("PARSE ERROR (vertex) : line " + lineNumber + " while loading mesh : " + mesh.name + "\n" + ex);
458
						vertices.Add (Vector3.zero);
459
					}
460
				}
461
462
				// uv - texture coordinate
463
				if (line.StartsWith ("vt")) {
464
					try {
465
						tempVector2.x = float.Parse (datas[1]);
466
						tempVector2.y = float.Parse (datas[2]);
467
						
468
						uv.Add (tempVector2);
469
					}
470
					catch (Exception ex) {
471
						Debug.LogWarning ("PARSE ERROR (uv) : line " + lineNumber + " while loading mesh : " + mesh.name + "\n" + ex);
472
						uv.Add (Vector2.zero);
473
					}
474
				}
475
476
				// normal
477
				if (line.StartsWith ("vn")) {
478
					try {
479
						tempVector3.x = float.Parse (datas[1]);
480
						tempVector3.y = float.Parse (datas[2]);
481
						tempVector3.z = float.Parse (datas[3]);
482
						
483
						normals.Add (tempVector3);
484
					}
485
					catch (Exception ex) {
486
						Debug.LogWarning ("PARSE ERROR (normal) : line " + lineNumber + " while loading mesh : " + mesh.name + "\n" + ex);
487
						normals.Add (Vector3.zero);
488
					}
489
				}
490
491
				// triangle (face)
492
				if (line.StartsWith ("f")) {
493
					try {
494
						triangles.Add (int.Parse (datas[1].Split ('/')[0]) - 1);
495
						triangles.Add (int.Parse (datas[2].Split ('/')[0]) - 1);
496
						triangles.Add (int.Parse (datas[3].Split ('/')[0]) - 1);
497
					}
498
					catch (Exception ex) {
499
						Debug.LogWarning ("PARSE ERROR (triangle) : line " + lineNumber + " while loading mesh : " + mesh.name + "\n" + ex);
500
						triangles.Add (1);
501
						triangles.Add (2);
502
						triangles.Add (3);
503
						// beurk beurk, but we preserve vertex/face order
504
					}
505
				}
506
507
				// else it's :
508
				//	_ a comment (#...)
509
				//	_ a smoothing group, but unity doesn't support it (s on/s off)
510
				//	_ a unsupported operation (ex : mtl)
511
512
				lineNumber++;
513
			}
514
515
			mesh.Clear ();
516
			mesh.vertices = vertices.ToArray ();
517
			mesh.uv = uv.ToArray ();
518
			mesh.normals = normals.ToArray ();
519
			mesh.triangles = triangles.ToArray ();
520
		}
521
522
		if (lFormat == LoadFormat.QMO) {
523
			//
524
		}
525
526
		reader.Close ();
527
	}
528
529
	/// <summary>
530
	/// Load a Mesh from a String (internally convert into a StringReader and call LoadFromStream).
531
	/// lFormat : format of mesh (obj/qmo)
532
	/// </summary>
533
534
	public static void SimpleLoadFromText (this Mesh mesh, string text, LoadFormat lFormat) {
535
		mesh.SimpleLoadFromStream (new StringReader (text), lFormat);
536
	}
537
// OLD CODE
538
}