Tanoda
pb_Stl_Importer.cs
Go to the documentation of this file.
1#pragma warning disable 0219
2
3using UnityEngine;
4using System.Text;
5using System.Collections;
6using System.Collections.Generic;
7using System.IO;
8
9namespace Parabox.STL
10{
14 public static class pb_Stl_Importer
15 {
16 const int MAX_FACETS_PER_MESH = 65535 / 3;
17
18 class Facet
19 {
20 public Vector3 normal;
21 public Vector3 a, b, c;
22
23 public override string ToString()
24 {
25 return string.Format("{0:F2}: {1:F2}, {2:F2}, {3:F2}", normal, a, b, c);
26 }
27 }
28
32 public static Mesh[] Import(string path)
33 {
34 if( IsBinary(path) )
35 {
36 try
37 {
38 return ImportBinary(path);
39 }
40 catch(System.Exception e)
41 {
42 UnityEngine.Debug.LogWarning(string.Format("Failed importing mesh at path {0}.\n{1}", path, e.ToString()));
43 return null;
44 }
45 }
46 else
47 {
48 return ImportAscii(path);
49 }
50 }
51
52 private static Mesh[] ImportBinary(string path)
53 {
54 Facet[] facets;
55
56 using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
57 {
58 using (BinaryReader br = new BinaryReader(fs, new ASCIIEncoding()))
59 {
60 // read header
61 byte[] header = br.ReadBytes(80);
62 uint facetCount = br.ReadUInt32();
63 facets = new Facet[facetCount];
64
65 for(uint i = 0; i < facetCount; i++)
66 {
67 facets[i] = new Facet();
68
69 facets[i].normal.x = br.ReadSingle();
70 facets[i].normal.y = br.ReadSingle();
71 facets[i].normal.z = br.ReadSingle();
72
73 facets[i].a.x = br.ReadSingle();
74 facets[i].a.y = br.ReadSingle();
75 facets[i].a.z = br.ReadSingle();
76
77 facets[i].b.x = br.ReadSingle();
78 facets[i].b.y = br.ReadSingle();
79 facets[i].b.z = br.ReadSingle();
80
81 facets[i].c.x = br.ReadSingle();
82 facets[i].c.y = br.ReadSingle();
83 facets[i].c.z = br.ReadSingle();
84
85 // padding
86 br.ReadUInt16();
87 }
88 }
89 }
90
91 return CreateMeshWithFacets(facets);
92 }
93
94 const int SOLID = 1;
95 const int FACET = 2;
96 const int OUTER = 3;
97 const int VERTEX = 4;
98 const int ENDLOOP = 5;
99 const int ENDFACET = 6;
100 const int ENDSOLID = 7;
101 const int EMPTY = 0;
102
103 private static int ReadState(string line)
104 {
105 if(line.StartsWith("solid"))
106 return SOLID;
107 else if(line.StartsWith("facet"))
108 return FACET;
109 else if(line.StartsWith("outer"))
110 return OUTER;
111 else if(line.StartsWith("vertex"))
112 return VERTEX;
113 else if(line.StartsWith("endloop"))
114 return ENDLOOP;
115 else if(line.StartsWith("endfacet"))
116 return ENDFACET;
117 else if(line.StartsWith("endsolid"))
118 return ENDSOLID;
119 else
120 return EMPTY;
121 }
122
123 private static Mesh[] ImportAscii(string path)
124 {
125 List<Facet> facets = new List<Facet>();
126
127 using(StreamReader sr = new StreamReader(path))
128 {
129 string line;
130 int state = EMPTY, vertex = 0;
131 Facet f = null;
132 bool exit = false;
133
134 while(sr.Peek() > 0 && !exit)
135 {
136 line = sr.ReadLine().Trim();
137 int previousState = state;
138 state = ReadState(line);
139
140 switch(state)
141 {
142 case SOLID:
143 continue;
144
145 case FACET:
146 f = new Facet();
147 f.normal = StringToVec3(line.Replace("facet normal ", ""));
148 break;
149
150 case OUTER:
151 vertex = 0;
152 break;
153
154 case VERTEX:
155 if(vertex == 0) f.a = StringToVec3(line.Replace("vertex ", ""));
156 else if(vertex == 1) f.b = StringToVec3(line.Replace("vertex ", ""));
157 else if(vertex == 2) f.c = StringToVec3(line.Replace("vertex ", ""));
158 vertex++;
159 break;
160
161 case ENDLOOP:
162 break;
163
164 case ENDFACET:
165 facets.Add(f);
166 break;
167
168 case ENDSOLID:
169 exit = true;
170 break;
171
172 case EMPTY:
173 default:
174 break;
175
176 }
177 }
178 }
179
180 return CreateMeshWithFacets(facets);
181 }
182
183 private static Vector3 StringToVec3(string str)
184 {
185 string[] split = str.Trim().Split(null);
186 Vector3 v = new Vector3();
187
188 float.TryParse(split[0], out v.x);
189 float.TryParse(split[1], out v.y);
190 float.TryParse(split[2], out v.z);
191
192 return v;
193 }
194
199 private static bool IsBinary(string path)
200 {
201 // http://stackoverflow.com/questions/968935/compare-binary-files-in-c-sharp
202 FileInfo file = new FileInfo(path);
203
204 if(file.Length < 130)
205 return false;
206
207 var isBinary = false;
208
209 using(FileStream f0 = file.OpenRead())
210 {
211 using(BufferedStream bs0 = new BufferedStream(f0))
212 {
213 for(long i = 0; i < 80; i++)
214 {
215 var readByte = bs0.ReadByte();
216 if (readByte == 0x0)
217 {
218 isBinary = true;
219 break;
220 }
221 }
222 }
223 }
224
225 if (!isBinary)
226 {
227 using (FileStream f0 = file.OpenRead())
228 {
229 using (BufferedStream bs0 = new BufferedStream(f0))
230 {
231 var byteArray = new byte[6];
232
233 for (var i = 0; i < 6; i++)
234 {
235 byteArray[i] = (byte)bs0.ReadByte();
236 }
237
238 var text = Encoding.UTF8.GetString(byteArray);
239 isBinary = text != "solid ";
240 }
241 }
242 }
243
244 return isBinary;
245 }
246
250 private static Mesh[] CreateMeshWithFacets(IList<Facet> facets)
251 {
252 int fl = facets.Count, f = 0, mvc = MAX_FACETS_PER_MESH * 3;
253 Mesh[] meshes = new Mesh[fl / MAX_FACETS_PER_MESH + 1];
254
255 for(int i = 0; i < meshes.Length; i++)
256 {
257 int len = System.Math.Min(mvc, (fl - f) * 3);
258 Vector3[] v = new Vector3[len];
259 Vector3[] n = new Vector3[len];
260 int[] t = new int[len];
261
262 for(int it = 0; it < len; it += 3)
263 {
264 v[it ] = facets[f].a;
265 v[it+1] = facets[f].b;
266 v[it+2] = facets[f].c;
267
268 n[it ] = facets[f].normal;
269 n[it+1] = facets[f].normal;
270 n[it+2] = facets[f].normal;
271
272 t[it ] = it;
273 t[it+1] = it+1;
274 t[it+2] = it+2;
275
276 f++;
277 }
278
279 meshes[i] = new Mesh();
280 meshes[i].vertices = v;
281 meshes[i].normals = n;
282 meshes[i].triangles = t;
283 }
284
285 return meshes;
286 }
287 }
288}
System.IO.FileMode FileMode
Definition: AssetLoader.cs:14