Developer Documentation

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
OBJWriter.cc
1 /* ========================================================================= *
2 * *
3 * OpenMesh *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openmesh.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenMesh. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 * ========================================================================= */
41
42 /*===========================================================================*\
43 * *
44 * $Revision$ *
45 * $Date$ *
46 * *
47 \*===========================================================================*/
48
49
50 //== INCLUDES =================================================================
51
52
53 //STL
54 #include <fstream>
55 #include <limits>
56
57 // OpenMesh
58 #include <OpenMesh/Core/IO/BinaryHelper.hh>
59 #include <OpenMesh/Core/IO/writer/OBJWriter.hh>
60 #include <OpenMesh/Core/IO/IOManager.hh>
61 #include <OpenMesh/Core/Utils/color_cast.hh>
62
63 //=== NAMESPACES ==============================================================
64
65
66 namespace OpenMesh {
67 namespace IO {
68
69
70 //=== INSTANCIATE =============================================================
71
72
73 // register the OBJLoader singleton with MeshLoader
74 _OBJWriter_ __OBJWriterinstance;
75 _OBJWriter_& OBJWriter() { return __OBJWriterinstance; }
76
77
78 //=== IMPLEMENTATION ==========================================================
79
80
81 _OBJWriter_::_OBJWriter_() { IOManager().register_module(this); }
82
83
84 //-----------------------------------------------------------------------------
85
86
87 bool
88 _OBJWriter_::
89 write(const std::string& _filename, BaseExporter& _be, Options _opt, std::streamsize _precision) const
90 {
91 std::fstream out(_filename.c_str(), std::ios_base::out );
92
93 if (!out)
94 {
95 omerr() << "[OBJWriter] : cannot open file "
96 << _filename << std::endl;
97 return false;
98 }
99
100 out.precision(_precision);
101
102 {
103 #if defined(WIN32)
104 std::string::size_type dot = _filename.find_last_of("\\/");
105 #else
106 std::string::size_type dot = _filename.rfind("/");
107 #endif
108
109 if (dot == std::string::npos){
110 path_ = "./";
111 objName_ = _filename;
112 }else{
113 path_ = _filename.substr(0,dot+1);
114 objName_ = _filename.substr(dot+1);
115 }
116
117 //remove the file extension
118 dot = objName_.find_last_of(".");
119
120 if(dot != std::string::npos)
121 objName_ = objName_.substr(0,dot);
122 }
123
124 bool result = write(out, _be, _opt, _precision);
125
126 out.close();
127 return result;
128 }
129
130 //-----------------------------------------------------------------------------
131
132 size_t _OBJWriter_::getMaterial(OpenMesh::Vec3f _color) const
133 {
134 for (size_t i=0; i < material_.size(); i++)
135 if(material_[i] == _color)
136 return i;
137
138 //not found add new material
139 material_.push_back( _color );
140 return material_.size()-1;
141 }
142
143 //-----------------------------------------------------------------------------
144
145 size_t _OBJWriter_::getMaterial(OpenMesh::Vec4f _color) const
146 {
147 for (size_t i=0; i < materialA_.size(); i++)
148 if(materialA_[i] == _color)
149 return i;
150
151 //not found add new material
152 materialA_.push_back( _color );
153 return materialA_.size()-1;
154 }
155
156 //-----------------------------------------------------------------------------
157
158 bool
159 _OBJWriter_::
160 writeMaterial(std::ostream& _out, BaseExporter& _be, Options _opt) const
161 {
162 OpenMesh::Vec3f c;
163 OpenMesh::Vec4f cA;
164
165 material_.clear();
166 materialA_.clear();
167
168 //iterate over faces
169 for (size_t i=0, nF=_be.n_faces(); i<nF; ++i)
170 {
171 //color with alpha
172 if ( _opt.color_has_alpha() ){
173 cA = color_cast<OpenMesh::Vec4f> (_be.colorA( FaceHandle(int(i)) ));
174 getMaterial(cA);
175 }else{
176 //and without alpha
177 c = color_cast<OpenMesh::Vec3f> (_be.color( FaceHandle(int(i)) ));
178 getMaterial(c);
179 }
180 }
181
182 //write the materials
183 if ( _opt.color_has_alpha() )
184 for (size_t i=0; i < materialA_.size(); i++){
185 _out << "newmtl " << "mat" << i << '\n';
186 _out << "Ka 0.5000 0.5000 0.5000" << '\n';
187 _out << "Kd " << materialA_[i][0] << ' ' << materialA_[i][1] << ' ' << materialA_[i][2] << '\n';
188 _out << "Tr " << materialA_[i][3] << '\n';
189 _out << "illum 1" << '\n';
190 }
191 else
192 for (size_t i=0; i < material_.size(); i++){
193 _out << "newmtl " << "mat" << i << '\n';
194 _out << "Ka 0.5000 0.5000 0.5000" << '\n';
195 _out << "Kd " << material_[i][0] << ' ' << material_[i][1] << ' ' << material_[i][2] << '\n';
196 _out << "illum 1" << '\n';
197 }
198
199 return true;
200 }
201
202 //-----------------------------------------------------------------------------
203
204
205 bool
206 _OBJWriter_::
207 write(std::ostream& _out, BaseExporter& _be, Options _opt, std::streamsize _precision) const
208 {
209 unsigned int idx;
210 size_t i, j,nV, nF;
211 Vec3f v, n;
212 Vec2f t;
213 VertexHandle vh;
214 std::vector<VertexHandle> vhandles;
215 bool useMatrial = false;
216 OpenMesh::Vec3f c;
217 OpenMesh::Vec4f cA;
218
219 omlog() << "[OBJWriter] : write file\n";
220
221 _out.precision(_precision);
222
223 // check exporter features
224 if (!check( _be, _opt))
225 return false;
226
227
228 // check writer features
229 if ( _opt.check(Options::Binary) || // not supported by format
230 _opt.check(Options::FaceNormal))
231 return false;
232
233
234 //create material file if needed
235 if ( _opt.check(Options::FaceColor) ){
236
237 std::string matFile = path_ + objName_ + ".mat";
238
239 std::fstream matStream(matFile.c_str(), std::ios_base::out );
240
241 if (!matStream)
242 {
243 omerr() << "[OBJWriter] : cannot write material file " << matFile << std::endl;
244
245 }else{
246 useMatrial = writeMaterial(matStream, _be, _opt);
247
248 matStream.close();
249 }
250 }
251
252 // header
253 _out << "# " << _be.n_vertices() << " vertices, ";
254 _out << _be.n_faces() << " faces" << '\n';
255
256 // material file
257 if (useMatrial && _opt.check(Options::FaceColor) )
258 _out << "mtllib " << objName_ << ".mat" << '\n';
259
260 // vertex data (point, normals, texcoords)
261 for (i=0, nV=_be.n_vertices(); i<nV; ++i)
262 {
263 vh = VertexHandle(int(i));
264 v = _be.point(vh);
265 n = _be.normal(vh);
266 t = _be.texcoord(vh);
267
268 _out << "v " << v[0] <<" "<< v[1] <<" "<< v[2] << '\n';
269
270 if (_opt.check(Options::VertexNormal))
271 _out << "vn " << n[0] <<" "<< n[1] <<" "<< n[2] << '\n';
272
273 if (_opt.check(Options::VertexTexCoord))
274 _out << "vt " << t[0] <<" "<< t[1] << '\n';
275 }
276
277 size_t lastMat = std::numeric_limits<std::size_t>::max();
278
279 // we do not want to write seperators if we only write vertex indices
280 bool onlyVertices = !_opt.check(Options::VertexTexCoord)
281 && !_opt.check(Options::VertexNormal);
282
283 // faces (indices starting at 1 not 0)
284 for (i=0, nF=_be.n_faces(); i<nF; ++i)
285 {
286
287 if (useMatrial && _opt.check(Options::FaceColor) ){
288 size_t material = std::numeric_limits<std::size_t>::max();
289
290 //color with alpha
291 if ( _opt.color_has_alpha() ){
292 cA = color_cast<OpenMesh::Vec4f> (_be.colorA( FaceHandle(int(i)) ));
293 material = getMaterial(cA);
294 } else{
295 //and without alpha
296 c = color_cast<OpenMesh::Vec3f> (_be.color( FaceHandle(int(i)) ));
297 material = getMaterial(c);
298 }
299
300 // if we are ina a new material block, specify in the file which material to use
301 if(lastMat != material) {
302 _out << "usemtl mat" << material << '\n';
303 lastMat = material;
304 }
305 }
306
307 _out << "f";
308
309 _be.get_vhandles(FaceHandle(int(i)), vhandles);
310
311 for (j=0; j< vhandles.size(); ++j)
312 {
313
314 // Write vertex index
315 idx = vhandles[j].idx() + 1;
316 _out << " " << idx;
317
318 if (!onlyVertices) {
319 // write separator
320 _out << "/" ;
321
322 // write vertex texture coordinate index
323 if (_opt.check(Options::VertexTexCoord))
324 _out << idx;
325
326 // write vertex normal index
327 if ( _opt.check(Options::VertexNormal) ) {
328 // write separator
329 _out << "/" ;
330 _out << idx;
331 }
332 }
333 }
334
335 _out << '\n';
336 }
337
338 material_.clear();
339 materialA_.clear();
340
341 return true;
342 }
343
344
345 //=============================================================================
346 } // namespace IO
347 } // namespace OpenMesh
348 //=============================================================================
OpenMesh::IO::Options::VertexNormal
Has (r) / store (w) vertex normals.
Definition: Options.hh:109
OpenMesh
Definition: MeshItems.hh:64
OpenMesh::IO::_IOManager_::register_module
bool register_module(BaseReader *_bl)
Definition: IOManager.hh:222
OpenMesh::IO::Options::FaceNormal
Has (r) / store (w) face normals.
Definition: Options.hh:113
OpenMesh::IO::_OBJWriter_
Definition: OBJWriter.hh:87
OpenMesh::IO::Options::FaceColor
Has (r) / store (w) face colors.
Definition: Options.hh:114
OpenMesh::IO::Options::VertexTexCoord
Has (r) / store (w) texture coordinates.
Definition: Options.hh:111
OpenMesh::IO::Options
Set options for reader/writer modules.
Definition: Options.hh:95
OpenMesh::IO::BaseExporter
Definition: BaseExporter.hh:89
OpenMesh::VectorT< float, 3 >
OpenMesh::VertexHandle
Handle for a vertex entity.
Definition: Handles.hh:125
OpenMesh::FaceHandle
Handle for a face entity.
Definition: Handles.hh:146
OpenMesh::dot
osg::Vec3f::ValueType dot(const osg::Vec3f &_v1, const osg::Vec3f &_v2)
Adapter for osg vector member computing a scalar product.
Definition: VectorAdapter.hh:181
OpenMesh::IO::Options::Binary
Set binary mode for r/w.
Definition: Options.hh:105
OpenMesh::IO::_OBJWriter_::write
bool write(const std::string &, BaseExporter &, Options, std::streamsize _precision=6) const
Definition: OBJWriter.cc:89
OpenMesh::IO::__OBJWriterinstance
_OBJWriter_ __OBJWriterinstance
Declare the single entity of the OBJ writer.
Definition: OBJWriter.cc:74
BaseExporter
Definition: BaseExporter.hh:1
OpenMesh::IO::IOManager
_IOManager_ & IOManager()
Definition: IOManager.cc:77