1
1
#include " loader.h"
2
- #include " mesh.h"
3
2
4
3
Loader::Loader (QObject* parent, const QString& filename)
5
4
: QThread(parent), filename(filename)
@@ -9,29 +8,122 @@ Loader::Loader(QObject* parent, const QString& filename)
9
8
10
9
void Loader::run ()
11
10
{
12
- { // Verify that this isn't an ascii stl file
13
- QFile file (filename);
14
- file.open (QIODevice::ReadOnly);
15
- if (file.read (5 ) == " solid" )
16
- {
17
- emit error_ascii_stl ();
18
- return ;
19
- }
11
+ Mesh* mesh = load_stl ();
12
+ if (mesh)
13
+ {
14
+ emit got_mesh (mesh);
15
+ emit loaded_file (filename);
16
+ }
17
+ }
18
+
19
+
20
+ // //////////////////////////////////////////////////////////////////////////////
21
+
22
+ struct Vec3
23
+ {
24
+ GLfloat x, y, z;
25
+ bool operator !=(const Vec3& rhs) const
26
+ {
27
+ return x != rhs.x || y != rhs.y || z != rhs.z ;
28
+ }
29
+ bool operator <(const Vec3& rhs) const
30
+ {
31
+ if (x != rhs.x ) return x < rhs.x ;
32
+ else if (y != rhs.y ) return y < rhs.y ;
33
+ else if (z != rhs.z ) return z < rhs.z ;
34
+ else return false ;
35
+ }
36
+ };
37
+
38
+ typedef std::pair<Vec3, GLuint> Vec3i;
39
+
40
+ // //////////////////////////////////////////////////////////////////////////////
41
+
42
+ Mesh* Loader::load_stl ()
43
+ {
44
+ QFile file (filename);
45
+ file.open (QIODevice::ReadOnly);
46
+ if (file.read (5 ) == " solid" )
47
+ {
48
+ emit error_ascii_stl ();
49
+ return NULL ;
50
+ }
51
+ // Skip the rest of the header material
52
+ file.read (75 );
20
53
21
- // Skip the rest of the buffer
22
- file.read (75 );
54
+ QDataStream data (&file);
55
+ data.setByteOrder (QDataStream::LittleEndian);
56
+ data.setFloatingPointPrecision (QDataStream::SinglePrecision);
23
57
24
- // Assume we're on a little-endian system for simplicity
25
- uint32_t tri_count;
26
- file. read ( reinterpret_cast < char *>(&tri_count), sizeof ( tri_count)) ;
58
+ // Load the triangle count from the .stl file
59
+ uint32_t tri_count;
60
+ data >> tri_count;
27
61
28
- if (file.size () != 84 + tri_count*50 )
62
+ // Verify that the file is the right size
63
+ if (file.size () != 84 + tri_count*50 )
64
+ {
65
+ emit error_bad_stl ();
66
+ return NULL ;
67
+ }
68
+
69
+ // Extract vertices into an array of xyz, unsigned pairs
70
+ QVector<Vec3i> verts (tri_count*3 );
71
+
72
+ // Dummy array, because readRawData is faster than skipRawData
73
+ char buffer[sizeof (float )*3 ];
74
+
75
+ // Store vertices in the array, processing one triangle at a time.
76
+ for (auto v=verts.begin (); v != verts.end (); v += 3 )
77
+ {
78
+ // Skip face's normal vector
79
+ data.readRawData (buffer, 3 *sizeof (float ));
80
+
81
+ // Load vertex data from .stl file into vertices
82
+ data >> v[0 ].first .x >> v[0 ].first .y >> v[0 ].first .z ;
83
+ data >> v[1 ].first .x >> v[1 ].first .y >> v[1 ].first .z ;
84
+ data >> v[2 ].first .x >> v[2 ].first .y >> v[2 ].first .z ;
85
+
86
+ // Skip face attribute
87
+ data.readRawData (buffer, sizeof (uint16_t ));
88
+ }
89
+
90
+ // Save indicies as the second element in the array
91
+ // (so that we can reconstruct triangle order after sorting)
92
+ for (size_t i=0 ; i < tri_count*3 ; ++i)
93
+ {
94
+ verts[i].second = i;
95
+ }
96
+
97
+ // Sort the set of vertices (to deduplicate)
98
+ std::sort (verts.begin (), verts.end ());
99
+
100
+ // This vector will store triangles as sets of 3 indices
101
+ std::vector<GLuint> indices (tri_count*3 );
102
+
103
+ // Go through the sorted vertex list, deduplicating and creating
104
+ // an indexed geometry representation for the triangles.
105
+ // Unique vertices are moved so that they occupy the first vertex_count
106
+ // positions in the verts array.
107
+ size_t vertex_count = 0 ;
108
+ for (auto v : verts)
109
+ {
110
+ if (!vertex_count || v.first != verts[vertex_count-1 ].first )
29
111
{
30
- emit error_bad_stl ();
31
- return ;
112
+ verts[vertex_count++] = v;
32
113
}
114
+ indices[v.second ] = vertex_count - 1 ;
33
115
}
116
+ verts.resize (vertex_count);
34
117
35
- emit got_mesh (Mesh::load_stl (filename));
36
- emit loaded_file (filename);
118
+ std::vector<GLfloat> flat_verts;
119
+ flat_verts.reserve (vertex_count*3 );
120
+ for (auto v : verts)
121
+ {
122
+ flat_verts.push_back (v.first .x );
123
+ flat_verts.push_back (v.first .y );
124
+ flat_verts.push_back (v.first .z );
125
+ }
126
+
127
+ return new Mesh (flat_verts, indices);
37
128
}
129
+
0 commit comments