1/*
2Open Asset Import Library (assimp)
3----------------------------------------------------------------------
4
5Copyright (c) 2006-2017, assimp team
6
7All rights reserved.
8
9Redistribution and use of this software in source and binary forms,
10with or without modification, are permitted provided that the
11following 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
27THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37OF 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
55using namespace Assimp;
56namespace Assimp {
57
58// ------------------------------------------------------------------------------------------------
59// Worker function for exporting a scene to Stereolithograpy. Prototyped and registered in Exporter.cpp
60void 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}
77void 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// ------------------------------------------------------------------------------------------------
99STLExporter :: 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// ------------------------------------------------------------------------------------------------
135void 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
161void 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