1 | /* |
2 | Open Asset Import Library (assimp) |
3 | ---------------------------------------------------------------------- |
4 | |
5 | Copyright (c) 2006-2017, assimp team |
6 | |
7 | All rights reserved. |
8 | |
9 | Redistribution and use of this software in source and binary forms, |
10 | with or without modification, are permitted provided that the |
11 | following conditions are met: |
12 | |
13 | * Redistributions of source code must retain the above |
14 | copyright notice, this list of conditions and the |
15 | following disclaimer. |
16 | |
17 | * Redistributions in binary form must reproduce the above |
18 | copyright notice, this list of conditions and the |
19 | following disclaimer in the documentation and/or other |
20 | materials provided with the distribution. |
21 | |
22 | * Neither the name of the assimp team, nor the names of its |
23 | contributors may be used to endorse or promote products |
24 | derived from this software without specific prior |
25 | written permission of the assimp team. |
26 | |
27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
28 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
29 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
30 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
31 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
32 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
33 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
34 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
35 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
36 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
37 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
38 | |
39 | ---------------------------------------------------------------------- |
40 | */ |
41 | |
42 | |
43 | |
44 | #if !defined(ASSIMP_BUILD_NO_EXPORT) && !defined(ASSIMP_BUILD_NO_STL_EXPORTER) |
45 | |
46 | #include "STLExporter.h" |
47 | #include <assimp/version.h> |
48 | #include <assimp/IOSystem.hpp> |
49 | #include <assimp/scene.h> |
50 | #include <assimp/Exporter.hpp> |
51 | #include <memory> |
52 | #include "Exceptional.h" |
53 | #include "ByteSwapper.h" |
54 | |
55 | using namespace Assimp; |
56 | namespace Assimp { |
57 | |
58 | // ------------------------------------------------------------------------------------------------ |
59 | // Worker function for exporting a scene to Stereolithograpy. Prototyped and registered in Exporter.cpp |
60 | void ExportSceneSTL(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) |
61 | { |
62 | // invoke the exporter |
63 | STLExporter exporter(pFile, pScene); |
64 | |
65 | if (exporter.mOutput.fail()) { |
66 | throw DeadlyExportError("output data creation failed. Most likely the file became too large: " + std::string(pFile)); |
67 | } |
68 | |
69 | // we're still here - export successfully completed. Write the file. |
70 | std::unique_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt" )); |
71 | if(outfile == NULL) { |
72 | throw DeadlyExportError("could not open output .stl file: " + std::string(pFile)); |
73 | } |
74 | |
75 | outfile->Write( exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()),1); |
76 | } |
77 | void ExportSceneSTLBinary(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) |
78 | { |
79 | // invoke the exporter |
80 | STLExporter exporter(pFile, pScene, true); |
81 | |
82 | if (exporter.mOutput.fail()) { |
83 | throw DeadlyExportError("output data creation failed. Most likely the file became too large: " + std::string(pFile)); |
84 | } |
85 | |
86 | // we're still here - export successfully completed. Write the file. |
87 | std::unique_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wb" )); |
88 | if(outfile == NULL) { |
89 | throw DeadlyExportError("could not open output .stl file: " + std::string(pFile)); |
90 | } |
91 | |
92 | outfile->Write( exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()),1); |
93 | } |
94 | |
95 | } // end of namespace Assimp |
96 | |
97 | |
98 | // ------------------------------------------------------------------------------------------------ |
99 | STLExporter :: STLExporter(const char* _filename, const aiScene* pScene, bool binary) |
100 | : filename(_filename) |
101 | , endl("\n" ) |
102 | { |
103 | // make sure that all formatting happens using the standard, C locale and not the user's current locale |
104 | const std::locale& l = std::locale("C" ); |
105 | mOutput.imbue(l); |
106 | mOutput.precision(16); |
107 | if (binary) { |
108 | char buf[80] = {0} ; |
109 | buf[0] = 'A'; buf[1] = 's'; buf[2] = 's'; buf[3] = 'i'; buf[4] = 'm'; buf[5] = 'p'; |
110 | buf[6] = 'S'; buf[7] = 'c'; buf[8] = 'e'; buf[9] = 'n'; buf[10] = 'e'; |
111 | mOutput.write(buf, 80); |
112 | unsigned int meshnum = 0; |
113 | for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) { |
114 | for (unsigned int j = 0; j < pScene->mMeshes[i]->mNumFaces; ++j) { |
115 | meshnum++; |
116 | } |
117 | } |
118 | AI_SWAP4(meshnum); |
119 | mOutput.write((char *)&meshnum, 4); |
120 | for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) { |
121 | WriteMeshBinary(pScene->mMeshes[i]); |
122 | } |
123 | } else { |
124 | const std::string& name = "AssimpScene" ; |
125 | |
126 | mOutput << "solid " << name << endl; |
127 | for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) { |
128 | WriteMesh(pScene->mMeshes[i]); |
129 | } |
130 | mOutput << "endsolid " << name << endl; |
131 | } |
132 | } |
133 | |
134 | // ------------------------------------------------------------------------------------------------ |
135 | void STLExporter :: WriteMesh(const aiMesh* m) |
136 | { |
137 | for (unsigned int i = 0; i < m->mNumFaces; ++i) { |
138 | const aiFace& f = m->mFaces[i]; |
139 | |
140 | // we need per-face normals. We specified aiProcess_GenNormals as pre-requisite for this exporter, |
141 | // but nonetheless we have to expect per-vertex normals. |
142 | aiVector3D nor; |
143 | if (m->mNormals) { |
144 | for(unsigned int a = 0; a < f.mNumIndices; ++a) { |
145 | nor += m->mNormals[f.mIndices[a]]; |
146 | } |
147 | nor.Normalize(); |
148 | } |
149 | mOutput << " facet normal " << nor.x << " " << nor.y << " " << nor.z << endl; |
150 | mOutput << " outer loop" << endl; |
151 | for(unsigned int a = 0; a < f.mNumIndices; ++a) { |
152 | const aiVector3D& v = m->mVertices[f.mIndices[a]]; |
153 | mOutput << " vertex " << v.x << " " << v.y << " " << v.z << endl; |
154 | } |
155 | |
156 | mOutput << " endloop" << endl; |
157 | mOutput << " endfacet" << endl << endl; |
158 | } |
159 | } |
160 | |
161 | void STLExporter :: WriteMeshBinary(const aiMesh* m) |
162 | { |
163 | for (unsigned int i = 0; i < m->mNumFaces; ++i) { |
164 | const aiFace& f = m->mFaces[i]; |
165 | // we need per-face normals. We specified aiProcess_GenNormals as pre-requisite for this exporter, |
166 | // but nonetheless we have to expect per-vertex normals. |
167 | aiVector3D nor; |
168 | if (m->mNormals) { |
169 | for(unsigned int a = 0; a < f.mNumIndices; ++a) { |
170 | nor += m->mNormals[f.mIndices[a]]; |
171 | } |
172 | nor.Normalize(); |
173 | } |
174 | ai_real nx = nor.x, ny = nor.y, nz = nor.z; |
175 | AI_SWAP4(nx); AI_SWAP4(ny); AI_SWAP4(nz); |
176 | mOutput.write((char *)&nx, 4); mOutput.write((char *)&ny, 4); mOutput.write((char *)&nz, 4); |
177 | for(unsigned int a = 0; a < f.mNumIndices; ++a) { |
178 | const aiVector3D& v = m->mVertices[f.mIndices[a]]; |
179 | ai_real vx = v.x, vy = v.y, vz = v.z; |
180 | AI_SWAP4(vx); AI_SWAP4(vy); AI_SWAP4(vz); |
181 | mOutput.write((char *)&vx, 4); mOutput.write((char *)&vy, 4); mOutput.write((char *)&vz, 4); |
182 | } |
183 | char dummy[2] = {0}; |
184 | mOutput.write(dummy, 2); |
185 | } |
186 | } |
187 | |
188 | #endif |
189 | |